├── win-vsproj ├── example │ ├── .gitignore │ ├── example.vcxproj.user │ ├── .editorconfig │ ├── example.vcxproj.filters │ └── example.vcxproj ├── iclient │ ├── iclient.vcxproj.user │ ├── .editorconfig │ ├── iclient.vcxproj.filters │ └── iclient.vcxproj └── iclient.sln ├── .gitignore ├── assets └── README │ ├── download_range.jpg │ ├── release-v1.0.1.jpg │ └── breakpoint_continue.jpg ├── include ├── iclient │ ├── iclient.h │ ├── curl_inc.h │ ├── url.h │ ├── response.h │ ├── http.h │ └── request.h └── curl │ ├── stdcheaders.h │ ├── mprintf.h │ ├── options.h │ ├── header.h │ ├── curlver.h │ ├── easy.h │ ├── urlapi.h │ ├── multi.h │ └── system.h ├── .vscode ├── c_cpp_properties.json └── launch.json ├── xmake.lua ├── src ├── util.h ├── executor.h ├── url.cpp ├── util.cpp ├── response.cpp ├── request.cpp ├── executor.cpp └── http.cpp ├── example ├── test_http_post.cpp ├── test_http_put.cpp ├── test_url.cpp ├── test_http_get.cpp ├── test_download.cpp ├── test_download_speed_limit.cpp ├── test_download_resume.cpp ├── test_download_range.cpp └── main.cpp ├── LICENSE ├── README.md └── makefile /win-vsproj/example/.gitignore: -------------------------------------------------------------------------------- 1 | test_download* 2 | dl_part* -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | build 3 | lib 4 | .xmake 5 | *.jpg 6 | *.dat 7 | win-vsproj/build 8 | win-vsproj/.vs 9 | -------------------------------------------------------------------------------- /assets/README/download_range.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leopard-C/iclient/HEAD/assets/README/download_range.jpg -------------------------------------------------------------------------------- /assets/README/release-v1.0.1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leopard-C/iclient/HEAD/assets/README/release-v1.0.1.jpg -------------------------------------------------------------------------------- /assets/README/breakpoint_continue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leopard-C/iclient/HEAD/assets/README/breakpoint_continue.jpg -------------------------------------------------------------------------------- /include/iclient/iclient.h: -------------------------------------------------------------------------------- 1 | #ifndef IC_CLIENT_H_ 2 | #define IC_CLIENT_H_ 3 | 4 | #include "request.h" 5 | #include "response.h" 6 | #include "url.h" 7 | 8 | #endif // IC_CLIENT_H_ 9 | -------------------------------------------------------------------------------- /win-vsproj/example/example.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /win-vsproj/iclient/iclient.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /win-vsproj/example/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{h,c,cpp,hpp,inc,inl,js,json}] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 4 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [*.{html,js,css,svg}] 11 | charset = utf-8 12 | indent_style = space 13 | indent_size = 2 14 | 15 | -------------------------------------------------------------------------------- /win-vsproj/iclient/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{h,c,cpp,hpp,inc,inl,js,json}] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 4 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [*.{html,js,css,svg}] 11 | charset = utf-8 12 | indent_style = space 13 | indent_size = 2 14 | 15 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Linux", 5 | "includePath": [ 6 | "${workspaceFolder}/include", 7 | "${default}" 8 | ], 9 | "defines": [], 10 | "cStandard": "c11", 11 | "cppStandard": "gnu++11", 12 | "intelliSenseMode": "linux-gcc-x64" 13 | } 14 | ], 15 | "version": 4 16 | } -------------------------------------------------------------------------------- /include/iclient/curl_inc.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file curl_inc.h 3 | * @brief include libcurl header file here. 4 | * @author Leopard-C (leopard.c@outlook.com) 5 | * @version 0.1 6 | * @date 2023-01-12 7 | * 8 | * @copyright Copyright (c) 2021-present, Jinbao Chen. 9 | */ 10 | #ifndef IC_CLIENT_CURL_INC_H_ 11 | #define IC_CLIENT_CURL_INC_H_ 12 | 13 | #ifndef BUILDING_LIBCURL 14 | # define BUILDING_LIBCURL 15 | #endif 16 | 17 | #include 18 | 19 | #endif // IC_CLIENT_CURL_INC_H_ 20 | -------------------------------------------------------------------------------- /xmake.lua: -------------------------------------------------------------------------------- 1 | 2 | add_rules("mode.debug", "mode.release") 3 | set_policy("build.warning", true) 4 | set_languages("c99", "cxx11") 5 | add_cxflags("-Wreturn-type", "-Wsign-compare", "-Wunused", "-Wswitch") 6 | add_cxflags("-Wno-deprecated-declarations") 7 | 8 | add_includedirs("include") 9 | 10 | target("iclient") 11 | set_kind("static") 12 | add_files("src/*.cpp") 13 | add_links("curl", "pthread", "dl") 14 | set_targetdir("lib/linux/$(arch)") 15 | 16 | target("example.out") 17 | set_kind("binary") 18 | add_files("example/*.cpp") 19 | add_deps("iclient") 20 | set_targetdir("bin") 21 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "g++-10 - Build and debug active file", 6 | "type": "cppdbg", 7 | "request": "launch", 8 | "program": "${workspaceFolder}/bin/example.out", 9 | "stopAtEntry": false, 10 | "cwd": "${workspaceFolder}", 11 | "environment": [], 12 | "externalConsole": false, 13 | "MIMode": "gdb", 14 | "setupCommands": [ 15 | { 16 | "description": "Enable pretty-printing for gdb", 17 | "text": "-enable-pretty-printing", 18 | "ignoreFailures": true 19 | } 20 | ], 21 | "miDebuggerPath": "/usr/bin/gdb", 22 | "sourceFileMap": {} 23 | } 24 | ], 25 | "logging": { 26 | "engineLogging": true, 27 | "traceResponse": true 28 | } 29 | } -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | #ifndef IC_CLIENT_UTIL_H_ 2 | #define IC_CLIENT_UTIL_H_ 3 | 4 | #include 5 | #include 6 | 7 | namespace ic { 8 | namespace client { 9 | namespace util { 10 | 11 | /** 12 | * @brief URL encode 13 | */ 14 | std::string escape(const std::string& str); 15 | 16 | /** 17 | * @brief URL decode 18 | */ 19 | std::string unescape(const std::string& str); 20 | 21 | /** 22 | * @brief Merge string array 23 | * @param strs string array 24 | * @param sep separator string 25 | */ 26 | std::string join(const std::vector& strs, const std::string& sep); 27 | 28 | std::string& trim(std::string& str); 29 | 30 | std::string& to_upper(std::string& str); 31 | std::string& to_lower(std::string& str); 32 | 33 | long get_file_size(const std::string& filename); 34 | 35 | /** 36 | * @brief Calculate "Host" filed in request header 37 | */ 38 | std::string get_host(const std::string& url); 39 | 40 | } // namespace util 41 | } // namespace client 42 | } // namespace ic 43 | 44 | #endif // IC_CLIENT_UTIL_H_ 45 | -------------------------------------------------------------------------------- /example/test_http_post.cpp: -------------------------------------------------------------------------------- 1 | #include "iclient/iclient.h" 2 | 3 | void test_http_post() { 4 | using namespace ic::client; 5 | Request request("http://httpbin.org/post"); 6 | request.set_http_method(http::Method::HTTP_POST); 7 | request.set_header("accept", "application/json"); 8 | 9 | auto response = request.Perform(); 10 | 11 | printf("----------------------------------------------\n"); 12 | printf("%s\n", to_string(response.status())); 13 | printf("----------------------------------------------\n"); 14 | if (response.ok()) { 15 | // Header 16 | printf("------ Headers -------------------------------\n"); 17 | for (auto& header : response.headers()) { 18 | printf("%s: %s\n", header.first.c_str(), header.second.c_str()); 19 | } 20 | // Data 21 | printf("------ Body ----------------------------------\n"); 22 | printf("%s\n", response.data().c_str()); 23 | printf("---------------------------------------------\n"); 24 | } 25 | printf("\n\n"); 26 | } 27 | -------------------------------------------------------------------------------- /example/test_http_put.cpp: -------------------------------------------------------------------------------- 1 | #include "iclient/iclient.h" 2 | 3 | void test_http_put() { 4 | using namespace ic::client; 5 | Request request("http://httpbin.org/put"); 6 | request.set_http_method(http::Method::HTTP_PUT); 7 | request.set_header("accept", "application/json"); 8 | auto response = request.Perform(); 9 | 10 | printf("----------------------------------------------\n"); 11 | printf("%s\n", ic::client::to_string(response.status())); 12 | printf("----------------------------------------------\n"); 13 | if (response.ok()) { 14 | // Header 15 | printf("------ Headers -------------------------------\n"); 16 | for (auto& header : response.headers()) { 17 | printf("%s: %s\n", header.first.c_str(), header.second.c_str()); 18 | } 19 | // Data 20 | printf("------ Body ----------------------------------\n"); 21 | printf("%s\n", response.data().c_str()); 22 | printf("---------------------------------------------\n"); 23 | } 24 | printf("\n\n"); 25 | } 26 | -------------------------------------------------------------------------------- /example/test_url.cpp: -------------------------------------------------------------------------------- 1 | #include "iclient/iclient.h" 2 | 3 | void test_url() { 4 | using namespace ic::client; 5 | Url url("https://api.icrystal.top/util/random"); 6 | url.SetParam("min", "1"); 7 | url.SetParam("max", "100"); 8 | url.SetParam("count", "20"); 9 | printf("GET: %s\n", url.ToString().c_str()); 10 | 11 | Request request(url.ToString()); 12 | request.set_verify_ssl(false); 13 | auto response = request.Perform(); 14 | 15 | if (response.ok()) { 16 | // Header 17 | printf("------ Headers -------------------------------\n"); 18 | for (auto& header : response.headers()) { 19 | printf("%s: %s\n", header.first.c_str(), header.second.c_str()); 20 | } 21 | // Data 22 | printf("------ Body ----------------------------------\n"); 23 | printf("%s\n", response.data().c_str()); 24 | printf("---------------------------------------------\n"); 25 | } 26 | else { 27 | printf("Request Error: %s %s\n", to_string(response.status()), http::to_string(response.http_status_code())); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Leopard-C 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /example/test_http_get.cpp: -------------------------------------------------------------------------------- 1 | #include "iclient/iclient.h" 2 | 3 | void test_http_get() { 4 | ic::client::Request request("http://httpbin.org/ip"); 5 | ic::client::Response response = request.Perform(); 6 | 7 | printf("---------------------------------------------\n"); 8 | printf("%s\n", ic::client::to_string(response.status())); 9 | printf("---------------------------------------------\n"); 10 | if (response.status() == ic::client::Status::SUCCESS 11 | && response.http_status_code() == ic::client::http::StatusCode::HTTP_200_OK) // equal to response.ok() 12 | { 13 | // Header 14 | printf("------ Headers -------------------------------\n"); 15 | auto& headers = response.headers(); 16 | for (auto& header : headers) { 17 | printf("%s: %s\n", header.first.c_str(), header.second.c_str()); 18 | } 19 | // Data 20 | printf("------ Body ----------------------------------\n"); 21 | printf("%s\n", response.data().c_str()); 22 | printf("---------------------------------------------\n"); 23 | } 24 | printf("\n\n"); 25 | } 26 | -------------------------------------------------------------------------------- /src/executor.h: -------------------------------------------------------------------------------- 1 | #ifndef IC_CLIENT_EXECUTOR_H_ 2 | #define IC_CLIENT_EXECUTOR_H_ 3 | 4 | #include "iclient/request.h" 5 | #include "iclient/response.h" 6 | #include "iclient/curl_inc.h" 7 | 8 | namespace ic { 9 | namespace client { 10 | 11 | class Executor { 12 | friend class Request; 13 | friend class Response; 14 | public: 15 | Executor(Request& request, Response& response); 16 | ~Executor(); 17 | 18 | void Perform(); 19 | 20 | void Reset(); 21 | 22 | public: 23 | friend size_t curl_write_header(char* buffer, size_t size, size_t nitems, void* user_ptr); 24 | friend size_t curl_write_data(void* buffer, size_t size, size_t nitems, void* user_ptr); 25 | friend int curl_xfer_info(void* clientp, curl_off_t download_total_bytes, curl_off_t download_now_bytes, 26 | curl_off_t upload_total_bytes, curl_off_t upload_now_bytes); 27 | 28 | private: 29 | bool Prepare(); 30 | 31 | private: 32 | CURL* curl_{nullptr}; 33 | FILE* file_stream_{nullptr}; 34 | curl_mime* curl_mime_{nullptr}; 35 | curl_slist* curl_request_headers_{nullptr}; 36 | Request& request_; 37 | Response& response_; 38 | }; 39 | 40 | } // namespace client 41 | } // namespace ic 42 | 43 | #endif // IC_CLIENT_EXECUTOR_H_ 44 | -------------------------------------------------------------------------------- /example/test_download.cpp: -------------------------------------------------------------------------------- 1 | #include "iclient/iclient.h" 2 | 3 | /* download file url */ 4 | extern const char* g_test_download_file_url; 5 | 6 | /* Progress bar */ 7 | bool g_curl_xfer_info(const ic::client::Request& request, 8 | curl_off_t download_total_bytes, curl_off_t download_now_bytes, 9 | curl_off_t upload_total_bytes, curl_off_t upload_now_bytes); 10 | void reset_progress_bar(); 11 | 12 | void test_download() { 13 | reset_progress_bar(); 14 | ic::client::Request request(g_test_download_file_url); 15 | request.set_verify_ssl(false); 16 | request.set_download_file("test_download.jpg"); 17 | request.set_transfer_progress_handler(g_curl_xfer_info); 18 | 19 | auto response = request.Perform(); 20 | 21 | printf("iclient status: %s\n", ic::client::to_string(response.status())); 22 | if (response.status() == ic::client::Status::SUCCESS 23 | && response.http_status_code() == ic::client::http::StatusCode::HTTP_200_OK) // equal to response.ok() 24 | { 25 | printf("------ Headers ------------------------------\n"); 26 | auto& headers = response.headers(); 27 | for (auto& header : headers) { 28 | printf("%s: %s\n", header.first.c_str(), header.second.c_str()); 29 | } 30 | } 31 | printf("\n\n"); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /include/curl/stdcheaders.h: -------------------------------------------------------------------------------- 1 | #ifndef CURLINC_STDCHEADERS_H 2 | #define CURLINC_STDCHEADERS_H 3 | /*************************************************************************** 4 | * _ _ ____ _ 5 | * Project ___| | | | _ \| | 6 | * / __| | | | |_) | | 7 | * | (__| |_| | _ <| |___ 8 | * \___|\___/|_| \_\_____| 9 | * 10 | * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. 11 | * 12 | * This software is licensed as described in the file COPYING, which 13 | * you should have received as part of this distribution. The terms 14 | * are also available at https://curl.se/docs/copyright.html. 15 | * 16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 17 | * copies of the Software, and permit persons to whom the Software is 18 | * furnished to do so, under the terms of the COPYING file. 19 | * 20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 | * KIND, either express or implied. 22 | * 23 | * SPDX-License-Identifier: curl 24 | * 25 | ***************************************************************************/ 26 | 27 | #include 28 | 29 | size_t fread(void *, size_t, size_t, FILE *); 30 | size_t fwrite(const void *, size_t, size_t, FILE *); 31 | 32 | int strcasecmp(const char *, const char *); 33 | int strncasecmp(const char *, const char *, size_t); 34 | 35 | #endif /* CURLINC_STDCHEADERS_H */ 36 | -------------------------------------------------------------------------------- /example/test_download_speed_limit.cpp: -------------------------------------------------------------------------------- 1 | #include "iclient/iclient.h" 2 | 3 | /* download file url */ 4 | extern const char* g_test_download_file_url; 5 | 6 | /* Progress bar */ 7 | bool g_curl_xfer_info(const ic::client::Request& request, 8 | curl_off_t download_total_bytes, curl_off_t download_now_bytes, 9 | curl_off_t upload_total_bytes, curl_off_t upload_now_bytes); 10 | void reset_progress_bar(); 11 | 12 | static void test_download_speed_limit_KBps(int speed) { 13 | reset_progress_bar(); 14 | ic::client::Request request(g_test_download_file_url); 15 | request.set_verify_ssl(false); 16 | char filename[128]; 17 | sprintf(filename, "test_download_speed_limit_%d.jpg", speed); 18 | request.set_download_file(filename); 19 | request.set_transfer_progress_handler(g_curl_xfer_info); 20 | request.set_max_download_speed(speed * 1024); 21 | printf("Speed Limit: %dKB/s\n", speed); 22 | 23 | auto response = request.Perform(); 24 | 25 | printf("iclient status: %s\n", ic::client::to_string(response.status())); 26 | if (response.status() == ic::client::Status::SUCCESS 27 | && response.http_status_code() == ic::client::http::StatusCode::HTTP_200_OK) 28 | { 29 | printf("------ Headers ------------------------------\n"); 30 | auto& headers = response.headers(); 31 | for (auto& header : headers) { 32 | printf("%s: %s\n", header.first.c_str(), header.second.c_str()); 33 | } 34 | } 35 | printf("\n\n"); 36 | } 37 | 38 | void test_download_speed_limit() { 39 | test_download_speed_limit_KBps(256); 40 | test_download_speed_limit_KBps(512); 41 | test_download_speed_limit_KBps(1024); 42 | } 43 | -------------------------------------------------------------------------------- /win-vsproj/example/example.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 6 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 7 | 8 | 9 | {f76de158-701c-444d-898e-62b134418908} 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | source 18 | 19 | 20 | source 21 | 22 | 23 | source 24 | 25 | 26 | source 27 | 28 | 29 | source 30 | 31 | 32 | source 33 | 34 | 35 | source 36 | 37 | 38 | source 39 | 40 | 41 | source 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/url.cpp: -------------------------------------------------------------------------------- 1 | #include "iclient/url.h" 2 | #include "util.h" 3 | 4 | namespace ic { 5 | namespace client { 6 | 7 | void Url::set_base_url(const std::string& base_url) { 8 | baseurl_changed_ = true; 9 | base_url_ = base_url; 10 | util::trim(base_url_); 11 | auto pos = base_url_.find('?'); 12 | if (pos != std::string::npos) { 13 | base_url_ = base_url_.substr(0, pos); 14 | } 15 | } 16 | 17 | void Url::AddParam(const std::string& key, const std::string& value) { 18 | params_.emplace(key, value); 19 | params_changed_ = true; 20 | } 21 | 22 | void Url::SetParam(const std::string& key, const std::string& value) { 23 | RemoveParam(key); 24 | AddParam(key, value); 25 | } 26 | 27 | void Url::RemoveParam(const std::string& key) { 28 | auto pair = params_.equal_range(key); 29 | if (pair.first != pair.second) { 30 | params_.erase(pair.first, pair.second); 31 | params_changed_ = true; 32 | } 33 | } 34 | 35 | void Url::ClearParams() { 36 | std::multimap().swap(params_); 37 | params_changed_ = true; 38 | } 39 | 40 | const std::string& Url::ToString() { 41 | if (!baseurl_changed_ && !params_changed_) { 42 | return url_; 43 | } 44 | url_ = base_url_; 45 | if (!params_.empty()) { 46 | url_ += '?' + GetParamsString(); 47 | } 48 | baseurl_changed_ = false; 49 | params_changed_ = false; 50 | return url_; 51 | } 52 | 53 | const std::string& Url::GetParamsString() { 54 | if (!params_changed_) { 55 | return params_str_; 56 | } 57 | params_changed_ = false; 58 | params_str_.clear(); 59 | if (params_.empty()) { 60 | return params_str_; 61 | } 62 | for (const auto& p : params_) { 63 | params_str_ += p.first; 64 | params_str_ += '='; 65 | params_str_ += util::escape(p.second); 66 | params_str_ += '&'; 67 | } 68 | params_str_.pop_back(); 69 | return params_str_; 70 | } 71 | 72 | } // namespace client 73 | } // namespace ic 74 | -------------------------------------------------------------------------------- /example/test_download_resume.cpp: -------------------------------------------------------------------------------- 1 | #include "iclient/iclient.h" 2 | 3 | /* download file url */ 4 | extern const char* g_test_download_file_url; 5 | 6 | /* Progress bar */ 7 | bool g_curl_xfer_info(const ic::client::Request& request, 8 | curl_off_t download_total_bytes, curl_off_t download_now_bytes, 9 | curl_off_t upload_total_bytes, curl_off_t upload_now_bytes); 10 | void reset_progress_bar(); 11 | 12 | // defined in test_download_range.cpp 13 | void download_range(const std::string& url, const std::string& local_file, size_t bytes_start, size_t bytes_end); 14 | 15 | // defined in the end of this file 16 | void download_resume(const std::string& url, const std::string& local_file); 17 | 18 | 19 | void test_download_resume() { 20 | /* Download first 4096 bytes */ 21 | download_range(g_test_download_file_url, "test_download_resume.jpg", 0, 4095); 22 | 23 | /* resume: breakpoint continuation */ 24 | /* download data remain */ 25 | download_resume(g_test_download_file_url, "test_download_resume.jpg"); 26 | } 27 | 28 | /** 29 | * @brief Get local file size 30 | */ 31 | static long get_file_size(const std::string& filename) { 32 | FILE* fp = fopen(filename.c_str(), "rb"); 33 | if (!fp) { 34 | return -1; 35 | } 36 | fseek(fp, 0L, SEEK_END); 37 | long size = ftell(fp); 38 | //fseek(fp, 0L, SEEK_SET); 39 | fclose(fp); 40 | return size; 41 | } 42 | 43 | void download_resume(const std::string& url, const std::string& local_file) { 44 | reset_progress_bar(); 45 | printf("downloading %s\n", url.c_str()); 46 | printf("local file: %s\n", local_file.c_str()); 47 | printf("resume from: %ld bytes\n", get_file_size(local_file)); 48 | 49 | ic::client::Request request(url); 50 | request.set_verify_ssl(false); 51 | request.set_download_file(local_file, true); 52 | request.set_transfer_progress_handler(g_curl_xfer_info); 53 | 54 | auto response = request.Perform(); 55 | 56 | printf("iclient status: %s\n", ic::client::to_string(response.status())); 57 | printf("\n\n"); 58 | } 59 | -------------------------------------------------------------------------------- /include/iclient/url.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file url.h 3 | * @author Leopard-C (leopard.c@outlook.com) 4 | * @version 0.1 5 | * @date 2023-01-12 6 | * 7 | * @copyright Copyright (c) 2021-present, Jinbao Chen. 8 | */ 9 | #ifndef IC_CLIENT_URL_H_ 10 | #define IC_CLIENT_URL_H_ 11 | #include 12 | #include 13 | 14 | namespace ic { 15 | namespace client { 16 | 17 | class Url { 18 | public: 19 | Url() = default; 20 | Url(const std::string& base_url) { set_base_url(base_url); } 21 | 22 | void set_base_url(const std::string& base_url); 23 | 24 | /** 25 | * @brief Add key-value, the same keys exist will be kept. 26 | */ 27 | void AddParam(const std::string& key, const std::string& value); 28 | void AddParam(const std::string& key, const char* value) { 29 | AddParam(key, std::string(value)); 30 | } 31 | void AddParam(const std::string& key, char* const value) { 32 | AddParam(key, std::string(value)); 33 | } 34 | template 35 | void AddParam(const std::string& key, const T& value) { 36 | AddParam(key, std::to_string(value)); 37 | } 38 | 39 | /** 40 | * @brief Set key-value, the same keys exist will be removed. 41 | */ 42 | void SetParam(const std::string& key, const std::string& value); 43 | void SetParam(const std::string& key, const char* value) { 44 | SetParam(key, std::string(value)); 45 | } 46 | void SetParam(const std::string& key, char* const value) { 47 | SetParam(key, std::string(value)); 48 | } 49 | template 50 | void SetParam(const std::string& key, const T& value) { 51 | SetParam(key, std::to_string(value)); 52 | } 53 | 54 | void RemoveParam(const std::string& key); 55 | 56 | void ClearParams(); 57 | 58 | const std::string& ToString(); 59 | const std::string& GetParamsString(); 60 | 61 | private: 62 | bool baseurl_changed_ = false; 63 | bool params_changed_ = false; 64 | std::string base_url_; 65 | std::string params_str_; 66 | std::string url_; 67 | std::multimap params_; 68 | }; 69 | 70 | } // namespace client 71 | } // namespace ic 72 | 73 | #endif // IC_CLIENT_URL_H_ 74 | -------------------------------------------------------------------------------- /include/curl/mprintf.h: -------------------------------------------------------------------------------- 1 | #ifndef CURLINC_MPRINTF_H 2 | #define CURLINC_MPRINTF_H 3 | /*************************************************************************** 4 | * _ _ ____ _ 5 | * Project ___| | | | _ \| | 6 | * / __| | | | |_) | | 7 | * | (__| |_| | _ <| |___ 8 | * \___|\___/|_| \_\_____| 9 | * 10 | * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. 11 | * 12 | * This software is licensed as described in the file COPYING, which 13 | * you should have received as part of this distribution. The terms 14 | * are also available at https://curl.se/docs/copyright.html. 15 | * 16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 17 | * copies of the Software, and permit persons to whom the Software is 18 | * furnished to do so, under the terms of the COPYING file. 19 | * 20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 | * KIND, either express or implied. 22 | * 23 | * SPDX-License-Identifier: curl 24 | * 25 | ***************************************************************************/ 26 | 27 | #include 28 | #include /* needed for FILE */ 29 | #include "curl.h" /* for CURL_EXTERN */ 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | CURL_EXTERN int curl_mprintf(const char *format, ...); 36 | CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...); 37 | CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...); 38 | CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, 39 | const char *format, ...); 40 | CURL_EXTERN int curl_mvprintf(const char *format, va_list args); 41 | CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args); 42 | CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args); 43 | CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, 44 | const char *format, va_list args); 45 | CURL_EXTERN char *curl_maprintf(const char *format, ...); 46 | CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); 47 | 48 | #ifdef __cplusplus 49 | } 50 | #endif 51 | 52 | #endif /* CURLINC_MPRINTF_H */ 53 | -------------------------------------------------------------------------------- /win-vsproj/iclient.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.33027.164 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iclient", "iclient\iclient.vcxproj", "{F58D4B56-8349-4D59-BA59-851691319F51}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example", "example\example.vcxproj", "{275AB4E9-9F0C-4D16-B0F4-13A1FCFAC0CC}" 9 | ProjectSection(ProjectDependencies) = postProject 10 | {F58D4B56-8349-4D59-BA59-851691319F51} = {F58D4B56-8349-4D59-BA59-851691319F51} 11 | EndProjectSection 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|x64 = Debug|x64 16 | Debug|x86 = Debug|x86 17 | Release|x64 = Release|x64 18 | Release|x86 = Release|x86 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {F58D4B56-8349-4D59-BA59-851691319F51}.Debug|x64.ActiveCfg = Debug|x64 22 | {F58D4B56-8349-4D59-BA59-851691319F51}.Debug|x64.Build.0 = Debug|x64 23 | {F58D4B56-8349-4D59-BA59-851691319F51}.Debug|x86.ActiveCfg = Debug|Win32 24 | {F58D4B56-8349-4D59-BA59-851691319F51}.Debug|x86.Build.0 = Debug|Win32 25 | {F58D4B56-8349-4D59-BA59-851691319F51}.Release|x64.ActiveCfg = Release|x64 26 | {F58D4B56-8349-4D59-BA59-851691319F51}.Release|x64.Build.0 = Release|x64 27 | {F58D4B56-8349-4D59-BA59-851691319F51}.Release|x86.ActiveCfg = Release|Win32 28 | {F58D4B56-8349-4D59-BA59-851691319F51}.Release|x86.Build.0 = Release|Win32 29 | {275AB4E9-9F0C-4D16-B0F4-13A1FCFAC0CC}.Debug|x64.ActiveCfg = Debug|x64 30 | {275AB4E9-9F0C-4D16-B0F4-13A1FCFAC0CC}.Debug|x64.Build.0 = Debug|x64 31 | {275AB4E9-9F0C-4D16-B0F4-13A1FCFAC0CC}.Debug|x86.ActiveCfg = Debug|Win32 32 | {275AB4E9-9F0C-4D16-B0F4-13A1FCFAC0CC}.Debug|x86.Build.0 = Debug|Win32 33 | {275AB4E9-9F0C-4D16-B0F4-13A1FCFAC0CC}.Release|x64.ActiveCfg = Release|x64 34 | {275AB4E9-9F0C-4D16-B0F4-13A1FCFAC0CC}.Release|x64.Build.0 = Release|x64 35 | {275AB4E9-9F0C-4D16-B0F4-13A1FCFAC0CC}.Release|x86.ActiveCfg = Release|Win32 36 | {275AB4E9-9F0C-4D16-B0F4-13A1FCFAC0CC}.Release|x86.Build.0 = Release|Win32 37 | EndGlobalSection 38 | GlobalSection(SolutionProperties) = preSolution 39 | HideSolutionNode = FALSE 40 | EndGlobalSection 41 | GlobalSection(ExtensibilityGlobals) = postSolution 42 | SolutionGuid = {ED6395DB-56E0-47E1-A6C0-F7A7D5157DAA} 43 | EndGlobalSection 44 | EndGlobal 45 | -------------------------------------------------------------------------------- /win-vsproj/iclient/iclient.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 6 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 7 | 8 | 9 | {aebebd4d-cac7-46bd-9e1b-4c72033b5b2d} 10 | 11 | 12 | {d4f8cb53-5828-4257-b586-678d6d435df1} 13 | 14 | 15 | {05e88bc7-5a59-4e64-9602-db168cde7eb3} 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | include\iclient 24 | 25 | 26 | include\iclient 27 | 28 | 29 | include\iclient 30 | 31 | 32 | include\iclient 33 | 34 | 35 | include\iclient 36 | 37 | 38 | include\iclient 39 | 40 | 41 | source 42 | 43 | 44 | source 45 | 46 | 47 | 48 | 49 | source 50 | 51 | 52 | source 53 | 54 | 55 | source 56 | 57 | 58 | source 59 | 60 | 61 | source 62 | 63 | 64 | source 65 | 66 | 67 | -------------------------------------------------------------------------------- /include/curl/options.h: -------------------------------------------------------------------------------- 1 | #ifndef CURLINC_OPTIONS_H 2 | #define CURLINC_OPTIONS_H 3 | /*************************************************************************** 4 | * _ _ ____ _ 5 | * Project ___| | | | _ \| | 6 | * / __| | | | |_) | | 7 | * | (__| |_| | _ <| |___ 8 | * \___|\___/|_| \_\_____| 9 | * 10 | * Copyright (C) 2018 - 2022, Daniel Stenberg, , et al. 11 | * 12 | * This software is licensed as described in the file COPYING, which 13 | * you should have received as part of this distribution. The terms 14 | * are also available at https://curl.se/docs/copyright.html. 15 | * 16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 17 | * copies of the Software, and permit persons to whom the Software is 18 | * furnished to do so, under the terms of the COPYING file. 19 | * 20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 | * KIND, either express or implied. 22 | * 23 | * SPDX-License-Identifier: curl 24 | * 25 | ***************************************************************************/ 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | typedef enum { 32 | CURLOT_LONG, /* long (a range of values) */ 33 | CURLOT_VALUES, /* (a defined set or bitmask) */ 34 | CURLOT_OFF_T, /* curl_off_t (a range of values) */ 35 | CURLOT_OBJECT, /* pointer (void *) */ 36 | CURLOT_STRING, /* (char * to zero terminated buffer) */ 37 | CURLOT_SLIST, /* (struct curl_slist *) */ 38 | CURLOT_CBPTR, /* (void * passed as-is to a callback) */ 39 | CURLOT_BLOB, /* blob (struct curl_blob *) */ 40 | CURLOT_FUNCTION /* function pointer */ 41 | } curl_easytype; 42 | 43 | /* Flag bits */ 44 | 45 | /* "alias" means it is provided for old programs to remain functional, 46 | we prefer another name */ 47 | #define CURLOT_FLAG_ALIAS (1<<0) 48 | 49 | /* The CURLOPTTYPE_* id ranges can still be used to figure out what type/size 50 | to use for curl_easy_setopt() for the given id */ 51 | struct curl_easyoption { 52 | const char *name; 53 | CURLoption id; 54 | curl_easytype type; 55 | unsigned int flags; 56 | }; 57 | 58 | CURL_EXTERN const struct curl_easyoption * 59 | curl_easy_option_by_name(const char *name); 60 | 61 | CURL_EXTERN const struct curl_easyoption * 62 | curl_easy_option_by_id(CURLoption id); 63 | 64 | CURL_EXTERN const struct curl_easyoption * 65 | curl_easy_option_next(const struct curl_easyoption *prev); 66 | 67 | #ifdef __cplusplus 68 | } /* end of extern "C" */ 69 | #endif 70 | #endif /* CURLINC_OPTIONS_H */ 71 | -------------------------------------------------------------------------------- /include/iclient/response.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file response.h 3 | * @brief Http Response. 4 | * @author Leopard-C (leopard.c@outlook.com) 5 | * @version 0.1 6 | * @date 2023-01-12 7 | * 8 | * @copyright Copyright (c) 2021-present, Jinbao Chen. 9 | */ 10 | #ifndef IC_CLIENT_RESPONSE_H_ 11 | #define IC_CLIENT_RESPONSE_H_ 12 | 13 | #include "curl_inc.h" 14 | #include "http.h" 15 | #include 16 | #include 17 | 18 | namespace ic { 19 | namespace client { 20 | 21 | /** 22 | * @brief iclient Status Code 23 | */ 24 | enum class Status { 25 | BUILDING, 26 | EXECUTING, 27 | INVALID_URL, 28 | SUCCESS, 29 | CONNECT_ERROR, 30 | CONNECT_DNS_ERROR, 31 | CONNECT_SSL_ERROR, 32 | ABORTED_BY_CALLBACK, 33 | TIMEOUT, 34 | RESPONSE_EMPTY, 35 | FAILED_TO_OPEN_OUTPUTFILE, 36 | OUTPUTFILE_BEING_USED, 37 | FAILED_TO_START, 38 | DOWNLOAD_ERROR, 39 | UNKNOWN_ERROR, 40 | }; 41 | 42 | Status from_curl_status_code(int code); 43 | const char* to_string(Status code); 44 | 45 | 46 | /** 47 | * @brief Http Response. 48 | */ 49 | class Response { 50 | friend class Executor; 51 | public: 52 | Response(Status status = Status::BUILDING); 53 | 54 | bool success() const { return status_ == Status::SUCCESS; } 55 | bool ok() const { return status_ == Status::SUCCESS && http_status_code_ == http::StatusCode::HTTP_200_OK; } 56 | Status status() const { return status_; } 57 | 58 | http::Version http_version() const { return http_version_; } 59 | http::StatusCode http_status_code() const { return http_status_code_; } 60 | 61 | const std::map& headers() const { return headers_; } 62 | bool HasHeader(const std::string& name) const; 63 | const std::string& GetHeader(const std::string& name); 64 | 65 | const std::string& server_ip() const { return server_ip_; } 66 | const std::string& data() const { return data_; } 67 | double total_time() const { return total_time_; } 68 | int num_connects() const { return num_connects_; } 69 | int num_redirects() const { return num_redirects_; } 70 | 71 | public: 72 | friend size_t curl_write_header(char* buffer, size_t size, size_t nitems, void* user_ptr); 73 | friend size_t curl_write_data(void* buffer, size_t size, size_t nitems, void* user_ptr); 74 | friend int curl_xfer_info(void* clientp, curl_off_t download_total_bytes, curl_off_t download_now_bytes, 75 | curl_off_t upload_total_bytes, curl_off_t upload_now_bytes); 76 | 77 | private: 78 | void ParseFromCurl(CURL* curl); 79 | 80 | private: 81 | Status status_{Status::BUILDING}; 82 | http::Version http_version_{http::Version::V1_1}; 83 | http::StatusCode http_status_code_{http::StatusCode::HTTP_UNKNOWN}; 84 | int num_connects_{0}; 85 | int num_redirects_{0}; 86 | double total_time_{0}; /* total time (unit: seconds) */ 87 | std::string server_ip_; 88 | std::string data_; 89 | std::map headers_; 90 | }; 91 | 92 | } // namespace client 93 | } // namespace ic 94 | 95 | #endif // IC_CLIENT_RESPONSE_H_ 96 | -------------------------------------------------------------------------------- /include/curl/header.h: -------------------------------------------------------------------------------- 1 | #ifndef CURLINC_HEADER_H 2 | #define CURLINC_HEADER_H 3 | /*************************************************************************** 4 | * _ _ ____ _ 5 | * Project ___| | | | _ \| | 6 | * / __| | | | |_) | | 7 | * | (__| |_| | _ <| |___ 8 | * \___|\___/|_| \_\_____| 9 | * 10 | * Copyright (C) 2018 - 2022, Daniel Stenberg, , et al. 11 | * 12 | * This software is licensed as described in the file COPYING, which 13 | * you should have received as part of this distribution. The terms 14 | * are also available at https://curl.se/docs/copyright.html. 15 | * 16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 17 | * copies of the Software, and permit persons to whom the Software is 18 | * furnished to do so, under the terms of the COPYING file. 19 | * 20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 | * KIND, either express or implied. 22 | * 23 | * SPDX-License-Identifier: curl 24 | * 25 | ***************************************************************************/ 26 | 27 | struct curl_header { 28 | char *name; /* this might not use the same case */ 29 | char *value; 30 | size_t amount; /* number of headers using this name */ 31 | size_t index; /* ... of this instance, 0 or higher */ 32 | unsigned int origin; /* see bits below */ 33 | void *anchor; /* handle privately used by libcurl */ 34 | }; 35 | 36 | /* 'origin' bits */ 37 | #define CURLH_HEADER (1<<0) /* plain server header */ 38 | #define CURLH_TRAILER (1<<1) /* trailers */ 39 | #define CURLH_CONNECT (1<<2) /* CONNECT headers */ 40 | #define CURLH_1XX (1<<3) /* 1xx headers */ 41 | #define CURLH_PSEUDO (1<<4) /* pseudo headers */ 42 | 43 | typedef enum { 44 | CURLHE_OK, 45 | CURLHE_BADINDEX, /* header exists but not with this index */ 46 | CURLHE_MISSING, /* no such header exists */ 47 | CURLHE_NOHEADERS, /* no headers at all exist (yet) */ 48 | CURLHE_NOREQUEST, /* no request with this number was used */ 49 | CURLHE_OUT_OF_MEMORY, /* out of memory while processing */ 50 | CURLHE_BAD_ARGUMENT, /* a function argument was not okay */ 51 | CURLHE_NOT_BUILT_IN /* if API was disabled in the build */ 52 | } CURLHcode; 53 | 54 | CURL_EXTERN CURLHcode curl_easy_header(CURL *easy, 55 | const char *name, 56 | size_t index, 57 | unsigned int origin, 58 | int request, 59 | struct curl_header **hout); 60 | 61 | CURL_EXTERN struct curl_header *curl_easy_nextheader(CURL *easy, 62 | unsigned int origin, 63 | int request, 64 | struct curl_header *prev); 65 | 66 | #endif /* CURLINC_HEADER_H */ 67 | -------------------------------------------------------------------------------- /src/util.cpp: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | #include "iclient/curl_inc.h" 3 | 4 | namespace ic { 5 | namespace client { 6 | namespace util { 7 | 8 | /** 9 | * @brief URL encode 10 | */ 11 | std::string escape(const std::string& str) { 12 | char* escaped = curl_escape(str.c_str(), static_cast(str.length())); 13 | if (escaped) { 14 | std::string ret(escaped); 15 | curl_free(escaped); 16 | return ret; 17 | } 18 | return {}; 19 | } 20 | 21 | /** 22 | * @brief URL decode 23 | */ 24 | std::string unescape(const std::string& str) { 25 | char* unescaped = curl_unescape(str.c_str(), static_cast(str.length())); 26 | if (unescaped) { 27 | std::string ret(unescaped); 28 | curl_free(unescaped); 29 | return ret; 30 | } 31 | return {}; 32 | } 33 | 34 | /** 35 | * @brief Merge string array 36 | * @param strs string array 37 | * @param sep separator string 38 | */ 39 | std::string join(const std::vector& strs, const std::string& sep) { 40 | if (strs.empty()) { 41 | return {}; 42 | } 43 | 44 | size_t length = 0; 45 | const size_t strs_size = strs.size(); 46 | const size_t sep_length = sep.length(); 47 | for (size_t i = 0; i < strs_size; ++i) { 48 | length += strs[i].length() + sep_length; 49 | } 50 | 51 | std::string joined; 52 | joined.reserve(length); 53 | joined += strs[0]; 54 | for (size_t i = 1; i < strs_size; ++i) { 55 | joined += sep; 56 | joined += strs[i]; 57 | } 58 | 59 | return joined; 60 | } 61 | 62 | std::string& trim(std::string& str) { 63 | str.erase(str.find_last_not_of(' ') + 1); 64 | str.erase(0, str.find_first_not_of(' ')); 65 | return str; 66 | } 67 | 68 | std::string& to_upper(std::string& str) { 69 | for (char& c : str) { 70 | if (c >= 'a' && c <= 'z') { 71 | c -= 32; 72 | } 73 | } 74 | return str; 75 | } 76 | 77 | std::string& to_lower(std::string& str) { 78 | for (char& c : str) { 79 | if (c >= 'A' && c <= 'Z') { 80 | c += 32; 81 | } 82 | } 83 | return str; 84 | } 85 | 86 | long get_file_size(const std::string& filename) { 87 | FILE* fp = fopen(filename.c_str(), "rb"); 88 | if (!fp) { 89 | return -1; 90 | } 91 | fseek(fp, 0L, SEEK_END); 92 | long size = ftell(fp); 93 | //fseek(fp, 0L, SEEK_SET); 94 | fclose(fp); 95 | return size; 96 | } 97 | 98 | /** 99 | * @brief Calculate "Host" filed in request header 100 | */ 101 | std::string get_host(const std::string& url) { 102 | auto pos_start = url.find("://"); 103 | if (pos_start == std::string::npos) { 104 | pos_start = 0; /* eg. www.example.com/example */ 105 | } 106 | else { 107 | pos_start += 3; /* eg. https://www.example.com/example */ 108 | } 109 | auto pos_end = url.find('/', pos_start); 110 | return url.substr(pos_start, pos_end - pos_start); 111 | } 112 | 113 | } // namespace util 114 | } // namespace client 115 | } // namespace ic 116 | -------------------------------------------------------------------------------- /include/curl/curlver.h: -------------------------------------------------------------------------------- 1 | #ifndef CURLINC_CURLVER_H 2 | #define CURLINC_CURLVER_H 3 | /*************************************************************************** 4 | * _ _ ____ _ 5 | * Project ___| | | | _ \| | 6 | * / __| | | | |_) | | 7 | * | (__| |_| | _ <| |___ 8 | * \___|\___/|_| \_\_____| 9 | * 10 | * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. 11 | * 12 | * This software is licensed as described in the file COPYING, which 13 | * you should have received as part of this distribution. The terms 14 | * are also available at https://curl.se/docs/copyright.html. 15 | * 16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 17 | * copies of the Software, and permit persons to whom the Software is 18 | * furnished to do so, under the terms of the COPYING file. 19 | * 20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 | * KIND, either express or implied. 22 | * 23 | * SPDX-License-Identifier: curl 24 | * 25 | ***************************************************************************/ 26 | 27 | /* This header file contains nothing but libcurl version info, generated by 28 | a script at release-time. This was made its own header file in 7.11.2 */ 29 | 30 | /* This is the global package copyright */ 31 | #define LIBCURL_COPYRIGHT "1996 - 2022 Daniel Stenberg, ." 32 | 33 | /* This is the version number of the libcurl package from which this header 34 | file origins: */ 35 | #define LIBCURL_VERSION "7.85.0" 36 | 37 | /* The numeric version number is also available "in parts" by using these 38 | defines: */ 39 | #define LIBCURL_VERSION_MAJOR 7 40 | #define LIBCURL_VERSION_MINOR 85 41 | #define LIBCURL_VERSION_PATCH 0 42 | 43 | /* This is the numeric version of the libcurl version number, meant for easier 44 | parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will 45 | always follow this syntax: 46 | 47 | 0xXXYYZZ 48 | 49 | Where XX, YY and ZZ are the main version, release and patch numbers in 50 | hexadecimal (using 8 bits each). All three numbers are always represented 51 | using two digits. 1.2 would appear as "0x010200" while version 9.11.7 52 | appears as "0x090b07". 53 | 54 | This 6-digit (24 bits) hexadecimal number does not show pre-release number, 55 | and it is always a greater number in a more recent release. It makes 56 | comparisons with greater than and less than work. 57 | 58 | Note: This define is the full hex number and _does not_ use the 59 | CURL_VERSION_BITS() macro since curl's own configure script greps for it 60 | and needs it to contain the full number. 61 | */ 62 | #define LIBCURL_VERSION_NUM 0x075500 63 | 64 | /* 65 | * This is the date and time when the full source package was created. The 66 | * timestamp is not stored in git, as the timestamp is properly set in the 67 | * tarballs by the maketgz script. 68 | * 69 | * The format of the date follows this template: 70 | * 71 | * "2007-11-23" 72 | */ 73 | #define LIBCURL_TIMESTAMP "2022-08-31" 74 | 75 | #define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z)) 76 | #define CURL_AT_LEAST_VERSION(x,y,z) \ 77 | (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) 78 | 79 | #endif /* CURLINC_CURLVER_H */ 80 | -------------------------------------------------------------------------------- /example/test_download_range.cpp: -------------------------------------------------------------------------------- 1 | #include "iclient/iclient.h" 2 | #include 3 | 4 | /* download file url */ 5 | extern const char* g_test_download_file_url; 6 | 7 | /* Progress bar */ 8 | bool g_curl_xfer_info(const ic::client::Request& request, 9 | curl_off_t download_total_bytes, curl_off_t download_now_bytes, 10 | curl_off_t upload_total_bytes, curl_off_t upload_now_bytes); 11 | void reset_progress_bar(); 12 | 13 | void download_range(const std::string& url, const std::string& local_file, size_t bytes_start, size_t bytes_end); 14 | bool merge_files(const std::vector& files, const std::string& output_file); 15 | 16 | 17 | void test_download_range() { 18 | std::vector dl_parts = { 19 | "dl_part_0-512k.dat", 20 | "dl_part_512-1024k.dat", 21 | "dl_part_1024-1536k.dat", 22 | "dl_part_1536-2048k.dat", 23 | "dl_part_2048-.dat", 24 | }; 25 | constexpr size_t KB = 1024; 26 | download_range(g_test_download_file_url, dl_parts[0], 0, 512 * KB - 1); 27 | download_range(g_test_download_file_url, dl_parts[1], 512 * KB, 1024 * KB - 1); 28 | download_range(g_test_download_file_url, dl_parts[2], 1024 * KB, 1536 * KB - 1); 29 | download_range(g_test_download_file_url, dl_parts[3], 1536 * KB, 2048 * KB - 1); 30 | download_range(g_test_download_file_url, dl_parts[4], 2048 * KB, ic::client::end); 31 | merge_files(dl_parts, "test_download_range.jpg"); 32 | } 33 | 34 | void download_range(const std::string& url, const std::string& local_filename, size_t bytes_start, size_t bytes_end) { 35 | reset_progress_bar(); 36 | printf("downloading %s\n", url.c_str()); 37 | printf("local file: %s\n", local_filename.c_str()); 38 | printf("range: %zu-%zu\n", bytes_start, bytes_end); 39 | 40 | ic::client::Request request(url); 41 | request.set_verify_ssl(false); 42 | request.set_download_file(local_filename); 43 | request.set_download_range(bytes_start, bytes_end); 44 | request.set_transfer_progress_handler(g_curl_xfer_info); 45 | 46 | auto response = request.Perform(); 47 | 48 | printf("iclient status: %s\n", ic::client::to_string(response.status())); 49 | printf("\n"); 50 | } 51 | 52 | void copy_data(FILE* fp_in, FILE* fp_out) { 53 | char buff[1024]; 54 | while (!feof(fp_in)) { 55 | size_t rn = fread(buff, 1, 1024, fp_in); 56 | fwrite(buff, 1, rn, fp_out); 57 | } 58 | } 59 | 60 | bool merge_files(const std::vector& input_files, const std::string& output_file) { 61 | printf("merge file: \n"); 62 | FILE* fp_out = fopen(output_file.c_str(), "wb+"); 63 | if (!fp_out) { 64 | printf("Open file %s failed\n", output_file.c_str()); 65 | return false; 66 | } 67 | 68 | bool ret = true; 69 | for (const auto& input_file : input_files) { 70 | printf(" %s\n", input_file.c_str()); 71 | FILE* fp_in = fopen(input_file.c_str(), "rb"); 72 | if (!fp_in) { 73 | printf("Open file %s failed\n", input_file.c_str()); 74 | ret = false; 75 | break; 76 | } 77 | copy_data(fp_in, fp_out); 78 | fclose(fp_in); 79 | } 80 | 81 | if (ret) { 82 | printf("output: %s\n", output_file.c_str()); 83 | long size = ftell(fp_out); 84 | printf("size: %ld\n", size); 85 | } 86 | 87 | fclose(fp_out); 88 | return ret; 89 | } 90 | -------------------------------------------------------------------------------- /include/curl/easy.h: -------------------------------------------------------------------------------- 1 | #ifndef CURLINC_EASY_H 2 | #define CURLINC_EASY_H 3 | /*************************************************************************** 4 | * _ _ ____ _ 5 | * Project ___| | | | _ \| | 6 | * / __| | | | |_) | | 7 | * | (__| |_| | _ <| |___ 8 | * \___|\___/|_| \_\_____| 9 | * 10 | * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. 11 | * 12 | * This software is licensed as described in the file COPYING, which 13 | * you should have received as part of this distribution. The terms 14 | * are also available at https://curl.se/docs/copyright.html. 15 | * 16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 17 | * copies of the Software, and permit persons to whom the Software is 18 | * furnished to do so, under the terms of the COPYING file. 19 | * 20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 | * KIND, either express or implied. 22 | * 23 | * SPDX-License-Identifier: curl 24 | * 25 | ***************************************************************************/ 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | /* Flag bits in the curl_blob struct: */ 31 | #define CURL_BLOB_COPY 1 /* tell libcurl to copy the data */ 32 | #define CURL_BLOB_NOCOPY 0 /* tell libcurl to NOT copy the data */ 33 | 34 | struct curl_blob { 35 | void *data; 36 | size_t len; 37 | unsigned int flags; /* bit 0 is defined, the rest are reserved and should be 38 | left zeroes */ 39 | }; 40 | 41 | CURL_EXTERN CURL *curl_easy_init(void); 42 | CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); 43 | CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); 44 | CURL_EXTERN void curl_easy_cleanup(CURL *curl); 45 | 46 | /* 47 | * NAME curl_easy_getinfo() 48 | * 49 | * DESCRIPTION 50 | * 51 | * Request internal information from the curl session with this function. The 52 | * third argument MUST be a pointer to a long, a pointer to a char * or a 53 | * pointer to a double (as the documentation describes elsewhere). The data 54 | * pointed to will be filled in accordingly and can be relied upon only if the 55 | * function returns CURLE_OK. This function is intended to get used *AFTER* a 56 | * performed transfer, all results from this function are undefined until the 57 | * transfer is completed. 58 | */ 59 | CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); 60 | 61 | 62 | /* 63 | * NAME curl_easy_duphandle() 64 | * 65 | * DESCRIPTION 66 | * 67 | * Creates a new curl session handle with the same options set for the handle 68 | * passed in. Duplicating a handle could only be a matter of cloning data and 69 | * options, internal state info and things like persistent connections cannot 70 | * be transferred. It is useful in multithreaded applications when you can run 71 | * curl_easy_duphandle() for each new thread to avoid a series of identical 72 | * curl_easy_setopt() invokes in every thread. 73 | */ 74 | CURL_EXTERN CURL *curl_easy_duphandle(CURL *curl); 75 | 76 | /* 77 | * NAME curl_easy_reset() 78 | * 79 | * DESCRIPTION 80 | * 81 | * Re-initializes a CURL handle to the default values. This puts back the 82 | * handle to the same state as it was in when it was just created. 83 | * 84 | * It does keep: live connections, the Session ID cache, the DNS cache and the 85 | * cookies. 86 | */ 87 | CURL_EXTERN void curl_easy_reset(CURL *curl); 88 | 89 | /* 90 | * NAME curl_easy_recv() 91 | * 92 | * DESCRIPTION 93 | * 94 | * Receives data from the connected socket. Use after successful 95 | * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. 96 | */ 97 | CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, 98 | size_t *n); 99 | 100 | /* 101 | * NAME curl_easy_send() 102 | * 103 | * DESCRIPTION 104 | * 105 | * Sends data over the connected socket. Use after successful 106 | * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. 107 | */ 108 | CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer, 109 | size_t buflen, size_t *n); 110 | 111 | 112 | /* 113 | * NAME curl_easy_upkeep() 114 | * 115 | * DESCRIPTION 116 | * 117 | * Performs connection upkeep for the given session handle. 118 | */ 119 | CURL_EXTERN CURLcode curl_easy_upkeep(CURL *curl); 120 | 121 | #ifdef __cplusplus 122 | } 123 | #endif 124 | 125 | #endif 126 | -------------------------------------------------------------------------------- /src/response.cpp: -------------------------------------------------------------------------------- 1 | #include "iclient/response.h" 2 | #include "iclient/http.h" 3 | #include "util.h" 4 | 5 | namespace ic { 6 | namespace client { 7 | 8 | extern std::string empty_string; 9 | 10 | /** 11 | * @brief iclient Status Code 12 | */ 13 | Status from_curl_status_code(int code) { 14 | switch (code) { 15 | case CURLcode::CURLE_OK: return Status::SUCCESS; 16 | case CURLcode::CURLE_GOT_NOTHING: return Status::RESPONSE_EMPTY; 17 | case CURLcode::CURLE_OPERATION_TIMEDOUT: return Status::TIMEOUT; 18 | case CURLcode::CURLE_COULDNT_CONNECT: return Status::CONNECT_ERROR; 19 | case CURLcode::CURLE_COULDNT_RESOLVE_HOST: return Status::CONNECT_DNS_ERROR; 20 | case CURLcode::CURLE_SSL_CONNECT_ERROR: return Status::CONNECT_SSL_ERROR; 21 | case CURLcode::CURLE_WRITE_ERROR: return Status::DOWNLOAD_ERROR; 22 | case CURLcode::CURLE_SEND_ERROR: return Status::FAILED_TO_START; 23 | case CURLcode::CURLE_ABORTED_BY_CALLBACK: return Status::ABORTED_BY_CALLBACK; 24 | default: return Status::UNKNOWN_ERROR; 25 | } 26 | } 27 | 28 | static const char* STR_STATUS_BUILDING = "BUILDING"; 29 | static const char* STR_STATUS_EXECUTING = "EXECUTING"; 30 | static const char* STR_STATUS_INVALID_URL = "INVALID_URL"; 31 | static const char* STR_STATUS_SUCCESS = "SUCCESS"; 32 | static const char* STR_STATUS_CONNECT_ERROR = "CONNECT_ERROR"; 33 | static const char* STR_STATUS_CONNECT_DNS_ERROR = "CONNECT_DNS_ERROR"; 34 | static const char* STR_STATUS_CONNECT_SSL_ERROR = "CONNECT_SSL_ERROR"; 35 | static const char* STR_STATUS_TIMEOUT = "TIMEOUT"; 36 | static const char* STR_STATUS_RESPONSE_EMPTY = "RESPONSE_EMPTY"; 37 | static const char* STR_STATUS_FAILED_TO_START = "FAILED_TO_START"; 38 | static const char* STR_STATUS_UNKNOWN_ERROR = "UNKNOWN_ERROR"; 39 | static const char* STR_STATUS_DOWNLOAD_ERROR = "DOWNLOAD_ERROR"; 40 | static const char* STR_STATUS_FAILED_TO_OPEN_OUTPUTFILE = "FAILED_TO_OPEN_OUTPUTFILE"; 41 | static const char* STR_STATUS_OUTPUTFILE_BEING_USED = "OUTPUTFILE_BEING_USED"; 42 | static const char* STR_STATUS_ABORTED_BY_CALLBACK = "ABORTED_BY_CALLBACK"; 43 | 44 | #ifdef CASE 45 | #undef CASE 46 | #endif 47 | 48 | #define CASE(code) case Status::code: return STR_STATUS_##code 49 | 50 | const char* to_string(Status code) { 51 | switch (code) { 52 | CASE(BUILDING); 53 | CASE(EXECUTING); 54 | CASE(INVALID_URL); 55 | CASE(SUCCESS); 56 | CASE(CONNECT_ERROR); 57 | CASE(CONNECT_DNS_ERROR); 58 | CASE(CONNECT_SSL_ERROR); 59 | CASE(TIMEOUT); 60 | CASE(RESPONSE_EMPTY); 61 | CASE(DOWNLOAD_ERROR); 62 | CASE(FAILED_TO_START); 63 | CASE(FAILED_TO_OPEN_OUTPUTFILE); 64 | CASE(OUTPUTFILE_BEING_USED); 65 | CASE(ABORTED_BY_CALLBACK); 66 | CASE(UNKNOWN_ERROR); 67 | default: return STR_STATUS_UNKNOWN_ERROR; 68 | } 69 | } 70 | 71 | 72 | Response::Response(Status status/* = Status::BUILDING*/) : status_(status) { 73 | data_.reserve(4096); 74 | } 75 | 76 | void Response::ParseFromCurl(CURL* curl) { 77 | long http_response_code = 0L; 78 | curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response_code); 79 | http_status_code_ = http::from_curl_http_response_code(static_cast(http_response_code)); 80 | 81 | long http_version = 0L; 82 | curl_easy_getinfo(curl, CURLINFO_HTTP_VERSION, &http_version); 83 | http_version_ = static_cast(http_version); 84 | 85 | /* total time (unit: seconds) */ 86 | curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time_); 87 | 88 | long connect_count = 0L; 89 | curl_easy_getinfo(curl, CURLINFO_NUM_CONNECTS, &connect_count); 90 | num_connects_ = static_cast(connect_count); 91 | 92 | long redirect_count = 0L; 93 | curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &redirect_count); 94 | num_redirects_ = static_cast(redirect_count); 95 | 96 | char* ip_str = nullptr; 97 | curl_easy_getinfo(curl, CURLINFO_PRIMARY_IP, &ip_str); 98 | if (ip_str) { 99 | server_ip_ = std::string(ip_str); 100 | } 101 | } 102 | 103 | const std::string& Response::GetHeader(const std::string& name) { 104 | std::string name_lower = name; 105 | util::to_lower(name_lower); 106 | auto iter = headers_.find(name_lower); 107 | if (iter != headers_.end()) { 108 | return iter->second; 109 | } 110 | return empty_string; 111 | } 112 | 113 | bool Response::HasHeader(const std::string& name) const { 114 | std::string name_lower = name; 115 | util::to_lower(name_lower); 116 | return headers_.find(name_lower) != headers_.end(); 117 | } 118 | 119 | } // namespace client 120 | } // namespace ic 121 | -------------------------------------------------------------------------------- /src/request.cpp: -------------------------------------------------------------------------------- 1 | #include "iclient/request.h" 2 | #include "executor.h" 3 | #include "util.h" 4 | 5 | namespace ic { 6 | namespace client { 7 | 8 | size_t end{ static_cast(-1) }; 9 | std::string empty_string; 10 | 11 | static const char* STR_SSL_CERT_TYPE_UNKNOWN = "UNKNOWN"; 12 | static const char* STR_SSL_CERT_TYPE_PEM = "PEM"; 13 | static const char* STR_SSL_CERT_TYPE_DER = "DER"; 14 | 15 | /** 16 | * @brief SSL Certificate Type. 17 | */ 18 | const char* to_string(SslCertificateType type) { 19 | switch (type) { 20 | case SslCertificateType::PME: return STR_SSL_CERT_TYPE_PEM; 21 | case SslCertificateType::DER: return STR_SSL_CERT_TYPE_DER; 22 | default: return STR_SSL_CERT_TYPE_UNKNOWN; 23 | } 24 | } 25 | 26 | /** 27 | * @brief Proxy Type. 28 | */ 29 | int to_curl(ProxyType type) { 30 | return type == ProxyType::HTTPS ? CURLPROXY_HTTPS : CURLPROXY_HTTP; 31 | } 32 | 33 | static const char* STR_PROXY_TYPE_HTTP = "HTTP"; 34 | static const char* STR_PROXY_TYPE_HTTPS = "HTTPS"; 35 | 36 | const char* to_string(ProxyType type) { 37 | return type == ProxyType::HTTPS ? STR_PROXY_TYPE_HTTPS : STR_PROXY_TYPE_HTTP; 38 | } 39 | 40 | /** 41 | * @brief Http Auth Type 42 | */ 43 | unsigned long to_curl(HttpAuthType type) { 44 | switch (type) { 45 | case HttpAuthType::BASIC: return CURLAUTH_BASIC; 46 | case HttpAuthType::DIGEST: return CURLAUTH_DIGEST; 47 | case HttpAuthType::ANY_SAFE: return CURLAUTH_ANYSAFE; 48 | case HttpAuthType::ANY: 49 | default: return CURLAUTH_ANY; 50 | } 51 | } 52 | 53 | static const char* STR_BASIC = "BASIC"; 54 | static const char* STR_DIGEST = "DIGEST"; 55 | static const char* STR_ANY = "ANY"; 56 | static const char* STR_ANY_SAFE = "ANY_SAFE"; 57 | 58 | const char* to_string(HttpAuthType type) { 59 | switch (type) { 60 | case HttpAuthType::BASIC: return STR_BASIC; 61 | case HttpAuthType::DIGEST: return STR_DIGEST; 62 | case HttpAuthType::ANY_SAFE: return STR_ANY_SAFE; 63 | case HttpAuthType::ANY: 64 | default: return STR_ANY; 65 | } 66 | } 67 | 68 | /** 69 | * @brief Perform request 70 | */ 71 | Response Request::Perform() { 72 | if (header("Host").empty()) { 73 | // Calculate 'Host' field 74 | std::string host = util::get_host(url_); 75 | if (host.empty()) { 76 | return Status::INVALID_URL; 77 | } 78 | } 79 | cancel_ = false; 80 | Response response; 81 | Executor executor(*this, response); 82 | executor.Perform(); 83 | return response; 84 | } 85 | 86 | void Request::Cancel() { 87 | cancel_ = true; 88 | } 89 | 90 | void Request::set_header(std::string name, const std::string& value) { 91 | util::to_lower(name); 92 | headers_[name] = value; 93 | } 94 | 95 | void Request::RemoveHeader(std::string name) { 96 | util::to_lower(name); 97 | auto iter = headers_.find(name); 98 | if (iter != headers_.end()) { 99 | headers_.erase(iter); 100 | } 101 | } 102 | 103 | const std::string& Request::header(std::string name) const { 104 | util::to_lower(name); 105 | auto iter = headers_.find(name); 106 | if (iter != headers_.end()) { 107 | return iter->second; 108 | } 109 | return empty_string; 110 | } 111 | 112 | void Request::RemoveMimeStringField(const std::string& name) { 113 | auto iter = mime_string_fields_.find(name); 114 | if (iter != mime_string_fields_.end()) { 115 | mime_string_fields_.erase(iter); 116 | } 117 | } 118 | 119 | void Request::RemoveMimeFileField(const std::string& name) { 120 | auto iter = mime_file_fields_.find(name); 121 | if (iter != mime_file_fields_.end()) { 122 | mime_file_fields_.erase(iter); 123 | } 124 | } 125 | 126 | const std::string& Request::mime_string_field(const std::string& name) const { 127 | auto iter = mime_string_fields_.find(name); 128 | if (iter != mime_string_fields_.end()) { 129 | return iter->second; 130 | } 131 | return empty_string; 132 | } 133 | 134 | const std::string& Request::nime_file_field(const std::string& name) const { 135 | auto iter = mime_file_fields_.find(name); 136 | if (iter != mime_file_fields_.end()) { 137 | return iter->second; 138 | } 139 | return empty_string; 140 | } 141 | 142 | void Request::set_download_range(size_t bytes_start, size_t bytes_end/* = end*/) { 143 | download_range_ = std::to_string(bytes_start) + '-'; 144 | if (bytes_end != end) { 145 | download_range_ += std::to_string(bytes_end); 146 | } 147 | } 148 | 149 | void Request::set_proxy(const std::string& host, uint32_t port, ProxyType type/* = ProxyType::HTTP*/) { 150 | proxy_data_.host = host; 151 | proxy_data_.port = port; 152 | proxy_data_.type = type; 153 | proxy_data_.username.clear(); 154 | proxy_data_.password.clear(); 155 | proxy_data_.auth_type = HttpAuthType::ANY; 156 | } 157 | 158 | } // namespace client 159 | } // namespace ic 160 | -------------------------------------------------------------------------------- /include/iclient/http.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file http.h 3 | * @author Leopard-C (leopard.c@outlook.com) 4 | * @version 0.1 5 | * @date 2023-01-12 6 | * 7 | * @copyright Copyright (c) 2021-present, Jinbao Chen. 8 | */ 9 | #ifndef IC_CLIENT_HTTP_H_ 10 | #define IC_CLIENT_HTTP_H_ 11 | 12 | #include 13 | 14 | namespace ic { 15 | namespace client { 16 | namespace http { 17 | 18 | /** 19 | * @brief Http Method. 20 | */ 21 | enum class Method { 22 | HTTP_UNKNOWN, 23 | HTTP_GET, 24 | HTTP_HEAD, 25 | HTTP_POST, 26 | HTTP_OPTIONS, 27 | HTTP_PUT, 28 | HTTP_DELETE, 29 | HTTP_CONNECT, 30 | HTTP_PATCH 31 | }; 32 | 33 | /** 34 | * @brief Http Version. 35 | */ 36 | enum class Version { 37 | V1_0, 38 | V1_1, 39 | V2_0, 40 | V2TLS, 41 | NONE 42 | }; 43 | 44 | /** 45 | * @brief Http Status Code. 46 | */ 47 | enum class StatusCode { 48 | HTTP_UNKNOWN = 0, 49 | 50 | HTTP_100_CONTINUE = 100, 51 | HTTP_101_SWITCHING_PROTOCOLS = 101, 52 | HTTP_102_PROCESSING = 102, 53 | HTTP_103_EARLY_HINTS = 103, 54 | 55 | HTTP_200_OK = 200, 56 | HTTP_201_CREATED = 201, 57 | HTTP_202_ACCEPTED = 202, 58 | HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203, 59 | HTTP_204_NO_CONTENT = 204, 60 | HTTP_205_RESET_CONTENT = 205, 61 | HTTP_206_PARTIAL_CONTENT = 206, 62 | HTTP_207_MULTI_STATUS = 207, 63 | HTTP_208_ALREADY_REPORTED = 208, 64 | HTTP_226_IM_USED = 226, 65 | 66 | HTTP_300_MULTIPLE_CHOICES = 300, 67 | HTTP_301_MOVED_PERMANENTLY = 301, 68 | HTTP_302_FOUND = 302, 69 | HTTP_303_SEE_OTHER = 303, 70 | HTTP_304_NOT_MODIFIED = 304, 71 | HTTP_305_USE_PROXY = 305, 72 | HTTP_306_SWITCH_PROXY = 306, 73 | HTTP_307_TEMPORARY_REDIRECT = 307, 74 | HTTP_308_PERMANENT_REDIRECT = 308, 75 | 76 | HTTP_400_BAD_REQUEST = 400, 77 | HTTP_401_UNAUTHORIZED = 401, 78 | HTTP_402_PAYMENT_REQUIRED = 402, 79 | HTTP_403_FORBIDDEN = 403, 80 | HTTP_404_NOT_FOUND = 404, 81 | HTTP_405_METHOD_NOT_ALLOWED = 405, 82 | HTTP_406_NOT_ACCEPTABLE = 406, 83 | HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407, 84 | HTTP_408_REQUEST_TIMEOUT = 408, 85 | HTTP_409_CONFLICT = 409, 86 | HTTP_410_GONE = 410, 87 | HTTP_411_LENGTH_REQUIRED = 411, 88 | HTTP_412_PRECONDITION_FAILED = 412, 89 | HTTP_413_PAYLOAD_TOO_LARGE = 413, 90 | HTTP_414_URI_TOO_LONG = 414, 91 | HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415, 92 | HTTP_416_RANGE_NOT_SATISFIABLE = 416, 93 | HTTP_417_EXPECTATION_FAILED = 417, 94 | HTTP_418_IM_A_TEAPOT = 418, 95 | HTTP_421_MISDIRECTED_REQUEST = 421, 96 | HTTP_422_UNPROCESSABLE_ENTITY = 422, 97 | HTTP_423_LOCKED = 423, 98 | HTTP_424_FAILED_DEPENDENCY = 424, 99 | HTTP_425_TOO_EARLY = 425, 100 | HTTP_426_UPGRADE_REQUIRED = 426, 101 | HTTP_428_PRECONDITION_REQUIRED = 428, 102 | HTTP_429_TOO_MANY_REQUESTS = 429, 103 | HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE = 431, 104 | HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS = 451, 105 | 106 | HTTP_500_INTERNAL_SERVER_ERROR = 500, 107 | HTTP_501_NOT_IMPLEMENTED = 501, 108 | HTTP_502_BAD_GATEWAY = 502, 109 | HTTP_503_SERVICE_UNAVAILABLE = 503, 110 | HTTP_504_GATEWAY_TIMEOUT = 504, 111 | HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505, 112 | HTTP_506_VARIANT_ALSO_NEGOTIATES = 506, 113 | HTTP_507_INSUFFICIENT_STORAGE = 507, 114 | HTTP_508_LOOP_DETECTED = 508, 115 | HTTP_510_NOT_EXTENDED = 510, 116 | HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = 511 117 | }; 118 | 119 | /** 120 | * @brief Http Connection Type 121 | */ 122 | enum class ConnectionType { 123 | CLOSE, 124 | KEEP_ALIVE, 125 | UPGRADE 126 | }; 127 | 128 | /** 129 | * @brief Http Content Type. 130 | */ 131 | enum class ContentType { 132 | UNKNOWN, 133 | 134 | NO_CONTENT, 135 | 136 | TEXT_CSS, 137 | TEXT_CSV, 138 | TEXT_HTML, 139 | TEXT_PLAIN, 140 | TEXT_XML, 141 | 142 | IMAGE_GIF, 143 | IMAGE_JPEG, 144 | IMAGE_PNG, 145 | IMAGE_TIFF, 146 | IMAGE_X_ICON, 147 | IMAGE_SVG_XML, 148 | 149 | VIDEO_MPEG, 150 | VIDEO_MP4, 151 | VIDEO_X_FLV, 152 | VIDEO_WEBM, 153 | 154 | MULTIPART_MIXED, 155 | MULTIPART_ALTERNATIVE, 156 | MULTIPART_RELATED, 157 | MULTIPART_FORM_DATA, 158 | 159 | AUDIO_MPEG, 160 | AUDIO_X_MS_WMA, 161 | AUDIO_X_WAV, 162 | 163 | APPLICATION_JAVASCRIPT, 164 | APPLICATION_OCTET_STREAM, 165 | APPLICATION_OGG, 166 | APPLICATION_PDF, 167 | APPLICATION_XHTML_XML, 168 | APPLICATION_X_SHOCKWAVE_FLASH, 169 | APPLICATION_JSON, 170 | APPLICATION_LD_JSON, 171 | APPLICATION_XML, 172 | APPLICATION_ZIP, 173 | APPLICATION_X_WWW_FORM_URLENCODED 174 | }; 175 | 176 | int to_curl_http_version(Version ver); 177 | Version from_curl_http_version(int ver); 178 | StatusCode from_curl_http_response_code(int code); 179 | 180 | const char* to_string(Method method); 181 | const char* to_string(Version ver); 182 | const char* to_string(StatusCode code); 183 | const char* to_string(ConnectionType type); 184 | const char* to_string(ConnectionType type); 185 | 186 | } // namespace http 187 | } // namespace client 188 | } // namespace ic 189 | 190 | #endif // IC_CLIENT_HTTP_H_ 191 | -------------------------------------------------------------------------------- /example/main.cpp: -------------------------------------------------------------------------------- 1 | /* VLD (memory leak detector) */ 2 | #ifdef _WIN32 3 | # define _USE_VLD 0 4 | # if _USE_VLD == 1 5 | # pragma comment(lib, "D:/CPP_INCLUDE/vld-2.7.0/lib/Win64/vld.lib") 6 | # include 7 | # endif // _USE_VLD 8 | #endif // _WIN32 9 | 10 | #include "iclient/iclient.h" 11 | #include 12 | #include 13 | 14 | #ifdef _WIN32 15 | # include 16 | #else 17 | # include 18 | # include 19 | #endif 20 | 21 | int g_term_width; 22 | int g_last_symbol_count = 0; 23 | int g_total_symbol_count = 0; 24 | 25 | const char* g_test_download_file_url = "https://i-blog.csdnimg.cn/direct/c96ecd7d2a23496b895e7f5bdec7f3ae.jpeg"; 26 | 27 | void test_url(); 28 | void test_http_get(); 29 | void test_http_post(); 30 | void test_http_put(); 31 | void test_download(); 32 | void test_download_resume(); 33 | void test_download_range(); 34 | void test_download_speed_limit(); 35 | 36 | void get_terminal_info(); 37 | 38 | 39 | /* Progress bar */ 40 | bool g_curl_xfer_info(const ic::client::Request& request, 41 | curl_off_t download_total_bytes, curl_off_t download_now_bytes, 42 | curl_off_t upload_total_bytes, curl_off_t upload_now_bytes); 43 | void reset_progress_bar(); 44 | 45 | 46 | int main() { 47 | get_terminal_info(); 48 | 49 | printf("0. quit\n"); 50 | printf("1. test_url\n"); 51 | printf("2. test_http_get\n"); 52 | printf("3. test_http_post\n"); 53 | printf("4. test_http_put\n"); 54 | printf("5. test_download\n"); 55 | printf("6. test_download_resume\n"); 56 | printf("7. test_download_range\n"); 57 | printf("8. test_download_speed_limit\n"); 58 | printf("Choose item(0-8): "); 59 | fflush(stdout); 60 | 61 | int id; 62 | int n = scanf("%d", &id); 63 | if (n <= 0) { 64 | printf("Invalid input!\n"); 65 | return 1; 66 | } 67 | printf("------------------------------\n\n"); 68 | 69 | switch (id) { 70 | case 0: break; 71 | case 1: test_url(); break; 72 | case 2: test_http_get(); break; 73 | case 3: test_http_post(); break; 74 | case 4: test_http_put(); break; 75 | case 5: test_download(); break; 76 | case 6: test_download_resume(); break; 77 | case 7: test_download_range(); break; 78 | case 8: test_download_speed_limit(); break; 79 | default: printf("Invalid input!\n"); break; 80 | } 81 | 82 | #ifdef _WIN32 83 | system("pause"); 84 | #endif 85 | 86 | return 0; 87 | } 88 | 89 | 90 | void get_terminal_info() { 91 | #ifdef _WIN32 92 | system("chcp 65001"); 93 | HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE); 94 | CONSOLE_SCREEN_BUFFER_INFO bInfo; 95 | GetConsoleScreenBufferInfo(hOutput, &bInfo); 96 | g_term_width = bInfo.srWindow.Right - bInfo.srWindow.Left; 97 | #else 98 | struct winsize size; 99 | ioctl(STDIN_FILENO, TIOCGWINSZ, &size); 100 | g_term_width = size.ws_col; 101 | #endif // _WIN32 102 | 103 | if (g_term_width > 132) { 104 | g_total_symbol_count = 100; 105 | } 106 | else if (g_term_width > 52) { 107 | g_total_symbol_count = g_term_width - 32; 108 | } 109 | else { 110 | g_total_symbol_count = 0; 111 | } 112 | 113 | g_last_symbol_count = 0; 114 | } 115 | 116 | void format_data_size(long long data_size, char* output_str, int output_str_size) { 117 | const int KB = 1024; 118 | const int MB = 1024 * 1024; 119 | const int GB = 1024 * 1024 * 1024; 120 | if (data_size < KB) { 121 | snprintf(output_str, output_str_size, "%lldB", data_size); 122 | } 123 | else if (data_size < 1024 * 1024) { 124 | snprintf(output_str, output_str_size, "%.2lfKB", data_size / static_cast(KB)); 125 | } 126 | else if (data_size < 1024 * 1024 * 1024) { 127 | snprintf(output_str, output_str_size, "%.2lfMB", data_size / static_cast(MB)); 128 | } 129 | else { 130 | snprintf(output_str, output_str_size, "%.2lfGB", data_size / static_cast(GB)); 131 | } 132 | } 133 | 134 | /* Progress bar */ 135 | bool g_curl_xfer_info(const ic::client::Request& request, 136 | curl_off_t download_total_bytes, curl_off_t download_now_bytes, 137 | curl_off_t upload_total_bytes, curl_off_t upload_now_bytes) 138 | { 139 | if (download_total_bytes > 0 && g_total_symbol_count > 0) { 140 | double percent = static_cast(download_now_bytes) / download_total_bytes; 141 | int curr_symbol_count = static_cast(g_total_symbol_count * percent); 142 | if (curr_symbol_count > g_last_symbol_count) { 143 | printf("\r["); 144 | for (int i = 0; i < curr_symbol_count - 1; ++i) { 145 | printf("="); 146 | } 147 | printf(">"); 148 | for (int i = curr_symbol_count; i < g_total_symbol_count; ++i) { 149 | printf(" "); 150 | } 151 | char dl_now_bytes_str[32], dl_total_bytes_str[32]; 152 | format_data_size(download_now_bytes, dl_now_bytes_str, sizeof(dl_now_bytes_str)); 153 | format_data_size(download_total_bytes, dl_total_bytes_str, sizeof(dl_total_bytes_str)); 154 | printf("] %9s/%-9s %5.2lf%%", dl_now_bytes_str, dl_total_bytes_str, percent * 100); 155 | fflush(stdout); 156 | g_last_symbol_count = curr_symbol_count; 157 | if (download_now_bytes >= download_total_bytes) { 158 | printf("\n"); 159 | } 160 | } 161 | } 162 | return true; 163 | } 164 | 165 | void reset_progress_bar() { 166 | g_last_symbol_count = 0; 167 | } 168 | -------------------------------------------------------------------------------- /include/curl/urlapi.h: -------------------------------------------------------------------------------- 1 | #ifndef CURLINC_URLAPI_H 2 | #define CURLINC_URLAPI_H 3 | /*************************************************************************** 4 | * _ _ ____ _ 5 | * Project ___| | | | _ \| | 6 | * / __| | | | |_) | | 7 | * | (__| |_| | _ <| |___ 8 | * \___|\___/|_| \_\_____| 9 | * 10 | * Copyright (C) 2018 - 2022, Daniel Stenberg, , et al. 11 | * 12 | * This software is licensed as described in the file COPYING, which 13 | * you should have received as part of this distribution. The terms 14 | * are also available at https://curl.se/docs/copyright.html. 15 | * 16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 17 | * copies of the Software, and permit persons to whom the Software is 18 | * furnished to do so, under the terms of the COPYING file. 19 | * 20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 | * KIND, either express or implied. 22 | * 23 | * SPDX-License-Identifier: curl 24 | * 25 | ***************************************************************************/ 26 | 27 | #include "curl.h" 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | /* the error codes for the URL API */ 34 | typedef enum { 35 | CURLUE_OK, 36 | CURLUE_BAD_HANDLE, /* 1 */ 37 | CURLUE_BAD_PARTPOINTER, /* 2 */ 38 | CURLUE_MALFORMED_INPUT, /* 3 */ 39 | CURLUE_BAD_PORT_NUMBER, /* 4 */ 40 | CURLUE_UNSUPPORTED_SCHEME, /* 5 */ 41 | CURLUE_URLDECODE, /* 6 */ 42 | CURLUE_OUT_OF_MEMORY, /* 7 */ 43 | CURLUE_USER_NOT_ALLOWED, /* 8 */ 44 | CURLUE_UNKNOWN_PART, /* 9 */ 45 | CURLUE_NO_SCHEME, /* 10 */ 46 | CURLUE_NO_USER, /* 11 */ 47 | CURLUE_NO_PASSWORD, /* 12 */ 48 | CURLUE_NO_OPTIONS, /* 13 */ 49 | CURLUE_NO_HOST, /* 14 */ 50 | CURLUE_NO_PORT, /* 15 */ 51 | CURLUE_NO_QUERY, /* 16 */ 52 | CURLUE_NO_FRAGMENT, /* 17 */ 53 | CURLUE_NO_ZONEID, /* 18 */ 54 | CURLUE_BAD_FILE_URL, /* 19 */ 55 | CURLUE_BAD_FRAGMENT, /* 20 */ 56 | CURLUE_BAD_HOSTNAME, /* 21 */ 57 | CURLUE_BAD_IPV6, /* 22 */ 58 | CURLUE_BAD_LOGIN, /* 23 */ 59 | CURLUE_BAD_PASSWORD, /* 24 */ 60 | CURLUE_BAD_PATH, /* 25 */ 61 | CURLUE_BAD_QUERY, /* 26 */ 62 | CURLUE_BAD_SCHEME, /* 27 */ 63 | CURLUE_BAD_SLASHES, /* 28 */ 64 | CURLUE_BAD_USER, /* 29 */ 65 | CURLUE_LAST 66 | } CURLUcode; 67 | 68 | typedef enum { 69 | CURLUPART_URL, 70 | CURLUPART_SCHEME, 71 | CURLUPART_USER, 72 | CURLUPART_PASSWORD, 73 | CURLUPART_OPTIONS, 74 | CURLUPART_HOST, 75 | CURLUPART_PORT, 76 | CURLUPART_PATH, 77 | CURLUPART_QUERY, 78 | CURLUPART_FRAGMENT, 79 | CURLUPART_ZONEID /* added in 7.65.0 */ 80 | } CURLUPart; 81 | 82 | #define CURLU_DEFAULT_PORT (1<<0) /* return default port number */ 83 | #define CURLU_NO_DEFAULT_PORT (1<<1) /* act as if no port number was set, 84 | if the port number matches the 85 | default for the scheme */ 86 | #define CURLU_DEFAULT_SCHEME (1<<2) /* return default scheme if 87 | missing */ 88 | #define CURLU_NON_SUPPORT_SCHEME (1<<3) /* allow non-supported scheme */ 89 | #define CURLU_PATH_AS_IS (1<<4) /* leave dot sequences */ 90 | #define CURLU_DISALLOW_USER (1<<5) /* no user+password allowed */ 91 | #define CURLU_URLDECODE (1<<6) /* URL decode on get */ 92 | #define CURLU_URLENCODE (1<<7) /* URL encode on set */ 93 | #define CURLU_APPENDQUERY (1<<8) /* append a form style part */ 94 | #define CURLU_GUESS_SCHEME (1<<9) /* legacy curl-style guessing */ 95 | #define CURLU_NO_AUTHORITY (1<<10) /* Allow empty authority when the 96 | scheme is unknown. */ 97 | #define CURLU_ALLOW_SPACE (1<<11) /* Allow spaces in the URL */ 98 | 99 | typedef struct Curl_URL CURLU; 100 | 101 | /* 102 | * curl_url() creates a new CURLU handle and returns a pointer to it. 103 | * Must be freed with curl_url_cleanup(). 104 | */ 105 | CURL_EXTERN CURLU *curl_url(void); 106 | 107 | /* 108 | * curl_url_cleanup() frees the CURLU handle and related resources used for 109 | * the URL parsing. It will not free strings previously returned with the URL 110 | * API. 111 | */ 112 | CURL_EXTERN void curl_url_cleanup(CURLU *handle); 113 | 114 | /* 115 | * curl_url_dup() duplicates a CURLU handle and returns a new copy. The new 116 | * handle must also be freed with curl_url_cleanup(). 117 | */ 118 | CURL_EXTERN CURLU *curl_url_dup(CURLU *in); 119 | 120 | /* 121 | * curl_url_get() extracts a specific part of the URL from a CURLU 122 | * handle. Returns error code. The returned pointer MUST be freed with 123 | * curl_free() afterwards. 124 | */ 125 | CURL_EXTERN CURLUcode curl_url_get(CURLU *handle, CURLUPart what, 126 | char **part, unsigned int flags); 127 | 128 | /* 129 | * curl_url_set() sets a specific part of the URL in a CURLU handle. Returns 130 | * error code. The passed in string will be copied. Passing a NULL instead of 131 | * a part string, clears that part. 132 | */ 133 | CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what, 134 | const char *part, unsigned int flags); 135 | 136 | /* 137 | * curl_url_strerror() turns a CURLUcode value into the equivalent human 138 | * readable error string. This is useful for printing meaningful error 139 | * messages. 140 | */ 141 | CURL_EXTERN const char *curl_url_strerror(CURLUcode); 142 | 143 | #ifdef __cplusplus 144 | } /* end of extern "C" */ 145 | #endif 146 | 147 | #endif /* CURLINC_URLAPI_H */ 148 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## iClient (iC Client) 2 | 3 | 【C++】基于`libcurl`的HTTP请求客户端。 4 | 5 | + C++版本:`c++11` 6 | + 支持`Windows`和`Linux` 7 | + 引入方法:`#include "iclient/iclient.h"` 8 | 9 | ## 1. 功能与特点 10 | 11 | + HTTP、POST、PUT、DELETE、HEAD请求 12 | + 是否重定向,及重定向最大次数 13 | + 超时(毫秒) 14 | + SSL证书和密钥 15 | + 验证HTTPS请求对象的合法性 16 | + HTTP(s)代理 17 | + 接受的内容编码方式 (Accept-Encoding) 18 | + Cookie 19 | + Post请求数据(可设置MIME类型) 20 | + 自定义传输进度处理(例如下载进度条) 21 | + 文件下载(普通下载、断点续传、分片下载) 22 | + 限制下载/上传速度 23 | 24 | ## 2. 关键命名空间与类 25 | 26 | + namespace `ic`: 27 | + namespace `client`: 28 | + namespace `http` 29 | + enum `Method`: GET/POST/HEAD/... 30 | + enum `StatusCode`: HTTP状态码 31 | + enum `Version`: V1_0/V1_1/V2_0/... 32 | + namespace `util` 33 | + enum `Status`: Request请求的状态码(如超时、DNS错误等) 34 | + struct `ProxyData`: 描述一个HTTP(s)代理的相关信息 35 | + class `Request` 36 | + class `Response` 37 | + class `Executor`: 真正执行Request请求 38 | + class `Url`: 封装URL对象,便于添加、合并参数 39 | 40 | ## 3. 编译构建 41 | 42 | 如果机器上没有安装`libcurl`,可以在 [Release页面](https://github.com/Leopard-C/iclient/releases/tag/v1.0.1) 下载。 43 | 44 | ![release-v1.0.1](assets/README/release-v1.0.1.jpg) 45 | 46 | 下载后,将静态库文件放在`lib`目录下,目录结构如下: 47 | 48 | ```shell 49 | lib 50 | ├── linux 51 | │   └── libcurl.a 52 | └── windows 53 | ├── Win32 54 | │   ├── Debug 55 | │   │   └── libcurl.lib 56 | │   └── Release 57 | │   └── libcurl.lib 58 | └── x64 59 | ├── Debug 60 | │   └── libcurl.lib 61 | └── Release 62 | └── libcurl.lib 63 | ``` 64 | 65 | 66 | + `linux`平台: 67 | 68 | ```shell 69 | # 使用makefile 70 | make iclient # 编译静态库文件 (lib/linux/x86_64/libiclient.a) 71 | make example.out # 编译示例代码 (bin/example.out) 72 | 73 | # 也可以使用xmake构建 74 | xmake f -m release 75 | xmake b iclient 76 | xmake b example.out 77 | ``` 78 | 79 | + `windows`平台: 80 | 81 | 使用`Visual Studio 2019`打开`win-build/iclient.sln`解决方案。 82 | 83 | 编译`iclient`项目生成静态库文件 (lib/windows/x64/Release/iclient.lib) 84 | 85 | 编译`example`项目生成示例程序 (bin/example.exe) 86 | 87 | 88 | ## 3. 简单使用 89 | 90 | 可以参考 `example/`目录下的文件 91 | 92 | ```shell 93 | $ tree example 94 | example 95 | ├── main.cpp 96 | ├── test_download.cpp 97 | ├── test_download_range.cpp 98 | ├── test_download_resume.cpp 99 | ├── test_download_speed_limit.cpp 100 | ├── test_http_get.cpp 101 | ├── test_http_post.cpp 102 | ├── test_http_put.cpp 103 | └── test_url.cpp 104 | ``` 105 | 106 | ### 3.1 `ic::client::Url`的使用 107 | 108 | 例如需要构造一个URL,`https://api.icrystal.top/util/random?min=1&max=100&count=20`,该链接含有3个参数。 109 | 110 | ```C++ 111 | ic::client::Url url("https://api.icrystal.top/util/random"); 112 | url.SetParam("min", 1); 113 | url.SetParam("max", 100); 114 | url.SetParam("count", 20) 115 | 116 | // 获取合并的参数串 117 | // "min=1&max=100&count=20" 118 | url.GetParamsString(); 119 | 120 | // 获取整个URL字符串 121 | // "https://api.icrystal.top/random?min=1&max=100&count=20" 122 | url.ToString(); 123 | ``` 124 | 125 | 注意 ! 126 | 127 | + AddParam: 添加参数,保留同名的其他参数,如: 128 | 129 | ```C++ 130 | AddParam("name", "Tom"); "name=Tom" 131 | AddParam("name", "Jack"); "name=Tom&name=Jack" 132 | ``` 133 | 134 | + setParam: 唯一参数,覆盖同名的参数值。 135 | 136 | ```C++ 137 | SetParam("name", "Tom"); "name=Tom" 138 | SetParam("name", "Jack"); "name=Jack" 139 | ``` 140 | 141 | ### 3.2 GET/POST请求 142 | 143 | GET请求 144 | 145 | ```C++ 146 | ic::client::Request request("http://httpbin.org/ip"); 147 | //request.set_http_method(ic::client::http::Method::HTTP_GET); // 默认为GET请求 148 | ic::client::Response res = request.Perform(); 149 | 150 | if (res.status() == ic::client::Status::SUCCESS && 151 | res.http_status_code() == ic::client::http::StatusCode::HTTP_200_OK) // 等价于 if (res.ok()) { ... } 152 | { 153 | std::cout << res.data() << std::endl; 154 | } 155 | ``` 156 | 157 | POST请求 158 | 159 | ```C++ 160 | ic::client::Request request("http://httpbin.org/ip"); 161 | request.set_http_method(ic::client::http::Method::HTTP_POST); 162 | ``` 163 | 164 | ### 3.3 设置/获取header 165 | 166 | Header名称不区分大小写! 167 | 168 | ```C++ 169 | // 设置Request的header 170 | request.set_header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Ap..."); 171 | request.set_header("referer", "https://www.biaud.com"); 172 | auto res = request.Perform(); 173 | 174 | // 获取Response的header 175 | // std::map 176 | auto& headers = res.headers(); 177 | for (auto& header : headers) { 178 | std::cout << header.first << ": " << header.second << std::endl; 179 | } 180 | res.HasHeader("Content-Length"); // true 181 | res.GetHeader("Content-Length"); // 10134 182 | ``` 183 | 184 | ### 3.4 设置代理 185 | 186 | ```C++ 187 | struct ProxyData { 188 | ProxyType type = ProxyType::HTTP; 189 | uint32_t port; 190 | HttpAuthType auth_type = HttpAuthType::ANY; 191 | std::string host; 192 | std::string username; 193 | std::string password; 194 | }; 195 | 196 | ProxyData proxy_data; 197 | proxy_data.host = "11.12.13.14"; 198 | proxy.data.port = 3011; 199 | proxy.type = ic::client::ProxyType::HTTP; 200 | request.set_proxy(proxy_data); 201 | 202 | // 或者 203 | request.set_proxy("11.12.13.14", 3011, ic::client::ProxyType::HTTP); 204 | ``` 205 | 206 | ### 3.5 设置Cookie 207 | 208 | ```C++ 209 | request.set_cookie("name=Tom&age=18"); 210 | request.set_cookie_file("/etc/xxx/cookie/12345.cookie"); 211 | ``` 212 | 213 | ### 3.6 设置Post Data 214 | 215 | ```C++ 216 | request.set_data("{\"name\":\"Tom\"}"); 217 | ``` 218 | 219 | ### 3.7 重定向(次数) 220 | 221 | ```C++ 222 | request.set_max_redirects(3); // 最多重定向3次 223 | request.set_max_redirects(0); // 设为0,表示禁止重定向 224 | request.set_max_redirects(-1); // 设为-1,表示不限制重定向次数(默认) 225 | ``` 226 | 227 | ### 3.8 HTTPS验证 228 | 229 | ```C++ 230 | request.set_verify_ssl_host(false); 231 | request.set_verify_ssl_peer(false); 232 | request.set_verify_ssl_status(false); 233 | request.set_verify_ssl(false); // 等价于上面三条语句 234 | ``` 235 | 236 | ### 3.9 下载文件 237 | 238 | ```C++ 239 | // @downloadFile: 下载的本地文件名 240 | // @resume(bool): 是否启用断点续传,默认不启用 241 | request.set_download_file("output.jpg"/*, false*/); 242 | 243 | // @range: 单位bytes 244 | // 包括0和4095 245 | request.set_download_range(0, 4095); 246 | ``` 247 | 248 | ### 3.10 设置传输进度回调函数 249 | 250 | ```C++ 251 | request.set_transfer_progress_handler(url_xfer_info_callback); 252 | ``` 253 | 254 | 其中,`url_xfer_info_callback` 函数签名如下 255 | 256 | ```C++ 257 | bool s_curl_xfer_info( 258 | const ic::client::Request& request, 259 | curl_off_t download_total_bytes, /* 总共需要下载的字节数 */ 260 | curl_off_t download_now_bytes, /* 已经下载的字节数 */ 261 | curl_off_t upload_total_bytes, /* 总共需要上传的字节数 */ 262 | curl_off_t upload_now_bytes); /* 已经上传的字节数 */ 263 | ``` 264 | 265 | ### 3.11 更多设置项 266 | 267 | 可查看 `include/iclient/request.h` 268 | 269 | ## 4. example 270 | 271 | `No.5 断点续传` 272 | 273 | ![breakpoint_continue](assets/README/breakpoint_continue.jpg) 274 | 275 | 276 | 277 | `No.6 分片下载`(可以放到不同的线程中同时下载,即多线程下载) 278 | 279 | ![download_range](assets/README/download_range.jpg) 280 | 281 | 282 | ## 5. 注意事项 283 | 284 | 如果使用`libcurl`和`openssl`的静态链接库,在多线程环境下发送`HTTPS`请求,需要在每个线程结束前调用`OPENSSL_thread_stop()`函数执行清理工作,否则可能产生内存泄露。 285 | 286 | ```c++ 287 | #include 288 | 289 | int main() { 290 | std::thread t([]{ 291 | // send https request 292 | 293 | OPENSSL_thread_stop(); // call before thread exit 294 | }); 295 | t.join(); 296 | return 0; 297 | } 298 | ``` 299 | 300 | > ref: https://curl.se/libcurl/c/threadsafe.html 301 | > 302 | > All current TLS libraries libcurl supports are thread-safe. 303 | > 304 | > OpenSSL 1.1.0+ can be safely used in multi-threaded applications provided that support for the underlying OS threading API is built-in. For older versions of OpenSSL, the user must set mutex callbacks. 305 | > 306 | > libcurl may not be able to fully clean up after multi-threaded OpenSSL depending on how OpenSSL was built and loaded as a library. It is possible in some rare circumstances a memory leak could occur unless you implement your own OpenSSL thread cleanup. 307 | > 308 | > For example, on Windows if both libcurl and OpenSSL are linked statically to a DLL or application then OpenSSL may leak memory unless the DLL or application calls OPENSSL_thread_stop() before each thread terminates. If OpenSSL is built as a DLL then it does this cleanup automatically and there is no leak. If libcurl is built as a DLL and OpenSSL is linked statically to it then libcurl does this cleanup automatically and there is no leak (added in libcurl 8.8.0). 309 | 310 | ## END 311 | 312 | 313 | 314 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # this is the build file for project 2 | # it is autogenerated by the xmake build system. 3 | # do not edit by hand. 4 | 5 | ifneq ($(VERBOSE),1) 6 | VV=@ 7 | endif 8 | 9 | CC=/usr/bin/gcc 10 | CXX=/usr/bin/gcc 11 | AS=/usr/bin/gcc 12 | MXX=/usr/bin/gcc 13 | MM=/usr/bin/gcc 14 | 15 | AR=/usr/bin/ar 16 | LD=/usr/bin/g++ 17 | SH=/usr/bin/g++ 18 | 19 | example.out_LD=/usr/bin/g++ 20 | example.out_CXX=/usr/bin/gcc 21 | example.out_CXX=/usr/bin/gcc 22 | iclient_AR=/usr/bin/ar 23 | iclient_CXX=/usr/bin/gcc 24 | iclient_CXX=/usr/bin/gcc 25 | 26 | example.out_CXXFLAGS=-m64 -fvisibility=hidden -fvisibility-inlines-hidden -O3 -std=c++11 -Iinclude -Wreturn-type -Wsign-compare -Wunused -Wswitch -Wno-deprecated-declarations -DNDEBUG 27 | example.out_CXXFLAGS=-m64 -fvisibility=hidden -fvisibility-inlines-hidden -O3 -std=c++11 -Iinclude -Wreturn-type -Wsign-compare -Wunused -Wswitch -Wno-deprecated-declarations -DNDEBUG 28 | example.out_LDFLAGS=-m64 -Llib/linux/x86_64 -s -liclient -lcurl -lpthread -ldl 29 | iclient_CXXFLAGS=-m64 -fvisibility=hidden -fvisibility-inlines-hidden -O3 -std=c++11 -Iinclude -Wreturn-type -Wsign-compare -Wunused -Wswitch -Wno-deprecated-declarations -DNDEBUG 30 | iclient_CXXFLAGS=-m64 -fvisibility=hidden -fvisibility-inlines-hidden -O3 -std=c++11 -Iinclude -Wreturn-type -Wsign-compare -Wunused -Wswitch -Wno-deprecated-declarations -DNDEBUG 31 | iclient_ARFLAGS=-cr 32 | 33 | default: example.out iclient 34 | 35 | all: example.out iclient 36 | 37 | .PHONY: default all example.out iclient 38 | 39 | example.out: bin/example.out 40 | bin/example.out: lib/linux/x86_64/libiclient.a build/.objs/example.out/linux/x86_64/release/example/test_url.cpp.o build/.objs/example.out/linux/x86_64/release/example/test_download_range.cpp.o build/.objs/example.out/linux/x86_64/release/example/test_http_post.cpp.o build/.objs/example.out/linux/x86_64/release/example/test_download_speed_limit.cpp.o build/.objs/example.out/linux/x86_64/release/example/test_download.cpp.o build/.objs/example.out/linux/x86_64/release/example/main.cpp.o build/.objs/example.out/linux/x86_64/release/example/test_download_resume.cpp.o build/.objs/example.out/linux/x86_64/release/example/test_http_put.cpp.o build/.objs/example.out/linux/x86_64/release/example/test_http_get.cpp.o 41 | @echo linking.release example.out 42 | @mkdir -p bin 43 | $(VV)$(example.out_LD) -o bin/example.out build/.objs/example.out/linux/x86_64/release/example/test_url.cpp.o build/.objs/example.out/linux/x86_64/release/example/test_download_range.cpp.o build/.objs/example.out/linux/x86_64/release/example/test_http_post.cpp.o build/.objs/example.out/linux/x86_64/release/example/test_download_speed_limit.cpp.o build/.objs/example.out/linux/x86_64/release/example/test_download.cpp.o build/.objs/example.out/linux/x86_64/release/example/main.cpp.o build/.objs/example.out/linux/x86_64/release/example/test_download_resume.cpp.o build/.objs/example.out/linux/x86_64/release/example/test_http_put.cpp.o build/.objs/example.out/linux/x86_64/release/example/test_http_get.cpp.o $(example.out_LDFLAGS) 44 | 45 | build/.objs/example.out/linux/x86_64/release/example/test_url.cpp.o: example/test_url.cpp 46 | @echo compiling.release example/test_url.cpp 47 | @mkdir -p build/.objs/example.out/linux/x86_64/release/example 48 | $(VV)$(example.out_CXX) -c $(example.out_CXXFLAGS) -o build/.objs/example.out/linux/x86_64/release/example/test_url.cpp.o example/test_url.cpp 49 | 50 | build/.objs/example.out/linux/x86_64/release/example/test_download_range.cpp.o: example/test_download_range.cpp 51 | @echo compiling.release example/test_download_range.cpp 52 | @mkdir -p build/.objs/example.out/linux/x86_64/release/example 53 | $(VV)$(example.out_CXX) -c $(example.out_CXXFLAGS) -o build/.objs/example.out/linux/x86_64/release/example/test_download_range.cpp.o example/test_download_range.cpp 54 | 55 | build/.objs/example.out/linux/x86_64/release/example/test_http_post.cpp.o: example/test_http_post.cpp 56 | @echo compiling.release example/test_http_post.cpp 57 | @mkdir -p build/.objs/example.out/linux/x86_64/release/example 58 | $(VV)$(example.out_CXX) -c $(example.out_CXXFLAGS) -o build/.objs/example.out/linux/x86_64/release/example/test_http_post.cpp.o example/test_http_post.cpp 59 | 60 | build/.objs/example.out/linux/x86_64/release/example/test_download_speed_limit.cpp.o: example/test_download_speed_limit.cpp 61 | @echo compiling.release example/test_download_speed_limit.cpp 62 | @mkdir -p build/.objs/example.out/linux/x86_64/release/example 63 | $(VV)$(example.out_CXX) -c $(example.out_CXXFLAGS) -o build/.objs/example.out/linux/x86_64/release/example/test_download_speed_limit.cpp.o example/test_download_speed_limit.cpp 64 | 65 | build/.objs/example.out/linux/x86_64/release/example/test_download.cpp.o: example/test_download.cpp 66 | @echo compiling.release example/test_download.cpp 67 | @mkdir -p build/.objs/example.out/linux/x86_64/release/example 68 | $(VV)$(example.out_CXX) -c $(example.out_CXXFLAGS) -o build/.objs/example.out/linux/x86_64/release/example/test_download.cpp.o example/test_download.cpp 69 | 70 | build/.objs/example.out/linux/x86_64/release/example/main.cpp.o: example/main.cpp 71 | @echo compiling.release example/main.cpp 72 | @mkdir -p build/.objs/example.out/linux/x86_64/release/example 73 | $(VV)$(example.out_CXX) -c $(example.out_CXXFLAGS) -o build/.objs/example.out/linux/x86_64/release/example/main.cpp.o example/main.cpp 74 | 75 | build/.objs/example.out/linux/x86_64/release/example/test_download_resume.cpp.o: example/test_download_resume.cpp 76 | @echo compiling.release example/test_download_resume.cpp 77 | @mkdir -p build/.objs/example.out/linux/x86_64/release/example 78 | $(VV)$(example.out_CXX) -c $(example.out_CXXFLAGS) -o build/.objs/example.out/linux/x86_64/release/example/test_download_resume.cpp.o example/test_download_resume.cpp 79 | 80 | build/.objs/example.out/linux/x86_64/release/example/test_http_put.cpp.o: example/test_http_put.cpp 81 | @echo compiling.release example/test_http_put.cpp 82 | @mkdir -p build/.objs/example.out/linux/x86_64/release/example 83 | $(VV)$(example.out_CXX) -c $(example.out_CXXFLAGS) -o build/.objs/example.out/linux/x86_64/release/example/test_http_put.cpp.o example/test_http_put.cpp 84 | 85 | build/.objs/example.out/linux/x86_64/release/example/test_http_get.cpp.o: example/test_http_get.cpp 86 | @echo compiling.release example/test_http_get.cpp 87 | @mkdir -p build/.objs/example.out/linux/x86_64/release/example 88 | $(VV)$(example.out_CXX) -c $(example.out_CXXFLAGS) -o build/.objs/example.out/linux/x86_64/release/example/test_http_get.cpp.o example/test_http_get.cpp 89 | 90 | iclient: lib/linux/x86_64/libiclient.a 91 | lib/linux/x86_64/libiclient.a: build/.objs/iclient/linux/x86_64/release/src/request.cpp.o build/.objs/iclient/linux/x86_64/release/src/response.cpp.o build/.objs/iclient/linux/x86_64/release/src/executor.cpp.o build/.objs/iclient/linux/x86_64/release/src/http.cpp.o build/.objs/iclient/linux/x86_64/release/src/url.cpp.o build/.objs/iclient/linux/x86_64/release/src/util.cpp.o 92 | @echo linking.release libiclient.a 93 | @mkdir -p lib/linux/x86_64 94 | $(VV)$(iclient_AR) $(iclient_ARFLAGS) lib/linux/x86_64/libiclient.a build/.objs/iclient/linux/x86_64/release/src/request.cpp.o build/.objs/iclient/linux/x86_64/release/src/response.cpp.o build/.objs/iclient/linux/x86_64/release/src/executor.cpp.o build/.objs/iclient/linux/x86_64/release/src/http.cpp.o build/.objs/iclient/linux/x86_64/release/src/url.cpp.o build/.objs/iclient/linux/x86_64/release/src/util.cpp.o 95 | 96 | build/.objs/iclient/linux/x86_64/release/src/request.cpp.o: src/request.cpp 97 | @echo compiling.release src/request.cpp 98 | @mkdir -p build/.objs/iclient/linux/x86_64/release/src 99 | $(VV)$(iclient_CXX) -c $(iclient_CXXFLAGS) -o build/.objs/iclient/linux/x86_64/release/src/request.cpp.o src/request.cpp 100 | 101 | build/.objs/iclient/linux/x86_64/release/src/response.cpp.o: src/response.cpp 102 | @echo compiling.release src/response.cpp 103 | @mkdir -p build/.objs/iclient/linux/x86_64/release/src 104 | $(VV)$(iclient_CXX) -c $(iclient_CXXFLAGS) -o build/.objs/iclient/linux/x86_64/release/src/response.cpp.o src/response.cpp 105 | 106 | build/.objs/iclient/linux/x86_64/release/src/executor.cpp.o: src/executor.cpp 107 | @echo compiling.release src/executor.cpp 108 | @mkdir -p build/.objs/iclient/linux/x86_64/release/src 109 | $(VV)$(iclient_CXX) -c $(iclient_CXXFLAGS) -o build/.objs/iclient/linux/x86_64/release/src/executor.cpp.o src/executor.cpp 110 | 111 | build/.objs/iclient/linux/x86_64/release/src/http.cpp.o: src/http.cpp 112 | @echo compiling.release src/http.cpp 113 | @mkdir -p build/.objs/iclient/linux/x86_64/release/src 114 | $(VV)$(iclient_CXX) -c $(iclient_CXXFLAGS) -o build/.objs/iclient/linux/x86_64/release/src/http.cpp.o src/http.cpp 115 | 116 | build/.objs/iclient/linux/x86_64/release/src/url.cpp.o: src/url.cpp 117 | @echo compiling.release src/url.cpp 118 | @mkdir -p build/.objs/iclient/linux/x86_64/release/src 119 | $(VV)$(iclient_CXX) -c $(iclient_CXXFLAGS) -o build/.objs/iclient/linux/x86_64/release/src/url.cpp.o src/url.cpp 120 | 121 | build/.objs/iclient/linux/x86_64/release/src/util.cpp.o: src/util.cpp 122 | @echo compiling.release src/util.cpp 123 | @mkdir -p build/.objs/iclient/linux/x86_64/release/src 124 | $(VV)$(iclient_CXX) -c $(iclient_CXXFLAGS) -o build/.objs/iclient/linux/x86_64/release/src/util.cpp.o src/util.cpp 125 | 126 | clean: clean_example.out clean_iclient 127 | 128 | clean_example.out: clean_iclient 129 | @rm -rf bin/example.out 130 | @rm -rf bin/example.out.sym 131 | @rm -rf build/.objs/example.out/linux/x86_64/release/example/test_url.cpp.o 132 | @rm -rf build/.objs/example.out/linux/x86_64/release/example/test_download_range.cpp.o 133 | @rm -rf build/.objs/example.out/linux/x86_64/release/example/test_http_post.cpp.o 134 | @rm -rf build/.objs/example.out/linux/x86_64/release/example/test_download_speed_limit.cpp.o 135 | @rm -rf build/.objs/example.out/linux/x86_64/release/example/test_download.cpp.o 136 | @rm -rf build/.objs/example.out/linux/x86_64/release/example/main.cpp.o 137 | @rm -rf build/.objs/example.out/linux/x86_64/release/example/test_download_resume.cpp.o 138 | @rm -rf build/.objs/example.out/linux/x86_64/release/example/test_http_put.cpp.o 139 | @rm -rf build/.objs/example.out/linux/x86_64/release/example/test_http_get.cpp.o 140 | 141 | clean_iclient: 142 | @rm -rf lib/linux/x86_64/libiclient.a 143 | @rm -rf lib/linux/x86_64/iclient.sym 144 | @rm -rf build/.objs/iclient/linux/x86_64/release/src/request.cpp.o 145 | @rm -rf build/.objs/iclient/linux/x86_64/release/src/response.cpp.o 146 | @rm -rf build/.objs/iclient/linux/x86_64/release/src/executor.cpp.o 147 | @rm -rf build/.objs/iclient/linux/x86_64/release/src/http.cpp.o 148 | @rm -rf build/.objs/iclient/linux/x86_64/release/src/url.cpp.o 149 | @rm -rf build/.objs/iclient/linux/x86_64/release/src/util.cpp.o 150 | 151 | -------------------------------------------------------------------------------- /include/iclient/request.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file request.h 3 | * @brief Http Request. 4 | * @author Leopard-C (leopard.c@outlook.com) 5 | * @version 0.1 6 | * @date 2023-01-12 7 | * 8 | * @copyright Copyright (c) 2021-present, Jinbao Chen. 9 | */ 10 | #ifndef IC_CLIENT_REQUEST_H_ 11 | #define IC_CLIENT_REQUEST_H_ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "http.h" 19 | #include "response.h" 20 | 21 | namespace ic { 22 | namespace client { 23 | 24 | extern size_t end; /* static_cast(-1) */ 25 | 26 | 27 | enum class SslCertificateType { 28 | PME, 29 | DER 30 | }; 31 | 32 | const char* to_string(SslCertificateType type); 33 | 34 | 35 | enum class ProxyType { 36 | HTTP, 37 | HTTPS 38 | }; 39 | 40 | int to_curl(ProxyType type); 41 | const char* to_string(ProxyType type); 42 | 43 | 44 | enum class HttpAuthType { 45 | BASIC, 46 | DIGEST, 47 | ANY, 48 | ANY_SAFE 49 | }; 50 | 51 | unsigned long to_curl(HttpAuthType type); 52 | const char* to_string(HttpAuthType type); 53 | 54 | 55 | enum class IpResolve { 56 | Whatever, 57 | V4, 58 | V6 59 | }; 60 | 61 | 62 | struct ProxyData { 63 | ProxyType type = ProxyType::HTTP; 64 | uint32_t port = 0; 65 | HttpAuthType auth_type = HttpAuthType::ANY; 66 | std::string host; 67 | std::string username; 68 | std::string password; 69 | bool empty() const { return host.empty() || port == 0; } 70 | }; 71 | 72 | 73 | /** 74 | * @brief Http Request. 75 | */ 76 | class Request { 77 | friend class Executor; 78 | public: 79 | /** 80 | * @brief Transfer Process Handler. 81 | * 82 | * @retval true: Continue transfer 83 | * @retval false: Cancel. 84 | */ 85 | using TransferProgressHandler = std::function; 87 | 88 | public: 89 | Request() = default; 90 | Request(const std::string& url) : url_(url) {} 91 | Request(http::Method method) : http_method_(method) {} 92 | Request(const std::string& url, http::Method method) : url_(url), http_method_(method) {} 93 | 94 | /* Perform request */ 95 | Response Perform(); 96 | 97 | /* Cancel request */ 98 | void Cancel(); 99 | 100 | void set_transfer_progress_handler(TransferProgressHandler handler) 101 | { on_transfer_progress_handler_ = handler; } 102 | 103 | /* Timeout */ 104 | int timeout() const { return timeout_ms_; } 105 | void set_timeout(int milliseconds) { timeout_ms_ = milliseconds; } 106 | 107 | /* Speed */ 108 | int64_t max_upload_speed() const { return max_upload_speed_; } 109 | int64_t max_download_speed() const { return max_download_speed_; } 110 | void set_max_upload_speed(int64_t bps) { max_upload_speed_ = bps; } 111 | void set_max_download_speed(int64_t bps) { max_download_speed_ = bps; } 112 | 113 | /* Buffer size */ 114 | int64_t buffer_size() const { return buffer_size_; } 115 | void set_buffer_size(int64_t buffer_size) { buffer_size_ = buffer_size; } 116 | 117 | /* Url */ 118 | const std::string& url() const { return url_; } 119 | void set_url(const std::string& url) { url_ = url; } 120 | 121 | /* Method */ 122 | http::Method http_method() const { return http_method_; } 123 | void set_http_method(http::Method method) { http_method_ = method; } 124 | 125 | /* Version */ 126 | http::Version http_version() const { return http_version_; } 127 | void set_http_version(http::Version ver) { http_version_ = ver; } 128 | 129 | /* Follow redirects */ 130 | int max_redirects() const { return max_redirects_; } 131 | void set_max_redirects(int count = -1) { max_redirects_ = count < -1 ? -1 : count; } 132 | 133 | /* Ip resolve */ 134 | IpResolve ip_resolve() const { return ip_resolve_; } 135 | void set_ip_resolve(IpResolve ip_resolve) { ip_resolve_ = ip_resolve; } 136 | 137 | /* Verify */ 138 | bool verify_ssl_peer() const { return verify_ssl_peer_; } 139 | bool verify_ssl_host() const { return verify_ssl_host_; } 140 | bool verify_ssl_status() const { return verify_ssl_status_; } 141 | void set_verify_ssl_peer(bool verify) { verify_ssl_peer_ = verify; } 142 | void set_verify_ssl_host(bool verify) { verify_ssl_host_ = verify; } 143 | void set_verify_ssl_status(bool verify) { verify_ssl_status_ = verify; } 144 | void set_verify_ssl(bool verify) { verify_ssl_peer_ = verify_ssl_host_ = verify_ssl_status_ = verify; } 145 | 146 | /* SSL cert & key */ 147 | SslCertificateType ssl_cert_type() const { return ssl_cert_type_; } 148 | const std::string& ssl_cert_file() const { return ssl_cert_file_; } 149 | const std::string& ssl_key() const { return ssl_key_file_; } 150 | const std::string& ssl_key_password() const { return ssl_key_file_password_; } 151 | void set_ssl_key(const std::string& key_file) { ssl_key_file_ = key_file; } 152 | void set_ssl_key_password(const std::string& passowrd) { ssl_key_file_password_ = passowrd; } 153 | void set_ssl_cert_type(SslCertificateType cert_type) { ssl_cert_type_ = cert_type; } 154 | void set_ssl_cert_file(const std::string& cert_file) { ssl_cert_file_ = cert_file; } 155 | void set_ssl_cert(SslCertificateType cert_type, const std::string& cert_file) { 156 | ssl_cert_type_ = cert_type; 157 | ssl_cert_file_ = cert_file; 158 | } 159 | 160 | /* Proxy */ 161 | const ProxyData& proxy() const { return proxy_data_; } 162 | void set_proxy(const ProxyData& proxy_data) { proxy_data_ = proxy_data; } 163 | void set_proxy(const std::string& host, uint32_t port, ProxyType type = ProxyType::HTTP); 164 | bool HasProxy() const { return !proxy_data_.empty(); } 165 | 166 | /* Accept Encodings */ 167 | const std::vector& accept_encodings() const { return accept_encodings_; } 168 | void set_accpet_encodings(const std::vector& encodings) { accept_encodings_ = encodings; } 169 | void set_accept_all_encodings() { std::vector().swap(accept_encodings_); } 170 | 171 | /* Header */ 172 | const std::map& headers() const { return headers_; } 173 | const std::string& header(std::string name) const; 174 | void set_headers(const std::map& headers) { headers_ = headers; } 175 | void set_header(std::string name, const std::string& value); 176 | void RemoveHeader(std::string name); 177 | void ClearHeaders() { std::map().swap(headers_); } 178 | 179 | /* Cookie */ 180 | const std::string& cookie() const { return cookie_; } 181 | const std::string& cookie_file() const { return cookie_file_; } 182 | void set_cookie(const std::string& cookie) { cookie_ = cookie; } 183 | void set_cookie_file(const std::string& cookie_file) { cookie_file_ = cookie_file; } 184 | void ClearCookie() { cookie_.clear(); cookie_file_.clear(); } 185 | 186 | /* Data */ 187 | const std::string& data() const { return data_; } 188 | void set_data(const std::string& data) { data_ = data; } 189 | void ClearData() { data_.clear(); } 190 | 191 | /* MimeField, string */ 192 | const std::map& mime_string_fields() const { return mime_string_fields_; } 193 | const std::map& mime_file_fields() const { return mime_file_fields_; } 194 | const std::string& mime_string_field(const std::string& name) const; 195 | const std::string& nime_file_field(const std::string& name) const; 196 | void set_mime_string_field(const std::string& name, const std::string value) { mime_string_fields_[name] = value; } 197 | void set_mime_file_field(const std::string& name, const std::string value) { mime_file_fields_[name] = value; } 198 | void RemoveMimeStringField(const std::string& name); 199 | void RemoveMimeFileField(const std::string& name); 200 | void ClearMimeStringFields() { mime_string_fields_.clear(); } 201 | void ClearMimeFileField() { mime_file_fields_.clear(); } 202 | 203 | /* Download to file */ 204 | const std::string& download_file() const { return download_file_; } 205 | const std::string& download_range() const { return download_range_; } 206 | bool download_resume() const { return download_resume_; } 207 | void set_download_file(const std::string& download_file, bool resume = false) 208 | { download_file_ = download_file; download_resume_ = resume; } 209 | void set_download_range(size_t bytes_start, size_t bytes_end = end); 210 | void set_download_resume(bool resume) { download_resume_ = resume; } 211 | 212 | /* User Data */ 213 | void* user_data() const { return user_data_; } 214 | void set_user_data(void* data) { user_data_ = data; } 215 | void ClearUserData() { user_data_ = nullptr; } 216 | 217 | friend size_t curl_write_header(char* buffer, size_t size, size_t nitems, void* user_ptr); 218 | friend size_t curl_write_data(void* buffer, size_t size, size_t nitems, void* user_ptr); 219 | friend int curl_xfer_info(void* clientp, curl_off_t download_total_bytes, curl_off_t download_now_bytes, 220 | curl_off_t upload_total_bytes, curl_off_t upload_now_bytes); 221 | 222 | private: 223 | bool cancel_{false}; 224 | 225 | std::string url_; 226 | http::Method http_method_{http::Method::HTTP_GET}; 227 | http::Version http_version_{http::Version::V1_1}; 228 | 229 | IpResolve ip_resolve_{IpResolve::Whatever}; 230 | 231 | /* Redirect */ 232 | int max_redirects_{-1}; 233 | 234 | /* Referer */ 235 | bool auto_referer_{true}; 236 | std::string referer_; 237 | 238 | /* Timeout: millseconds */ 239 | int timeout_ms_{-1}; 240 | 241 | /* Upload/Download Speed, bytes per second */ 242 | int64_t max_upload_speed_{0}; 243 | int64_t max_download_speed_{0}; 244 | 245 | /* Buffer size (bytes) */ 246 | int64_t buffer_size_{16 * 1024}; /* Default: 16kB */ 247 | 248 | /* User Data */ 249 | void* user_data_{nullptr}; 250 | 251 | /* Transfer progress */ 252 | TransferProgressHandler on_transfer_progress_handler_{nullptr}; 253 | 254 | /* SSL */ 255 | bool verify_ssl_peer_{false}; 256 | bool verify_ssl_host_{false}; 257 | bool verify_ssl_status_{false}; 258 | SslCertificateType ssl_cert_type_{SslCertificateType::PME}; 259 | std::string ssl_cert_file_; 260 | std::string ssl_key_file_; 261 | std::string ssl_key_file_password_; 262 | 263 | /* Proxy Data */ 264 | ProxyData proxy_data_; 265 | 266 | /* Accept encodings */ 267 | std::vector accept_encodings_; 268 | 269 | /* Request headers */ 270 | std::map headers_; 271 | 272 | /* User-Agent */ 273 | std::string user_agent_; 274 | 275 | /* Post Data */ 276 | std::string data_; 277 | 278 | /* Mime Fileds */ 279 | std::map mime_string_fields_; 280 | std::map mime_file_fields_; 281 | 282 | /* Cookie */ 283 | std::string cookie_; 284 | std::string cookie_file_; 285 | 286 | /* Download to file */ 287 | bool download_resume_{false}; // true => dl_range_ will be ignored. 288 | std::string download_file_; 289 | std::string download_range_; 290 | }; 291 | 292 | } // namespace client 293 | } // namespace ic 294 | 295 | #endif // IC_CLIENT_REQUEST_H_ 296 | -------------------------------------------------------------------------------- /win-vsproj/iclient/iclient.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {f58d4b56-8349-4d59-ba59-851691319f51} 25 | iclient 26 | 10.0 27 | 28 | 29 | 30 | StaticLibrary 31 | false 32 | v142 33 | MultiByte 34 | 35 | 36 | StaticLibrary 37 | false 38 | v142 39 | false 40 | MultiByte 41 | 42 | 43 | StaticLibrary 44 | false 45 | v142 46 | MultiByte 47 | 48 | 49 | StaticLibrary 50 | false 51 | v142 52 | false 53 | MultiByte 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | ..\..\lib\windows\$(Platform)\$(Configuration)\ 76 | $(SolutionDir)build\$(ProjectName)\$(Platform)\$(Configuration)\ 77 | 78 | 79 | false 80 | ..\..\lib\windows\$(Platform)\$(Configuration)\ 81 | $(SolutionDir)build\$(ProjectName)\$(Platform)\$(Configuration)\ 82 | 83 | 84 | true 85 | ..\..\lib\windows\$(Platform)\$(Configuration)\ 86 | $(SolutionDir)build\$(ProjectName)\$(Platform)\$(Configuration)\ 87 | 88 | 89 | false 90 | ..\..\lib\windows\$(Platform)\$(Configuration)\ 91 | $(SolutionDir)build\$(ProjectName)\$(Platform)\$(Configuration)\ 92 | 93 | 94 | 95 | Level3 96 | true 97 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 98 | true 99 | /utf-8 %(AdditionalOptions) 100 | $(IntDir)\$(RelativeDir) 101 | stdcpp17 102 | true 103 | 4819;4996 104 | ..\..\include 105 | EditAndContinue 106 | MultiThreadedDebugDLL 107 | 108 | 109 | Console 110 | true 111 | /ignore:4099 %(AdditionalOptions) 112 | .\lib\$(Platform)\$(Configuration) 113 | 114 | 115 | 116 | 117 | Level3 118 | true 119 | true 120 | true 121 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 122 | true 123 | /utf-8 %(AdditionalOptions) 124 | $(IntDir)\$(RelativeDir) 125 | stdcpp17 126 | true 127 | 4819;4996 128 | ..\..\include 129 | None 130 | 131 | 132 | Console 133 | true 134 | true 135 | true 136 | /ignore:4099 %(AdditionalOptions) 137 | .\lib\$(Platform)\$(Configuration) 138 | 139 | 140 | 141 | 142 | Level3 143 | true 144 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 145 | true 146 | /utf-8 %(AdditionalOptions) 147 | $(IntDir)\$(RelativeDir) 148 | stdcpp17 149 | true 150 | 4819;4996 151 | ..\..\include 152 | EditAndContinue 153 | MultiThreadedDebugDLL 154 | 155 | 156 | Console 157 | true 158 | .\lib\$(Platform)\$(Configuration) 159 | /ignore:4099 %(AdditionalOptions) 160 | 161 | 162 | 163 | 164 | Level3 165 | true 166 | true 167 | true 168 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 169 | true 170 | /utf-8 %(AdditionalOptions) 171 | $(IntDir)\$(RelativeDir) 172 | stdcpp17 173 | true 174 | 4819;4996 175 | ..\..\include 176 | None 177 | 178 | 179 | Console 180 | true 181 | true 182 | true 183 | /ignore:4099 %(AdditionalOptions) 184 | .\lib\$(Platform)\$(Configuration) 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | -------------------------------------------------------------------------------- /win-vsproj/example/example.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {275ab4e9-9f0c-4d16-b0f4-13a1fcfac0cc} 25 | example 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | MultiByte 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | MultiByte 41 | 42 | 43 | Application 44 | true 45 | v142 46 | MultiByte 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | MultiByte 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | ..\..\bin\ 76 | $(SolutionDir)build\$(ProjectName)\$(Platform)\$(Configuration)\ 77 | 78 | 79 | false 80 | ..\..\bin\ 81 | $(SolutionDir)build\$(ProjectName)\$(Platform)\$(Configuration)\ 82 | 83 | 84 | true 85 | ..\..\bin\ 86 | $(SolutionDir)build\$(ProjectName)\$(Platform)\$(Configuration)\ 87 | 88 | 89 | false 90 | ..\..\bin\ 91 | $(SolutionDir)build\$(ProjectName)\$(Platform)\$(Configuration)\ 92 | 93 | 94 | 95 | Level3 96 | true 97 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 98 | true 99 | /utf-8 %(AdditionalOptions) 100 | $(IntDir)\$(RelativeDir) 101 | stdcpp17 102 | true 103 | 4819;4996 104 | ..\..\include 105 | 106 | 107 | Console 108 | true 109 | /ignore:4099 %(AdditionalOptions) 110 | ..\..\lib\windows\$(Platform)\$(Configuration) 111 | wldap32.lib;winmm.lib;crypt32.lib;normaliz.lib;ws2_32.lib;iclient.lib;libcurl.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 112 | 113 | 114 | 115 | 116 | Level3 117 | true 118 | true 119 | true 120 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 121 | true 122 | /utf-8 %(AdditionalOptions) 123 | $(IntDir)\$(RelativeDir) 124 | stdcpp17 125 | true 126 | 4819;4996 127 | ..\..\include 128 | 129 | 130 | Console 131 | true 132 | true 133 | false 134 | /ignore:4099 %(AdditionalOptions) 135 | ..\..\lib\windows\$(Platform)\$(Configuration) 136 | wldap32.lib;winmm.lib;crypt32.lib;normaliz.lib;ws2_32.lib;iclient.lib;libcurl.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 137 | 138 | 139 | 140 | 141 | Level3 142 | true 143 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 144 | true 145 | /utf-8 %(AdditionalOptions) 146 | $(IntDir)\$(RelativeDir) 147 | stdcpp17 148 | true 149 | 4819;4996 150 | ..\..\include 151 | 152 | 153 | Console 154 | true 155 | ..\..\lib\windows\$(Platform)\$(Configuration) 156 | /ignore:4099 %(AdditionalOptions) 157 | wldap32.lib;winmm.lib;crypt32.lib;normaliz.lib;ws2_32.lib;iclient.lib;libcurl.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 158 | 159 | 160 | 161 | 162 | Level3 163 | true 164 | true 165 | true 166 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 167 | true 168 | /utf-8 %(AdditionalOptions) 169 | $(IntDir)\$(RelativeDir) 170 | stdcpp17 171 | true 172 | 4819;4996 173 | ..\..\include 174 | 175 | 176 | Console 177 | true 178 | true 179 | false 180 | /ignore:4099 %(AdditionalOptions) 181 | ..\..\lib\windows\$(Platform)\$(Configuration) 182 | wldap32.lib;winmm.lib;crypt32.lib;normaliz.lib;ws2_32.lib;iclient.lib;libcurl.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | -------------------------------------------------------------------------------- /src/executor.cpp: -------------------------------------------------------------------------------- 1 | #include "executor.h" 2 | #include "util.h" 3 | #include 4 | #include 5 | 6 | namespace ic { 7 | namespace client { 8 | 9 | /* Global init/cleanup libcurl */ 10 | static std::mutex s_iclient_mutex; 11 | static std::atomic_uint64_t s_iclient_init_count; 12 | 13 | static void global_init() { 14 | if (s_iclient_init_count.fetch_add(1) == 0) { 15 | std::lock_guard lck(s_iclient_mutex); 16 | curl_global_init(CURL_GLOBAL_ALL); 17 | } 18 | } 19 | 20 | static void global_cleanup() { 21 | if (s_iclient_init_count.fetch_sub(1) == 1) { 22 | std::lock_guard lck(s_iclient_mutex); 23 | curl_global_cleanup(); 24 | } 25 | } 26 | 27 | 28 | size_t curl_write_header(char* buffer, size_t size, size_t nitems, void* user_ptr); 29 | size_t curl_write_data(void* buffer, size_t size, size_t nitems, void* user_ptr); 30 | int curl_xfer_info(void* clientp, curl_off_t download_total_bytes, curl_off_t download_now_bytes, 31 | curl_off_t upload_total_bytes, curl_off_t upload_now_bytes); 32 | 33 | 34 | Executor::Executor(Request& request, Response& response) 35 | : request_(request), response_(response) 36 | { 37 | global_init(); 38 | curl_ = curl_easy_init(); 39 | } 40 | 41 | Executor::~Executor() { 42 | Reset(); 43 | curl_easy_cleanup(curl_); 44 | global_cleanup(); 45 | } 46 | 47 | void Executor::Reset() { 48 | if (curl_mime_) { 49 | curl_mime_free(curl_mime_); 50 | curl_mime_ = nullptr; 51 | } 52 | if (curl_request_headers_) { 53 | curl_slist_free_all(curl_request_headers_); 54 | curl_request_headers_ = nullptr; 55 | } 56 | if (curl_) { 57 | curl_easy_reset(curl_); 58 | } 59 | } 60 | 61 | void Executor::Perform() { 62 | /* Normally prepare for query */ 63 | if (Prepare()) { 64 | CURLcode code = curl_easy_perform(curl_); 65 | response_.status_ = from_curl_status_code(code); 66 | response_.ParseFromCurl(curl_); 67 | } 68 | 69 | /* close file stream pointer */ 70 | if (file_stream_) { 71 | fclose(file_stream_); 72 | file_stream_ = nullptr; 73 | } 74 | } 75 | 76 | bool Executor::Prepare() { 77 | /* URL */ 78 | if (request_.url_.empty()) { 79 | response_.status_ = Status::INVALID_URL; 80 | return false; 81 | } 82 | curl_easy_setopt(curl_, CURLOPT_URL, request_.url_.c_str()); 83 | 84 | /* Http method */ 85 | switch (request_.http_method_) { 86 | case http::Method::HTTP_POST: 87 | //curl_easy_setopt(curl_, CURLOPT_POST, 1L); 88 | curl_easy_setopt(curl_, CURLOPT_CUSTOMREQUEST, "POST"); 89 | break; 90 | case http::Method::HTTP_HEAD: 91 | curl_easy_setopt(curl_, CURLOPT_NOBODY, 1L); 92 | break; 93 | case http::Method::HTTP_PUT: 94 | curl_easy_setopt(curl_, CURLOPT_CUSTOMREQUEST, "PUT"); 95 | break; 96 | case http::Method::HTTP_DELETE: 97 | curl_easy_setopt(curl_, CURLOPT_CUSTOMREQUEST, "DELETE"); 98 | break; 99 | case http::Method::HTTP_CONNECT: 100 | curl_easy_setopt(curl_, CURLOPT_CONNECT_ONLY, 1L); 101 | break; 102 | case http::Method::HTTP_OPTIONS: 103 | curl_easy_setopt(curl_, CURLOPT_CUSTOMREQUEST, "OPTIONS"); 104 | break; 105 | case http::Method::HTTP_PATCH: 106 | curl_easy_setopt(curl_, CURLOPT_CUSTOMREQUEST, "PATCH"); 107 | break; 108 | case http::Method::HTTP_UNKNOWN: 109 | case http::Method::HTTP_GET: 110 | default: 111 | curl_easy_setopt(curl_, CURLOPT_HTTPGET, 1L); 112 | break; 113 | } 114 | 115 | /* Process writing header */ 116 | curl_easy_setopt(curl_, CURLOPT_PRIVATE, this); 117 | curl_easy_setopt(curl_, CURLOPT_HEADERFUNCTION, curl_write_header); 118 | curl_easy_setopt(curl_, CURLOPT_HEADERDATA, this); 119 | 120 | /* Process writing data */ 121 | curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, curl_write_data); 122 | curl_easy_setopt(curl_, CURLOPT_WRITEDATA, this); 123 | curl_easy_setopt(curl_, CURLOPT_NOSIGNAL, 1L); 124 | 125 | /* POST Data */ 126 | if (!request_.data_.empty()) { 127 | curl_easy_setopt(curl_, CURLOPT_POSTFIELDSIZE, static_cast(request_.data_.size())); 128 | curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, request_.data_.c_str()); 129 | } 130 | else { 131 | if (curl_mime_ != nullptr) { 132 | curl_mime_free(curl_mime_); 133 | curl_mime_ = nullptr; 134 | } 135 | curl_mime_ = curl_mime_init(curl_); 136 | /* String */ 137 | for (const auto& mime_field : request_.mime_string_fields_) { 138 | auto* field = curl_mime_addpart(curl_mime_); 139 | curl_mime_name(field, mime_field.first.c_str()); 140 | curl_mime_data(field, mime_field.second.c_str(), static_cast(mime_field.second.length())); 141 | } 142 | /* File */ 143 | for (const auto& mime_field : request_.mime_file_fields_) { 144 | auto* field = curl_mime_addpart(curl_mime_); 145 | curl_mime_name(field, mime_field.first.c_str()); 146 | curl_mime_filedata(field, mime_field.second.c_str()); 147 | } 148 | if (!request_.mime_string_fields_.empty() || !request_.mime_file_fields_.empty()) { 149 | curl_easy_setopt(curl_, CURLOPT_MIMEPOST, curl_mime_); 150 | } 151 | } 152 | 153 | /* Http version */ 154 | curl_easy_setopt(curl_, CURLOPT_HTTP_VERSION, to_curl_http_version(request_.http_version_)); 155 | 156 | /* Follow requests */ 157 | if (request_.max_redirects_ != 0) { 158 | curl_easy_setopt(curl_, CURLOPT_FOLLOWLOCATION, 1L); 159 | curl_easy_setopt(curl_, CURLOPT_MAXREDIRS, static_cast(request_.max_redirects_)); 160 | } 161 | else { 162 | curl_easy_setopt(curl_, CURLOPT_FOLLOWLOCATION, 0L); 163 | } 164 | 165 | /* Referer */ 166 | curl_easy_setopt(curl_, CURLOPT_AUTOREFERER, request_.auto_referer_ ? 1L : 0L); 167 | if (request_.referer_.length() > 0) { 168 | curl_easy_setopt(curl_, CURLOPT_REFERER, request_.referer_.c_str()); 169 | } 170 | 171 | /* timeout */ 172 | if (request_.timeout_ms_ > 0) { 173 | curl_easy_setopt(curl_, CURLOPT_TIMEOUT_MS, static_cast(request_.timeout_ms_)); 174 | } 175 | 176 | /* ip resolve */ 177 | curl_easy_setopt(curl_, CURLOPT_IPRESOLVE, request_.ip_resolve_); 178 | 179 | /* Transfer info */ 180 | if (request_.on_transfer_progress_handler_ != nullptr) { 181 | curl_easy_setopt(curl_, CURLOPT_XFERINFODATA, &request_); 182 | curl_easy_setopt(curl_, CURLOPT_XFERINFOFUNCTION, curl_xfer_info); 183 | curl_easy_setopt(curl_, CURLOPT_NOPROGRESS, 0L); 184 | } 185 | else { 186 | curl_easy_setopt(curl_, CURLOPT_NOPROGRESS, 1L); 187 | } 188 | 189 | /* Download to file */ 190 | if (!request_.download_file_.empty()) { 191 | if (file_stream_) { 192 | response_.status_ = Status::OUTPUTFILE_BEING_USED; 193 | return false; 194 | } 195 | if (request_.download_resume_) { 196 | /* Get file's current size */ 197 | long size = util::get_file_size(request_.download_file_); 198 | if (size < 0) { 199 | response_.status_ = Status::FAILED_TO_OPEN_OUTPUTFILE; 200 | return false; 201 | } 202 | curl_easy_setopt(curl_, CURLOPT_RESUME_FROM, size); 203 | file_stream_ = fopen(request_.download_file_.c_str(), "ab+"); // append 204 | } 205 | else { 206 | if (!request_.download_range_.empty()) { 207 | curl_easy_setopt(curl_, CURLOPT_RANGE, request_.download_range_.c_str()); 208 | } 209 | file_stream_ = fopen(request_.download_file_.c_str(), "wb+"); // overwrite 210 | } 211 | if (!file_stream_) { 212 | response_.status_ = Status::FAILED_TO_OPEN_OUTPUTFILE; 213 | return false; 214 | } 215 | } 216 | 217 | /* Verify SSL */ 218 | curl_easy_setopt(curl_, CURLOPT_SSL_VERIFYPEER, (request_.verify_ssl_peer_) ? 1L : 0L); 219 | curl_easy_setopt(curl_, CURLOPT_SSL_VERIFYHOST, (request_.verify_ssl_host_) ? 2L : 0L); 220 | curl_easy_setopt(curl_, CURLOPT_SSL_VERIFYSTATUS, (request_.verify_ssl_status_) ? 1L : 0L); 221 | 222 | /* SSL cert & key */ 223 | if (!request_.ssl_cert_file_.empty()) { 224 | curl_easy_setopt(curl_, CURLOPT_SSLCERT, request_.ssl_cert_file_.c_str()); 225 | curl_easy_setopt(curl_, CURLOPT_SSLCERTTYPE, to_string(request_.ssl_cert_type_)); 226 | if (!request_.ssl_key_file_.empty()) { 227 | curl_easy_setopt(curl_, CURLOPT_SSLKEY, request_.ssl_key_file_.c_str()); 228 | } 229 | if (!request_.ssl_key_file_password_.empty()) { 230 | curl_easy_setopt(curl_, CURLOPT_KEYPASSWD, request_.ssl_key_file_password_.c_str()); 231 | } 232 | } 233 | 234 | /* Header */ 235 | if (curl_request_headers_ != nullptr) { 236 | curl_slist_free_all(curl_request_headers_); 237 | curl_request_headers_ = nullptr; 238 | } 239 | for (const auto& header : request_.headers_) { 240 | std::string header_merged; 241 | header_merged.reserve(header.first.size() + header.second.size() + 1); 242 | header_merged += header.first; 243 | header_merged += ':'; 244 | header_merged += header.second; 245 | curl_request_headers_ = curl_slist_append(curl_request_headers_, header_merged.c_str()); 246 | } 247 | if (curl_request_headers_) { 248 | curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, curl_request_headers_); 249 | } 250 | 251 | /* Cookie */ 252 | if (!request_.cookie_.empty()) { 253 | curl_easy_setopt(curl_, CURLOPT_COOKIE, request_.cookie_.c_str()); 254 | } 255 | else if (!request_.cookie_file_.empty()) { 256 | curl_easy_setopt(curl_, CURLOPT_COOKIEFILE, request_.cookie_file_.c_str()); 257 | } 258 | 259 | /* Proxy */ 260 | if (request_.HasProxy()) { 261 | const auto& proxyData = request_.proxy(); 262 | curl_easy_setopt(curl_, CURLOPT_PROXY, proxyData.host.c_str()); 263 | curl_easy_setopt(curl_, CURLOPT_PROXYTYPE, to_curl(proxyData.type)); 264 | curl_easy_setopt(curl_, CURLOPT_PROXYPORT, proxyData.port); 265 | if (!proxyData.username.empty()) { 266 | curl_easy_setopt(curl_, CURLOPT_PROXYAUTH, to_curl(proxyData.auth_type)); 267 | curl_easy_setopt(curl_, CURLOPT_PROXYUSERNAME, proxyData.username.c_str()); 268 | if (!proxyData.password.empty()) { 269 | curl_easy_setopt(curl_, CURLOPT_PROXYPASSWORD, proxyData.password.c_str()); 270 | } 271 | } 272 | } 273 | 274 | /* Encodings */ 275 | std::string joined = util::join(request_.accept_encodings_, ", "); 276 | curl_easy_setopt(curl_, CURLOPT_ACCEPT_ENCODING, joined.c_str()); 277 | 278 | /* Speed */ 279 | if (request_.max_upload_speed_ > 0) { 280 | curl_easy_setopt(curl_, CURLOPT_MAX_SEND_SPEED_LARGE, request_.max_upload_speed_); 281 | } 282 | if (request_.max_download_speed_ > 0) { 283 | curl_easy_setopt(curl_, CURLOPT_MAX_RECV_SPEED_LARGE, request_.max_download_speed_); 284 | } 285 | 286 | /* Buffer size */ 287 | curl_easy_setopt(curl_, CURLOPT_BUFFERSIZE, request_.buffer_size_); 288 | 289 | return true; 290 | } 291 | 292 | 293 | /** 294 | * @brief process accepted headers 295 | */ 296 | size_t curl_write_header(char* buffer, size_t size, size_t nitems, void* user_ptr) { 297 | Executor* executor_ptr = static_cast(user_ptr); 298 | auto& headers = executor_ptr->response_.headers_; 299 | const size_t data_length = size * nitems; 300 | if (data_length == 0) { 301 | return 0; 302 | } 303 | 304 | std::string data(buffer, data_length); 305 | 306 | if (data_length == 2 && data == "\r\n") { 307 | return data_length; 308 | } 309 | if (data_length >= 4 && data.substr(0, 5) == "HTTP/") { 310 | return data_length; 311 | } 312 | if (data_length >= 2 && data[data_length - 2] == '\r' && data[data_length - 1] == '\n') { 313 | data.pop_back(); 314 | data.pop_back(); 315 | } 316 | 317 | auto pos = data.find(':'); 318 | if (pos == std::string::npos) { 319 | return data_length; 320 | } 321 | 322 | std::string name = data.substr(0, pos); 323 | std::string value = data.substr(pos + 1); 324 | 325 | /* Transform header's name to lower case !!! */ 326 | util::trim(name); 327 | util::to_lower(name); 328 | headers[name] = value; 329 | 330 | return data_length; 331 | } 332 | 333 | 334 | /** 335 | * @brief process accepted data 336 | */ 337 | size_t curl_write_data(void* buffer, size_t size, size_t nitems, void* user_ptr) { 338 | Executor* executor_ptr = static_cast(user_ptr); 339 | const size_t data_length = size * nitems; 340 | if (data_length > 0) { 341 | /* Write to file */ 342 | if (executor_ptr->file_stream_) { 343 | fwrite(buffer, size, nitems, executor_ptr->file_stream_); 344 | } 345 | /* Write to response data */ 346 | else { 347 | Response& response = executor_ptr->response_; 348 | response.data_.append(static_cast(buffer), data_length); 349 | } 350 | } 351 | return data_length; 352 | } 353 | 354 | int curl_xfer_info(void* clientp, curl_off_t download_total_bytes, curl_off_t download_now_bytes, 355 | curl_off_t upload_total_bytes, curl_off_t upload_now_bytes) 356 | { 357 | const Request* request_ptr = static_cast(clientp); 358 | if (request_ptr->cancel_) { 359 | return 1; 360 | } 361 | if (request_ptr != nullptr && request_ptr->on_transfer_progress_handler_ != nullptr) { 362 | bool ret = request_ptr->on_transfer_progress_handler_(*request_ptr, 363 | download_total_bytes, download_now_bytes, upload_total_bytes, upload_now_bytes); 364 | if (!ret) { 365 | return 1; 366 | } 367 | } 368 | return 0; 369 | } 370 | 371 | } // namespace client 372 | } // namespace ic 373 | -------------------------------------------------------------------------------- /include/curl/multi.h: -------------------------------------------------------------------------------- 1 | #ifndef CURLINC_MULTI_H 2 | #define CURLINC_MULTI_H 3 | /*************************************************************************** 4 | * _ _ ____ _ 5 | * Project ___| | | | _ \| | 6 | * / __| | | | |_) | | 7 | * | (__| |_| | _ <| |___ 8 | * \___|\___/|_| \_\_____| 9 | * 10 | * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. 11 | * 12 | * This software is licensed as described in the file COPYING, which 13 | * you should have received as part of this distribution. The terms 14 | * are also available at https://curl.se/docs/copyright.html. 15 | * 16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 17 | * copies of the Software, and permit persons to whom the Software is 18 | * furnished to do so, under the terms of the COPYING file. 19 | * 20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 | * KIND, either express or implied. 22 | * 23 | * SPDX-License-Identifier: curl 24 | * 25 | ***************************************************************************/ 26 | /* 27 | This is an "external" header file. Don't give away any internals here! 28 | 29 | GOALS 30 | 31 | o Enable a "pull" interface. The application that uses libcurl decides where 32 | and when to ask libcurl to get/send data. 33 | 34 | o Enable multiple simultaneous transfers in the same thread without making it 35 | complicated for the application. 36 | 37 | o Enable the application to select() on its own file descriptors and curl's 38 | file descriptors simultaneous easily. 39 | 40 | */ 41 | 42 | /* 43 | * This header file should not really need to include "curl.h" since curl.h 44 | * itself includes this file and we expect user applications to do #include 45 | * without the need for especially including multi.h. 46 | * 47 | * For some reason we added this include here at one point, and rather than to 48 | * break existing (wrongly written) libcurl applications, we leave it as-is 49 | * but with this warning attached. 50 | */ 51 | #include "curl.h" 52 | 53 | #ifdef __cplusplus 54 | extern "C" { 55 | #endif 56 | 57 | #if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) 58 | typedef struct Curl_multi CURLM; 59 | #else 60 | typedef void CURLM; 61 | #endif 62 | 63 | typedef enum { 64 | CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or 65 | curl_multi_socket*() soon */ 66 | CURLM_OK, 67 | CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ 68 | CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */ 69 | CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */ 70 | CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ 71 | CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ 72 | CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ 73 | CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was 74 | attempted to get added - again */ 75 | CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a 76 | callback */ 77 | CURLM_WAKEUP_FAILURE, /* wakeup is unavailable or failed */ 78 | CURLM_BAD_FUNCTION_ARGUMENT, /* function called with a bad parameter */ 79 | CURLM_ABORTED_BY_CALLBACK, 80 | CURLM_UNRECOVERABLE_POLL, 81 | CURLM_LAST 82 | } CURLMcode; 83 | 84 | /* just to make code nicer when using curl_multi_socket() you can now check 85 | for CURLM_CALL_MULTI_SOCKET too in the same style it works for 86 | curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ 87 | #define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM 88 | 89 | /* bitmask bits for CURLMOPT_PIPELINING */ 90 | #define CURLPIPE_NOTHING 0L 91 | #define CURLPIPE_HTTP1 1L 92 | #define CURLPIPE_MULTIPLEX 2L 93 | 94 | typedef enum { 95 | CURLMSG_NONE, /* first, not used */ 96 | CURLMSG_DONE, /* This easy handle has completed. 'result' contains 97 | the CURLcode of the transfer */ 98 | CURLMSG_LAST /* last, not used */ 99 | } CURLMSG; 100 | 101 | struct CURLMsg { 102 | CURLMSG msg; /* what this message means */ 103 | CURL *easy_handle; /* the handle it concerns */ 104 | union { 105 | void *whatever; /* message-specific data */ 106 | CURLcode result; /* return code for transfer */ 107 | } data; 108 | }; 109 | typedef struct CURLMsg CURLMsg; 110 | 111 | /* Based on poll(2) structure and values. 112 | * We don't use pollfd and POLL* constants explicitly 113 | * to cover platforms without poll(). */ 114 | #define CURL_WAIT_POLLIN 0x0001 115 | #define CURL_WAIT_POLLPRI 0x0002 116 | #define CURL_WAIT_POLLOUT 0x0004 117 | 118 | struct curl_waitfd { 119 | curl_socket_t fd; 120 | short events; 121 | short revents; /* not supported yet */ 122 | }; 123 | 124 | /* 125 | * Name: curl_multi_init() 126 | * 127 | * Desc: inititalize multi-style curl usage 128 | * 129 | * Returns: a new CURLM handle to use in all 'curl_multi' functions. 130 | */ 131 | CURL_EXTERN CURLM *curl_multi_init(void); 132 | 133 | /* 134 | * Name: curl_multi_add_handle() 135 | * 136 | * Desc: add a standard curl handle to the multi stack 137 | * 138 | * Returns: CURLMcode type, general multi error code. 139 | */ 140 | CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, 141 | CURL *curl_handle); 142 | 143 | /* 144 | * Name: curl_multi_remove_handle() 145 | * 146 | * Desc: removes a curl handle from the multi stack again 147 | * 148 | * Returns: CURLMcode type, general multi error code. 149 | */ 150 | CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, 151 | CURL *curl_handle); 152 | 153 | /* 154 | * Name: curl_multi_fdset() 155 | * 156 | * Desc: Ask curl for its fd_set sets. The app can use these to select() or 157 | * poll() on. We want curl_multi_perform() called as soon as one of 158 | * them are ready. 159 | * 160 | * Returns: CURLMcode type, general multi error code. 161 | */ 162 | CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, 163 | fd_set *read_fd_set, 164 | fd_set *write_fd_set, 165 | fd_set *exc_fd_set, 166 | int *max_fd); 167 | 168 | /* 169 | * Name: curl_multi_wait() 170 | * 171 | * Desc: Poll on all fds within a CURLM set as well as any 172 | * additional fds passed to the function. 173 | * 174 | * Returns: CURLMcode type, general multi error code. 175 | */ 176 | CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle, 177 | struct curl_waitfd extra_fds[], 178 | unsigned int extra_nfds, 179 | int timeout_ms, 180 | int *ret); 181 | 182 | /* 183 | * Name: curl_multi_poll() 184 | * 185 | * Desc: Poll on all fds within a CURLM set as well as any 186 | * additional fds passed to the function. 187 | * 188 | * Returns: CURLMcode type, general multi error code. 189 | */ 190 | CURL_EXTERN CURLMcode curl_multi_poll(CURLM *multi_handle, 191 | struct curl_waitfd extra_fds[], 192 | unsigned int extra_nfds, 193 | int timeout_ms, 194 | int *ret); 195 | 196 | /* 197 | * Name: curl_multi_wakeup() 198 | * 199 | * Desc: wakes up a sleeping curl_multi_poll call. 200 | * 201 | * Returns: CURLMcode type, general multi error code. 202 | */ 203 | CURL_EXTERN CURLMcode curl_multi_wakeup(CURLM *multi_handle); 204 | 205 | /* 206 | * Name: curl_multi_perform() 207 | * 208 | * Desc: When the app thinks there's data available for curl it calls this 209 | * function to read/write whatever there is right now. This returns 210 | * as soon as the reads and writes are done. This function does not 211 | * require that there actually is data available for reading or that 212 | * data can be written, it can be called just in case. It returns 213 | * the number of handles that still transfer data in the second 214 | * argument's integer-pointer. 215 | * 216 | * Returns: CURLMcode type, general multi error code. *NOTE* that this only 217 | * returns errors etc regarding the whole multi stack. There might 218 | * still have occurred problems on individual transfers even when 219 | * this returns OK. 220 | */ 221 | CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, 222 | int *running_handles); 223 | 224 | /* 225 | * Name: curl_multi_cleanup() 226 | * 227 | * Desc: Cleans up and removes a whole multi stack. It does not free or 228 | * touch any individual easy handles in any way. We need to define 229 | * in what state those handles will be if this function is called 230 | * in the middle of a transfer. 231 | * 232 | * Returns: CURLMcode type, general multi error code. 233 | */ 234 | CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); 235 | 236 | /* 237 | * Name: curl_multi_info_read() 238 | * 239 | * Desc: Ask the multi handle if there's any messages/informationals from 240 | * the individual transfers. Messages include informationals such as 241 | * error code from the transfer or just the fact that a transfer is 242 | * completed. More details on these should be written down as well. 243 | * 244 | * Repeated calls to this function will return a new struct each 245 | * time, until a special "end of msgs" struct is returned as a signal 246 | * that there is no more to get at this point. 247 | * 248 | * The data the returned pointer points to will not survive calling 249 | * curl_multi_cleanup(). 250 | * 251 | * The 'CURLMsg' struct is meant to be very simple and only contain 252 | * very basic information. If more involved information is wanted, 253 | * we will provide the particular "transfer handle" in that struct 254 | * and that should/could/would be used in subsequent 255 | * curl_easy_getinfo() calls (or similar). The point being that we 256 | * must never expose complex structs to applications, as then we'll 257 | * undoubtably get backwards compatibility problems in the future. 258 | * 259 | * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out 260 | * of structs. It also writes the number of messages left in the 261 | * queue (after this read) in the integer the second argument points 262 | * to. 263 | */ 264 | CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, 265 | int *msgs_in_queue); 266 | 267 | /* 268 | * Name: curl_multi_strerror() 269 | * 270 | * Desc: The curl_multi_strerror function may be used to turn a CURLMcode 271 | * value into the equivalent human readable error string. This is 272 | * useful for printing meaningful error messages. 273 | * 274 | * Returns: A pointer to a null-terminated error message. 275 | */ 276 | CURL_EXTERN const char *curl_multi_strerror(CURLMcode); 277 | 278 | /* 279 | * Name: curl_multi_socket() and 280 | * curl_multi_socket_all() 281 | * 282 | * Desc: An alternative version of curl_multi_perform() that allows the 283 | * application to pass in one of the file descriptors that have been 284 | * detected to have "action" on them and let libcurl perform. 285 | * See man page for details. 286 | */ 287 | #define CURL_POLL_NONE 0 288 | #define CURL_POLL_IN 1 289 | #define CURL_POLL_OUT 2 290 | #define CURL_POLL_INOUT 3 291 | #define CURL_POLL_REMOVE 4 292 | 293 | #define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD 294 | 295 | #define CURL_CSELECT_IN 0x01 296 | #define CURL_CSELECT_OUT 0x02 297 | #define CURL_CSELECT_ERR 0x04 298 | 299 | typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ 300 | curl_socket_t s, /* socket */ 301 | int what, /* see above */ 302 | void *userp, /* private callback 303 | pointer */ 304 | void *socketp); /* private socket 305 | pointer */ 306 | /* 307 | * Name: curl_multi_timer_callback 308 | * 309 | * Desc: Called by libcurl whenever the library detects a change in the 310 | * maximum number of milliseconds the app is allowed to wait before 311 | * curl_multi_socket() or curl_multi_perform() must be called 312 | * (to allow libcurl's timed events to take place). 313 | * 314 | * Returns: The callback should return zero. 315 | */ 316 | typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ 317 | long timeout_ms, /* see above */ 318 | void *userp); /* private callback 319 | pointer */ 320 | 321 | CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, 322 | int *running_handles); 323 | 324 | CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle, 325 | curl_socket_t s, 326 | int ev_bitmask, 327 | int *running_handles); 328 | 329 | CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, 330 | int *running_handles); 331 | 332 | #ifndef CURL_ALLOW_OLD_MULTI_SOCKET 333 | /* This macro below was added in 7.16.3 to push users who recompile to use 334 | the new curl_multi_socket_action() instead of the old curl_multi_socket() 335 | */ 336 | #define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z) 337 | #endif 338 | 339 | /* 340 | * Name: curl_multi_timeout() 341 | * 342 | * Desc: Returns the maximum number of milliseconds the app is allowed to 343 | * wait before curl_multi_socket() or curl_multi_perform() must be 344 | * called (to allow libcurl's timed events to take place). 345 | * 346 | * Returns: CURLM error code. 347 | */ 348 | CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, 349 | long *milliseconds); 350 | 351 | typedef enum { 352 | /* This is the socket callback function pointer */ 353 | CURLOPT(CURLMOPT_SOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 1), 354 | 355 | /* This is the argument passed to the socket callback */ 356 | CURLOPT(CURLMOPT_SOCKETDATA, CURLOPTTYPE_OBJECTPOINT, 2), 357 | 358 | /* set to 1 to enable pipelining for this multi handle */ 359 | CURLOPT(CURLMOPT_PIPELINING, CURLOPTTYPE_LONG, 3), 360 | 361 | /* This is the timer callback function pointer */ 362 | CURLOPT(CURLMOPT_TIMERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 4), 363 | 364 | /* This is the argument passed to the timer callback */ 365 | CURLOPT(CURLMOPT_TIMERDATA, CURLOPTTYPE_OBJECTPOINT, 5), 366 | 367 | /* maximum number of entries in the connection cache */ 368 | CURLOPT(CURLMOPT_MAXCONNECTS, CURLOPTTYPE_LONG, 6), 369 | 370 | /* maximum number of (pipelining) connections to one host */ 371 | CURLOPT(CURLMOPT_MAX_HOST_CONNECTIONS, CURLOPTTYPE_LONG, 7), 372 | 373 | /* maximum number of requests in a pipeline */ 374 | CURLOPT(CURLMOPT_MAX_PIPELINE_LENGTH, CURLOPTTYPE_LONG, 8), 375 | 376 | /* a connection with a content-length longer than this 377 | will not be considered for pipelining */ 378 | CURLOPT(CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, CURLOPTTYPE_OFF_T, 9), 379 | 380 | /* a connection with a chunk length longer than this 381 | will not be considered for pipelining */ 382 | CURLOPT(CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, CURLOPTTYPE_OFF_T, 10), 383 | 384 | /* a list of site names(+port) that are blocked from pipelining */ 385 | CURLOPT(CURLMOPT_PIPELINING_SITE_BL, CURLOPTTYPE_OBJECTPOINT, 11), 386 | 387 | /* a list of server types that are blocked from pipelining */ 388 | CURLOPT(CURLMOPT_PIPELINING_SERVER_BL, CURLOPTTYPE_OBJECTPOINT, 12), 389 | 390 | /* maximum number of open connections in total */ 391 | CURLOPT(CURLMOPT_MAX_TOTAL_CONNECTIONS, CURLOPTTYPE_LONG, 13), 392 | 393 | /* This is the server push callback function pointer */ 394 | CURLOPT(CURLMOPT_PUSHFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 14), 395 | 396 | /* This is the argument passed to the server push callback */ 397 | CURLOPT(CURLMOPT_PUSHDATA, CURLOPTTYPE_OBJECTPOINT, 15), 398 | 399 | /* maximum number of concurrent streams to support on a connection */ 400 | CURLOPT(CURLMOPT_MAX_CONCURRENT_STREAMS, CURLOPTTYPE_LONG, 16), 401 | 402 | CURLMOPT_LASTENTRY /* the last unused */ 403 | } CURLMoption; 404 | 405 | 406 | /* 407 | * Name: curl_multi_setopt() 408 | * 409 | * Desc: Sets options for the multi handle. 410 | * 411 | * Returns: CURLM error code. 412 | */ 413 | CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, 414 | CURLMoption option, ...); 415 | 416 | 417 | /* 418 | * Name: curl_multi_assign() 419 | * 420 | * Desc: This function sets an association in the multi handle between the 421 | * given socket and a private pointer of the application. This is 422 | * (only) useful for curl_multi_socket uses. 423 | * 424 | * Returns: CURLM error code. 425 | */ 426 | CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, 427 | curl_socket_t sockfd, void *sockp); 428 | 429 | 430 | /* 431 | * Name: curl_push_callback 432 | * 433 | * Desc: This callback gets called when a new stream is being pushed by the 434 | * server. It approves or denies the new stream. It can also decide 435 | * to completely fail the connection. 436 | * 437 | * Returns: CURL_PUSH_OK, CURL_PUSH_DENY or CURL_PUSH_ERROROUT 438 | */ 439 | #define CURL_PUSH_OK 0 440 | #define CURL_PUSH_DENY 1 441 | #define CURL_PUSH_ERROROUT 2 /* added in 7.72.0 */ 442 | 443 | struct curl_pushheaders; /* forward declaration only */ 444 | 445 | CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h, 446 | size_t num); 447 | CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h, 448 | const char *name); 449 | 450 | typedef int (*curl_push_callback)(CURL *parent, 451 | CURL *easy, 452 | size_t num_headers, 453 | struct curl_pushheaders *headers, 454 | void *userp); 455 | 456 | #ifdef __cplusplus 457 | } /* end of extern "C" */ 458 | #endif 459 | 460 | #endif 461 | -------------------------------------------------------------------------------- /include/curl/system.h: -------------------------------------------------------------------------------- 1 | #ifndef CURLINC_SYSTEM_H 2 | #define CURLINC_SYSTEM_H 3 | /*************************************************************************** 4 | * _ _ ____ _ 5 | * Project ___| | | | _ \| | 6 | * / __| | | | |_) | | 7 | * | (__| |_| | _ <| |___ 8 | * \___|\___/|_| \_\_____| 9 | * 10 | * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. 11 | * 12 | * This software is licensed as described in the file COPYING, which 13 | * you should have received as part of this distribution. The terms 14 | * are also available at https://curl.se/docs/copyright.html. 15 | * 16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 17 | * copies of the Software, and permit persons to whom the Software is 18 | * furnished to do so, under the terms of the COPYING file. 19 | * 20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 | * KIND, either express or implied. 22 | * 23 | * SPDX-License-Identifier: curl 24 | * 25 | ***************************************************************************/ 26 | 27 | /* 28 | * Try to keep one section per platform, compiler and architecture, otherwise, 29 | * if an existing section is reused for a different one and later on the 30 | * original is adjusted, probably the piggybacking one can be adversely 31 | * changed. 32 | * 33 | * In order to differentiate between platforms/compilers/architectures use 34 | * only compiler built in predefined preprocessor symbols. 35 | * 36 | * curl_off_t 37 | * ---------- 38 | * 39 | * For any given platform/compiler curl_off_t must be typedef'ed to a 64-bit 40 | * wide signed integral data type. The width of this data type must remain 41 | * constant and independent of any possible large file support settings. 42 | * 43 | * As an exception to the above, curl_off_t shall be typedef'ed to a 32-bit 44 | * wide signed integral data type if there is no 64-bit type. 45 | * 46 | * As a general rule, curl_off_t shall not be mapped to off_t. This rule shall 47 | * only be violated if off_t is the only 64-bit data type available and the 48 | * size of off_t is independent of large file support settings. Keep your 49 | * build on the safe side avoiding an off_t gating. If you have a 64-bit 50 | * off_t then take for sure that another 64-bit data type exists, dig deeper 51 | * and you will find it. 52 | * 53 | */ 54 | 55 | #if defined(__DJGPP__) || defined(__GO32__) 56 | # if defined(__DJGPP__) && (__DJGPP__ > 1) 57 | # define CURL_TYPEOF_CURL_OFF_T long long 58 | # define CURL_FORMAT_CURL_OFF_T "lld" 59 | # define CURL_FORMAT_CURL_OFF_TU "llu" 60 | # define CURL_SUFFIX_CURL_OFF_T LL 61 | # define CURL_SUFFIX_CURL_OFF_TU ULL 62 | # else 63 | # define CURL_TYPEOF_CURL_OFF_T long 64 | # define CURL_FORMAT_CURL_OFF_T "ld" 65 | # define CURL_FORMAT_CURL_OFF_TU "lu" 66 | # define CURL_SUFFIX_CURL_OFF_T L 67 | # define CURL_SUFFIX_CURL_OFF_TU UL 68 | # endif 69 | # define CURL_TYPEOF_CURL_SOCKLEN_T int 70 | 71 | #elif defined(__SALFORDC__) 72 | # define CURL_TYPEOF_CURL_OFF_T long 73 | # define CURL_FORMAT_CURL_OFF_T "ld" 74 | # define CURL_FORMAT_CURL_OFF_TU "lu" 75 | # define CURL_SUFFIX_CURL_OFF_T L 76 | # define CURL_SUFFIX_CURL_OFF_TU UL 77 | # define CURL_TYPEOF_CURL_SOCKLEN_T int 78 | 79 | #elif defined(__BORLANDC__) 80 | # if (__BORLANDC__ < 0x520) 81 | # define CURL_TYPEOF_CURL_OFF_T long 82 | # define CURL_FORMAT_CURL_OFF_T "ld" 83 | # define CURL_FORMAT_CURL_OFF_TU "lu" 84 | # define CURL_SUFFIX_CURL_OFF_T L 85 | # define CURL_SUFFIX_CURL_OFF_TU UL 86 | # else 87 | # define CURL_TYPEOF_CURL_OFF_T __int64 88 | # define CURL_FORMAT_CURL_OFF_T "I64d" 89 | # define CURL_FORMAT_CURL_OFF_TU "I64u" 90 | # define CURL_SUFFIX_CURL_OFF_T i64 91 | # define CURL_SUFFIX_CURL_OFF_TU ui64 92 | # endif 93 | # define CURL_TYPEOF_CURL_SOCKLEN_T int 94 | 95 | #elif defined(__TURBOC__) 96 | # define CURL_TYPEOF_CURL_OFF_T long 97 | # define CURL_FORMAT_CURL_OFF_T "ld" 98 | # define CURL_FORMAT_CURL_OFF_TU "lu" 99 | # define CURL_SUFFIX_CURL_OFF_T L 100 | # define CURL_SUFFIX_CURL_OFF_TU UL 101 | # define CURL_TYPEOF_CURL_SOCKLEN_T int 102 | 103 | #elif defined(__POCC__) 104 | # if (__POCC__ < 280) 105 | # define CURL_TYPEOF_CURL_OFF_T long 106 | # define CURL_FORMAT_CURL_OFF_T "ld" 107 | # define CURL_FORMAT_CURL_OFF_TU "lu" 108 | # define CURL_SUFFIX_CURL_OFF_T L 109 | # define CURL_SUFFIX_CURL_OFF_TU UL 110 | # elif defined(_MSC_VER) 111 | # define CURL_TYPEOF_CURL_OFF_T __int64 112 | # define CURL_FORMAT_CURL_OFF_T "I64d" 113 | # define CURL_FORMAT_CURL_OFF_TU "I64u" 114 | # define CURL_SUFFIX_CURL_OFF_T i64 115 | # define CURL_SUFFIX_CURL_OFF_TU ui64 116 | # else 117 | # define CURL_TYPEOF_CURL_OFF_T long long 118 | # define CURL_FORMAT_CURL_OFF_T "lld" 119 | # define CURL_FORMAT_CURL_OFF_TU "llu" 120 | # define CURL_SUFFIX_CURL_OFF_T LL 121 | # define CURL_SUFFIX_CURL_OFF_TU ULL 122 | # endif 123 | # define CURL_TYPEOF_CURL_SOCKLEN_T int 124 | 125 | #elif defined(__LCC__) 126 | # if defined(__MCST__) /* MCST eLbrus Compiler Collection */ 127 | # define CURL_TYPEOF_CURL_OFF_T long 128 | # define CURL_FORMAT_CURL_OFF_T "ld" 129 | # define CURL_FORMAT_CURL_OFF_TU "lu" 130 | # define CURL_SUFFIX_CURL_OFF_T L 131 | # define CURL_SUFFIX_CURL_OFF_TU UL 132 | # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t 133 | # define CURL_PULL_SYS_TYPES_H 1 134 | # define CURL_PULL_SYS_SOCKET_H 1 135 | # else /* Local (or Little) C Compiler */ 136 | # define CURL_TYPEOF_CURL_OFF_T long 137 | # define CURL_FORMAT_CURL_OFF_T "ld" 138 | # define CURL_FORMAT_CURL_OFF_TU "lu" 139 | # define CURL_SUFFIX_CURL_OFF_T L 140 | # define CURL_SUFFIX_CURL_OFF_TU UL 141 | # define CURL_TYPEOF_CURL_SOCKLEN_T int 142 | # endif 143 | 144 | #elif defined(__SYMBIAN32__) 145 | # if defined(__EABI__) /* Treat all ARM compilers equally */ 146 | # define CURL_TYPEOF_CURL_OFF_T long long 147 | # define CURL_FORMAT_CURL_OFF_T "lld" 148 | # define CURL_FORMAT_CURL_OFF_TU "llu" 149 | # define CURL_SUFFIX_CURL_OFF_T LL 150 | # define CURL_SUFFIX_CURL_OFF_TU ULL 151 | # elif defined(__CW32__) 152 | # pragma longlong on 153 | # define CURL_TYPEOF_CURL_OFF_T long long 154 | # define CURL_FORMAT_CURL_OFF_T "lld" 155 | # define CURL_FORMAT_CURL_OFF_TU "llu" 156 | # define CURL_SUFFIX_CURL_OFF_T LL 157 | # define CURL_SUFFIX_CURL_OFF_TU ULL 158 | # elif defined(__VC32__) 159 | # define CURL_TYPEOF_CURL_OFF_T __int64 160 | # define CURL_FORMAT_CURL_OFF_T "lld" 161 | # define CURL_FORMAT_CURL_OFF_TU "llu" 162 | # define CURL_SUFFIX_CURL_OFF_T LL 163 | # define CURL_SUFFIX_CURL_OFF_TU ULL 164 | # endif 165 | # define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int 166 | 167 | #elif defined(__MWERKS__) 168 | # define CURL_TYPEOF_CURL_OFF_T long long 169 | # define CURL_FORMAT_CURL_OFF_T "lld" 170 | # define CURL_FORMAT_CURL_OFF_TU "llu" 171 | # define CURL_SUFFIX_CURL_OFF_T LL 172 | # define CURL_SUFFIX_CURL_OFF_TU ULL 173 | # define CURL_TYPEOF_CURL_SOCKLEN_T int 174 | 175 | #elif defined(_WIN32_WCE) 176 | # define CURL_TYPEOF_CURL_OFF_T __int64 177 | # define CURL_FORMAT_CURL_OFF_T "I64d" 178 | # define CURL_FORMAT_CURL_OFF_TU "I64u" 179 | # define CURL_SUFFIX_CURL_OFF_T i64 180 | # define CURL_SUFFIX_CURL_OFF_TU ui64 181 | # define CURL_TYPEOF_CURL_SOCKLEN_T int 182 | 183 | #elif defined(__MINGW32__) 184 | # define CURL_TYPEOF_CURL_OFF_T long long 185 | # define CURL_FORMAT_CURL_OFF_T "I64d" 186 | # define CURL_FORMAT_CURL_OFF_TU "I64u" 187 | # define CURL_SUFFIX_CURL_OFF_T LL 188 | # define CURL_SUFFIX_CURL_OFF_TU ULL 189 | # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t 190 | # define CURL_PULL_SYS_TYPES_H 1 191 | # define CURL_PULL_WS2TCPIP_H 1 192 | 193 | #elif defined(__VMS) 194 | # if defined(__VAX) 195 | # define CURL_TYPEOF_CURL_OFF_T long 196 | # define CURL_FORMAT_CURL_OFF_T "ld" 197 | # define CURL_FORMAT_CURL_OFF_TU "lu" 198 | # define CURL_SUFFIX_CURL_OFF_T L 199 | # define CURL_SUFFIX_CURL_OFF_TU UL 200 | # else 201 | # define CURL_TYPEOF_CURL_OFF_T long long 202 | # define CURL_FORMAT_CURL_OFF_T "lld" 203 | # define CURL_FORMAT_CURL_OFF_TU "llu" 204 | # define CURL_SUFFIX_CURL_OFF_T LL 205 | # define CURL_SUFFIX_CURL_OFF_TU ULL 206 | # endif 207 | # define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int 208 | 209 | #elif defined(__OS400__) 210 | # if defined(__ILEC400__) 211 | # define CURL_TYPEOF_CURL_OFF_T long long 212 | # define CURL_FORMAT_CURL_OFF_T "lld" 213 | # define CURL_FORMAT_CURL_OFF_TU "llu" 214 | # define CURL_SUFFIX_CURL_OFF_T LL 215 | # define CURL_SUFFIX_CURL_OFF_TU ULL 216 | # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t 217 | # define CURL_PULL_SYS_TYPES_H 1 218 | # define CURL_PULL_SYS_SOCKET_H 1 219 | # endif 220 | 221 | #elif defined(__MVS__) 222 | # if defined(__IBMC__) || defined(__IBMCPP__) 223 | # if defined(_ILP32) 224 | # elif defined(_LP64) 225 | # endif 226 | # if defined(_LONG_LONG) 227 | # define CURL_TYPEOF_CURL_OFF_T long long 228 | # define CURL_FORMAT_CURL_OFF_T "lld" 229 | # define CURL_FORMAT_CURL_OFF_TU "llu" 230 | # define CURL_SUFFIX_CURL_OFF_T LL 231 | # define CURL_SUFFIX_CURL_OFF_TU ULL 232 | # elif defined(_LP64) 233 | # define CURL_TYPEOF_CURL_OFF_T long 234 | # define CURL_FORMAT_CURL_OFF_T "ld" 235 | # define CURL_FORMAT_CURL_OFF_TU "lu" 236 | # define CURL_SUFFIX_CURL_OFF_T L 237 | # define CURL_SUFFIX_CURL_OFF_TU UL 238 | # else 239 | # define CURL_TYPEOF_CURL_OFF_T long 240 | # define CURL_FORMAT_CURL_OFF_T "ld" 241 | # define CURL_FORMAT_CURL_OFF_TU "lu" 242 | # define CURL_SUFFIX_CURL_OFF_T L 243 | # define CURL_SUFFIX_CURL_OFF_TU UL 244 | # endif 245 | # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t 246 | # define CURL_PULL_SYS_TYPES_H 1 247 | # define CURL_PULL_SYS_SOCKET_H 1 248 | # endif 249 | 250 | #elif defined(__370__) 251 | # if defined(__IBMC__) || defined(__IBMCPP__) 252 | # if defined(_ILP32) 253 | # elif defined(_LP64) 254 | # endif 255 | # if defined(_LONG_LONG) 256 | # define CURL_TYPEOF_CURL_OFF_T long long 257 | # define CURL_FORMAT_CURL_OFF_T "lld" 258 | # define CURL_FORMAT_CURL_OFF_TU "llu" 259 | # define CURL_SUFFIX_CURL_OFF_T LL 260 | # define CURL_SUFFIX_CURL_OFF_TU ULL 261 | # elif defined(_LP64) 262 | # define CURL_TYPEOF_CURL_OFF_T long 263 | # define CURL_FORMAT_CURL_OFF_T "ld" 264 | # define CURL_FORMAT_CURL_OFF_TU "lu" 265 | # define CURL_SUFFIX_CURL_OFF_T L 266 | # define CURL_SUFFIX_CURL_OFF_TU UL 267 | # else 268 | # define CURL_TYPEOF_CURL_OFF_T long 269 | # define CURL_FORMAT_CURL_OFF_T "ld" 270 | # define CURL_FORMAT_CURL_OFF_TU "lu" 271 | # define CURL_SUFFIX_CURL_OFF_T L 272 | # define CURL_SUFFIX_CURL_OFF_TU UL 273 | # endif 274 | # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t 275 | # define CURL_PULL_SYS_TYPES_H 1 276 | # define CURL_PULL_SYS_SOCKET_H 1 277 | # endif 278 | 279 | #elif defined(TPF) 280 | # define CURL_TYPEOF_CURL_OFF_T long 281 | # define CURL_FORMAT_CURL_OFF_T "ld" 282 | # define CURL_FORMAT_CURL_OFF_TU "lu" 283 | # define CURL_SUFFIX_CURL_OFF_T L 284 | # define CURL_SUFFIX_CURL_OFF_TU UL 285 | # define CURL_TYPEOF_CURL_SOCKLEN_T int 286 | 287 | #elif defined(__TINYC__) /* also known as tcc */ 288 | # define CURL_TYPEOF_CURL_OFF_T long long 289 | # define CURL_FORMAT_CURL_OFF_T "lld" 290 | # define CURL_FORMAT_CURL_OFF_TU "llu" 291 | # define CURL_SUFFIX_CURL_OFF_T LL 292 | # define CURL_SUFFIX_CURL_OFF_TU ULL 293 | # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t 294 | # define CURL_PULL_SYS_TYPES_H 1 295 | # define CURL_PULL_SYS_SOCKET_H 1 296 | 297 | #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) /* Oracle Solaris Studio */ 298 | # if !defined(__LP64) && (defined(__ILP32) || \ 299 | defined(__i386) || \ 300 | defined(__sparcv8) || \ 301 | defined(__sparcv8plus)) 302 | # define CURL_TYPEOF_CURL_OFF_T long long 303 | # define CURL_FORMAT_CURL_OFF_T "lld" 304 | # define CURL_FORMAT_CURL_OFF_TU "llu" 305 | # define CURL_SUFFIX_CURL_OFF_T LL 306 | # define CURL_SUFFIX_CURL_OFF_TU ULL 307 | # elif defined(__LP64) || \ 308 | defined(__amd64) || defined(__sparcv9) 309 | # define CURL_TYPEOF_CURL_OFF_T long 310 | # define CURL_FORMAT_CURL_OFF_T "ld" 311 | # define CURL_FORMAT_CURL_OFF_TU "lu" 312 | # define CURL_SUFFIX_CURL_OFF_T L 313 | # define CURL_SUFFIX_CURL_OFF_TU UL 314 | # endif 315 | # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t 316 | # define CURL_PULL_SYS_TYPES_H 1 317 | # define CURL_PULL_SYS_SOCKET_H 1 318 | 319 | #elif defined(__xlc__) /* IBM xlc compiler */ 320 | # if !defined(_LP64) 321 | # define CURL_TYPEOF_CURL_OFF_T long long 322 | # define CURL_FORMAT_CURL_OFF_T "lld" 323 | # define CURL_FORMAT_CURL_OFF_TU "llu" 324 | # define CURL_SUFFIX_CURL_OFF_T LL 325 | # define CURL_SUFFIX_CURL_OFF_TU ULL 326 | # else 327 | # define CURL_TYPEOF_CURL_OFF_T long 328 | # define CURL_FORMAT_CURL_OFF_T "ld" 329 | # define CURL_FORMAT_CURL_OFF_TU "lu" 330 | # define CURL_SUFFIX_CURL_OFF_T L 331 | # define CURL_SUFFIX_CURL_OFF_TU UL 332 | # endif 333 | # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t 334 | # define CURL_PULL_SYS_TYPES_H 1 335 | # define CURL_PULL_SYS_SOCKET_H 1 336 | 337 | /* ===================================== */ 338 | /* KEEP MSVC THE PENULTIMATE ENTRY */ 339 | /* ===================================== */ 340 | 341 | #elif defined(_MSC_VER) 342 | # if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) 343 | # define CURL_TYPEOF_CURL_OFF_T __int64 344 | # define CURL_FORMAT_CURL_OFF_T "I64d" 345 | # define CURL_FORMAT_CURL_OFF_TU "I64u" 346 | # define CURL_SUFFIX_CURL_OFF_T i64 347 | # define CURL_SUFFIX_CURL_OFF_TU ui64 348 | # else 349 | # define CURL_TYPEOF_CURL_OFF_T long 350 | # define CURL_FORMAT_CURL_OFF_T "ld" 351 | # define CURL_FORMAT_CURL_OFF_TU "lu" 352 | # define CURL_SUFFIX_CURL_OFF_T L 353 | # define CURL_SUFFIX_CURL_OFF_TU UL 354 | # endif 355 | # define CURL_TYPEOF_CURL_SOCKLEN_T int 356 | 357 | /* ===================================== */ 358 | /* KEEP GENERIC GCC THE LAST ENTRY */ 359 | /* ===================================== */ 360 | 361 | #elif defined(__GNUC__) && !defined(_SCO_DS) 362 | # if !defined(__LP64__) && \ 363 | (defined(__ILP32__) || defined(__i386__) || defined(__hppa__) || \ 364 | defined(__ppc__) || defined(__powerpc__) || defined(__arm__) || \ 365 | defined(__sparc__) || defined(__mips__) || defined(__sh__) || \ 366 | defined(__XTENSA__) || \ 367 | (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4) || \ 368 | (defined(__LONG_MAX__) && __LONG_MAX__ == 2147483647L)) 369 | # define CURL_TYPEOF_CURL_OFF_T long long 370 | # define CURL_FORMAT_CURL_OFF_T "lld" 371 | # define CURL_FORMAT_CURL_OFF_TU "llu" 372 | # define CURL_SUFFIX_CURL_OFF_T LL 373 | # define CURL_SUFFIX_CURL_OFF_TU ULL 374 | # elif defined(__LP64__) || \ 375 | defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) || \ 376 | defined(__e2k__) || \ 377 | (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 8) || \ 378 | (defined(__LONG_MAX__) && __LONG_MAX__ == 9223372036854775807L) 379 | # define CURL_TYPEOF_CURL_OFF_T long 380 | # define CURL_FORMAT_CURL_OFF_T "ld" 381 | # define CURL_FORMAT_CURL_OFF_TU "lu" 382 | # define CURL_SUFFIX_CURL_OFF_T L 383 | # define CURL_SUFFIX_CURL_OFF_TU UL 384 | # endif 385 | # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t 386 | # define CURL_PULL_SYS_TYPES_H 1 387 | # define CURL_PULL_SYS_SOCKET_H 1 388 | 389 | #else 390 | /* generic "safe guess" on old 32 bit style */ 391 | # define CURL_TYPEOF_CURL_OFF_T long 392 | # define CURL_FORMAT_CURL_OFF_T "ld" 393 | # define CURL_FORMAT_CURL_OFF_TU "lu" 394 | # define CURL_SUFFIX_CURL_OFF_T L 395 | # define CURL_SUFFIX_CURL_OFF_TU UL 396 | # define CURL_TYPEOF_CURL_SOCKLEN_T int 397 | #endif 398 | 399 | #ifdef _AIX 400 | /* AIX needs */ 401 | #define CURL_PULL_SYS_POLL_H 402 | #endif 403 | 404 | 405 | /* CURL_PULL_WS2TCPIP_H is defined above when inclusion of header file */ 406 | /* ws2tcpip.h is required here to properly make type definitions below. */ 407 | #ifdef CURL_PULL_WS2TCPIP_H 408 | # include 409 | # include 410 | # include 411 | #endif 412 | 413 | /* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */ 414 | /* sys/types.h is required here to properly make type definitions below. */ 415 | #ifdef CURL_PULL_SYS_TYPES_H 416 | # include 417 | #endif 418 | 419 | /* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file */ 420 | /* sys/socket.h is required here to properly make type definitions below. */ 421 | #ifdef CURL_PULL_SYS_SOCKET_H 422 | # include 423 | #endif 424 | 425 | /* CURL_PULL_SYS_POLL_H is defined above when inclusion of header file */ 426 | /* sys/poll.h is required here to properly make type definitions below. */ 427 | #ifdef CURL_PULL_SYS_POLL_H 428 | # include 429 | #endif 430 | 431 | /* Data type definition of curl_socklen_t. */ 432 | #ifdef CURL_TYPEOF_CURL_SOCKLEN_T 433 | typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; 434 | #endif 435 | 436 | /* Data type definition of curl_off_t. */ 437 | 438 | #ifdef CURL_TYPEOF_CURL_OFF_T 439 | typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; 440 | #endif 441 | 442 | /* 443 | * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow 444 | * these to be visible and exported by the external libcurl interface API, 445 | * while also making them visible to the library internals, simply including 446 | * curl_setup.h, without actually needing to include curl.h internally. 447 | * If some day this section would grow big enough, all this should be moved 448 | * to its own header file. 449 | */ 450 | 451 | /* 452 | * Figure out if we can use the ## preprocessor operator, which is supported 453 | * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ 454 | * or __cplusplus so we need to carefully check for them too. 455 | */ 456 | 457 | #if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ 458 | defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ 459 | defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ 460 | defined(__ILEC400__) 461 | /* This compiler is believed to have an ISO compatible preprocessor */ 462 | #define CURL_ISOCPP 463 | #else 464 | /* This compiler is believed NOT to have an ISO compatible preprocessor */ 465 | #undef CURL_ISOCPP 466 | #endif 467 | 468 | /* 469 | * Macros for minimum-width signed and unsigned curl_off_t integer constants. 470 | */ 471 | 472 | #if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) 473 | # define CURLINC_OFF_T_C_HLPR2(x) x 474 | # define CURLINC_OFF_T_C_HLPR1(x) CURLINC_OFF_T_C_HLPR2(x) 475 | # define CURL_OFF_T_C(Val) CURLINC_OFF_T_C_HLPR1(Val) ## \ 476 | CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) 477 | # define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val) ## \ 478 | CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) 479 | #else 480 | # ifdef CURL_ISOCPP 481 | # define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix 482 | # else 483 | # define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix 484 | # endif 485 | # define CURLINC_OFF_T_C_HLPR1(Val,Suffix) CURLINC_OFF_T_C_HLPR2(Val,Suffix) 486 | # define CURL_OFF_T_C(Val) CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) 487 | # define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) 488 | #endif 489 | 490 | #endif /* CURLINC_SYSTEM_H */ 491 | -------------------------------------------------------------------------------- /src/http.cpp: -------------------------------------------------------------------------------- 1 | #include "iclient/http.h" 2 | #include "iclient/curl_inc.h" 3 | 4 | namespace ic { 5 | namespace client { 6 | namespace http { 7 | 8 | /*********************************************************************** 9 | * 10 | * 1. Http Method 11 | * 12 | ************************************************************************/ 13 | 14 | static const char* STR_METHOD_HTTP_UNKNOWN = "UNKNOWN"; 15 | static const char* STR_METHOD_HTTP_GET = "GET"; 16 | static const char* STR_METHOD_HTTP_HEAD = "HEAD"; 17 | static const char* STR_METHOD_HTTP_POST = "POST"; 18 | static const char* STR_METHOD_HTTP_PUT = "PUT"; 19 | static const char* STR_METHOD_HTTP_DELETE = "DELETE"; 20 | static const char* STR_METHOD_HTTP_CONNECT = "CONNECT"; 21 | static const char* STR_METHOD_HTTP_OPTIONS = "OPTIONS"; 22 | static const char* STR_METHOD_HTTP_PATCH = "PATCH"; 23 | 24 | #ifdef CASE 25 | #undef CASE 26 | #endif 27 | 28 | #define CASE(type) case Method::type: return STR_METHOD_##type 29 | 30 | const char* to_string(Method method) { 31 | switch (method) { 32 | CASE(HTTP_GET); 33 | CASE(HTTP_HEAD); 34 | CASE(HTTP_POST); 35 | CASE(HTTP_OPTIONS); 36 | CASE(HTTP_PUT); 37 | CASE(HTTP_DELETE); 38 | CASE(HTTP_CONNECT); 39 | CASE(HTTP_PATCH); 40 | CASE(HTTP_UNKNOWN); 41 | default: return STR_METHOD_HTTP_UNKNOWN; 42 | } 43 | } 44 | 45 | /*********************************************************************** 46 | * 47 | * 2. Http Version 48 | * 49 | ************************************************************************/ 50 | 51 | #undef CASE 52 | #define CASE(ver) case Version::V##ver: return CURL_HTTP_VERSION_##ver 53 | 54 | int to_curl_http_version(Version ver) { 55 | switch (ver) { 56 | CASE(1_0); 57 | CASE(1_1); 58 | CASE(2_0); 59 | CASE(2TLS); 60 | default: return CURL_HTTP_VERSION_NONE; 61 | } 62 | } 63 | 64 | #undef CASE 65 | #define CASE(ver) case CURL_HTTP_VERSION_##ver: return Version::V##ver 66 | 67 | Version from_curl_http_version(int ver) { 68 | switch (ver) { 69 | CASE(1_0); 70 | CASE(1_1); 71 | CASE(2_0); 72 | CASE(2TLS); 73 | default: return Version::NONE; 74 | } 75 | } 76 | 77 | static const char* STR_VERSION_NONE = "HTTP/None"; 78 | static const char* STR_VERSION_V1_0 = "HTTP/1.0"; 79 | static const char* STR_VERSION_V1_1 = "HTTP/1.1"; 80 | static const char* STR_VERSION_V2_0 = "HTTP/2.0"; 81 | static const char* STR_VERSION_V2TLS = "HTTP/2.0-TLS"; 82 | 83 | #undef CASE 84 | #define CASE(type) case Version::type: return STR_VERSION_##type 85 | 86 | const char* to_string(Version ver) { 87 | switch (ver) { 88 | CASE(V1_0); 89 | CASE(V1_1); 90 | CASE(V2_0); 91 | CASE(V2TLS); 92 | CASE(NONE); 93 | default: return STR_VERSION_NONE; 94 | } 95 | } 96 | 97 | /*********************************************************************** 98 | * 99 | * 3. Http Status Code 100 | * 101 | ************************************************************************/ 102 | 103 | StatusCode from_curl_http_response_code(int code) { 104 | switch (code) { 105 | case 100: return StatusCode::HTTP_100_CONTINUE; 106 | case 101: return StatusCode::HTTP_101_SWITCHING_PROTOCOLS; 107 | case 102: return StatusCode::HTTP_102_PROCESSING; 108 | case 103: return StatusCode::HTTP_103_EARLY_HINTS; 109 | 110 | case 200: return StatusCode::HTTP_200_OK; 111 | case 201: return StatusCode::HTTP_201_CREATED; 112 | case 202: return StatusCode::HTTP_202_ACCEPTED; 113 | case 203: return StatusCode::HTTP_203_NON_AUTHORITATIVE_INFORMATION; 114 | case 204: return StatusCode::HTTP_204_NO_CONTENT; 115 | case 205: return StatusCode::HTTP_205_RESET_CONTENT; 116 | case 206: return StatusCode::HTTP_206_PARTIAL_CONTENT; 117 | case 207: return StatusCode::HTTP_207_MULTI_STATUS; 118 | case 208: return StatusCode::HTTP_208_ALREADY_REPORTED; 119 | case 226: return StatusCode::HTTP_226_IM_USED; 120 | 121 | case 300: return StatusCode::HTTP_300_MULTIPLE_CHOICES; 122 | case 301: return StatusCode::HTTP_301_MOVED_PERMANENTLY; 123 | case 302: return StatusCode::HTTP_302_FOUND; 124 | case 303: return StatusCode::HTTP_303_SEE_OTHER; 125 | case 304: return StatusCode::HTTP_304_NOT_MODIFIED; 126 | case 305: return StatusCode::HTTP_305_USE_PROXY; 127 | case 306: return StatusCode::HTTP_306_SWITCH_PROXY; 128 | case 307: return StatusCode::HTTP_307_TEMPORARY_REDIRECT; 129 | case 308: return StatusCode::HTTP_308_PERMANENT_REDIRECT; 130 | 131 | case 400: return StatusCode::HTTP_400_BAD_REQUEST; 132 | case 401: return StatusCode::HTTP_401_UNAUTHORIZED; 133 | case 402: return StatusCode::HTTP_402_PAYMENT_REQUIRED; 134 | case 403: return StatusCode::HTTP_403_FORBIDDEN; 135 | case 404: return StatusCode::HTTP_404_NOT_FOUND; 136 | case 405: return StatusCode::HTTP_405_METHOD_NOT_ALLOWED; 137 | case 406: return StatusCode::HTTP_406_NOT_ACCEPTABLE; 138 | case 407: return StatusCode::HTTP_407_PROXY_AUTHENTICATION_REQUIRED; 139 | case 408: return StatusCode::HTTP_408_REQUEST_TIMEOUT; 140 | case 409: return StatusCode::HTTP_409_CONFLICT; 141 | case 410: return StatusCode::HTTP_410_GONE; 142 | case 411: return StatusCode::HTTP_411_LENGTH_REQUIRED; 143 | case 412: return StatusCode::HTTP_412_PRECONDITION_FAILED; 144 | case 413: return StatusCode::HTTP_413_PAYLOAD_TOO_LARGE; 145 | case 414: return StatusCode::HTTP_414_URI_TOO_LONG; 146 | case 415: return StatusCode::HTTP_415_UNSUPPORTED_MEDIA_TYPE; 147 | case 416: return StatusCode::HTTP_416_RANGE_NOT_SATISFIABLE; 148 | case 417: return StatusCode::HTTP_417_EXPECTATION_FAILED; 149 | case 418: return StatusCode::HTTP_418_IM_A_TEAPOT; 150 | case 421: return StatusCode::HTTP_421_MISDIRECTED_REQUEST; 151 | case 422: return StatusCode::HTTP_422_UNPROCESSABLE_ENTITY; 152 | case 423: return StatusCode::HTTP_423_LOCKED; 153 | case 424: return StatusCode::HTTP_424_FAILED_DEPENDENCY; 154 | case 425: return StatusCode::HTTP_425_TOO_EARLY; 155 | case 426: return StatusCode::HTTP_426_UPGRADE_REQUIRED; 156 | case 428: return StatusCode::HTTP_428_PRECONDITION_REQUIRED; 157 | case 429: return StatusCode::HTTP_429_TOO_MANY_REQUESTS; 158 | case 431: return StatusCode::HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE; 159 | case 451: return StatusCode::HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS; 160 | 161 | case 500: return StatusCode::HTTP_500_INTERNAL_SERVER_ERROR; 162 | case 501: return StatusCode::HTTP_501_NOT_IMPLEMENTED; 163 | case 502: return StatusCode::HTTP_502_BAD_GATEWAY; 164 | case 503: return StatusCode::HTTP_503_SERVICE_UNAVAILABLE; 165 | case 504: return StatusCode::HTTP_504_GATEWAY_TIMEOUT; 166 | case 505: return StatusCode::HTTP_505_HTTP_VERSION_NOT_SUPPORTED; 167 | case 506: return StatusCode::HTTP_506_VARIANT_ALSO_NEGOTIATES; 168 | case 507: return StatusCode::HTTP_507_INSUFFICIENT_STORAGE; 169 | case 508: return StatusCode::HTTP_508_LOOP_DETECTED; 170 | case 510: return StatusCode::HTTP_510_NOT_EXTENDED; 171 | case 511: return StatusCode::HTTP_511_NETWORK_AUTHENTICATION_REQUIRED; 172 | 173 | case 0: 174 | default: return StatusCode::HTTP_UNKNOWN; 175 | } 176 | } 177 | 178 | #if 1 // Http Status Code Message 179 | static const char* STR_STATUS_CODE_HTTP_UNKNOWN = "UNKNOWN"; 180 | static const char* STR_STATUS_CODE_HTTP_100_CONTINUE = "100 Continue"; 181 | static const char* STR_STATUS_CODE_HTTP_101_SWITCHING_PROTOCOLS = "101 Switching Protocols"; 182 | static const char* STR_STATUS_CODE_HTTP_102_PROCESSING = "102 Processing"; 183 | static const char* STR_STATUS_CODE_HTTP_103_EARLY_HINTS = "103 Early Hints"; 184 | static const char* STR_STATUS_CODE_HTTP_200_OK = "200 OK"; 185 | static const char* STR_STATUS_CODE_HTTP_201_CREATED = "201 Created"; 186 | static const char* STR_STATUS_CODE_HTTP_202_ACCEPTED = "202 Accepted"; 187 | static const char* STR_STATUS_CODE_HTTP_203_NON_AUTHORITATIVE_INFORMATION = "203 Non-Authoritative Information"; 188 | static const char* STR_STATUS_CODE_HTTP_204_NO_CONTENT = "204 No Content"; 189 | static const char* STR_STATUS_CODE_HTTP_205_RESET_CONTENT = "205 Reset Content"; 190 | static const char* STR_STATUS_CODE_HTTP_206_PARTIAL_CONTENT = "206 Partial Content"; 191 | static const char* STR_STATUS_CODE_HTTP_207_MULTI_STATUS = "207 Multi-Status"; 192 | static const char* STR_STATUS_CODE_HTTP_208_ALREADY_REPORTED = "208 Already Reported"; 193 | static const char* STR_STATUS_CODE_HTTP_226_IM_USED = "226 IM Used"; 194 | static const char* STR_STATUS_CODE_HTTP_300_MULTIPLE_CHOICES = "300 Multiple Choices"; 195 | static const char* STR_STATUS_CODE_HTTP_301_MOVED_PERMANENTLY = "301 Moved Permanently"; 196 | static const char* STR_STATUS_CODE_HTTP_302_FOUND = "302 Found"; 197 | static const char* STR_STATUS_CODE_HTTP_303_SEE_OTHER = "303 See Other"; 198 | static const char* STR_STATUS_CODE_HTTP_304_NOT_MODIFIED = "304 Not Modified"; 199 | static const char* STR_STATUS_CODE_HTTP_305_USE_PROXY = "305 Use Proxy"; 200 | static const char* STR_STATUS_CODE_HTTP_306_SWITCH_PROXY = "306 Switch Proxy"; 201 | static const char* STR_STATUS_CODE_HTTP_307_TEMPORARY_REDIRECT = "307 Temporary Redirect"; 202 | static const char* STR_STATUS_CODE_HTTP_308_PERMANENT_REDIRECT = "308 Permanent Redirect"; 203 | static const char* STR_STATUS_CODE_HTTP_400_BAD_REQUEST = "400 Bad Request"; 204 | static const char* STR_STATUS_CODE_HTTP_401_UNAUTHORIZED = "401 Unauthorized"; 205 | static const char* STR_STATUS_CODE_HTTP_402_PAYMENT_REQUIRED = "402 Payment Required"; 206 | static const char* STR_STATUS_CODE_HTTP_403_FORBIDDEN = "403 Forbidden"; 207 | static const char* STR_STATUS_CODE_HTTP_404_NOT_FOUND = "404 Not Found"; 208 | static const char* STR_STATUS_CODE_HTTP_405_METHOD_NOT_ALLOWED = "405 Method Not Allowed"; 209 | static const char* STR_STATUS_CODE_HTTP_406_NOT_ACCEPTABLE = "406 Not Acceptable"; 210 | static const char* STR_STATUS_CODE_HTTP_407_PROXY_AUTHENTICATION_REQUIRED = "407 Proxy Authentication Required"; 211 | static const char* STR_STATUS_CODE_HTTP_408_REQUEST_TIMEOUT = "408 Request Timeout"; 212 | static const char* STR_STATUS_CODE_HTTP_409_CONFLICT = "409 Conflict"; 213 | static const char* STR_STATUS_CODE_HTTP_410_GONE = "410 Gone"; 214 | static const char* STR_STATUS_CODE_HTTP_411_LENGTH_REQUIRED = "411 Length Required"; 215 | static const char* STR_STATUS_CODE_HTTP_412_PRECONDITION_FAILED = "412 Precondition Failed"; 216 | static const char* STR_STATUS_CODE_HTTP_413_PAYLOAD_TOO_LARGE = "413 Payload Too Large"; 217 | static const char* STR_STATUS_CODE_HTTP_414_URI_TOO_LONG = "414 URI Too Long"; 218 | static const char* STR_STATUS_CODE_HTTP_415_UNSUPPORTED_MEDIA_TYPE = "415 Unsupported Media Type"; 219 | static const char* STR_STATUS_CODE_HTTP_416_RANGE_NOT_SATISFIABLE = "416 Range Not Satisfiable"; 220 | static const char* STR_STATUS_CODE_HTTP_417_EXPECTATION_FAILED = "417 Expectation Failed"; 221 | static const char* STR_STATUS_CODE_HTTP_418_IM_A_TEAPOT = "418 I'm a teapot"; 222 | static const char* STR_STATUS_CODE_HTTP_421_MISDIRECTED_REQUEST = "421 Misdirected Request"; 223 | static const char* STR_STATUS_CODE_HTTP_422_UNPROCESSABLE_ENTITY = "422 Unprocessable Entity"; 224 | static const char* STR_STATUS_CODE_HTTP_423_LOCKED = "423 Locked"; 225 | static const char* STR_STATUS_CODE_HTTP_424_FAILED_DEPENDENCY = "424 Failed Dependency"; 226 | static const char* STR_STATUS_CODE_HTTP_425_TOO_EARLY = "425 Too Early"; 227 | static const char* STR_STATUS_CODE_HTTP_426_UPGRADE_REQUIRED = "426 Upgrade Required"; 228 | static const char* STR_STATUS_CODE_HTTP_428_PRECONDITION_REQUIRED = "428 Precondition Required"; 229 | static const char* STR_STATUS_CODE_HTTP_429_TOO_MANY_REQUESTS = "429 Too Many Requests"; 230 | static const char* STR_STATUS_CODE_HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE = "431 Request Header Fields Too Large"; 231 | static const char* STR_STATUS_CODE_HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS = "451 Unavailable For Legal Reasons"; 232 | static const char* STR_STATUS_CODE_HTTP_500_INTERNAL_SERVER_ERROR = "500 Internal Server Error"; 233 | static const char* STR_STATUS_CODE_HTTP_501_NOT_IMPLEMENTED = "501 Not Implemented"; 234 | static const char* STR_STATUS_CODE_HTTP_502_BAD_GATEWAY = "502 Bad Gateway"; 235 | static const char* STR_STATUS_CODE_HTTP_503_SERVICE_UNAVAILABLE = "503 Service Unavailable"; 236 | static const char* STR_STATUS_CODE_HTTP_504_GATEWAY_TIMEOUT = "504 Gateway Timeout"; 237 | static const char* STR_STATUS_CODE_HTTP_505_HTTP_VERSION_NOT_SUPPORTED = "505 HTTP Version Not Supported"; 238 | static const char* STR_STATUS_CODE_HTTP_506_VARIANT_ALSO_NEGOTIATES = "506 Variant Also Negotiates"; 239 | static const char* STR_STATUS_CODE_HTTP_507_INSUFFICIENT_STORAGE = "507 Insufficient Storage"; 240 | static const char* STR_STATUS_CODE_HTTP_508_LOOP_DETECTED = "508 Loop Detected"; 241 | static const char* STR_STATUS_CODE_HTTP_510_NOT_EXTENDED = "510 Not Extended"; 242 | static const char* STR_STATUS_CODE_HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = "511 Network Authentication Required"; 243 | #endif 244 | 245 | #undef CASE 246 | #define CASE(code) case StatusCode::HTTP_##code: return STR_STATUS_CODE_HTTP_##code 247 | 248 | const char* to_string(StatusCode code) { 249 | switch (code) { 250 | CASE(UNKNOWN); 251 | CASE(100_CONTINUE); 252 | CASE(101_SWITCHING_PROTOCOLS); 253 | CASE(102_PROCESSING); 254 | CASE(103_EARLY_HINTS); 255 | 256 | CASE(200_OK); 257 | CASE(201_CREATED); 258 | CASE(202_ACCEPTED); 259 | CASE(203_NON_AUTHORITATIVE_INFORMATION); 260 | CASE(204_NO_CONTENT); 261 | CASE(205_RESET_CONTENT); 262 | CASE(206_PARTIAL_CONTENT); 263 | CASE(207_MULTI_STATUS); 264 | CASE(208_ALREADY_REPORTED); 265 | CASE(226_IM_USED); 266 | 267 | CASE(300_MULTIPLE_CHOICES); 268 | CASE(301_MOVED_PERMANENTLY); 269 | CASE(302_FOUND); 270 | CASE(303_SEE_OTHER); 271 | CASE(304_NOT_MODIFIED); 272 | CASE(305_USE_PROXY); 273 | CASE(306_SWITCH_PROXY); 274 | CASE(307_TEMPORARY_REDIRECT); 275 | CASE(308_PERMANENT_REDIRECT); 276 | 277 | CASE(400_BAD_REQUEST); 278 | CASE(401_UNAUTHORIZED); 279 | CASE(402_PAYMENT_REQUIRED); 280 | CASE(403_FORBIDDEN); 281 | CASE(404_NOT_FOUND); 282 | CASE(405_METHOD_NOT_ALLOWED); 283 | CASE(406_NOT_ACCEPTABLE); 284 | CASE(407_PROXY_AUTHENTICATION_REQUIRED); 285 | CASE(408_REQUEST_TIMEOUT); 286 | CASE(409_CONFLICT); 287 | CASE(410_GONE); 288 | CASE(411_LENGTH_REQUIRED); 289 | CASE(412_PRECONDITION_FAILED); 290 | CASE(413_PAYLOAD_TOO_LARGE); 291 | CASE(414_URI_TOO_LONG); 292 | CASE(415_UNSUPPORTED_MEDIA_TYPE); 293 | CASE(416_RANGE_NOT_SATISFIABLE); 294 | CASE(417_EXPECTATION_FAILED); 295 | CASE(418_IM_A_TEAPOT); 296 | CASE(421_MISDIRECTED_REQUEST); 297 | CASE(422_UNPROCESSABLE_ENTITY); 298 | CASE(423_LOCKED); 299 | CASE(424_FAILED_DEPENDENCY); 300 | CASE(425_TOO_EARLY); 301 | CASE(426_UPGRADE_REQUIRED); 302 | CASE(428_PRECONDITION_REQUIRED); 303 | CASE(429_TOO_MANY_REQUESTS); 304 | CASE(431_REQUEST_HEADER_FIELDS_TOO_LARGE); 305 | CASE(451_UNAVAILABLE_FOR_LEGAL_REASONS); 306 | 307 | CASE(500_INTERNAL_SERVER_ERROR); 308 | CASE(501_NOT_IMPLEMENTED); 309 | CASE(502_BAD_GATEWAY); 310 | CASE(503_SERVICE_UNAVAILABLE); 311 | CASE(504_GATEWAY_TIMEOUT); 312 | CASE(505_HTTP_VERSION_NOT_SUPPORTED); 313 | CASE(506_VARIANT_ALSO_NEGOTIATES); 314 | CASE(507_INSUFFICIENT_STORAGE); 315 | CASE(508_LOOP_DETECTED); 316 | CASE(510_NOT_EXTENDED); 317 | CASE(511_NETWORK_AUTHENTICATION_REQUIRED); 318 | 319 | default: return STR_STATUS_CODE_HTTP_UNKNOWN; 320 | } 321 | } 322 | 323 | 324 | /*********************************************************************** 325 | * 326 | * 4. Http Connection Type 327 | * 328 | ************************************************************************/ 329 | 330 | static const char* STR_CONNECTION_TYPE_UNKNOWN = "UNKNOWN"; 331 | static const char* STR_CONNECTION_TYPE_CLOSE = "close"; 332 | static const char* STR_CONNECTION_TYPE_KEEP_ALIVE = "keep-alive"; 333 | static const char* STR_CONNECTION_TYPE_UPGRADE = "upgrade"; 334 | 335 | #undef CASE 336 | #define CASE(type) case ConnectionType::type: return STR_CONNECTION_TYPE_##type 337 | 338 | const char* to_string(ConnectionType type) { 339 | switch (type) { 340 | CASE(CLOSE); 341 | CASE(KEEP_ALIVE); 342 | CASE(UPGRADE); 343 | default: return STR_CONNECTION_TYPE_UNKNOWN; 344 | } 345 | } 346 | 347 | /*********************************************************************** 348 | * 349 | * 5. Http Content Type 350 | * 351 | ************************************************************************/ 352 | 353 | #if 1 // Http Content Type String 354 | static const char* STR_CONTENT_TYPE_UNKNOWN = "UNKNOWN"; 355 | static const char* STR_CONTENT_TYPE_NO_CONTENT = ""; 356 | static const char* STR_CONTENT_TYPE_TEXT_CSS = "text/css"; 357 | static const char* STR_CONTENT_TYPE_TEXT_CSV = "text/csv"; 358 | static const char* STR_CONTENT_TYPE_TEXT_HTML = "text/html"; 359 | static const char* STR_CONTENT_TYPE_TEXT_PLAIN = "text/plain"; 360 | static const char* STR_CONTENT_TYPE_TEXT_XML = "text/xml"; 361 | static const char* STR_CONTENT_TYPE_IMAGE_GIF = "image/gif"; 362 | static const char* STR_CONTENT_TYPE_IMAGE_JPEG = "image/jpeg"; 363 | static const char* STR_CONTENT_TYPE_IMAGE_PNG = "image/png"; 364 | static const char* STR_CONTENT_TYPE_IMAGE_TIFF = "image/tiff"; 365 | static const char* STR_CONTENT_TYPE_IMAGE_X_ICON = "image/x-icon"; 366 | static const char* STR_CONTENT_TYPE_IMAGE_SVG_XML = "image/svg+xml"; 367 | static const char* STR_CONTENT_TYPE_VIDEO_MPEG = "video/mpeg"; 368 | static const char* STR_CONTENT_TYPE_VIDEO_MP4 = "video/mp4"; 369 | static const char* STR_CONTENT_TYPE_VIDEO_X_FLV = "video/x-flv"; 370 | static const char* STR_CONTENT_TYPE_VIDEO_WEBM = "video/webm"; 371 | static const char* STR_CONTENT_TYPE_MULTIPART_MIXED = "multipart/mixed"; 372 | static const char* STR_CONTENT_TYPE_MULTIPART_ALTERNATIVE = "multipart/alternative"; 373 | static const char* STR_CONTENT_TYPE_MULTIPART_RELATED = "multipart/related"; 374 | static const char* STR_CONTENT_TYPE_MULTIPART_FORM_DATA = "multipart/form-data"; 375 | static const char* STR_CONTENT_TYPE_AUDIO_MPEG = "audio/mpeg"; 376 | static const char* STR_CONTENT_TYPE_AUDIO_X_MS_WMA = "audio/x-ms-wma"; 377 | static const char* STR_CONTENT_TYPE_AUDIO_X_WAV = "audio/x-wav"; 378 | static const char* STR_CONTENT_TYPE_APPLICATION_JAVASCRIPT = "application/javascript"; 379 | static const char* STR_CONTENT_TYPE_APPLICATION_OCTET_STREAM = "application/octet-stream"; 380 | static const char* STR_CONTENT_TYPE_APPLICATION_OGG = "application/ogg"; 381 | static const char* STR_CONTENT_TYPE_APPLICATION_PDF = "application/pdf"; 382 | static const char* STR_CONTENT_TYPE_APPLICATION_XHTML_XML = "application/xhtml+xml"; 383 | static const char* STR_CONTENT_TYPE_APPLICATION_X_SHOCKWAVE_FLASH = "application/x-shockwave-flash"; 384 | static const char* STR_CONTENT_TYPE_APPLICATION_JSON = "application/json"; 385 | static const char* STR_CONTENT_TYPE_APPLICATION_LD_JSON = "application/ld+json"; 386 | static const char* STR_CONTENT_TYPE_APPLICATION_XML = "application/xml"; 387 | static const char* STR_CONTENT_TYPE_APPLICATION_ZIP = "application/zip"; 388 | static const char* STR_CONTENT_TYPE_APPLICATION_X_WWW_FORM_URLENCODED = "application/x-www-form-urlencoded"; 389 | #endif 390 | 391 | #undef CASE 392 | #define CASE(type) case ContentType::type: return STR_CONTENT_TYPE_##type 393 | 394 | const char* to_string(ContentType type) { 395 | switch (type) { 396 | CASE(NO_CONTENT); 397 | CASE(TEXT_CSS); 398 | CASE(TEXT_CSV); 399 | CASE(TEXT_HTML); 400 | CASE(TEXT_PLAIN); 401 | CASE(TEXT_XML); 402 | CASE(IMAGE_GIF); 403 | CASE(IMAGE_JPEG); 404 | CASE(IMAGE_PNG); 405 | CASE(IMAGE_TIFF); 406 | CASE(IMAGE_X_ICON); 407 | CASE(IMAGE_SVG_XML); 408 | CASE(VIDEO_MPEG); 409 | CASE(VIDEO_MP4); 410 | CASE(VIDEO_X_FLV); 411 | CASE(VIDEO_WEBM); 412 | CASE(MULTIPART_MIXED); 413 | CASE(MULTIPART_ALTERNATIVE); 414 | CASE(MULTIPART_RELATED); 415 | CASE(MULTIPART_FORM_DATA); 416 | CASE(AUDIO_MPEG); 417 | CASE(AUDIO_X_MS_WMA); 418 | CASE(AUDIO_X_WAV); 419 | CASE(APPLICATION_JAVASCRIPT); 420 | CASE(APPLICATION_OCTET_STREAM); 421 | CASE(APPLICATION_OGG); 422 | CASE(APPLICATION_PDF); 423 | CASE(APPLICATION_XHTML_XML); 424 | CASE(APPLICATION_X_SHOCKWAVE_FLASH); 425 | CASE(APPLICATION_JSON); 426 | CASE(APPLICATION_LD_JSON); 427 | CASE(APPLICATION_XML); 428 | CASE(APPLICATION_ZIP); 429 | CASE(APPLICATION_X_WWW_FORM_URLENCODED); 430 | default: return STR_CONTENT_TYPE_UNKNOWN; 431 | } 432 | } 433 | 434 | /*********************************************************************** 435 | * 436 | * END 437 | * 438 | ************************************************************************/ 439 | 440 | #undef CASE 441 | 442 | } // namespace http 443 | } // namespace client 444 | } // namespace ic 445 | --------------------------------------------------------------------------------