Forráskód Böngészése

replace head_cb,body_cb,chunked_cb to http_cb

ithewei 3 éve
szülő
commit
f72c592b0f

+ 1 - 1
README-CN.md

@@ -477,7 +477,7 @@ ab -c 100 -n 100000 http://127.0.0.1:8080/
 
 
 - **libhv QQ群**: `739352073`,欢迎加群交流
 - **libhv QQ群**: `739352073`,欢迎加群交流
 - **libhv 源码剖析**: <https://hewei.blog.csdn.net/article/details/123295998>
 - **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教程01--介绍与体验](https://hewei.blog.csdn.net/article/details/113702536)
 - [libhv教程02--编译与安装](https://hewei.blog.csdn.net/article/details/113704737)
 - [libhv教程02--编译与安装](https://hewei.blog.csdn.net/article/details/113704737)
 - [libhv教程03--链库与使用](https://hewei.blog.csdn.net/article/details/113706378)
 - [libhv教程03--链库与使用](https://hewei.blog.csdn.net/article/details/113706378)

+ 11 - 20
examples/curl.cpp

@@ -263,24 +263,19 @@ int main(int argc, char* argv[]) {
         }
         }
     }
     }
     req.url = url;
     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;
     hv::HttpClient cli;
     // http_proxy
     // http_proxy
@@ -314,6 +309,7 @@ send:
     if (verbose) {
     if (verbose) {
         fprintf(stderr, "%s\n", req.Dump(true, true).c_str());
         fprintf(stderr, "%s\n", req.Dump(true, true).c_str());
     }
     }
+    HttpResponse res;
     ret = cli.send(&req, &res);
     ret = cli.send(&req, &res);
     if (ret != 0) {
     if (ret != 0) {
         fprintf(stderr, "* Failed:%s:%d\n", http_client_strerror(ret), ret);
         fprintf(stderr, "* Failed:%s:%d\n", http_client_strerror(ret), ret);
@@ -323,11 +319,6 @@ send:
             hv_sleep(retry_delay);
             hv_sleep(retry_delay);
             goto send;
             goto send;
         }
         }
-    } else {
-        if (verbose) {
-            fprintf(stderr, "%s", res.Dump(true, false).c_str());
-        }
-        printf("%s", res.body.c_str());
     }
     }
     if (--send_count > 0) {
     if (--send_count > 0) {
         fprintf(stderr, "\nsend again later...%d\n", send_count);
         fprintf(stderr, "\nsend again later...%d\n", send_count);

+ 69 - 37
examples/wget.cpp

@@ -1,12 +1,16 @@
 /*
 /*
  * @build: make examples
  * @build: make examples
  * @server bin/httpd -s restart -d
  * @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;
     HFile file;
     if (file.open(filepath, "wb") != 0) {
     if (file.open(filepath, "wb") != 0) {
         fprintf(stderr, "Failed to open file %s\n", filepath);
         fprintf(stderr, "Failed to open file %s\n", filepath);
@@ -14,73 +18,84 @@ static int wget(const char* url, const char* filepath) {
     }
     }
     printf("Save file to %s ...\n", filepath);
     printf("Save file to %s ...\n", filepath);
 
 
+    HttpClient cli;
+    HttpRequest req;
+    req.url = url;
+    HttpResponse resp;
+
     // HEAD
     // 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;
         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");
         fprintf(stderr, "404 Not Found\n");
         return -1;
         return -1;
     }
     }
 
 
     bool use_range = false;
     bool use_range = false;
     int range_bytes = 1 << 20; // 1M
     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
     // use Range if server accept_ranges and content_length > 1M
-    if (resp->status_code == 200 &&
+    if (resp.status_code == 200 &&
         accept_ranges == "bytes" &&
         accept_ranges == "bytes" &&
         content_length > range_bytes) {
         content_length > range_bytes) {
         use_range = true;
         use_range = true;
     }
     }
 
 
     // GET
     // GET
+    req.method = HTTP_GET;
+    req.timeout = 3600; // 1h
     if (!use_range) {
     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;
             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;
         return 0;
     }
     }
 
 
     // Range: bytes=from-to
     // Range: bytes=from-to
     long from = 0, to = 0;
     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) {
     while (from < content_length) {
         to = from + range_bytes - 1;
         to = from + range_bytes - 1;
         if (to >= content_length) to = content_length - 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) {
         if (ret != 0) {
-            fprintf(stderr, "request failed!\n");
+            fprintf(stderr, "request error: %d\n", ret);
             return -1;
             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;
         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;
     return 0;
 }
 }
@@ -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;
     return 0;
 }
 }

+ 2 - 2
examples/wrk.cpp

@@ -57,8 +57,8 @@ typedef struct connection_s {
         , ok_cnt(0)
         , ok_cnt(0)
         , readbytes(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
         };
         };
     }
     }
 
 

+ 7 - 11
http/Http1Parser.cpp

@@ -75,9 +75,7 @@ int on_body(http_parser* parser, const char *at, size_t length) {
     // printd("on_body:%.*s\n", (int)length, at);
     // printd("on_body:%.*s\n", (int)length, at);
     Http1Parser* hp = (Http1Parser*)parser->data;
     Http1Parser* hp = (Http1Parser*)parser->data;
     hp->state = HP_BODY;
     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);
         hp->parsed->body.append(at, length);
     }
     }
     return 0;
     return 0;
@@ -87,6 +85,7 @@ int on_message_begin(http_parser* parser) {
     printd("on_message_begin\n");
     printd("on_message_begin\n");
     Http1Parser* hp = (Http1Parser*)parser->data;
     Http1Parser* hp = (Http1Parser*)parser->data;
     hp->state = HP_MESSAGE_BEGIN;
     hp->state = HP_MESSAGE_BEGIN;
+    hp->invokeHttpCb();
     return 0;
     return 0;
 }
 }
 
 
@@ -126,9 +125,7 @@ int on_headers_complete(http_parser* parser) {
         }
         }
     }
     }
     hp->state = HP_HEADERS_COMPLETE;
     hp->state = HP_HEADERS_COMPLETE;
-    if (hp->parsed->head_cb) {
-        hp->parsed->head_cb(hp->parsed->headers);
-    }
+    hp->invokeHttpCb();
     return skip_body ? 1 : 0;
     return skip_body ? 1 : 0;
 }
 }
 
 
@@ -136,18 +133,20 @@ int on_message_complete(http_parser* parser) {
     printd("on_message_complete\n");
     printd("on_message_complete\n");
     Http1Parser* hp = (Http1Parser*)parser->data;
     Http1Parser* hp = (Http1Parser*)parser->data;
     hp->state = HP_MESSAGE_COMPLETE;
     hp->state = HP_MESSAGE_COMPLETE;
+    hp->invokeHttpCb();
     return 0;
     return 0;
 }
 }
 
 
 int on_chunk_header(http_parser* parser) {
 int on_chunk_header(http_parser* parser) {
     printd("on_chunk_header:%llu\n", parser->content_length);
     printd("on_chunk_header:%llu\n", parser->content_length);
     Http1Parser* hp = (Http1Parser*)parser->data;
     Http1Parser* hp = (Http1Parser*)parser->data;
-    hp->state = HP_CHUNK_HEADER;
     int chunk_size = parser->content_length;
     int chunk_size = parser->content_length;
     int reserve_size = MIN(chunk_size + 1, MAX_CONTENT_LENGTH);
     int reserve_size = MIN(chunk_size + 1, MAX_CONTENT_LENGTH);
     if (reserve_size > hp->parsed->body.capacity()) {
     if (reserve_size > hp->parsed->body.capacity()) {
         hp->parsed->body.reserve(reserve_size);
         hp->parsed->body.reserve(reserve_size);
     }
     }
+    hp->state = HP_CHUNK_HEADER;
+    hp->invokeHttpCb(NULL, chunk_size);
     return 0;
     return 0;
 }
 }
 
 
@@ -155,9 +154,6 @@ int on_chunk_complete(http_parser* parser) {
     printd("on_chunk_complete\n");
     printd("on_chunk_complete\n");
     Http1Parser* hp = (Http1Parser*)parser->data;
     Http1Parser* hp = (Http1Parser*)parser->data;
     hp->state = HP_CHUNK_COMPLETE;
     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;
     return 0;
 }
 }

+ 7 - 14
http/Http1Parser.h

@@ -4,20 +4,6 @@
 #include "HttpParser.h"
 #include "HttpParser.h"
 #include "http_parser.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 {
 class Http1Parser : public HttpParser {
 public:
 public:
     static http_parser_settings     cbs;
     static http_parser_settings     cbs;
@@ -132,6 +118,13 @@ public:
         submited = res;
         submited = res;
         return 0;
         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_
 #endif // HV_HTTP1_PARSER_H_

+ 2 - 7
http/HttpMessage.h

@@ -88,10 +88,6 @@ typedef std::map<std::string, std::string, hv::StringCaseLess>  http_headers;
 typedef std::vector<HttpCookie>                                 http_cookies;
 typedef std::vector<HttpCookie>                                 http_cookies;
 typedef std::string                                             http_body;
 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_headers DefaultHeaders;
 HV_EXPORT extern http_body    NoBody;
 HV_EXPORT extern http_body    NoBody;
 
 
@@ -106,9 +102,8 @@ public:
     http_cookies        cookies;
     http_cookies        cookies;
     http_body           body;
     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
     // structured content
     void*               content;    // DATA_NO_COPY
     void*               content;    // DATA_NO_COPY

+ 1 - 3
http/client/AsyncHttpClient.cpp

@@ -144,9 +144,7 @@ int AsyncHttpClient::sendRequest(const SocketChannelPtr& channel) {
         resp = new HttpResponse;
         resp = new HttpResponse;
         ctx->resp.reset(resp);
         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->InitResponse(resp);
     ctx->parser->SubmitRequest(req);
     ctx->parser->SubmitRequest(req);

+ 9 - 10
http/client/http_client.cpp

@@ -225,9 +225,7 @@ int http_client_send(http_client_t* cli, HttpRequest* req, HttpResponse* resp) {
 
 
     http_client_make_request(cli, req);
     http_client_make_request(cli, req);
 
 
-    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);
 
 
     int ret = __http_client_send(cli, req, resp);
     int ret = __http_client_send(cli, req, resp);
     if (ret != 0) return ret;
     if (ret != 0) return ret;
@@ -295,13 +293,14 @@ static size_t s_header_cb(char* buf, size_t size, size_t cnt, void* userdata) {
 static size_t s_body_cb(char* buf, size_t size, size_t cnt, void *userdata) {
 static size_t s_body_cb(char* buf, size_t size, size_t cnt, void *userdata) {
     if (buf == NULL || userdata == NULL)    return 0;
     if (buf == NULL || userdata == NULL)    return 0;
     size_t len = size * cnt;
     size_t len = size * cnt;
-    HttpResponse* resp = (HttpResponse*)userdata;
-    if (resp->head_cb) {
-        resp->head_cb(resp->headers);
-        resp->head_cb = NULL;
-    }
-    if (resp->body_cb) {
-        resp->body_cb(buf, len);
+    HttpMessage* resp = (HttpMessage*)userdata;
+    if (resp->http_cb) {
+        if (resp->content == NULL && resp->content_length == 0) {
+            resp->content = buf;
+            resp->content_length = len;
+            resp->http_cb(resp, HP_HEADERS_COMPLETE, NULL, 0);
+        }
+        resp->http_cb(resp, HP_BODY, buf, len);
     } else {
     } else {
         resp->body.append(buf, len);
         resp->body.append(buf, len);
     }
     }

+ 13 - 0
http/httpdef.h

@@ -9,6 +9,19 @@
 enum http_version { HTTP_V1 = 1, HTTP_V2 = 2 };
 enum http_version { HTTP_V1 = 1, HTTP_V2 = 2 };
 enum http_session_type { HTTP_CLIENT, HTTP_SERVER };
 enum http_session_type { HTTP_CLIENT, HTTP_SERVER };
 enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
 enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
+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
+};
 
 
 // http_status
 // http_status
 // XX(num, name, string)
 // XX(num, name, string)