Skip to content

Commit

Permalink
replace head_cb,body_cb,chunked_cb to http_cb
Browse files Browse the repository at this point in the history
  • Loading branch information
ithewei committed Mar 27, 2022
1 parent 89f2b62 commit f72c592
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 105 deletions.
2 changes: 1 addition & 1 deletion README-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ ab -c 100 -n 100000 http://127.0.0.1:8080/

- **libhv QQ群**: `739352073`,欢迎加群交流
- **libhv 源码剖析**: <https://hewei.blog.csdn.net/article/details/123295998>
- **libhv 教程**: <https://hewei.blog.csdn.net/article/details/113733758>
- **libhv 教程目录**: <https://hewei.blog.csdn.net/article/details/113733758>
- [libhv教程01--介绍与体验](https://hewei.blog.csdn.net/article/details/113702536)
- [libhv教程02--编译与安装](https://hewei.blog.csdn.net/article/details/113704737)
- [libhv教程03--链库与使用](https://hewei.blog.csdn.net/article/details/113706378)
Expand Down
31 changes: 11 additions & 20 deletions examples/curl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,24 +263,19 @@ int main(int argc, char* argv[]) {
}
}
req.url = url;

HttpResponse res;
/*
res.head_cb = [](const http_headers& headers){
if (verbose) {
for (auto& header : headers) {
fprintf(stderr, "%s: %s\r\n", header.first.c_str(), header.second.c_str());
req.http_cb = [](HttpMessage* res, http_parser_state state, const char* data, size_t size) {
if (state == HP_HEADERS_COMPLETE) {
if (verbose) {
fprintf(stderr, "%s", res->Dump(true, false).c_str());
}
} else if (state == HP_BODY) {
if (data && size) {
printf("%.*s", (int)size, data);
// This program no need to save data to body.
// res->body.append(data, size);
}
fprintf(stderr, "\r\n");
}
};
res.body_cb = [](const char* data, size_t size){
printf("%.*s", (int)size, data);
};
*/
res.chunked_cb = [](const char* data, size_t size){
printf("%.*s", (int)size, data);
};

hv::HttpClient cli;
// http_proxy
Expand Down Expand Up @@ -314,6 +309,7 @@ int main(int argc, char* argv[]) {
if (verbose) {
fprintf(stderr, "%s\n", req.Dump(true, true).c_str());
}
HttpResponse res;
ret = cli.send(&req, &res);
if (ret != 0) {
fprintf(stderr, "* Failed:%s:%d\n", http_client_strerror(ret), ret);
Expand All @@ -323,11 +319,6 @@ int main(int argc, char* argv[]) {
hv_sleep(retry_delay);
goto send;
}
} else {
if (verbose) {
fprintf(stderr, "%s", res.Dump(true, false).c_str());
}
printf("%s", res.body.c_str());
}
if (--send_count > 0) {
fprintf(stderr, "\nsend again later...%d\n", send_count);
Expand Down
106 changes: 69 additions & 37 deletions examples/wget.cpp
Original file line number Diff line number Diff line change
@@ -1,86 +1,101 @@
/*
* @build: make examples
* @server bin/httpd -s restart -d
* @client bin/wget 127.0.0.1:8080/
* @client bin/wget http://127.0.0.1:8080/
*/

#include "requests.h"
#include "http_client.h"
#include "htime.h"
using namespace hv;

static int wget(const char* url, const char* filepath) {
typedef std::function<void(size_t received_bytes, size_t total_bytes)> wget_progress_cb;

static int wget(const char* url, const char* filepath, wget_progress_cb progress_cb = NULL) {
HFile file;
if (file.open(filepath, "wb") != 0) {
fprintf(stderr, "Failed to open file %s\n", filepath);
return -20;
}
printf("Save file to %s ...\n", filepath);

HttpClient cli;
HttpRequest req;
req.url = url;
HttpResponse resp;

// HEAD
auto resp = requests::head(url);
if (resp == NULL) {
fprintf(stderr, "request failed!\n");
req.method = HTTP_HEAD;
int ret = cli.send(&req, &resp);
if (ret != 0) {
fprintf(stderr, "request error: %d\n", ret);
return -1;
}
printd("%s", resp->Dump(true, false).c_str());
if (resp->status_code == HTTP_STATUS_NOT_FOUND) {
printd("%s", resp.Dump(true, false).c_str());
if (resp.status_code == HTTP_STATUS_NOT_FOUND) {
fprintf(stderr, "404 Not Found\n");
return -1;
}

bool use_range = false;
int range_bytes = 1 << 20; // 1M
std::string accept_ranges = resp->GetHeader("Accept-Ranges");
size_t content_length = hv::from_string<size_t>(resp->GetHeader("Content-Length"));
std::string accept_ranges = resp.GetHeader("Accept-Ranges");
size_t content_length = hv::from_string<size_t>(resp.GetHeader("Content-Length"));
// use Range if server accept_ranges and content_length > 1M
if (resp->status_code == 200 &&
if (resp.status_code == 200 &&
accept_ranges == "bytes" &&
content_length > range_bytes) {
use_range = true;
}

// GET
req.method = HTTP_GET;
req.timeout = 3600; // 1h
if (!use_range) {
resp = requests::get(url);
if (resp == NULL) {
fprintf(stderr, "request failed!\n");
size_t received_bytes = 0;
req.http_cb = [&file, &content_length, &received_bytes, &progress_cb]
(HttpMessage* resp, http_parser_state state, const char* data, size_t size) {
if (state == HP_HEADERS_COMPLETE) {
content_length = hv::from_string<size_t>(resp->GetHeader("Content-Length"));
printd("%s", resp->Dump(true, false).c_str());
} else if (state == HP_BODY) {
if (data && size) {
file.write(data, size);
received_bytes += size;

if (progress_cb) {
progress_cb(received_bytes, content_length);
}
}
}
};
ret = cli.send(&req, &resp);
if (ret != 0) {
fprintf(stderr, "request error: %d\n", ret);
return -1;
}
printd("%s", resp->Dump(true, false).c_str());
file.write(resp->body.data(), resp->body.size());
printf("progress: %ld/%ld = 100%%\n", (long)resp->body.size(), (long)resp->body.size());
return 0;
}

// Range: bytes=from-to
long from = 0, to = 0;
int last_progress = 0;
http_client_t* cli = http_client_new();
HttpRequestPtr req(new HttpRequest);
req->method = HTTP_GET;
req->url = url;
while (from < content_length) {
to = from + range_bytes - 1;
if (to >= content_length) to = content_length - 1;
req->SetRange(from, to);
printd("%s", req->Dump(true, false).c_str());
int ret = http_client_send(cli, req.get(), resp.get());
req.SetRange(from, to);
printd("%s", req.Dump(true, false).c_str());
ret = cli.send(&req, &resp);
if (ret != 0) {
fprintf(stderr, "request failed!\n");
fprintf(stderr, "request error: %d\n", ret);
return -1;
}
printd("%s", resp->Dump(true, false).c_str());
file.write(resp->body.data(), resp->body.size());
printd("%s", resp.Dump(true, false).c_str());
file.write(resp.body.data(), resp.body.size());
from = to + 1;

// print progress
int cur_progress = from * 100 / content_length;
if (cur_progress > last_progress) {
printf("\rprogress: %ld/%ld = %d%%", (long)from, (long)content_length, (int)cur_progress);
fflush(stdout);
last_progress = cur_progress;
if (progress_cb) {
progress_cb(from, content_length);
}
}
printf("\n");
http_client_del(cli);

return 0;
}
Expand All @@ -101,6 +116,23 @@ int main(int argc, char** argv) {
}
}

wget(url, filepath);
unsigned int start_time = gettick_ms();
int last_progress = 0;
wget(url, filepath, [&last_progress](size_t received_bytes, size_t total_bytes) {
// print progress
if (total_bytes == 0) {
printf("\rprogress: %lu/? = ?", (unsigned long)received_bytes);
} else {
int cur_progress = received_bytes * 100 / total_bytes;
if (cur_progress > last_progress) {
printf("\rprogress: %lu/%lu = %d%%", (unsigned long)received_bytes, (unsigned long)total_bytes, (int)cur_progress);
last_progress = cur_progress;
}
}
fflush(stdout);
});
unsigned int end_time = gettick_ms();
printf("\ncost time %u ms\n", end_time - start_time);

return 0;
}
4 changes: 2 additions & 2 deletions examples/wrk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ typedef struct connection_s {
, ok_cnt(0)
, readbytes(0)
{
response->body_cb = [](const char* data, size_t size) {
// No need to save data
response->http_cb = [](HttpMessage* res, http_parser_state state, const char* data, size_t size) {
// wrk no need to save data to body
};
}

Expand Down
18 changes: 7 additions & 11 deletions http/Http1Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,7 @@ int on_body(http_parser* parser, const char *at, size_t length) {
// printd("on_body:%.*s\n", (int)length, at);
Http1Parser* hp = (Http1Parser*)parser->data;
hp->state = HP_BODY;
if (hp->parsed->body_cb) {
hp->parsed->body_cb(at, length);
} else {
if (hp->invokeHttpCb(at, length) != 0) {
hp->parsed->body.append(at, length);
}
return 0;
Expand All @@ -87,6 +85,7 @@ int on_message_begin(http_parser* parser) {
printd("on_message_begin\n");
Http1Parser* hp = (Http1Parser*)parser->data;
hp->state = HP_MESSAGE_BEGIN;
hp->invokeHttpCb();
return 0;
}

Expand Down Expand Up @@ -126,38 +125,35 @@ int on_headers_complete(http_parser* parser) {
}
}
hp->state = HP_HEADERS_COMPLETE;
if (hp->parsed->head_cb) {
hp->parsed->head_cb(hp->parsed->headers);
}
hp->invokeHttpCb();
return skip_body ? 1 : 0;
}

int on_message_complete(http_parser* parser) {
printd("on_message_complete\n");
Http1Parser* hp = (Http1Parser*)parser->data;
hp->state = HP_MESSAGE_COMPLETE;
hp->invokeHttpCb();
return 0;
}

int on_chunk_header(http_parser* parser) {
printd("on_chunk_header:%llu\n", parser->content_length);
Http1Parser* hp = (Http1Parser*)parser->data;
hp->state = HP_CHUNK_HEADER;
int chunk_size = parser->content_length;
int reserve_size = MIN(chunk_size + 1, MAX_CONTENT_LENGTH);
if (reserve_size > hp->parsed->body.capacity()) {
hp->parsed->body.reserve(reserve_size);
}
hp->state = HP_CHUNK_HEADER;
hp->invokeHttpCb(NULL, chunk_size);
return 0;
}

int on_chunk_complete(http_parser* parser) {
printd("on_chunk_complete\n");
Http1Parser* hp = (Http1Parser*)parser->data;
hp->state = HP_CHUNK_COMPLETE;
if (hp->parsed->chunked_cb) {
hp->parsed->chunked_cb(hp->parsed->body.c_str(), hp->parsed->body.size());
hp->parsed->body.clear();
}
hp->invokeHttpCb();
return 0;
}
21 changes: 7 additions & 14 deletions http/Http1Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,6 @@
#include "HttpParser.h"
#include "http_parser.h"

enum http_parser_state {
HP_START_REQ_OR_RES,
HP_MESSAGE_BEGIN,
HP_URL,
HP_STATUS,
HP_HEADER_FIELD,
HP_HEADER_VALUE,
HP_HEADERS_COMPLETE,
HP_CHUNK_HEADER,
HP_BODY,
HP_CHUNK_COMPLETE,
HP_MESSAGE_COMPLETE
};

class Http1Parser : public HttpParser {
public:
static http_parser_settings cbs;
Expand Down Expand Up @@ -132,6 +118,13 @@ class Http1Parser : public HttpParser {
submited = res;
return 0;
}

// HttpMessage::http_cb
int invokeHttpCb(const char* data = NULL, size_t size = 0) {
if (parsed->http_cb == NULL) return -1;
parsed->http_cb(parsed, state, data, size);
return 0;
}
};

#endif // HV_HTTP1_PARSER_H_
9 changes: 2 additions & 7 deletions http/HttpMessage.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,6 @@ typedef std::map<std::string, std::string, hv::StringCaseLess> http_headers;
typedef std::vector<HttpCookie> http_cookies;
typedef std::string http_body;

typedef std::function<void(const http_headers& headers)> http_head_cb;
typedef std::function<void(const char* data, size_t size)> http_body_cb;
typedef std::function<void(const char* data, size_t size)> http_chunked_cb;

HV_EXPORT extern http_headers DefaultHeaders;
HV_EXPORT extern http_body NoBody;

Expand All @@ -106,9 +102,8 @@ class HV_EXPORT HttpMessage {
http_cookies cookies;
http_body body;

http_head_cb head_cb;
http_body_cb body_cb;
http_chunked_cb chunked_cb; // Transfer-Encoding: chunked
// http_cb
std::function<void(HttpMessage*, http_parser_state state, const char* data, size_t size)> http_cb;

// structured content
void* content; // DATA_NO_COPY
Expand Down
4 changes: 1 addition & 3 deletions http/client/AsyncHttpClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,7 @@ int AsyncHttpClient::sendRequest(const SocketChannelPtr& channel) {
resp = new HttpResponse;
ctx->resp.reset(resp);
}
if (req->head_cb) resp->head_cb = std::move(req->head_cb);
if (req->body_cb) resp->body_cb = std::move(req->body_cb);
if (req->chunked_cb) resp->chunked_cb = std::move(req->chunked_cb);
if (req->http_cb) resp->http_cb = std::move(req->http_cb);

ctx->parser->InitResponse(resp);
ctx->parser->SubmitRequest(req);
Expand Down
Loading

0 comments on commit f72c592

Please sign in to comment.