Browse Source

Add requests::downloadFile

ithewei 3 years ago
parent
commit
33320d29c6
5 changed files with 76 additions and 16 deletions
  1. 2 3
      cpputil/hmap.h
  2. 2 1
      cpputil/hstring.cpp
  3. 2 1
      cpputil/hstring.h
  4. 14 8
      examples/http_client_test.cpp
  5. 56 3
      http/client/requests.h

+ 2 - 3
cpputil/hmap.h

@@ -46,11 +46,10 @@ public:
 #endif
 
 // KeyValue
+namespace hv {
 typedef std::map<std::string, std::string>      keyval_t;
 typedef std::MultiMap<std::string, std::string> multi_keyval_t;
-
-namespace hv {
-typedef HV_MAP<std::string, std::string> KeyValue;
+typedef HV_MAP<std::string, std::string>        KeyValue;
 }
 
 #endif // HV_MAP_H_

+ 2 - 1
cpputil/hstring.cpp

@@ -7,7 +7,8 @@
 
 namespace hv {
 
-std::string empty_string;
+std::string                         empty_string;
+std::map<std::string, std::string>  empty_map;
 
 std::string& toupper(std::string& str) {
     // std::transform(str.begin(), str.end(), str.begin(), ::toupper);

+ 2 - 1
cpputil/hstring.h

@@ -16,7 +16,8 @@
 
 namespace hv {
 
-HV_EXPORT extern std::string empty_string;
+HV_EXPORT extern std::string                        empty_string;
+HV_EXPORT extern std::map<std::string, std::string> empty_map;
 
 typedef std::vector<std::string> StringList;
 

+ 14 - 8
examples/http_client_test.cpp

@@ -79,20 +79,26 @@ static void test_requests() {
     }
 
     // Content-Type: multipart/form-data
-    requests::Request req(new HttpRequest);
-    req->method = HTTP_POST;
-    req->url = "http://127.0.0.1:8080/echo";
-    req->content_type = MULTIPART_FORM_DATA;
-    req->SetFormData("username", "admin");
-    req->SetFormFile("avatar", "avatar.jpg");
-    resp = requests::request(req);
+    std::map<std::string, std::string> params;
+    params["user"] = "admin";
+    params["pswd"] = "123456";
+    resp = requests::uploadFormFile("http://127.0.0.1:8080/echo", "avatar", "avatar.jpg", params);
     if (resp == NULL) {
-        printf("request failed!\n");
+        printf("uploadFormFile failed!\n");
     } else {
         printf("%d %s\r\n", resp->status_code, resp->status_message());
         printf("%s\n", resp->body.c_str());
     }
 
+    /*
+    size_t filesize = requests::downloadFile("http://www.example.com/index.html", "index.html");
+    if (filesize == 0) {
+        printf("downloadFile failed!\n");
+    } else {
+        printf("downloadFile success!\n");
+    }
+    */
+
     // async
     /*
     // Request req(new HttpRequest);

+ 56 - 3
http/client/requests.h

@@ -58,7 +58,7 @@ HV_INLINE Response request(http_method method, const char* url, const http_body&
     return request(req);
 }
 
-HV_INLINE Response uploadFile(http_method method, const char* url, const char* filepath, const http_headers& headers = DefaultHeaders) {
+HV_INLINE Response uploadFile(const char* url, const char* filepath, http_method method = HTTP_POST, const http_headers& headers = DefaultHeaders) {
     Request req(new HttpRequest);
     req->method = method;
     req->url = url;
@@ -70,11 +70,15 @@ HV_INLINE Response uploadFile(http_method method, const char* url, const char* f
 }
 
 #ifndef WITHOUT_HTTP_CONTENT
-HV_INLINE Response uploadFormFile(http_method method, const char* url, const char* name, const char* filepath, const http_headers& headers = DefaultHeaders) {
+HV_INLINE Response uploadFormFile(const char* url, const char* name, const char* filepath, std::map<std::string, std::string>& params = hv::empty_map, http_method method = HTTP_POST, const http_headers& headers = DefaultHeaders) {
     Request req(new HttpRequest);
     req->method = method;
     req->url = url;
-    req->FormFile(name, filepath);
+    req->content_type = MULTIPART_FORM_DATA;
+    req->SetFormFile(name, filepath);
+    for (auto& param : params) {
+        req->SetFormData(param.first.c_str(), param.second);
+    }
     if (&headers != &DefaultHeaders) {
         req->headers = headers;
     }
@@ -82,6 +86,55 @@ HV_INLINE Response uploadFormFile(http_method method, const char* url, const cha
 }
 #endif
 
+// see examples/wget.cpp
+typedef std::function<void(size_t received_bytes, size_t total_bytes)> download_progress_cb;
+HV_INLINE size_t downloadFile(const char* url, const char* filepath, download_progress_cb progress_cb = NULL) {
+    // open file
+    std::string filepath_download(filepath);
+    filepath_download += ".download";
+    HFile file;
+    int ret = file.open(filepath_download.c_str(), "wb");
+    if (ret != 0) {
+        return 0;
+    }
+    // download
+    Request req(new HttpRequest);
+    req->method = HTTP_GET;
+    req->url = url;
+    size_t content_length = 0;
+    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"));
+        } else if (state == HP_BODY) {
+            if (data && size) {
+                // write file
+                file.write(data, size);
+                received_bytes += size;
+                if (progress_cb) {
+                    progress_cb(received_bytes, content_length);
+                }
+            }
+        }
+    };
+    auto resp = request(req);
+    file.close();
+    if (resp == NULL || resp->status_code != 200) {
+        return 0;
+    }
+    // check filesize
+    if (content_length != 0) {
+        if (hv_filesize(filepath_download.c_str()) == content_length) {
+            rename(filepath_download.c_str(), filepath);
+        } else {
+            remove(filepath_download.c_str());
+            return 0;
+        }
+    }
+    return hv_filesize(filepath);
+}
+
 HV_INLINE Response head(const char* url, const http_headers& headers = DefaultHeaders) {
     return request(HTTP_HEAD, url, NoBody, headers);
 }