久久精品国产精品国产精品污,男人扒开添女人下部免费视频,一级国产69式性姿势免费视频,夜鲁夜鲁很鲁在线视频 视频,欧美丰满少妇一区二区三区,国产偷国产偷亚洲高清人乐享,中文 在线 日韩 亚洲 欧美,熟妇人妻无乱码中文字幕真矢织江,一区二区三区人妻制服国产

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

libcurl的封装,支持同步异步请求,支持多线程下载,支持https(z)

發(fā)布時間:2023/12/14 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 libcurl的封装,支持同步异步请求,支持多线程下载,支持https(z) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

最近在做一個項目,需要用到http get post等

需求分析需要做到同步和異步,異步請求的返回以可選的回調(diào)通知的方式進(jìn)行。

本人以Linux為例,一步一步的來實現(xiàn)。

  • 配置并且編譯libcurl
    我以在Linux底下的交叉編譯舉例。
    libcurl源碼下載:?http://curl.haxx.se/download.html
    配置libcurl支持https和zlib壓縮,必須需要openssl和zlib庫
    openssl庫源碼下載:?http://www.openssl.org/source/。下載1.02a以上的版本,避開心臟出血漏洞。
    zlib源碼下載:http://www.zlib.net/。下載最新版本代碼。
    新建文件夾carbon。源碼解壓至目錄carbon。

    1.1 配置openssl并且編譯
    配置和編譯腳本:
    1 #!/bin/bash2 # Cross-compile environment for Android on ARMv7 and x863 #4 # Contents licensed under the terms of the OpenSSL license5 # http://www.openssl.org/source/license.html6 #7 # See http://wiki.openssl.org/index.php/FIPS_Library_and_Android8 # and http://wiki.openssl.org/index.php/Android9 10 #####################################################################11 12 # Set ANDROID_NDK_ROOT to you NDK location. For example,13 # /opt/android-ndk-r8e or /opt/android-ndk-r9. This can be done in a14 # login script. If ANDROID_NDK_ROOT is not specified, the script will15 # try to pick it up with the value of _ANDROID_NDK_ROOT below. If16 # ANDROID_NDK_ROOT is set, then the value is ignored.17 # _ANDROID_NDK="android-ndk-r8e"18 #_ANDROID_NDK="android-ndk-r9"19 _ANDROID_NDK="android-ndk-r10"20 ANDROID_NDK_ROOT=$HOME/ndk/android-ndk-r10d21 # Set _ANDROID_EABI to the EABI you want to use. You can find the22 # list in $ANDROID_NDK_ROOT/toolchains. This value is always used.23 # _ANDROID_EABI="x86-4.6"24 # _ANDROID_EABI="arm-linux-androideabi-4.6"25 _ANDROID_EABI="arm-linux-androideabi-4.8"26 export ROOTDIR="${PWD}"27 28 # Set _ANDROID_ARCH to the architecture you are building for.29 # This value is always used.30 # _ANDROID_ARCH=arch-x8631 _ANDROID_ARCH=arch-arm32 33 # Set _ANDROID_API to the API you want to use. You should set it34 # to one of: android-14, android-9, android-8, android-14, android-535 # android-4, or android-3. You can't set it to the latest (for36 # example, API-17) because the NDK does not supply the platform. At37 # Android 5.0, there will likely be another platform added (android-22?).38 # This value is always used.39 # _ANDROID_API="android-14"40 # _ANDROID_API="android-18"41 # _ANDROID_API="android-19"42 _ANDROID_API="android-5"43 44 #####################################################################45 46 # If the user did not specify the NDK location, try and pick it up.47 # We expect something like ANDROID_NDK_ROOT=/opt/android-ndk-r8e48 # or ANDROID_NDK_ROOT=/usr/local/android-ndk-r8e.49 50 if [ -z "$ANDROID_NDK_ROOT" ]; then51 52 _ANDROID_NDK_ROOT=""53 if [ -z "$_ANDROID_NDK_ROOT" ] && [ -d "/usr/local/$_ANDROID_NDK" ]; then54 _ANDROID_NDK_ROOT="/usr/local/$_ANDROID_NDK"55 fi56 57 if [ -z "$_ANDROID_NDK_ROOT" ] && [ -d "/opt/$_ANDROID_NDK" ]; then58 _ANDROID_NDK_ROOT="/opt/$_ANDROID_NDK"59 fi60 61 if [ -z "$_ANDROID_NDK_ROOT" ] && [ -d "$HOME/$_ANDROID_NDK" ]; then62 _ANDROID_NDK_ROOT="$HOME/$_ANDROID_NDK"63 fi64 65 if [ -z "$_ANDROID_NDK_ROOT" ] && [ -d "$PWD/$_ANDROID_NDK" ]; then66 _ANDROID_NDK_ROOT="$PWD/$_ANDROID_NDK"67 fi68 69 # If a path was set, then export it70 if [ ! -z "$_ANDROID_NDK_ROOT" ] && [ -d "$_ANDROID_NDK_ROOT" ]; then71 export ANDROID_NDK_ROOT="$_ANDROID_NDK_ROOT"72 fi73 fi74 75 # Error checking76 # ANDROID_NDK_ROOT should always be set by the user (even when not running this script)77 # http://groups.google.com/group/android-ndk/browse_thread/thread/a998e139aca71d7778 if [ -z "$ANDROID_NDK_ROOT" ] || [ ! -d "$ANDROID_NDK_ROOT" ]; then79 echo "Error: ANDROID_NDK_ROOT is not a valid path. Please edit this script."80 # echo "$ANDROID_NDK_ROOT"81 # exit 182 fi83 84 # Error checking85 if [ ! -d "$ANDROID_NDK_ROOT/toolchains" ]; then86 echo "Error: ANDROID_NDK_ROOT/toolchains is not a valid path. Please edit this script."87 # echo "$ANDROID_NDK_ROOT/toolchains"88 # exit 189 fi90 91 # Error checking92 if [ ! -d "$ANDROID_NDK_ROOT/toolchains/$_ANDROID_EABI" ]; then93 echo "Error: ANDROID_EABI is not a valid path. Please edit this script."94 # echo "$ANDROID_NDK_ROOT/toolchains/$_ANDROID_EABI"95 # exit 196 fi97 98 #####################################################################99 100 # Based on ANDROID_NDK_ROOT, try and pick up the required toolchain. We expect something like: 101 # /opt/android-ndk-r83/toolchains/arm-linux-androideabi-4.7/prebuilt/linux-x86_64/bin 102 # Once we locate the toolchain, we add it to the PATH. Note: this is the 'hard way' of 103 # doing things according to the NDK documentation for Ice Cream Sandwich. 104 # https://android.googlesource.com/platform/ndk/+/ics-mr0/docs/STANDALONE-TOOLCHAIN.html 105 106 ANDROID_TOOLCHAIN="" 107 for host in "linux-x86_64" "linux-x86" "darwin-x86_64" "darwin-x86" 108 do 109 if [ -d "$ANDROID_NDK_ROOT/toolchains/$_ANDROID_EABI/prebuilt/$host/bin" ]; then 110 ANDROID_TOOLCHAIN="$ANDROID_NDK_ROOT/toolchains/$_ANDROID_EABI/prebuilt/$host/bin" 111 break 112 fi 113 done 114 115 # Error checking 116 if [ -z "$ANDROID_TOOLCHAIN" ] || [ ! -d "$ANDROID_TOOLCHAIN" ]; then 117 echo "Error: ANDROID_TOOLCHAIN is not valid. Please edit this script." 118 # echo "$ANDROID_TOOLCHAIN" 119 # exit 1 120 fi 121 122 case $_ANDROID_ARCH in 123 arch-arm) 124 ANDROID_TOOLS="arm-linux-androideabi-gcc arm-linux-androideabi-ranlib arm-linux-androideabi-ld" 125 ;; 126 arch-x86) 127 ANDROID_TOOLS="i686-linux-android-gcc i686-linux-android-ranlib i686-linux-android-ld" 128 ;; 129 *) 130 echo "ERROR ERROR ERROR" 131 ;; 132 esac 133 134 for tool in $ANDROID_TOOLS 135 do 136 # Error checking 137 if [ ! -e "$ANDROID_TOOLCHAIN/$tool" ]; then 138 echo "Error: Failed to find $tool. Please edit this script." 139 # echo "$ANDROID_TOOLCHAIN/$tool" 140 # exit 1 141 fi 142 done 143 144 # Only modify/export PATH if ANDROID_TOOLCHAIN good 145 if [ ! -z "$ANDROID_TOOLCHAIN" ]; then 146 export ANDROID_TOOLCHAIN="$ANDROID_TOOLCHAIN" 147 export PATH="$ANDROID_TOOLCHAIN":"$PATH" 148 fi 149 150 ##################################################################### 151 152 # For the Android SYSROOT. Can be used on the command line with --sysroot 153 # https://android.googlesource.com/platform/ndk/+/ics-mr0/docs/STANDALONE-TOOLCHAIN.html 154 export ANDROID_SYSROOT="$ANDROID_NDK_ROOT/platforms/$_ANDROID_API/$_ANDROID_ARCH" 155 export SYSROOT="$ANDROID_SYSROOT" 156 export NDK_SYSROOT="$ANDROID_SYSROOT" 157 158 # Error checking 159 if [ -z "$ANDROID_SYSROOT" ] || [ ! -d "$ANDROID_SYSROOT" ]; then 160 echo "Error: ANDROID_SYSROOT is not valid. Please edit this script." 161 # echo "$ANDROID_SYSROOT" 162 # exit 1 163 fi 164 165 ##################################################################### 166 167 # If the user did not specify the FIPS_SIG location, try and pick it up 168 # If the user specified a bad location, then try and pick it up too. 169 if [ -z "$FIPS_SIG" ] || [ ! -e "$FIPS_SIG" ]; then 170 171 # Try and locate it 172 _FIPS_SIG="" 173 if [ -d "/usr/local/ssl/$_ANDROID_API" ]; then 174 _FIPS_SIG=`find "/usr/local/ssl/$_ANDROID_API" -name incore` 175 fi 176 177 if [ ! -e "$_FIPS_SIG" ]; then 178 _FIPS_SIG=`find $PWD -name incore` 179 fi 180 181 # If a path was set, then export it 182 if [ ! -z "$_FIPS_SIG" ] && [ -e "$_FIPS_SIG" ]; then 183 export FIPS_SIG="$_FIPS_SIG" 184 fi 185 fi 186 187 # Error checking. Its OK to ignore this if you are *not* building for FIPS 188 if [ -z "$FIPS_SIG" ] || [ ! -e "$FIPS_SIG" ]; then 189 echo "Error: FIPS_SIG does not specify incore module. Please edit this script." 190 # echo "$FIPS_SIG" 191 # exit 1 192 fi 193 194 ##################################################################### 195 196 # Most of these should be OK (MACHINE, SYSTEM, ARCH). RELEASE is ignored. 197 export MACHINE=armv7 198 export RELEASE=2.6.37 199 export SYSTEM=android 200 export ARCH=arm 201 export CROSS_COMPILE="arm-linux-androideabi-" 202 203 if [ "$_ANDROID_ARCH" == "arch-x86" ]; then 204 export MACHINE=i686 205 export RELEASE=2.6.37 206 export SYSTEM=android 207 export ARCH=x86 208 export CROSS_COMPILE="i686-linux-android-" 209 fi 210 211 # For the Android toolchain 212 # https://android.googlesource.com/platform/ndk/+/ics-mr0/docs/STANDALONE-TOOLCHAIN.html 213 export ANDROID_SYSROOT="$ANDROID_NDK_ROOT/platforms/$_ANDROID_API/$_ANDROID_ARCH" 214 export SYSROOT="$ANDROID_SYSROOT" 215 export NDK_SYSROOT="$ANDROID_SYSROOT" 216 export ANDROID_NDK_SYSROOT="$ANDROID_SYSROOT" 217 export ANDROID_API="$_ANDROID_API" 218 219 # CROSS_COMPILE and ANDROID_DEV are DFW (Don't Fiddle With). Its used by OpenSSL build system. 220 # export CROSS_COMPILE="arm-linux-androideabi-" 221 export ANDROID_DEV="$ANDROID_NDK_ROOT/platforms/$_ANDROID_API/$_ANDROID_ARCH/usr" 222 export HOSTCC=gcc 223 224 VERBOSE=1 225 if [ ! -z "$VERBOSE" ] && [ "$VERBOSE" != "0" ]; then 226 echo "ANDROID_NDK_ROOT: $ANDROID_NDK_ROOT" 227 echo "ANDROID_ARCH: $_ANDROID_ARCH" 228 echo "ANDROID_EABI: $_ANDROID_EABI" 229 echo "ANDROID_API: $ANDROID_API" 230 echo "ANDROID_SYSROOT: $ANDROID_SYSROOT" 231 echo "ANDROID_TOOLCHAIN: $ANDROID_TOOLCHAIN" 232 echo "FIPS_SIG: $FIPS_SIG" 233 echo "CROSS_COMPILE: $CROSS_COMPILE" 234 echo "ANDROID_DEV: $ANDROID_DEV" 235 fi 236 237 cd openssl 238 if [ $# -gt 0 ]; then 239 perl -pi -e 's/install: all install_docs install_sw/install: install_docs install_sw/g' Makefile.org 240 ./config -DOPENSSL_NO_HEARTBEATS no-shared no-ssl2 no-ssl3 no-comp no-hw no-engine --openssldir=${ROOTDIR}/build/openssl 241 fi 242 make depend 243 make && make install

    1.2 配置zlib并且編譯
    配置腳本:

    1 #!/bin/sh2 3 export ROOTDIR="${PWD}"4 cd zlib/5 6 export CROSS_COMPILE="arm-linux-androideabi"7 export CPPFLAGS="-fPIC"8 export CFLAGS="-fPIC"9 export AR=${CROSS_COMPILE}-ar 10 export AS=${CROSS_COMPILE}-as 11 export LD=${CROSS_COMPILE}-ld 12 export RANLIB=${CROSS_COMPILE}-ranlib 13 export CC=${CROSS_COMPILE}-gcc 14 export CXX=${CROSS_COMPILE}-g++ 15 export NM=${CROSS_COMPILE}-nm 16 17 ./configure --prefix=${ROOTDIR}/build/zlib --static

    配置成功之后,cd進(jìn)代碼目錄執(zhí)行make && make install命令即可

    1.3 配置libcurl并且編譯

    配置腳本:
    1 #!/bin/sh2 3 export ROOTDIR="${PWD}"4 cd curl-7.42.1/5 6 export CROSS_COMPILE="arm-linux-androideabi"7 export CPPFLAGS="-fPIC -I${ROOTDIR}/build/openssl/include -I${ROOTDIR}/build/zlib/include"8 export CFLAGS="-fPIC -I${ROOTDIR}/build/openssl/include -I${ROOTDIR}/build/zlib/include"9 10 export LDFLAGS="-L${ROOTDIR}/build/openssl/lib -L${ROOTDIR}/build/zlib/lib" 11 export LIBS="-lssl -lcrypto -lz" 12 13 export AR=${CROSS_COMPILE}-ar 14 export AS=${CROSS_COMPILE}-as 15 export LD=${CROSS_COMPILE}-ld 16 export RANLIB=${CROSS_COMPILE}-ranlib 17 export CC=${CROSS_COMPILE}-gcc 18 export CXX=${CROSS_COMPILE}-g++ 19 export NM=${CROSS_COMPILE}-nm 20 21 ./configure --prefix=${ROOTDIR}/build/curl --target=${CROSS_COMPILE} --host=${CROSS_COMPILE} --build=i686-linux --enable-static=libcurl.a --enable-shared=libcurl.so --enable-symbol-hiding --enable-optimize --enable-ftp --enable-http --enable-file --enable-proxy --enable-tftp --enable-smtp --enable-telnet --enable-cookies --enable-ipv6 --with-ssl --with-zlib --without-libssh2 --with-random=/dev/urandom

    配置成功之后,cd進(jìn)代碼目錄執(zhí)行make && make install命令即可

    本配置使用的是android的ndk工具鏈gcc 4.8
    在配置openssl時,指定了ANDROID_NDK_ROOT的值為ndk的路徑,可以參看腳本的值進(jìn)行對應(yīng)的設(shè)置
    可以在ndk目錄的build/tools目錄找到make-standalone-toolchain.sh文件,執(zhí)行make-standalone-toolchain.sh --help --help來查看幫助
    構(gòu)建自己的ndk gcc工具鏈,最后將生成的工具鏈路徑加入進(jìn)環(huán)境變量PATH即可

  • 封裝libcurl庫
    代碼使用C++封裝,并且使用了C++11的特性,編譯時需要指定-std=c++11
    頭文件: 1 #ifndef __HTTP_REQUEST_H2 #define __HTTP_REQUEST_H3 4 5 #include <string>6 #include <map>7 #include <memory>8 #include <functional>9 #include <vector>10 11 //************************************12 // Usage: 13 // class MyResultClass14 // {15 // public:16 // MyResultClass() : m_request_finished(false) { }17 // ~MyResultClass() { }18 // 19 // public:20 // void MyRequestResultCallback(int id, bool success, const std::string& data)21 // {22 // if (success)23 // {24 // std::ofstream outfile;25 // outfile.open("baidu.html", std::ios_base::binary | std::ios_base::trunc);26 // if (outfile.good()) outfile.write(data.c_str(), data.size());27 // }28 // m_request_finished = true;29 // }30 // bool IsRequestFinish(void) { return m_request_finished; }31 // private:32 // bool m_request_finished;33 // };34 //35 // MyResultClass mc;36 // HttpRequest request;37 // request.SetRequestUrl("http://www.baidu.com");38 // request.SetResultCallback(std::bind(&MyResultClass::MyRequestResultCallback, &mc, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));39 // request.SetRequestHeader("User-Agent:Mozilla/4.04[en](Win95;I;Nav)");40 // HANDLE hRequest = request.PerformRequest(HttpRequest::REQUEST_ASYNC);41 // if (hRequest)42 // {43 // while (mc.IsRequestFinish() == false) Sleep(300);44 // long http_code;45 // if (request.GetHttpCode(hRequest, &http_code))46 // std::cout << "http code: " << http_code << std::endl;47 // std::string header;48 // if (request.GetReceiveHeader(hRequest, &header))49 // std::cout << header << std::endl;50 // HttpRequest::Close(hRequest);51 // }52 // /*recommended HttpRequest::Close(hRequest) while doing async request job and dont need request handle anymore*/53 //************************************54 55 class HttpLock;56 57 #ifndef _WIN3258 typedef void* HANDLE;59 #endif60 61 class HttpRequest62 {63 public:64 typedef enum {65 REQUEST_SYNC,66 REQUEST_ASYNC,67 }RequestType;68 69 typedef enum {70 REQUEST_OK,71 REQUEST_INVALID_OPT,72 REQUEST_PERFORM_ERROR,73 REQUEST_OPENFILE_ERROR,74 REQUEST_INIT_ERROR,75 }RequestResult;76 77 //int id, bool success, const std::string& data78 typedef std::function<void(int, bool, const std::string&)> ResultCallback;79 80 friend class HttpHelper;81 82 HttpRequest();83 ~HttpRequest();84 85 86 int SetRetryTimes(int retry_times = s_kRetryCount);87 int SetRequestId(int id);88 int SetRequestTimeout(long time_out = 0);89 int SetRequestUrl(const std::string& url);90 91 //************************************92 // Method: SetMovedUrl93 // FullName: HttpRequest::SetMovedUrl94 // Access: public 95 // Returns: int96 // Description: set http redirect follow location97 // Parameter: bool get_moved_url -- true means redirect http url98 //************************************99 int SetMovedUrl(bool get_moved_url); 100 101 int SetPostData(const std::string& message); 102 int SetPostData(const void* data, unsigned int size); 103 104 //************************************ 105 // Method: SetRequestHeader 106 // FullName: HttpRequest::SetRequestHeader 107 // Access: public 108 // Returns: int 109 // Description: set http request header, for example : Range:bytes=554554- 110 // Parameter: std::map<std::string, std::string>& 111 // Parameter: std::string> & headers 112 //************************************ 113 int SetRequestHeader(const std::map<std::string, std::string>& headers); 114 int SetRequestHeader(const std::string& header); 115 116 int SetRequestProxy(const std::string& proxy, long proxy_port); 117 118 119 int SetResultCallback(ResultCallback rc); 120 121 HANDLE PerformRequest(RequestType request_type); 122 static void Close(HANDLE request_handle); 123 124 static bool GetHttpCode(HANDLE request_handle, long* http_code); 125 static bool GetReceiveHeader(HANDLE request_handle, std::string* header); 126 static bool GetReceiveContent(HANDLE request_handle, std::string* receive); 127 static bool GetErrorString(HANDLE request_handle, std::string* error_string); 128 129 protected: 130 131 class RequestHelper { 132 public: 133 RequestHelper(); 134 ~RequestHelper(); 135 136 friend class HttpRequest; 137 friend class HttpHelper; 138 139 int SetRetryTimes(int retry_times) { m_retry_times = retry_times; return REQUEST_OK; } 140 141 int SetRequestTimeout(long time_out = 0); 142 int SetRequestUrl(const std::string& url); 143 int SetMovedUrl(bool get_moved_url); 144 int SetPostData(const void* data, unsigned int size); 145 int SetRequestHeader(const std::string& header); 146 int SetRequestProxy(const std::string& proxy, long proxy_port); 147 148 int SetResultCallback(ResultCallback rc); 149 150 int Perform(); 151 152 long GetHttpCode() { return m_http_code; } 153 bool GetHeader(std::string* header); 154 bool GetContent(std::string* receive); 155 bool GetErrorString(std::string* error_string); 156 157 bool SelfClose(void) { return m_close_self; } 158 159 protected: 160 void ReqeustResultDefault(int id, bool success, const std::string& data); 161 162 private: 163 HANDLE m_curl_handle; 164 HANDLE m_http_headers; 165 #ifdef _WIN32 166 HANDLE m_perform_thread; 167 #else 168 pthread_t m_perform_thread; 169 #endif 170 171 int m_retry_times; 172 int m_id; 173 bool m_close_self; 174 bool m_is_running; 175 long m_http_code; 176 177 std::string m_receive_content; 178 std::string m_receive_header; 179 std::string m_error_string; 180 char* m_post_data; 181 182 ResultCallback m_result_callback; 183 }; 184 185 private: 186 std::shared_ptr<RequestHelper> m_request_handle; 187 static const int s_kRetryCount = 3; 188 }; 189 190 //************************************ 191 // Usage: HttpDownloader 192 // class DownCallbackClass 193 // { 194 // public: 195 // DownCallbackClass() :m_down_finished(false) {} 196 // ~DownCallbackClass() {} 197 // public: 198 // void DownResultCallback(int id, bool success, const std::string& data) 199 // { 200 // m_down_finished = true; 201 // } 202 // int down_callback(double total_size, double downloaded_size, void* userdata) 203 // { 204 // long tmp = static_cast<long>(downloaded_size / total_size * 100); 205 // printf("\r下載進(jìn)度%d", tmp); 206 // return 0; 207 // } 208 // bool IsDownFinished(void) { return m_down_finished; } 209 // private: 210 // bool m_down_finished; 211 // }; 212 // HttpDownloader download; 213 // DownCallbackClass dc; 214 // const char* down_url = "http://dlsw.baidu.com/sw-search-sp/soft/71/10998/OfflineBaiduPlayer_151_V4.1.2.263.1432003947.exe"; 215 // const char* down_file = "BaiduPlayer.exe"; 216 // 217 // download.SetDownloadUrl(down_url); 218 // download.SetProgressCallback(std::bind(&DownCallbackClass::down_callback, &dc, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 219 // download.SetResultCallback(std::bind(&DownCallbackClass::DownResultCallback, &dc, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 220 // download.DownloadFile(down_file); 221 // HANDLE hDownload = download.StartDownload(HttpDownloader::DOWN_ASYNC); 222 // if (hDownload) 223 // { 224 // while (dc.IsDownFinished() == false) Sleep(300); 225 // //to do download finish clean up 226 // HttpDownloader::Close(hDownload); 227 // } 228 //************************************ 229 230 class HttpDownloader 231 { 232 public: 233 typedef enum { 234 DOWN_SYNC, 235 DOWN_ASYNC, 236 }DownType; 237 238 //double total_size, double downloaded_size, void* userdata 239 typedef std::function<int(double, double, void*)> ProgressCallback; 240 //int id, bool success, const std::string& data 241 typedef std::function<void(int, bool, const std::string&)> ResultCallback; 242 243 friend class HttpHelper; 244 245 HttpDownloader(); 246 ~HttpDownloader(); 247 248 int SetRequestProxy(const std::string& proxy, long proxy_port); 249 int SetRetryTimes(int retry_times = s_kRetryCount); 250 int SetTimeout(long time_out = 0); 251 int SetDownloadUrl(const std::string& url); 252 int SetUserData(void* userdata); 253 int SetRequestId(int id); 254 int SetProgressCallback(ProgressCallback pc); 255 int SetResultCallback(ResultCallback rc); 256 257 int DownloadFile(const std::string& file_name, int thread_count = 5); 258 HANDLE StartDownload(DownType down_type); 259 static bool CancelDownload(HANDLE handle); 260 static void Close(HANDLE handle); 261 262 static bool GetHttpCode(HANDLE handle, long* http_code); 263 static bool GetReceiveHeader(HANDLE handle, std::string* header); 264 static bool GetErrorString(HANDLE handle, std::string* error_string); 265 static void* GetUserData(HANDLE handle); 266 267 protected: 268 269 class DownloadHelper { 270 public: 271 typedef struct tThreadChunk 272 { 273 FILE* _fp; 274 long _startidx; 275 long _endidx; 276 277 DownloadHelper* _download; 278 }ThreadChunk; 279 280 DownloadHelper(); 281 ~DownloadHelper(); 282 283 friend class HttpDownloader; 284 friend class HttpHelper; 285 friend ThreadChunk; 286 287 void SetRetryTimes(int retry_times) { m_retry_times = retry_times; } 288 void SetRequestId(int id) { m_id = id; } 289 int SetTimeout(long time_out = 0); 290 int SetRequestUrl(const std::string& url); 291 int SetRequestProxy(const std::string& proxy, long proxy_port); 292 293 void SetUserData(void *userdata) { m_userdata = userdata; } 294 int SetProgressCallback(ProgressCallback pc); 295 int SetResultCallback(ResultCallback rc); 296 int SetDownloadFile(const std::string& file_name); 297 int SetDownloadThreadCount(int thread_count); 298 299 int Perform(); 300 301 int GetHttpCode() { return m_http_code; } 302 bool GetHeader(std::string* header); 303 bool GetErrorString(std::string* error_string); 304 bool SelfClose(void) { return m_close_self; } 305 void* GetUserData(void) { return m_userdata; } 306 307 protected: 308 int DownloadDefaultCallback(double total_size, double downloaded_size, void* userdata); 309 void ResultDefaultCallback(int id, bool success, const std::string& data); 310 double GetDownloadFileSize(); 311 int DoDownload(ThreadChunk* thread_chunk); 312 int SplitDownloadCount(double down_size); 313 void Reset(void); 314 315 private: 316 #ifdef _WIN32 317 HANDLE m_perform_thread; 318 #else 319 pthread_t m_perform_thread; 320 #endif 321 322 int m_retry_times; 323 int m_thread_count; 324 int m_id; 325 long m_time_out; 326 327 std::string m_file_path; 328 std::string m_url; 329 std::string m_http_proxy; 330 std::string m_receive_header; 331 std::string m_error_string; 332 333 bool m_close_self; 334 bool m_multi_download; 335 bool m_download_fail; 336 bool m_is_running; 337 bool m_is_cancel; 338 void* m_userdata; 339 long m_http_code; 340 long m_proxy_port; 341 double m_total_size; 342 double m_downloaded_size; 343 344 std::shared_ptr<HttpLock> m_httplock; 345 ProgressCallback m_download_callback; 346 ResultCallback m_result_callback; 347 }; 348 349 private: 350 std::shared_ptr<DownloadHelper> m_request_handle; 351 352 static const int s_kRetryCount = 3; 353 static const int s_kThreadCount = 4; 354 }; 355 356 #endif /*__HTTP_REQUEST_H*/

    實現(xiàn)文件:

    1 // [5/11/2015 Carbon]2 /*3 _ooOoo_4 o888888888o 5 888 " . " 8886 (| -_- |) 7 O\ = /O 8 ____/` --- '\____ 9 .' \\| |// `. 10 / \\||| : |||// \ 11 / _||||| -:- |||||- \ 12 | | \\\ - /// | | 13 | \_| ''\---/'' |_/ | 14 \ .-\__ `-` __/-. / 15 _____`. .' /--.--\ `. . _____ 16 ."" '< `.___\_ <|> _/___.' >' "". 17 | | : `- \`.;` \ _ / `;.`/ - ` : | | 18 \ \ `-. \_ __\ /__ _/ .-` / / 19 ========`-.____`-.___\_____/___.-`____.-'======== 20 `=---='21 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^22 佛祖保佑 永無BUG23 */ 24 #ifdef _WIN3225 #include "stdafx.h"26 #else27 #include <pthread.h>28 #include <stdio.h>29 #include <unistd.h>30 #endif31 32 #include "./curl/curl.h" //libcurl interface33 #include "HttpRequest.h" //HttpRequest class34 35 #include <list>36 #include <regex>37 #include <sstream>38 39 40 #ifndef _WIN3241 typedef unsigned long DWORD;42 #define INVALID_HANDLE_VALUE (void*)0xffffffff43 #define TRUE 144 #define FALSE 045 #endif //#ifndef _WIN3246 47 class HttpLock48 {49 public:50 #ifdef _WIN3251 HttpLock() { InitializeCriticalSection(&m_cs); }52 ~HttpLock() { DeleteCriticalSection(&m_cs); }53 54 void Lock() { EnterCriticalSection(&m_cs); }55 void UnLock() { LeaveCriticalSection(&m_cs); }56 #else57 HttpLock() { pthread_mutex_init(&m_lock, NULL); }58 ~HttpLock() { pthread_mutex_destroy(&m_lock); }59 60 int Lock(){ return pthread_mutex_lock(&m_lock); }61 int UnLock() { return pthread_mutex_unlock(&m_lock); }62 #endif63 64 private:65 #ifdef _WIN3266 CRITICAL_SECTION m_cs;67 #else68 pthread_mutex_t m_lock;69 #endif70 };71 72 class DoHttpLock73 {74 public:75 DoHttpLock(std::shared_ptr<HttpLock> & lock)76 : m_lock(lock)77 {78 m_lock->Lock();79 }80 81 ~DoHttpLock()82 {83 m_lock->UnLock();84 }85 86 private:87 std::shared_ptr<HttpLock> m_lock;88 };89 90 class HttpHelper {91 protected:92 HttpHelper()93 {94 curl_global_init(CURL_GLOBAL_DEFAULT);95 96 s_share_handle = curl_share_init();97 curl_share_setopt(s_share_handle, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);98 }99 100 public:101 ~HttpHelper()102 {103 curl_share_cleanup(s_share_handle);104 curl_global_cleanup();105 106 s_async_requests.clear();107 s_async_downloads.clear();108 }109 110 static HttpHelper& Instance()111 {112 static HttpHelper the_single_instance;113 s_id++;114 return the_single_instance;115 }116 117 static void set_share_handle(CURL* curl_handle)118 {119 curl_easy_setopt(curl_handle, CURLOPT_SHARE, s_share_handle);120 curl_easy_setopt(curl_handle, CURLOPT_DNS_CACHE_TIMEOUT, 60 * 5);121 }122 123 static std::list< std::shared_ptr<HttpRequest::RequestHelper> > s_async_requests;124 static std::list< std::shared_ptr<HttpDownloader::DownloadHelper> > s_async_downloads;125 126 static int s_id;127 static std::shared_ptr<HttpLock> s_request_lock;128 static std::shared_ptr<HttpLock> s_download_lock;129 static CURLSH* s_share_handle;130 131 #ifdef _WIN32132 static DWORD WINAPI RequestThread(LPVOID param)133 #else134 static void* RequestThread(void* param)135 #endif136 {137 #ifdef _WIN32138 Sleep(10);139 #else140 usleep(10 * 1000);141 #endif142 143 std::shared_ptr<HttpRequest::RequestHelper>* request = reinterpret_cast<std::shared_ptr<HttpRequest::RequestHelper>*>(param);144 145 if (request)146 {147 (*request)->Perform();148 if ((*request)->SelfClose())149 {150 DoHttpLock http_lock(s_request_lock);151 HttpHelper::s_async_requests.remove(*request);152 }153 154 }155 156 #ifdef _WIN32157 return 1;158 #else159 return NULL;160 #endif161 }162 163 static size_t RetriveHeaderFunction(char *buffer, size_t size, size_t nitems, void *userdata)164 {165 std::string* receive_header = reinterpret_cast<std::string*>(userdata);166 if (receive_header && buffer)167 {168 receive_header->append(reinterpret_cast<const char*>(buffer), size * nitems);169 }170 171 return nitems * size;172 }173 174 static size_t RetriveContentFunction(char *ptr, size_t size, size_t nmemb, void *userdata)175 {176 std::string* receive_content = reinterpret_cast<std::string*>(userdata);177 if (receive_content && ptr)178 {179 receive_content->append(reinterpret_cast<const char*>(ptr), size * nmemb);180 }181 182 return nmemb * size;183 }184 185 #ifdef _WIN32186 static DWORD WINAPI DownloadThread(LPVOID param)187 #else188 static void* DownloadThread(void* param)189 #endif190 {191 #ifdef _WIN32192 Sleep(10);193 #else194 usleep(10 * 1000);195 #endif196 197 std::shared_ptr<HttpDownloader::DownloadHelper>* request = reinterpret_cast<std::shared_ptr<HttpDownloader::DownloadHelper>*>(param);198 199 if (request)200 {201 (*request)->Perform();202 203 if ((*request)->SelfClose())204 {205 DoHttpLock http_lock(s_download_lock);206 HttpHelper::s_async_downloads.remove(*request);207 }208 209 }210 211 #ifdef _WIN32212 return 1;213 #else214 return NULL;215 #endif216 }217 218 static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)219 {220 HttpDownloader::DownloadHelper::ThreadChunk* thread_chunk = reinterpret_cast<HttpDownloader::DownloadHelper::ThreadChunk*>(userdata);221 222 if (thread_chunk->_download->m_is_cancel)223 {224 return 0;225 }226 227 DoHttpLock http_lock(thread_chunk->_download->m_httplock);228 size_t written = 0;229 int real_size = size * nmemb;230 if (thread_chunk->_endidx > 0)231 {232 if (thread_chunk->_startidx <= thread_chunk->_endidx)233 {234 if (thread_chunk->_startidx + real_size > thread_chunk->_endidx)235 {236 real_size = thread_chunk->_endidx - thread_chunk->_startidx + 1;237 }238 }239 }240 241 int seek_error = fseek(thread_chunk->_fp, thread_chunk->_startidx, SEEK_SET);242 if (seek_error != 0)243 {244 perror("fseek");245 }246 else247 {248 written = fwrite(ptr, 1, real_size, thread_chunk->_fp);249 }250 thread_chunk->_download->m_downloaded_size += written;251 thread_chunk->_startidx += written;252 253 return written;254 }255 256 static int progress_callback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)257 {258 HttpDownloader::DownloadHelper::ThreadChunk* thread_chunk = reinterpret_cast<HttpDownloader::DownloadHelper::ThreadChunk*>(clientp);259 260 DoHttpLock http_lock(thread_chunk->_download->m_httplock);261 262 double total_size = thread_chunk->_download->m_total_size;263 double downloaded_size = thread_chunk->_download->m_downloaded_size;264 void* userdata = thread_chunk->_download->m_userdata;265 int callback_result = thread_chunk->_download->m_download_callback(total_size, downloaded_size, userdata);266 267 return callback_result;268 }269 270 #ifdef _WIN32271 static DWORD WINAPI DownloadWork(LPVOID param)272 #else273 static void* DownloadWork(void* param)274 #endif275 {276 HttpDownloader::DownloadHelper::ThreadChunk* thread_chunk = reinterpret_cast<HttpDownloader::DownloadHelper::ThreadChunk*>(param);277 278 #ifdef _WIN32279 return thread_chunk->_download->DoDownload(thread_chunk);280 #else281 return (void *)(thread_chunk->_download->DoDownload(thread_chunk));282 #endif283 }284 };285 286 std::list< std::shared_ptr<HttpRequest::RequestHelper> > HttpHelper::s_async_requests;287 std::list< std::shared_ptr<HttpDownloader::DownloadHelper> > HttpHelper::s_async_downloads;288 int HttpHelper::s_id = 0;289 std::shared_ptr<HttpLock> HttpHelper::s_request_lock(new HttpLock);290 std::shared_ptr<HttpLock> HttpHelper::s_download_lock(new HttpLock);291 CURLSH* HttpHelper::s_share_handle = nullptr;292 293 HttpRequest::HttpRequest()294 : m_request_handle(new HttpRequest::RequestHelper)295 {296 HttpHelper::Instance();297 }298 299 HttpRequest::~HttpRequest()300 {301 }302 303 int HttpRequest::SetRetryTimes(int retry_times)304 {305 if (m_request_handle)306 {307 m_request_handle->SetRetryTimes(retry_times);308 return REQUEST_OK;309 }310 311 return REQUEST_INIT_ERROR;312 }313 314 int HttpRequest::SetRequestId(int id)315 {316 if (m_request_handle)317 {318 m_request_handle->m_id = id;319 return REQUEST_OK;320 }321 322 return REQUEST_INIT_ERROR;323 }324 325 int HttpRequest::SetRequestTimeout(long time_out)326 {327 if (m_request_handle)328 {329 if (m_request_handle->SetRequestTimeout(time_out) == CURLE_OK)330 {331 return REQUEST_OK;332 }333 else334 {335 return REQUEST_INVALID_OPT;336 }337 }338 339 return REQUEST_INIT_ERROR;340 }341 342 int HttpRequest::SetRequestUrl(const std::string& url)343 {344 if (m_request_handle)345 {346 if (m_request_handle->SetRequestUrl(url) == CURLE_OK)347 {348 return REQUEST_OK;349 }350 else351 {352 return REQUEST_INVALID_OPT;353 }354 }355 356 return REQUEST_INIT_ERROR;357 }358 359 int HttpRequest::SetMovedUrl(bool get_moved_url)360 {361 if (m_request_handle)362 {363 if (m_request_handle->SetMovedUrl(get_moved_url) == CURLE_OK)364 {365 return REQUEST_OK;366 }367 else368 {369 return REQUEST_INVALID_OPT;370 }371 }372 373 return REQUEST_INIT_ERROR;374 }375 376 int HttpRequest::SetPostData(const std::string& message)377 {378 return SetPostData(message.c_str(), message.size());379 }380 381 int HttpRequest::SetPostData(const void* data, unsigned int size)382 {383 if (m_request_handle)384 {385 if (m_request_handle->SetPostData(data, size) == CURLE_OK)386 {387 return REQUEST_OK;388 }389 else390 {391 return REQUEST_INVALID_OPT;392 }393 }394 return REQUEST_INIT_ERROR;395 }396 397 int HttpRequest::SetRequestHeader(const std::map<std::string, std::string>& headers)398 {399 if (m_request_handle)400 {401 for (auto it = headers.begin(); it != headers.end(); ++it)402 {403 std::string header = it->first;404 header += ": ";405 header += it->second;406 if (m_request_handle->SetRequestHeader(header) != CURLE_OK)407 {408 return REQUEST_INVALID_OPT;409 }410 }411 return REQUEST_OK;412 }413 414 return REQUEST_INIT_ERROR;415 }416 417 int HttpRequest::SetRequestHeader(const std::string& header)418 {419 if (m_request_handle)420 {421 if (m_request_handle->SetRequestHeader(header) == CURLE_OK)422 {423 return REQUEST_OK;424 }425 else426 {427 return REQUEST_INVALID_OPT;428 }429 }430 return REQUEST_INIT_ERROR;431 }432 433 int HttpRequest::SetRequestProxy(const std::string& proxy, long proxy_port)434 {435 if (m_request_handle)436 {437 if (m_request_handle->SetRequestProxy(proxy, proxy_port) == CURLE_OK)438 {439 return REQUEST_OK;440 }441 else442 {443 return REQUEST_INVALID_OPT;444 }445 }446 447 return REQUEST_INIT_ERROR;448 }449 450 int HttpRequest::SetResultCallback(ResultCallback rc)451 {452 if (m_request_handle)453 {454 m_request_handle->SetResultCallback(rc);455 return REQUEST_OK;456 }457 458 return REQUEST_INIT_ERROR;459 }460 461 void HttpRequest::Close(HANDLE request_handle)462 {463 std::shared_ptr<RequestHelper>* request = (reinterpret_cast<std::shared_ptr<RequestHelper> *>(request_handle));464 if (request == INVALID_HANDLE_VALUE || request == nullptr)465 {466 return;467 }468 469 bool basync = false;470 471 DoHttpLock http_lock(HttpHelper::s_request_lock);472 for (auto it = HttpHelper::s_async_requests.begin(); it != HttpHelper::s_async_requests.end(); ++it)473 {474 if ((*request) == *it)475 {476 #ifdef _WIN32477 if (WaitForSingleObject((*request)->m_perform_thread, 10) == WAIT_OBJECT_0)478 #else479 if(pthread_kill((*request)->m_perform_thread, 0) != 0)480 #endif481 {482 HttpHelper::s_async_requests.remove(*request);483 }484 else485 {486 (*request)->m_close_self = true;487 }488 basync = true;489 break;490 }491 }492 493 if (basync == false)494 {495 //request->reset();496 }497 }498 499 HANDLE HttpRequest::PerformRequest(RequestType request_type)500 {501 if (m_request_handle)502 {503 if (m_request_handle->m_is_running)504 {505 return nullptr;506 }507 508 if (request_type == REQUEST_SYNC)509 {510 m_request_handle->Perform();511 512 return &m_request_handle;513 }514 else if (request_type == REQUEST_ASYNC)515 {516 DoHttpLock http_lock(HttpHelper::s_request_lock);517 518 HttpHelper::s_async_requests.push_back(m_request_handle);519 std::shared_ptr<RequestHelper>& request = HttpHelper::s_async_requests.back();520 521 #ifdef _WIN32522 DWORD thread_id;523 HANDLE async_thread = CreateThread(NULL, 0, HttpHelper::RequestThread, &request, 0, &thread_id);524 request->m_perform_thread = async_thread;525 #else526 pthread_create(&(request->m_perform_thread), NULL, HttpHelper::RequestThread, &request);527 #endif528 529 return &request;530 }531 532 return nullptr;533 }534 535 return nullptr;536 }537 538 bool HttpRequest::GetHttpCode(HANDLE request_handle, long* http_code)539 {540 std::shared_ptr<RequestHelper>* request = reinterpret_cast<std::shared_ptr<RequestHelper>*>(request_handle);541 if (request && http_code)542 {543 *http_code = (*request)->GetHttpCode();544 return true;545 }546 547 return false;548 }549 550 bool HttpRequest::GetReceiveHeader(HANDLE request_handle, std::string* header)551 {552 std::shared_ptr<RequestHelper>* request = reinterpret_cast<std::shared_ptr<RequestHelper>*>(request_handle);553 if (request)554 {555 return (*request)->GetHeader(header);556 }557 558 return false;559 }560 561 bool HttpRequest::GetReceiveContent(HANDLE request_handle, std::string* receive)562 {563 std::shared_ptr<RequestHelper>* request = reinterpret_cast<std::shared_ptr<RequestHelper>*>(request_handle);564 if (request)565 {566 return (*request)->GetContent(receive);567 }568 569 return false;570 }571 572 bool HttpRequest::GetErrorString(HANDLE request_handle, std::string* error_string)573 {574 std::shared_ptr<RequestHelper>* request = reinterpret_cast<std::shared_ptr<RequestHelper>*>(request_handle);575 if (request)576 {577 return (*request)->GetErrorString(error_string);578 }579 580 return false;581 }582 583 HttpRequest::RequestHelper::RequestHelper()584 : m_curl_handle(nullptr)585 #ifdef _WIN32586 , m_perform_thread(nullptr)587 #else588 , m_perform_thread(-1)589 #endif590 , m_http_headers(nullptr)591 , m_close_self(false)592 , m_is_running(false)593 , m_retry_times(HttpRequest::s_kRetryCount)594 , m_http_code(0)595 , m_post_data(nullptr)596 {597 m_result_callback = std::bind(&RequestHelper::ReqeustResultDefault, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);598 m_id = HttpHelper::s_id;599 m_curl_handle = curl_easy_init();600 HttpHelper::set_share_handle(m_curl_handle);601 }602 603 HttpRequest::RequestHelper::~RequestHelper()604 {605 if (m_curl_handle)606 {607 curl_easy_cleanup(m_curl_handle);608 }609 if (m_http_headers)610 {611 curl_slist_free_all(reinterpret_cast<curl_slist*>(m_http_headers));612 }613 if (m_post_data)614 {615 delete m_post_data;616 m_post_data = nullptr;617 }618 #ifdef _WIN32619 if (m_perform_thread)620 {621 CloseHandle(m_perform_thread);622 }623 #endif624 }625 626 int HttpRequest::RequestHelper::SetRequestTimeout(long time_out)627 {628 if (m_curl_handle)629 {630 return curl_easy_setopt(m_curl_handle, CURLOPT_TIMEOUT, 0);631 }632 633 return CURLE_FAILED_INIT;634 }635 636 int HttpRequest::RequestHelper::SetRequestUrl(const std::string& url)637 {638 if (m_curl_handle)639 {640 if (url.substr(0, 5) == "https")641 {642 curl_easy_setopt(m_curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);643 curl_easy_setopt(m_curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);644 }645 646 return curl_easy_setopt(m_curl_handle, CURLOPT_URL, url.c_str());647 }648 649 return CURLE_FAILED_INIT;650 }651 652 int HttpRequest::RequestHelper::SetMovedUrl(bool get_moved_url)653 {654 if (m_curl_handle)655 {656 if (get_moved_url)657 {658 curl_easy_setopt(m_curl_handle, CURLOPT_MAXREDIRS, 5);659 return curl_easy_setopt(m_curl_handle, CURLOPT_FOLLOWLOCATION, 1L);660 }661 else662 {663 return curl_easy_setopt(m_curl_handle, CURLOPT_FOLLOWLOCATION, 0L);664 }665 }666 667 return CURLE_FAILED_INIT;668 }669 670 int HttpRequest::RequestHelper::SetPostData(const void* data, unsigned int size)671 {672 if (m_curl_handle /*&& data && size > 0*/)673 {674 CURLcode curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_POST, 1);675 if (curl_code == CURLE_OK)676 {677 if (m_post_data)678 {679 delete m_post_data;680 m_post_data = nullptr;681 }682 683 if (size == 0)684 {685 curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_POSTFIELDS, "");686 }687 else688 {689 m_post_data = new char[size];690 memcpy(m_post_data, data, size);691 curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_POSTFIELDS, m_post_data);692 }693 }694 695 if (curl_code == CURLE_OK)696 {697 curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_POSTFIELDSIZE, size);698 }699 700 return curl_code;701 }702 703 return CURLE_FAILED_INIT;704 }705 706 int HttpRequest::RequestHelper::SetRequestHeader(const std::string& header)707 {708 if (m_curl_handle && header.empty() == false)709 {710 m_http_headers = curl_slist_append(reinterpret_cast<curl_slist*>(m_http_headers), header.c_str());711 712 return m_http_headers ? CURLE_OK : CURLE_FAILED_INIT;713 }714 715 return CURLE_FAILED_INIT;716 }717 718 int HttpRequest::RequestHelper::SetRequestProxy(const std::string& proxy, long proxy_port)719 {720 //CURLOPT_PROXY721 if (m_curl_handle)722 {723 CURLcode curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_PROXYPORT, proxy_port);724 725 curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_PROXY, proxy.c_str());726 727 return curl_code;728 }729 730 return CURLE_FAILED_INIT;731 }732 733 int HttpRequest::RequestHelper::SetResultCallback(ResultCallback rc)734 {735 m_result_callback = rc;736 737 return CURLE_OK;738 }739 740 void HttpRequest::RequestHelper::ReqeustResultDefault(int id, bool success, const std::string& data)741 {742 //default request callback do nothing743 }744 745 int HttpRequest::RequestHelper::Perform()746 {747 if (m_curl_handle)748 {749 CURLcode curl_code;750 if (m_http_headers)751 {752 curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_HTTPHEADER, reinterpret_cast<curl_slist*>(m_http_headers));753 if (curl_code != CURLE_OK)754 {755 return curl_code;756 }757 }758 759 m_is_running = true;760 m_receive_header.clear();761 m_receive_content.clear();762 763 //set force http redirect764 SetMovedUrl(true);765 766 curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_HEADERFUNCTION, HttpHelper::RetriveHeaderFunction);767 curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_HEADERDATA, &m_receive_header);768 769 curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_WRITEFUNCTION, HttpHelper::RetriveContentFunction);770 curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_WRITEDATA, &m_receive_content);771 772 curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_NOPROGRESS, 1);773 774 curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_NOSIGNAL, 1);775 curl_code = curl_easy_setopt(m_curl_handle, CURLOPT_CONNECTTIMEOUT_MS, 0);776 777 curl_code = curl_easy_perform(m_curl_handle);778 if (curl_code == CURLE_OPERATION_TIMEDOUT)779 {780 int retry_count = m_retry_times;781 while (retry_count > 0)782 {783 curl_code = curl_easy_perform(m_curl_handle);784 if (curl_code != CURLE_OPERATION_TIMEDOUT) break;785 retry_count--;786 }787 }788 789 curl_easy_getinfo(m_curl_handle, CURLINFO_RESPONSE_CODE, &m_http_code);790 if (curl_code == CURLE_OK && m_http_code == 200)791 {792 m_result_callback(m_id, true, m_receive_content);793 }794 else795 {796 const char* err_string = curl_easy_strerror(curl_code);797 m_error_string = err_string;798 curl_code = CURLE_HTTP_POST_ERROR;799 m_result_callback(m_id, false, m_receive_content);800 }801 802 m_is_running = false;803 804 if (m_http_headers)805 {806 curl_slist_free_all(reinterpret_cast<curl_slist*>(m_http_headers));807 m_http_headers = nullptr;808 }809 810 return curl_code;811 }812 813 return CURLE_FAILED_INIT;814 }815 816 bool HttpRequest::RequestHelper::GetHeader(std::string* header)817 {818 if (m_receive_header.empty()) return false;819 else if (header) *header = m_receive_header;820 821 return true;822 }823 824 bool HttpRequest::RequestHelper::GetContent(std::string* receive)825 {826 if (m_receive_content.empty()) return false;827 else if (receive) *receive = m_receive_content;828 829 return true;830 }831 832 bool HttpRequest::RequestHelper::GetErrorString(std::string* error_string)833 {834 if (m_error_string.empty()) return false;835 else if (error_string) *error_string = m_error_string;836 837 return true;838 }839 840 HttpDownloader::HttpDownloader()841 :m_request_handle(new HttpDownloader::DownloadHelper)842 {843 HttpHelper::Instance();844 }845 846 HttpDownloader::~HttpDownloader()847 {848 849 }850 851 int HttpDownloader::SetRequestProxy(const std::string& proxy, long proxy_port)852 {853 if (m_request_handle)854 {855 if (m_request_handle->SetRequestProxy(proxy, proxy_port) == CURLE_OK)856 {857 return 0;858 }859 else860 {861 return HttpRequest::REQUEST_INVALID_OPT;862 }863 }864 865 return HttpRequest::REQUEST_INIT_ERROR;866 }867 868 int HttpDownloader::SetRetryTimes(int retry_times /* = s_kRetryCount */)869 {870 if (m_request_handle)871 {872 m_request_handle->SetRetryTimes(retry_times);873 return HttpRequest::REQUEST_OK;874 }875 876 return HttpRequest::REQUEST_INIT_ERROR;877 }878 879 int HttpDownloader::SetTimeout(long time_out /* = 0 */)880 {881 if (m_request_handle)882 {883 if (m_request_handle->SetTimeout(time_out) == CURLE_OK)884 {885 return HttpRequest::REQUEST_OK;886 }887 else888 {889 return HttpRequest::REQUEST_INVALID_OPT;890 }891 }892 893 return HttpRequest::REQUEST_INIT_ERROR;894 }895 896 int HttpDownloader::SetDownloadUrl(const std::string& url)897 {898 if (m_request_handle)899 {900 if (m_request_handle->SetRequestUrl(url) == CURLE_OK)901 {902 return HttpRequest::REQUEST_OK;903 }904 else905 {906 return HttpRequest::REQUEST_INVALID_OPT;907 }908 }909 910 return HttpRequest::REQUEST_INIT_ERROR;911 }912 913 int HttpDownloader::SetUserData(void* userdata)914 {915 if (m_request_handle)916 {917 m_request_handle->SetUserData(userdata);918 919 return HttpRequest::REQUEST_OK;920 }921 return HttpRequest::REQUEST_INIT_ERROR;922 }923 924 int HttpDownloader::SetRequestId(int id)925 {926 if (m_request_handle)927 {928 m_request_handle->SetRequestId(id);929 return HttpRequest::REQUEST_OK;930 }931 932 return HttpRequest::REQUEST_INIT_ERROR;933 }934 935 int HttpDownloader::SetProgressCallback(ProgressCallback pc)936 {937 if (m_request_handle)938 {939 m_request_handle->SetProgressCallback(pc);940 941 return HttpRequest::REQUEST_OK;942 }943 944 return HttpRequest::REQUEST_INIT_ERROR;945 }946 947 int HttpDownloader::SetResultCallback(ResultCallback rc)948 {949 if (m_request_handle)950 {951 m_request_handle->SetResultCallback(rc);952 953 return HttpRequest::REQUEST_OK;954 }955 956 return HttpRequest::REQUEST_INIT_ERROR;957 }958 959 int HttpDownloader::DownloadFile(const std::string& file_name, int thread_count /* = 5 */)960 {961 if (m_request_handle)962 {963 m_request_handle->SetDownloadFile(file_name);964 m_request_handle->SetDownloadThreadCount(thread_count);965 }966 967 return HttpRequest::REQUEST_INIT_ERROR;968 }969 970 HANDLE HttpDownloader::StartDownload(DownType down_type)971 {972 if (m_request_handle)973 {974 if (m_request_handle->m_is_running)975 {976 return nullptr;977 }978 979 m_request_handle->Reset();980 981 if (down_type == DOWN_SYNC)982 {983 m_request_handle->Perform();984 985 return &m_request_handle;986 }987 else if (down_type == DOWN_ASYNC)988 {989 DoHttpLock http_lock(HttpHelper::s_download_lock);990 HttpHelper::s_async_downloads.push_back(m_request_handle);991 std::shared_ptr<DownloadHelper>& request = HttpHelper::s_async_downloads.back();992 993 #ifdef _WIN32994 DWORD thread_id;995 HANDLE async_thread = CreateThread(NULL, 0, HttpHelper::DownloadThread, &request, 0, &thread_id);996 request->m_perform_thread = async_thread;997 #else998 pthread_create(&(request->m_perform_thread), NULL, HttpHelper::DownloadThread, &request);999 #endif 1000 1001 return &request; 1002 } 1003 1004 return nullptr; 1005 } 1006 1007 return nullptr; 1008 } 1009 1010 void HttpDownloader::Close(HANDLE handle) 1011 { 1012 std::shared_ptr<DownloadHelper>* request = (reinterpret_cast<std::shared_ptr<DownloadHelper> *>(handle)); 1013 if (request == INVALID_HANDLE_VALUE || request == nullptr) 1014 { 1015 return; 1016 } 1017 1018 bool basync = false; 1019 1020 DoHttpLock http_lock(HttpHelper::s_download_lock); 1021 for (auto it = HttpHelper::s_async_downloads.begin(); it != HttpHelper::s_async_downloads.end(); ++it) 1022 { 1023 if ((*request) == *it) 1024 { 1025 #ifdef _WIN32 1026 if (WaitForSingleObject((*request)->m_perform_thread, 10) == WAIT_OBJECT_0) 1027 #else 1028 if(pthread_kill((*request)->m_perform_thread, 0) != 0) 1029 #endif 1030 { 1031 HttpHelper::s_async_downloads.remove(*request); 1032 } 1033 else 1034 { 1035 (*request)->m_close_self = true; 1036 } 1037 basync = true; 1038 break; 1039 } 1040 } 1041 1042 if (basync == false) 1043 { 1044 (*request)->m_is_cancel = true; 1045 //request->reset(); 1046 } 1047 } 1048 1049 bool HttpDownloader::CancelDownload(HANDLE handle) 1050 { 1051 std::shared_ptr<DownloadHelper>* request = (reinterpret_cast<std::shared_ptr<DownloadHelper> *>(handle)); 1052 if (request == INVALID_HANDLE_VALUE || request == nullptr) 1053 { 1054 return false; 1055 } 1056 1057 (*request)->m_is_cancel = true; 1058 1059 return true; 1060 } 1061 1062 bool HttpDownloader::GetHttpCode(HANDLE handle, long* http_code) 1063 { 1064 std::shared_ptr<DownloadHelper>* request = reinterpret_cast<std::shared_ptr<DownloadHelper>*>(handle); 1065 if (request && http_code) 1066 { 1067 *http_code = (*request)->GetHttpCode(); 1068 return true; 1069 } 1070 1071 return false; 1072 } 1073 1074 bool HttpDownloader::GetErrorString(HANDLE handle, std::string* error_string) 1075 { 1076 std::shared_ptr<DownloadHelper>* request = reinterpret_cast<std::shared_ptr<DownloadHelper>*>(handle); 1077 if (request) 1078 { 1079 return (*request)->GetErrorString(error_string); 1080 } 1081 1082 return false; 1083 } 1084 1085 bool HttpDownloader::GetReceiveHeader(HANDLE handle, std::string* header) 1086 { 1087 std::shared_ptr<DownloadHelper>* request = reinterpret_cast<std::shared_ptr<DownloadHelper>*>(handle); 1088 if (request) 1089 { 1090 return (*request)->GetHeader(header); 1091 } 1092 1093 return false; 1094 } 1095 1096 void* HttpDownloader::GetUserData(HANDLE handle) 1097 { 1098 1099 std::shared_ptr<DownloadHelper>* request = reinterpret_cast<std::shared_ptr<DownloadHelper>*>(handle); 1100 if (request) 1101 { 1102 return (*request)->GetUserData(); 1103 } 1104 1105 return nullptr; 1106 } 1107 1108 HttpDownloader::DownloadHelper::DownloadHelper() 1109 #ifdef _WIN32 1110 : m_perform_thread(nullptr) 1111 #else 1112 : m_perform_thread(-1) 1113 #endif 1114 , m_close_self(false) 1115 , m_retry_times(HttpDownloader::s_kRetryCount) 1116 , m_thread_count(HttpDownloader::s_kThreadCount) 1117 , m_http_code(0) 1118 , m_time_out(0) 1119 , m_proxy_port(0) 1120 , m_total_size(0.0) 1121 , m_downloaded_size(0.0) 1122 , m_multi_download(false) 1123 , m_download_fail(true) 1124 , m_is_running(false) 1125 , m_httplock(new HttpLock) 1126 , m_userdata(NULL) 1127 { 1128 m_download_callback = std::bind(&DownloadHelper::DownloadDefaultCallback, this, 1129 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); 1130 m_result_callback = std::bind(&DownloadHelper::ResultDefaultCallback, this, 1131 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); 1132 m_id = HttpHelper::s_id; 1133 } 1134 1135 HttpDownloader::DownloadHelper::~DownloadHelper() 1136 { 1137 if (m_perform_thread) 1138 { 1139 #ifdef _WIN32 1140 CloseHandle(m_perform_thread); 1141 m_perform_thread = nullptr; 1142 #endif 1143 } 1144 } 1145 1146 int HttpDownloader::DownloadHelper::SetTimeout(long time_out /* = 0 */) 1147 { 1148 m_time_out = time_out; 1149 1150 return CURLE_OK; 1151 } 1152 1153 int HttpDownloader::DownloadHelper::SetRequestUrl(const std::string& url) 1154 { 1155 m_url = url; 1156 1157 return CURLE_OK; 1158 } 1159 1160 int HttpDownloader::DownloadHelper::SetRequestProxy(const std::string& proxy, long proxy_port) 1161 { 1162 m_http_proxy = proxy; 1163 m_proxy_port = proxy_port; 1164 1165 return CURLE_OK; 1166 } 1167 1168 int HttpDownloader::DownloadHelper::SetProgressCallback(ProgressCallback pc) 1169 { 1170 m_download_callback = pc; 1171 1172 return CURLE_OK; 1173 } 1174 1175 int HttpDownloader::DownloadHelper::SetResultCallback(ResultCallback rc) 1176 { 1177 m_result_callback = rc; 1178 1179 return CURLE_OK; 1180 } 1181 1182 int HttpDownloader::DownloadHelper::SetDownloadFile(const std::string& file_name) 1183 { 1184 m_file_path = file_name; 1185 1186 return CURLE_OK; 1187 } 1188 1189 int HttpDownloader::DownloadHelper::SetDownloadThreadCount(int thread_count) 1190 { 1191 m_thread_count = thread_count; 1192 1193 return CURLE_OK; 1194 } 1195 1196 int HttpDownloader::DownloadHelper::Perform() 1197 { 1198 m_total_size = GetDownloadFileSize(); 1199 if (m_total_size < 0) 1200 { 1201 return HttpRequest::REQUEST_PERFORM_ERROR; 1202 } 1203 1204 std::string out_file_name = m_file_path; 1205 std::string src_file_name = out_file_name; 1206 out_file_name += ".dl"; 1207 1208 FILE *fp = nullptr; 1209 #ifdef _WIN32 1210 DeleteFileA(out_file_name.c_str()); 1211 fopen_s(&fp, out_file_name.c_str(), "wb"); 1212 #else 1213 unlink(out_file_name.c_str()); 1214 fp = fopen(out_file_name.c_str(), "wb"); 1215 #endif 1216 if (!fp) 1217 { 1218 return HttpRequest::REQUEST_OPENFILE_ERROR; 1219 } 1220 1221 int down_code = HttpRequest::REQUEST_PERFORM_ERROR; 1222 int thread_count = SplitDownloadCount(m_total_size); 1223 1224 m_thread_count = thread_count > m_thread_count ? m_thread_count : thread_count; 1225 //文件大小有分開下載的必要并且服務(wù)器支持多線程下載時,啟用多線程下載 1226 if (m_multi_download && m_thread_count > 1) 1227 { 1228 long gap = static_cast<long>(m_total_size) / m_thread_count; 1229 #ifdef _WIN32 1230 std::vector<HANDLE> threads; 1231 #else 1232 std::vector<pthread_t> threads; 1233 #endif 1234 1235 for (int i = 0; i < m_thread_count; i++) 1236 { 1237 ThreadChunk* thread_chunk = new ThreadChunk; 1238 thread_chunk->_fp = fp; 1239 thread_chunk->_download = this; 1240 1241 if (i < m_thread_count - 1) 1242 { 1243 thread_chunk->_startidx = i * gap; 1244 thread_chunk->_endidx = thread_chunk->_startidx + gap - 1; 1245 } 1246 else 1247 { 1248 thread_chunk->_startidx = i * gap; 1249 thread_chunk->_endidx = -1; 1250 } 1251 1252 #ifdef _WIN32 1253 DWORD thread_id; 1254 HANDLE hThread = CreateThread(NULL, 0, HttpHelper::DownloadWork, thread_chunk, 0, &(thread_id)); 1255 #else 1256 pthread_t hThread; 1257 pthread_create(&hThread, NULL, HttpHelper::DownloadWork, thread_chunk); 1258 #endif 1259 threads.push_back(hThread); 1260 } 1261 1262 #ifdef _WIN32 1263 WaitForMultipleObjects(threads.size(), &threads[0], TRUE, INFINITE); 1264 for (HANDLE handle : threads) 1265 { 1266 CloseHandle(handle); 1267 } 1268 #else 1269 for(pthread_t thread : threads) 1270 { 1271 pthread_join(thread, NULL); 1272 } 1273 #endif 1274 } 1275 else 1276 { 1277 ThreadChunk* thread_chunk = new ThreadChunk; 1278 thread_chunk->_fp = fp; 1279 thread_chunk->_download = this; 1280 thread_chunk->_startidx = 0; 1281 thread_chunk->_endidx = 0; 1282 down_code = DoDownload(thread_chunk); 1283 } 1284 1285 fclose(fp); 1286 1287 if (m_download_fail == false) 1288 { 1289 #ifdef _WIN32 1290 MoveFileExA(out_file_name.c_str(), src_file_name.c_str(), MOVEFILE_REPLACE_EXISTING); 1291 #else 1292 unlink(src_file_name.c_str()); 1293 rename(out_file_name.c_str(), src_file_name.c_str()); 1294 #endif 1295 } 1296 else 1297 { 1298 #ifdef _WIN32 1299 DeleteFileA(out_file_name.c_str()); 1300 #else 1301 unlink(out_file_name.c_str()); 1302 #endif 1303 } 1304 1305 m_result_callback(m_id, m_download_fail ? false : true, m_error_string); 1306 1307 m_is_running = false; 1308 1309 return down_code; 1310 } 1311 1312 bool HttpDownloader::DownloadHelper::GetHeader(std::string* header) 1313 { 1314 if (m_receive_header.empty()) return false; 1315 else if (header) *header = m_receive_header; 1316 1317 return true; 1318 } 1319 1320 bool HttpDownloader::DownloadHelper::GetErrorString(std::string* error_string) 1321 { 1322 if (m_error_string.empty()) return false; 1323 else if (error_string) *error_string = m_error_string; 1324 1325 return true; 1326 } 1327 1328 int HttpDownloader::DownloadHelper::DownloadDefaultCallback(double total_size, double downloaded_size, void* userdata) 1329 { 1330 return 0; 1331 } 1332 1333 void HttpDownloader::DownloadHelper::ResultDefaultCallback(int id, bool success, const std::string& data) 1334 { 1335 } 1336 1337 double HttpDownloader::DownloadHelper::GetDownloadFileSize() 1338 { 1339 if (m_url.empty()) 1340 { 1341 return -1.0; 1342 } 1343 else 1344 { 1345 double down_file_length = -1.0; 1346 CURL *handle = curl_easy_init(); 1347 HttpHelper::set_share_handle(handle); 1348 1349 if (handle) 1350 { 1351 curl_easy_setopt(handle, CURLOPT_URL, m_url.c_str()); 1352 curl_easy_setopt(handle, CURLOPT_HEADER, 1); 1353 curl_easy_setopt(handle, CURLOPT_NOBODY, 1); 1354 curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1); 1355 curl_easy_setopt(handle, CURLOPT_MAXREDIRS, 5); 1356 curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, HttpHelper::RetriveHeaderFunction); 1357 curl_easy_setopt(handle, CURLOPT_HEADERDATA, &m_receive_header); 1358 curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, HttpHelper::RetriveContentFunction); 1359 curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL); 1360 curl_easy_setopt(handle, CURLOPT_RANGE, "2-"); 1361 1362 CURLcode curl_code = curl_easy_perform(handle); 1363 1364 if (curl_code == CURLE_OPERATION_TIMEDOUT) 1365 { 1366 int retry_count = m_retry_times; 1367 while (retry_count > 0) 1368 { 1369 curl_code = curl_easy_perform(handle); 1370 if (curl_code != CURLE_OPERATION_TIMEDOUT) break; 1371 retry_count--; 1372 } 1373 } 1374 1375 curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &m_http_code); 1376 1377 if (curl_code == CURLE_OK) 1378 { 1379 curl_easy_getinfo(handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &down_file_length); 1380 1381 //匹配"Content-Range: bytes 2-1449/26620" 則證明支持多線程下載 1382 std::regex pattern("CONTENT-RANGE\\s*:\\s*\\w+\\s*(\\d+)-(\\d*)/(\\d+)", std::regex::icase); 1383 m_multi_download = std::regex_search(m_receive_header, pattern); 1384 } 1385 else 1386 { 1387 const char* err_string = curl_easy_strerror(curl_code); 1388 m_error_string = err_string; 1389 } 1390 1391 curl_easy_cleanup(handle); 1392 } 1393 1394 return down_file_length; 1395 } 1396 } 1397 1398 int HttpDownloader::DownloadHelper::DoDownload(ThreadChunk* thread_chunk) 1399 { 1400 CURL* curl_handle = curl_easy_init(); 1401 HttpHelper::set_share_handle(curl_handle); 1402 1403 if (thread_chunk->_download->m_url.substr(0, 5) == "https") 1404 { 1405 curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); 1406 curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); 1407 } 1408 1409 curl_easy_setopt(curl_handle, CURLOPT_URL, thread_chunk->_download->m_url.c_str()); 1410 1411 const char* user_agent = ("Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0"); 1412 curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, user_agent); 1413 1414 curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 5L); 1415 curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L); 1416 1417 curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1L); 1418 curl_easy_setopt(curl_handle, CURLOPT_POST, 0L); 1419 1420 curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT_MS, 0L); 1421 curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, thread_chunk->_download->m_time_out); //0 means block always 1422 1423 curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, HttpHelper::write_callback); 1424 curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, thread_chunk); 1425 curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, HttpHelper::RetriveHeaderFunction); 1426 curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, NULL); 1427 1428 curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 0L); 1429 curl_easy_setopt(curl_handle, CURLOPT_XFERINFOFUNCTION, HttpHelper::progress_callback); 1430 curl_easy_setopt(curl_handle, CURLOPT_XFERINFODATA, thread_chunk); 1431 1432 curl_easy_setopt(curl_handle, CURLOPT_LOW_SPEED_LIMIT, 1L); 1433 curl_easy_setopt(curl_handle, CURLOPT_LOW_SPEED_TIME, 5L); 1434 1435 if (thread_chunk->_endidx != 0) 1436 { 1437 std::string down_range; 1438 std::ostringstream ostr; 1439 if (thread_chunk->_endidx > 0) 1440 { 1441 ostr << thread_chunk->_startidx << "-" << thread_chunk->_endidx; 1442 } 1443 else 1444 { 1445 ostr << thread_chunk->_startidx << "-"; 1446 } 1447 1448 down_range = ostr.str(); 1449 curl_easy_setopt(curl_handle, CURLOPT_RANGE, down_range.c_str()); 1450 } 1451 1452 CURLcode curl_code = curl_easy_perform(curl_handle); 1453 if (curl_code == CURLE_OPERATION_TIMEDOUT) 1454 { 1455 int retry_count = m_retry_times; 1456 while (retry_count > 0) 1457 { 1458 curl_code = curl_easy_perform(curl_handle); 1459 if (curl_code != CURLE_OPERATION_TIMEDOUT) break; 1460 retry_count--; 1461 } 1462 } 1463 1464 long http_code; 1465 curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &http_code); 1466 if (curl_code == CURLE_OK && (http_code >= 200 && http_code <= 300)) 1467 { 1468 m_http_code = http_code; 1469 thread_chunk->_download->m_download_fail = false; 1470 } 1471 else 1472 { 1473 const char* err_string = curl_easy_strerror(curl_code); 1474 m_error_string = err_string; 1475 thread_chunk->_download->m_download_fail = true; 1476 m_http_code = http_code; 1477 } 1478 1479 curl_easy_cleanup(curl_handle); 1480 1481 delete thread_chunk; 1482 1483 return curl_code; 1484 } 1485 1486 int HttpDownloader::DownloadHelper::SplitDownloadCount(double down_size) 1487 { 1488 const double size_2mb = 2.0 * 1024 * 1024; 1489 const double size_10mb = 10.0 * 1024 * 1024; 1490 const double size_50mb = 50.0 * 1024 * 1024; 1491 1492 if (down_size <= size_2mb) 1493 { 1494 return 1; 1495 } 1496 else if (down_size > size_2mb && down_size <= size_10mb) 1497 { 1498 return static_cast<int>(down_size / (size_2mb)); 1499 } 1500 else if (down_size > size_10mb && down_size <= size_50mb) 1501 { 1502 return HttpDownloader::s_kThreadCount + 1; 1503 } 1504 else 1505 { 1506 int down_count = static_cast<int>(down_size / size_10mb); 1507 return down_count > 10 ? 10 : down_count; 1508 } 1509 1510 return 1; 1511 } 1512 1513 void HttpDownloader::DownloadHelper::Reset() 1514 { 1515 if (m_is_running) 1516 { 1517 return; 1518 } 1519 1520 if (m_perform_thread) //thread run over because if m_is_running set true, Reset wont be invoke 1521 { 1522 #ifdef _WIN32 1523 CloseHandle(m_perform_thread); 1524 m_perform_thread = nullptr; 1525 #endif 1526 } 1527 1528 m_close_self = false; 1529 m_multi_download = false; 1530 m_download_fail = true; 1531 m_is_running = false; 1532 m_is_cancel = false; 1533 m_http_code = 0; 1534 m_total_size = 0.0; 1535 m_downloaded_size = 0.0; 1536 1537 m_receive_header = ""; 1538 m_error_string = ""; 1539 }

    libcurl的http請求默認(rèn)是Get。如果指定了Post數(shù)據(jù),則是Post請求。

    ?

  • 使用libcurl庫
    demo使用封裝的庫來模擬請求數(shù)據(jù)和下載文件。
    例子很簡單,直接看代碼:
    1 // http_request.cpp : 定義控制臺應(yīng)用程序的入口點。2 //3 4 #include "HttpRequest.h"5 6 #include <iostream>7 #include <string>8 #include <fstream>9 #include <functional>10 11 class DownCallbackClass12 {13 public:14 DownCallbackClass() :m_down_finished(false) {}15 ~DownCallbackClass() {}16 public:17 void DownResultCallback(int id, bool success, const std::string& data)18 {19 m_down_finished = true;20 }21 int down_callback(double total_size, double downloaded_size, void* userdata)22 {23 long tmp = static_cast<long>(downloaded_size / total_size * 100);24 printf("\r下載進(jìn)度%d", tmp);25 return 0;26 }27 bool IsDownFinished(void) { return m_down_finished; }28 private:29 bool m_down_finished;30 };31 32 class MyResultClass33 {34 public:35 MyResultClass() : m_request_finished(false) { }36 ~MyResultClass() { }37 38 public:39 void MyRequestResultCallback(int id, bool success, const std::string& data)40 {41 if (success)42 {43 std::ofstream outfile;44 outfile.open("baidu.html", std::ios_base::binary | std::ios_base::trunc);45 if (outfile.good()) outfile.write(data.c_str(), data.size());46 }47 m_request_finished = true;48 }49 bool IsRequestFinish(void) { return m_request_finished; }50 private:51 bool m_request_finished;52 };53 54 int _tmain(int argc, _TCHAR* argv[])55 {56 MyResultClass mc;57 58 HttpRequest request;59 request.SetRequestUrl("http://www.baidu.com");60 request.SetResultCallback(std::bind(&MyResultClass::MyRequestResultCallback, &mc, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));61 request.SetRequestHeader("User-Agent:Mozilla/4.04[en](Win95;I;Nav)");62 63 HANDLE hRequest = request.PerformRequest(HttpRequest::REQUEST_ASYNC);64 if (hRequest)65 {66 while (mc.IsRequestFinish() == false) Sleep(300);67 long http_code;68 if (request.GetHttpCode(hRequest, &http_code))69 std::cout << "http code: " << http_code << std::endl;70 71 std::string header;72 if (request.GetReceiveHeader(hRequest, &header))73 {74 std::cout << header << std::endl;75 }76 77 HttpRequest::Close(hRequest);78 }79 80 HttpDownloader download;81 DownCallbackClass dc;82 const char* down_url = "http://dlsw.baidu.com/sw-search-sp/soft/71/10998/OfflineBaiduPlayer_151_V4.1.2.263.1432003947.exe";83 const char* down_file = "BaiduPlayer.exe";84 85 download.SetDownloadUrl(down_url);86 download.SetProgressCallback(std::bind(&DownCallbackClass::down_callback, &dc, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));87 download.SetResultCallback(std::bind(&DownCallbackClass::DownResultCallback, &dc, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));88 download.DownloadFile(down_file);89 HANDLE hDownload = download.StartDownload(HttpDownloader::DOWN_ASYNC);90 if (hDownload)91 {92 while (dc.IsDownFinished() == false)93 {94 Sleep(300);95 }96 //to do download finish clean up97 HttpDownloader::Close(hDownload);98 }99 100 return 0; 101 }

    ?

  • 轉(zhuǎn)載于:https://www.cnblogs.com/lehoho/p/9367287.html

    總結(jié)

    以上是生活随笔為你收集整理的libcurl的封装,支持同步异步请求,支持多线程下载,支持https(z)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

    天堂亚洲免费视频 | 无码吃奶揉捏奶头高潮视频 | 精品久久久无码人妻字幂 | 嫩b人妻精品一区二区三区 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 无码帝国www无码专区色综合 | 欧美 亚洲 国产 另类 | 一二三四在线观看免费视频 | 呦交小u女精品视频 | 未满小14洗澡无码视频网站 | 色综合视频一区二区三区 | 精品一区二区三区波多野结衣 | 麻豆蜜桃av蜜臀av色欲av | 成在人线av无码免费 | 爽爽影院免费观看 | 国产深夜福利视频在线 | 日本乱偷人妻中文字幕 | 国产综合在线观看 | аⅴ资源天堂资源库在线 | 丰满少妇女裸体bbw | 东京热一精品无码av | 国产精品久久久久7777 | 又大又紧又粉嫩18p少妇 | 丰满人妻翻云覆雨呻吟视频 | 无码纯肉视频在线观看 | 成人精品天堂一区二区三区 | 国内精品久久毛片一区二区 | 理论片87福利理论电影 | 国产精品国产三级国产专播 | 老头边吃奶边弄进去呻吟 | 波多野结衣av在线观看 | 亚洲日本在线电影 | 在线观看国产一区二区三区 | 久久久久av无码免费网 | 欧美性生交xxxxx久久久 | 在线 国产 欧美 亚洲 天堂 | 久久综合网欧美色妞网 | 国产精品无码mv在线观看 | 国产av无码专区亚洲awww | 亚洲色在线无码国产精品不卡 | 麻豆md0077饥渴少妇 | 亚洲精品国偷拍自产在线观看蜜桃 | 天堂а√在线中文在线 | 又色又爽又黄的美女裸体网站 | 男人的天堂2018无码 | 蜜桃视频插满18在线观看 | 精品一区二区三区波多野结衣 | 欧美xxxx黑人又粗又长 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 国内精品一区二区三区不卡 | 中文无码成人免费视频在线观看 | 午夜精品久久久久久久久 | 男女性色大片免费网站 | 欧美丰满熟妇xxxx性ppx人交 | 人妻天天爽夜夜爽一区二区 | 国产免费无码一区二区视频 | 国产三级精品三级男人的天堂 | 国产精品免费大片 | 午夜精品一区二区三区在线观看 | 精品国产av色一区二区深夜久久 | 亚洲精品成a人在线观看 | 76少妇精品导航 | 免费观看激色视频网站 | 国产疯狂伦交大片 | 国产精品无码一区二区桃花视频 | 免费中文字幕日韩欧美 | 性做久久久久久久久 | 亚洲国产午夜精品理论片 | 亚洲 a v无 码免 费 成 人 a v | 国产肉丝袜在线观看 | 国产亚洲精品久久久久久久 | 伊人久久大香线焦av综合影院 | av人摸人人人澡人人超碰下载 | 欧美性猛交内射兽交老熟妇 | 九月婷婷人人澡人人添人人爽 | 97久久超碰中文字幕 | 亚洲欧洲日本综合aⅴ在线 | 99久久亚洲精品无码毛片 | 少妇的肉体aa片免费 | 国产精品视频免费播放 | 午夜精品久久久久久久 | 国产亚洲欧美日韩亚洲中文色 | 丰满肥臀大屁股熟妇激情视频 | 人人澡人摸人人添 | 桃花色综合影院 | 欧美午夜特黄aaaaaa片 | 久久久精品456亚洲影院 | 一本久久伊人热热精品中文字幕 | 色噜噜亚洲男人的天堂 | 九九久久精品国产免费看小说 | 精品一区二区三区无码免费视频 | 久久久久久久人妻无码中文字幕爆 | 精品熟女少妇av免费观看 | 欧美丰满少妇xxxx性 | 亚洲中文字幕成人无码 | 美女黄网站人色视频免费国产 | 少妇无码av无码专区在线观看 | 亚洲 a v无 码免 费 成 人 a v | 欧美 日韩 亚洲 在线 | 亚洲成av人影院在线观看 | 最近的中文字幕在线看视频 | 少妇人妻大乳在线视频 | 久久人妻内射无码一区三区 | 久久精品一区二区三区四区 | av无码不卡在线观看免费 | 又紧又大又爽精品一区二区 | 午夜无码人妻av大片色欲 | 欧美老人巨大xxxx做受 | 亚洲精品一区二区三区婷婷月 | 东京热无码av男人的天堂 | 国产麻豆精品一区二区三区v视界 | 亲嘴扒胸摸屁股激烈网站 | 国产乱人伦av在线无码 | 午夜性刺激在线视频免费 | 国产成人久久精品流白浆 | 高潮喷水的毛片 | 性生交大片免费看女人按摩摩 | 国产亚洲精品精品国产亚洲综合 | 丰满少妇熟乱xxxxx视频 | 中文字幕乱码人妻无码久久 | 麻豆成人精品国产免费 | 亚洲国产日韩a在线播放 | 亚洲第一网站男人都懂 | 亚洲爆乳精品无码一区二区三区 | 精品人妻中文字幕有码在线 | 午夜性刺激在线视频免费 | 99久久久无码国产aaa精品 | 丰满少妇熟乱xxxxx视频 | 免费无码一区二区三区蜜桃大 | 欧美性生交活xxxxxdddd | 国産精品久久久久久久 | 波多野结衣 黑人 | 亚洲国产午夜精品理论片 | 四虎4hu永久免费 | 久久亚洲中文字幕无码 | 精品一二三区久久aaa片 | 国产口爆吞精在线视频 | 色婷婷欧美在线播放内射 | 亚洲 激情 小说 另类 欧美 | 牲欲强的熟妇农村老妇女视频 | 日本精品高清一区二区 | 国产精品va在线播放 | 97精品人妻一区二区三区香蕉 | 在线播放无码字幕亚洲 | 欧美肥老太牲交大战 | 麻豆蜜桃av蜜臀av色欲av | 国产尤物精品视频 | 亚洲成av人综合在线观看 | 国产超级va在线观看视频 | 亚洲国产精品一区二区美利坚 | 国产精品高潮呻吟av久久4虎 | 无码国内精品人妻少妇 | 久久久中文字幕日本无吗 | 国产成人无码一二三区视频 | 激情五月综合色婷婷一区二区 | 大肉大捧一进一出好爽视频 | 人妻熟女一区 | www国产精品内射老师 | 精品久久8x国产免费观看 | 天堂久久天堂av色综合 | 精品无人国产偷自产在线 | 国产精品久久久av久久久 | 无码人妻少妇伦在线电影 | 国产情侣作爱视频免费观看 | 成人动漫在线观看 | 久久久久久久久蜜桃 | 天堂亚洲2017在线观看 | 中文精品无码中文字幕无码专区 | 国产精品亚洲а∨无码播放麻豆 | 欧美日韩一区二区综合 | 色噜噜亚洲男人的天堂 | 伦伦影院午夜理论片 | 亚洲无人区一区二区三区 | 少女韩国电视剧在线观看完整 | 色妞www精品免费视频 | 国产精品国产三级国产专播 | 国产艳妇av在线观看果冻传媒 | 中文字幕av无码一区二区三区电影 | 最新国产乱人伦偷精品免费网站 | 日韩 欧美 动漫 国产 制服 | 美女张开腿让人桶 | 无码人妻丰满熟妇区毛片18 | 精品国产aⅴ无码一区二区 | 性欧美熟妇videofreesex | 精品欧洲av无码一区二区三区 | 中文字幕人成乱码熟女app | 无码人妻丰满熟妇区五十路百度 | 亚洲小说春色综合另类 | 亚洲va中文字幕无码久久不卡 | 人妻插b视频一区二区三区 | 高清无码午夜福利视频 | 久久国产精品偷任你爽任你 | 成人综合网亚洲伊人 | 国产午夜福利亚洲第一 | 久久精品视频在线看15 | 国产亚洲精品久久久久久国模美 | 久久人人爽人人爽人人片ⅴ | 高潮毛片无遮挡高清免费视频 | 日韩亚洲欧美精品综合 | 日本熟妇大屁股人妻 | 97精品国产97久久久久久免费 | 欧美freesex黑人又粗又大 | 日韩人妻少妇一区二区三区 | 一本色道久久综合狠狠躁 | 亚洲人成网站色7799 | 亚洲欧洲日本无在线码 | 香港三级日本三级妇三级 | 欧美日韩一区二区免费视频 | 国产亚洲欧美在线专区 | 玩弄中年熟妇正在播放 | 国产精品久久久久久无码 | 日韩av无码一区二区三区 | 午夜福利一区二区三区在线观看 | 久久视频在线观看精品 | 露脸叫床粗话东北少妇 | 国产精品人人爽人人做我的可爱 | 丰满岳乱妇在线观看中字无码 | 亚洲成a人片在线观看无码3d | 国产成人精品一区二区在线小狼 | 亚洲成av人片在线观看无码不卡 | 少妇性l交大片欧洲热妇乱xxx | 黑人巨大精品欧美黑寡妇 | 熟女俱乐部五十路六十路av | 无码午夜成人1000部免费视频 | 久久久中文久久久无码 | 黑人大群体交免费视频 | 国产香蕉尹人视频在线 | 日韩精品无码免费一区二区三区 | 国产美女精品一区二区三区 | 久久久久久九九精品久 | 亚洲娇小与黑人巨大交 | 青草视频在线播放 | 在线观看欧美一区二区三区 | 国产网红无码精品视频 | 色偷偷人人澡人人爽人人模 | 日日橹狠狠爱欧美视频 | 精品偷拍一区二区三区在线看 | 无码纯肉视频在线观看 | 自拍偷自拍亚洲精品10p | 色综合久久中文娱乐网 | 无码人妻出轨黑人中文字幕 | 日韩在线不卡免费视频一区 | www成人国产高清内射 | 成人精品天堂一区二区三区 | 国产精品亚洲五月天高清 | 免费中文字幕日韩欧美 | 一本大道伊人av久久综合 | 国产av人人夜夜澡人人爽麻豆 | 国产精品怡红院永久免费 | 国产熟妇高潮叫床视频播放 | 老子影院午夜伦不卡 | 性欧美熟妇videofreesex | 色婷婷av一区二区三区之红樱桃 | 亚洲s色大片在线观看 | 日本一区二区三区免费播放 | 亚洲欧美色中文字幕在线 | 成人免费视频一区二区 | 牲欲强的熟妇农村老妇女 | 欧美三级不卡在线观看 | 国产亚洲精品久久久久久 | а天堂中文在线官网 | 亚洲日韩av一区二区三区四区 | 性欧美牲交在线视频 | 东京热男人av天堂 | 国产办公室秘书无码精品99 | 国产 浪潮av性色四虎 | 亚洲精品久久久久中文第一幕 | 国产精品igao视频网 | 学生妹亚洲一区二区 | 强奷人妻日本中文字幕 | 久久综合久久自在自线精品自 | 国产97在线 | 亚洲 | 日韩av无码中文无码电影 | 亚洲国产精品一区二区美利坚 | 日日摸夜夜摸狠狠摸婷婷 | 东京热无码av男人的天堂 | 无遮挡啪啪摇乳动态图 | 国产福利视频一区二区 | 国产两女互慰高潮视频在线观看 | 久久亚洲中文字幕精品一区 | 国产激情艳情在线看视频 | 美女毛片一区二区三区四区 | 人妻体内射精一区二区三四 | 丰满少妇女裸体bbw | 国产精品高潮呻吟av久久4虎 | www国产精品内射老师 | 国产va免费精品观看 | 亚洲 激情 小说 另类 欧美 | 午夜精品一区二区三区的区别 | 一区二区传媒有限公司 | 少妇性l交大片欧洲热妇乱xxx | 99国产欧美久久久精品 | 久久五月精品中文字幕 | 牛和人交xxxx欧美 | 日本一卡2卡3卡四卡精品网站 | 国产成人一区二区三区别 | 老头边吃奶边弄进去呻吟 | 久久亚洲精品成人无码 | 国产精品内射视频免费 | 亚洲成a人片在线观看无码3d | 欧美日韩人成综合在线播放 | 亚洲成在人网站无码天堂 | 国产精品亚洲а∨无码播放麻豆 | 小泽玛莉亚一区二区视频在线 | 成人aaa片一区国产精品 | av在线亚洲欧洲日产一区二区 | 亚洲国产欧美日韩精品一区二区三区 | 国产极品美女高潮无套在线观看 | 亚洲国产精品无码久久久久高潮 | 久久成人a毛片免费观看网站 | 亚洲一区二区三区播放 | 爽爽影院免费观看 | 午夜性刺激在线视频免费 | 婷婷丁香六月激情综合啪 | 丰满护士巨好爽好大乳 | 久久久精品成人免费观看 | 内射后入在线观看一区 | 久久久精品欧美一区二区免费 | 人妻无码αv中文字幕久久琪琪布 | 日韩精品乱码av一区二区 | 久久久久国色av免费观看性色 | 亚洲区小说区激情区图片区 | 亚洲gv猛男gv无码男同 | 亚洲中文字幕在线无码一区二区 | 久久视频在线观看精品 | 四虎4hu永久免费 | 四虎国产精品免费久久 | 岛国片人妻三上悠亚 | 中文字幕av伊人av无码av | 人人澡人人妻人人爽人人蜜桃 | 曰韩少妇内射免费播放 | 久久精品女人的天堂av | 奇米影视7777久久精品人人爽 | 麻花豆传媒剧国产免费mv在线 | 日韩成人一区二区三区在线观看 | 久久久久久av无码免费看大片 | 捆绑白丝粉色jk震动捧喷白浆 | 人妻少妇被猛烈进入中文字幕 | 久久99精品国产麻豆蜜芽 | 国产97在线 | 亚洲 | 成在人线av无码免观看麻豆 | 亚无码乱人伦一区二区 | 国产福利视频一区二区 | 无码一区二区三区在线观看 | 久久久婷婷五月亚洲97号色 | 少妇性l交大片 | 中文字幕av无码一区二区三区电影 | 国产亚洲日韩欧美另类第八页 | 免费国产黄网站在线观看 | 少妇被粗大的猛进出69影院 | 97夜夜澡人人双人人人喊 | 18精品久久久无码午夜福利 | 久久久久亚洲精品男人的天堂 | 国产免费久久精品国产传媒 | 综合激情五月综合激情五月激情1 | 国产精品久久久一区二区三区 | 狠狠色丁香久久婷婷综合五月 | 99视频精品全部免费免费观看 | 三上悠亚人妻中文字幕在线 | 久在线观看福利视频 | 国产av无码专区亚洲a∨毛片 | 亚洲无人区午夜福利码高清完整版 | 久久亚洲日韩精品一区二区三区 | 九月婷婷人人澡人人添人人爽 | 成人av无码一区二区三区 | 国产性生交xxxxx无码 | 中文字幕久久久久人妻 | 日日夜夜撸啊撸 | 国产午夜精品一区二区三区嫩草 | 亚洲欧美日韩成人高清在线一区 | 亚洲精品一区三区三区在线观看 | 大地资源中文第3页 | 99riav国产精品视频 | 一个人看的www免费视频在线观看 | 国产成人精品一区二区在线小狼 | 国产猛烈高潮尖叫视频免费 | 欧美老熟妇乱xxxxx | 国产精品无码一区二区三区不卡 | 欧美 丝袜 自拍 制服 另类 | 久久亚洲精品成人无码 | 亚拍精品一区二区三区探花 | 久久精品国产99精品亚洲 | 欧美性生交活xxxxxdddd | 极品尤物被啪到呻吟喷水 | 久久精品人妻少妇一区二区三区 | 丰满人妻一区二区三区免费视频 | 国产又粗又硬又大爽黄老大爷视 | 98国产精品综合一区二区三区 | 国产极品美女高潮无套在线观看 | 日韩亚洲欧美精品综合 | 午夜免费福利小电影 | 国产精品爱久久久久久久 | 人妻无码久久精品人妻 | 爆乳一区二区三区无码 | 无遮挡啪啪摇乳动态图 | 久久久久免费精品国产 | 成人精品一区二区三区中文字幕 | 伊人久久婷婷五月综合97色 | aⅴ亚洲 日韩 色 图网站 播放 | 九九综合va免费看 | 暴力强奷在线播放无码 | 国产成人无码av片在线观看不卡 | 亚洲性无码av中文字幕 | 国产亚洲精品久久久久久大师 | 中文精品久久久久人妻不卡 | 99麻豆久久久国产精品免费 | 国产无遮挡吃胸膜奶免费看 | 国产精品丝袜黑色高跟鞋 | 男人的天堂av网站 | 欧美老妇交乱视频在线观看 | 精品国产一区二区三区四区在线看 | 国产精品久久久久久久影院 | 亚洲欧洲日本综合aⅴ在线 | 亚洲国产欧美在线成人 | 久久国产36精品色熟妇 | 99久久99久久免费精品蜜桃 | 美女张开腿让人桶 | 精品国产一区二区三区av 性色 | av在线亚洲欧洲日产一区二区 | 色噜噜亚洲男人的天堂 | 国产成人av免费观看 | 国产精品久久久 | 好男人社区资源 | 国产精品人人妻人人爽 | 爽爽影院免费观看 | 综合网日日天干夜夜久久 | 亚洲春色在线视频 | 成人毛片一区二区 | 亚洲精品无码人妻无码 | √天堂中文官网8在线 | 欧美日韩综合一区二区三区 | 青青久在线视频免费观看 | av无码不卡在线观看免费 | 曰本女人与公拘交酡免费视频 | 麻豆av传媒蜜桃天美传媒 | 亚洲日韩乱码中文无码蜜桃臀网站 | 性色欲网站人妻丰满中文久久不卡 | 无码一区二区三区在线观看 | 精品无码国产自产拍在线观看蜜 | 又大又紧又粉嫩18p少妇 | 夜夜影院未满十八勿进 | 国产精品久久久av久久久 | 在线观看欧美一区二区三区 | 亚洲精品综合一区二区三区在线 | 国产av一区二区精品久久凹凸 | 性欧美熟妇videofreesex | 亚洲中文无码av永久不收费 | 亚洲中文字幕无码一久久区 | 丰满护士巨好爽好大乳 | 久在线观看福利视频 | 国产精品无码永久免费888 | 熟妇激情内射com | 亚洲色www成人永久网址 | 九一九色国产 | 帮老师解开蕾丝奶罩吸乳网站 | 日本精品久久久久中文字幕 | 纯爱无遮挡h肉动漫在线播放 | 成年美女黄网站色大免费全看 | 中文字幕av无码一区二区三区电影 | 成人女人看片免费视频放人 | 亚洲精品国产精品乱码视色 | 2020最新国产自产精品 | 精品欧洲av无码一区二区三区 | 国产精品沙发午睡系列 | 国产激情精品一区二区三区 | 精品国产一区二区三区四区在线看 | 亚洲色无码一区二区三区 | 国产性生交xxxxx无码 | 欧美成人午夜精品久久久 | 高清不卡一区二区三区 | 国产精品无码一区二区三区不卡 | 日韩人妻无码一区二区三区久久99 | 色五月丁香五月综合五月 | 国产女主播喷水视频在线观看 | 久久久成人毛片无码 | 2019午夜福利不卡片在线 | 日本精品高清一区二区 | 亚洲无人区午夜福利码高清完整版 | 国产成人精品视频ⅴa片软件竹菊 | 国产av无码专区亚洲a∨毛片 | 麻豆国产丝袜白领秘书在线观看 | 麻豆av传媒蜜桃天美传媒 | 人人澡人人透人人爽 | 97色伦图片97综合影院 | 国产激情精品一区二区三区 | 一本久久a久久精品亚洲 | 亚洲国产av美女网站 | 国产在热线精品视频 | 熟妇人妻中文av无码 | 国产一区二区三区精品视频 | 亚洲欧美精品伊人久久 | 国产在线精品一区二区高清不卡 | 在线天堂新版最新版在线8 | 国产又粗又硬又大爽黄老大爷视 | 免费看少妇作爱视频 | 波多野结衣aⅴ在线 | 日韩av无码中文无码电影 | 综合网日日天干夜夜久久 | 中文精品无码中文字幕无码专区 | 夜夜高潮次次欢爽av女 | 丰满岳乱妇在线观看中字无码 | 亚洲精品中文字幕久久久久 | 国产9 9在线 | 中文 | 国产激情一区二区三区 | 久久人人爽人人人人片 | 天海翼激烈高潮到腰振不止 | 久久精品国产亚洲精品 | 一个人免费观看的www视频 | 国产精品视频免费播放 | 亚洲天堂2017无码 | 精品无码国产一区二区三区av | 久久成人a毛片免费观看网站 | 国产片av国语在线观看 | 青青青手机频在线观看 | 99er热精品视频 | 粗大的内捧猛烈进出视频 | 国产精品久久久午夜夜伦鲁鲁 | 久久久国产一区二区三区 | 色欲综合久久中文字幕网 | 日韩人妻无码一区二区三区久久99 | 欧美日韩一区二区免费视频 | 成 人 免费观看网站 | 在线欧美精品一区二区三区 | 国产亚洲精品久久久ai换 | 亚洲人成影院在线观看 | 国产美女极度色诱视频www | 性欧美牲交xxxxx视频 | 欧美人与善在线com | 一本色道久久综合亚洲精品不卡 | 久久人妻内射无码一区三区 | 日日摸日日碰夜夜爽av | 中国女人内谢69xxxx | 欧美激情综合亚洲一二区 | 欧美三级不卡在线观看 | 国产午夜亚洲精品不卡 | 蜜桃av抽搐高潮一区二区 | 人人爽人人澡人人高潮 | 亚洲精品午夜国产va久久成人 | 欧美阿v高清资源不卡在线播放 | 精品欧美一区二区三区久久久 | 无码一区二区三区在线观看 | 免费视频欧美无人区码 | 国产在线aaa片一区二区99 | 67194成是人免费无码 | 国产sm调教视频在线观看 | 久久精品国产一区二区三区 | 一二三四在线观看免费视频 | 18禁止看的免费污网站 | 一本精品99久久精品77 | 亚洲精品成人av在线 | 四十如虎的丰满熟妇啪啪 | 免费观看又污又黄的网站 | 色欲久久久天天天综合网精品 | 国产人妖乱国产精品人妖 | 一区二区传媒有限公司 | 中文字幕av日韩精品一区二区 | 亚洲中文字幕在线无码一区二区 | 亚洲自偷自拍另类第1页 | 少妇激情av一区二区 | 麻豆精产国品 | 国产av一区二区三区最新精品 | 国产成人综合在线女婷五月99播放 | 啦啦啦www在线观看免费视频 | 亚洲熟妇自偷自拍另类 | 日韩欧美中文字幕公布 | 天天做天天爱天天爽综合网 | 福利一区二区三区视频在线观看 | 国内少妇偷人精品视频 | 熟女俱乐部五十路六十路av | 性啪啪chinese东北女人 | 亚洲自偷精品视频自拍 | 丰满少妇熟乱xxxxx视频 | 夜夜影院未满十八勿进 | 成人精品视频一区二区 | 国产偷自视频区视频 | 天堂久久天堂av色综合 | 99在线 | 亚洲 | 亚洲日韩一区二区 | 亚洲熟女一区二区三区 | 男人和女人高潮免费网站 | 亚洲人亚洲人成电影网站色 | 国产精品久久久久久亚洲毛片 | 成人无码视频免费播放 | 欧美国产日产一区二区 | 国产综合在线观看 | 国产精品久久福利网站 | 亚洲国产精品一区二区第一页 | 欧美人与善在线com | 国产69精品久久久久app下载 | 久久久精品人妻久久影视 | 少妇厨房愉情理9仑片视频 | 亚洲国产精品毛片av不卡在线 | 亚洲熟妇色xxxxx欧美老妇 | 东京热一精品无码av | 三上悠亚人妻中文字幕在线 | 水蜜桃色314在线观看 | 天天躁日日躁狠狠躁免费麻豆 | 乱人伦人妻中文字幕无码久久网 | 日韩av无码一区二区三区 | 精品久久久久久亚洲精品 | 亚洲另类伦春色综合小说 | 亚洲精品午夜国产va久久成人 | 国产乱码精品一品二品 | 国产亚洲精品久久久久久久久动漫 | 无码国模国产在线观看 | 亚洲综合无码一区二区三区 | 国产无套内射久久久国产 | 一本加勒比波多野结衣 | 国产一区二区三区影院 | 亚洲日韩av一区二区三区中文 | 麻豆精品国产精华精华液好用吗 | 国产人妻人伦精品 | 人人妻人人澡人人爽人人精品浪潮 | 国产精品99久久精品爆乳 | 国产一区二区不卡老阿姨 | aⅴ在线视频男人的天堂 | 国产两女互慰高潮视频在线观看 | 人人妻人人澡人人爽欧美精品 | 国产乱人偷精品人妻a片 | 国产亚洲精品久久久久久久 | 国产欧美精品一区二区三区 | 色老头在线一区二区三区 | 亚洲国产一区二区三区在线观看 | 77777熟女视频在线观看 а天堂中文在线官网 | 高清无码午夜福利视频 | 永久免费观看国产裸体美女 | 欧美人与物videos另类 | 成在人线av无码免费 | 亚洲高清偷拍一区二区三区 | 蜜臀aⅴ国产精品久久久国产老师 | 中文字幕无码人妻少妇免费 | 亚洲精品综合一区二区三区在线 | 亚洲狠狠婷婷综合久久 | 久久综合九色综合97网 | 欧美日韩人成综合在线播放 | 日本xxxx色视频在线观看免费 | 成熟妇人a片免费看网站 | 色婷婷欧美在线播放内射 | 亚洲 a v无 码免 费 成 人 a v | 国产色在线 | 国产 | 老司机亚洲精品影院无码 | 亚洲成av人片在线观看无码不卡 | 激情爆乳一区二区三区 | 国产精品对白交换视频 | 在线 国产 欧美 亚洲 天堂 | 激情内射亚州一区二区三区爱妻 | 国产极品美女高潮无套在线观看 | 性开放的女人aaa片 | 77777熟女视频在线观看 а天堂中文在线官网 | 麻豆精品国产精华精华液好用吗 | 日韩亚洲欧美中文高清在线 | 国产精品嫩草久久久久 | av无码久久久久不卡免费网站 | 天堂亚洲2017在线观看 | 一本大道久久东京热无码av | 国产精品va在线观看无码 | 国内精品久久久久久中文字幕 | 久久精品无码一区二区三区 | 国产另类ts人妖一区二区 | 波多野结衣一区二区三区av免费 | 亚洲 a v无 码免 费 成 人 a v | 国产高清av在线播放 | 国产极品美女高潮无套在线观看 | 熟妇女人妻丰满少妇中文字幕 | 亚洲精品中文字幕乱码 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 中文字幕乱码人妻无码久久 | 国产精品a成v人在线播放 | 国产高潮视频在线观看 | 日本精品人妻无码77777 天堂一区人妻无码 | 久久99精品国产麻豆 | 精品无码国产一区二区三区av | 性色欲情网站iwww九文堂 | 亚洲国产精品久久久久久 | 爽爽影院免费观看 | 国产在线aaa片一区二区99 | 爆乳一区二区三区无码 | 日韩av无码中文无码电影 | 小泽玛莉亚一区二区视频在线 | 国内精品九九久久久精品 | 麻豆精品国产精华精华液好用吗 | 疯狂三人交性欧美 | 国产福利视频一区二区 | 亚洲成av人在线观看网址 | 蜜桃视频插满18在线观看 | 对白脏话肉麻粗话av | 国产精品高潮呻吟av久久4虎 | 亚洲欧美中文字幕5发布 | 国产两女互慰高潮视频在线观看 | 亚洲伊人久久精品影院 | 日日摸天天摸爽爽狠狠97 | 黑人玩弄人妻中文在线 | 无码帝国www无码专区色综合 | 黄网在线观看免费网站 | 国精品人妻无码一区二区三区蜜柚 | 日韩亚洲欧美精品综合 | 亚洲精品鲁一鲁一区二区三区 | 国产精品久久久一区二区三区 | 久久综合网欧美色妞网 | 国产sm调教视频在线观看 | 国产卡一卡二卡三 | 欧美性色19p | 精品国产一区av天美传媒 | 色婷婷综合中文久久一本 | 国产精品高潮呻吟av久久 | 亚洲高清偷拍一区二区三区 | 亚洲精品久久久久久久久久久 | 国产精品久久久久久久9999 | 国产xxx69麻豆国语对白 | 国产成人无码av片在线观看不卡 | 永久免费观看国产裸体美女 | 无码人妻出轨黑人中文字幕 | 无码福利日韩神码福利片 | 成人三级无码视频在线观看 | 2020久久超碰国产精品最新 | 影音先锋中文字幕无码 | 大肉大捧一进一出好爽视频 | 国产精品久久久av久久久 | 欧美阿v高清资源不卡在线播放 | √天堂中文官网8在线 | 精品久久久无码人妻字幂 | 强奷人妻日本中文字幕 | 黑人巨大精品欧美黑寡妇 | 无套内谢老熟女 | 欧美日韩人成综合在线播放 | 亚洲色欲色欲欲www在线 | 欧美乱妇无乱码大黄a片 | 欧美 日韩 人妻 高清 中文 | 久久久久久九九精品久 | 国产人成高清在线视频99最全资源 | www国产亚洲精品久久久日本 | 国产av人人夜夜澡人人爽麻豆 | 国产艳妇av在线观看果冻传媒 | 免费视频欧美无人区码 | 四虎永久在线精品免费网址 | 亚洲国产高清在线观看视频 | 樱花草在线播放免费中文 | 成人无码视频在线观看网站 | 成人一在线视频日韩国产 | 久久97精品久久久久久久不卡 | 四虎国产精品一区二区 | 中文字幕 亚洲精品 第1页 | 国产精品久久久久久久9999 | 国产精品嫩草久久久久 | 亚洲精品午夜国产va久久成人 | 免费国产成人高清在线观看网站 | 亚洲无人区午夜福利码高清完整版 | 人妻中文无码久热丝袜 | 九九热爱视频精品 | 国产凸凹视频一区二区 | √8天堂资源地址中文在线 | 香港三级日本三级妇三级 | 好男人社区资源 | 亚洲一区二区三区无码久久 | 97夜夜澡人人爽人人喊中国片 | 亚洲日本va午夜在线电影 | 内射后入在线观看一区 | 无码人妻出轨黑人中文字幕 | 日本www一道久久久免费榴莲 | 老熟妇仑乱视频一区二区 | 中文字幕 人妻熟女 | 最新版天堂资源中文官网 | 国产在线一区二区三区四区五区 | 亚洲精品一区国产 | 国内揄拍国内精品人妻 | 女人和拘做爰正片视频 | 人妻天天爽夜夜爽一区二区 | 蜜臀aⅴ国产精品久久久国产老师 | 欧美三级a做爰在线观看 | 国产片av国语在线观看 | 国内少妇偷人精品视频 | 国产无套粉嫩白浆在线 | 亚洲中文字幕乱码av波多ji | 98国产精品综合一区二区三区 | 日韩精品无码一区二区中文字幕 | 亚洲综合久久一区二区 | 人人妻人人澡人人爽欧美一区 | 久久久无码中文字幕久... | 国产精品高潮呻吟av久久4虎 | 欧美日韩视频无码一区二区三 | 女人被男人爽到呻吟的视频 | 国产欧美精品一区二区三区 | 免费国产黄网站在线观看 | 亚洲综合色区中文字幕 | 久久国产精品萌白酱免费 | 国产在线aaa片一区二区99 | 中文字幕无码乱人伦 | 图片小说视频一区二区 | 亚洲の无码国产の无码影院 | 人妻插b视频一区二区三区 | 天天摸天天碰天天添 | 丰满护士巨好爽好大乳 | 亚洲精品国产精品乱码不卡 | 蜜桃视频韩日免费播放 | 国精产品一区二区三区 | 永久免费精品精品永久-夜色 | 未满成年国产在线观看 | 国产片av国语在线观看 | 99久久精品无码一区二区毛片 | 人妻无码αv中文字幕久久琪琪布 | 欧美性生交xxxxx久久久 | 丝袜人妻一区二区三区 | 国产精品爱久久久久久久 | 欧美国产日产一区二区 | 国产精品内射视频免费 | 国产精品福利视频导航 | 中文字幕精品av一区二区五区 | 国产精品国产三级国产专播 | 人人澡人摸人人添 | 色婷婷综合中文久久一本 | 日韩精品无码一区二区中文字幕 | 婷婷五月综合缴情在线视频 | 国产美女极度色诱视频www | 伊人久久大香线蕉av一区二区 | 成人无码精品1区2区3区免费看 | 水蜜桃亚洲一二三四在线 | 无码人妻丰满熟妇区五十路百度 | 久久国产36精品色熟妇 | 日韩亚洲欧美中文高清在线 | 无码纯肉视频在线观看 | 亚洲成a人一区二区三区 | 六月丁香婷婷色狠狠久久 | 天天拍夜夜添久久精品大 | 美女扒开屁股让男人桶 | 中文毛片无遮挡高清免费 | 最近中文2019字幕第二页 | 午夜无码人妻av大片色欲 | 亚洲国产综合无码一区 | √天堂中文官网8在线 | 亚洲va欧美va天堂v国产综合 | 丰满肥臀大屁股熟妇激情视频 | 无码人中文字幕 | 一本色道久久综合亚洲精品不卡 | 青草青草久热国产精品 | 男人和女人高潮免费网站 | 给我免费的视频在线观看 | 国产精品成人av在线观看 | 精品无人国产偷自产在线 | 亚洲色欲色欲天天天www | 国产深夜福利视频在线 | 久久久久久国产精品无码下载 | 无码人妻少妇伦在线电影 | 日日摸夜夜摸狠狠摸婷婷 | 精品人人妻人人澡人人爽人人 | 人妻无码αv中文字幕久久琪琪布 | 免费网站看v片在线18禁无码 | 无遮无挡爽爽免费视频 | 国产香蕉97碰碰久久人人 | 国产两女互慰高潮视频在线观看 | 日韩精品一区二区av在线 | 亚洲午夜福利在线观看 | 久久99精品国产麻豆 | 久久久久99精品国产片 | 精品成在人线av无码免费看 | 婷婷五月综合激情中文字幕 | 黑人玩弄人妻中文在线 | 国产精品亚洲五月天高清 | 国产精品亚洲lv粉色 | 欧美人与动性行为视频 | 亚洲 另类 在线 欧美 制服 | 成在人线av无码免费 | 大肉大捧一进一出视频出来呀 | 四虎永久在线精品免费网址 | 最新版天堂资源中文官网 | 无码中文字幕色专区 | 天堂а√在线地址中文在线 | 精品无人区无码乱码毛片国产 | 蜜桃臀无码内射一区二区三区 | 成年女人永久免费看片 | 亚洲成色在线综合网站 | 图片区 小说区 区 亚洲五月 | 精品国偷自产在线视频 | 鲁一鲁av2019在线 | 亚洲综合精品香蕉久久网 | 在线看片无码永久免费视频 | 日韩精品无码一区二区中文字幕 | 暴力强奷在线播放无码 | 国产精品无套呻吟在线 | 久久久久久九九精品久 | 久久久久国色av免费观看性色 | 国产国语老龄妇女a片 | 亚洲国产av美女网站 | 国产97色在线 | 免 | 欧美兽交xxxx×视频 | 亚洲人亚洲人成电影网站色 | 中文字幕av无码一区二区三区电影 | 樱花草在线社区www | 在线播放亚洲第一字幕 | 亚洲色在线无码国产精品不卡 | 黑人玩弄人妻中文在线 | a在线亚洲男人的天堂 | 无码人妻黑人中文字幕 | 老头边吃奶边弄进去呻吟 | 成在人线av无码免观看麻豆 | 中文字幕无码日韩专区 | 又色又爽又黄的美女裸体网站 | 久久无码中文字幕免费影院蜜桃 | 18禁止看的免费污网站 | 亚洲欧洲中文日韩av乱码 | 欧美人与物videos另类 | 人妻中文无码久热丝袜 | 2020久久超碰国产精品最新 | 国产精品无码一区二区桃花视频 | 亚洲国产精品一区二区第一页 | 99视频精品全部免费免费观看 | 国产特级毛片aaaaaa高潮流水 | 曰韩少妇内射免费播放 | 无码人妻出轨黑人中文字幕 | 野狼第一精品社区 | 青青草原综合久久大伊人精品 | 男女超爽视频免费播放 | 欧美乱妇无乱码大黄a片 | 动漫av一区二区在线观看 | 亚洲欧美日韩成人高清在线一区 | 激情人妻另类人妻伦 | av小次郎收藏 | 漂亮人妻洗澡被公强 日日躁 | 少妇邻居内射在线 | 日本护士xxxxhd少妇 | 麻豆国产人妻欲求不满 | 帮老师解开蕾丝奶罩吸乳网站 | 日本精品人妻无码免费大全 | 国产无遮挡又黄又爽免费视频 | 人妻少妇精品久久 | 少妇人妻偷人精品无码视频 | 高潮毛片无遮挡高清免费视频 | 亚洲成a人片在线观看日本 | 国产一区二区三区日韩精品 | 亚洲国产欧美日韩精品一区二区三区 | 中文无码伦av中文字幕 | 亚洲熟悉妇女xxx妇女av | 亚洲狠狠色丁香婷婷综合 | 国内精品久久久久久中文字幕 | 又粗又大又硬又长又爽 | 国产偷自视频区视频 | 国产人妻久久精品二区三区老狼 | 国产精品亚洲综合色区韩国 | 久久99精品久久久久久动态图 | 男女性色大片免费网站 | 亚洲а∨天堂久久精品2021 | 奇米影视7777久久精品人人爽 | 久久人人爽人人爽人人片av高清 | 又湿又紧又大又爽a视频国产 | 国产欧美精品一区二区三区 | 精品无码国产一区二区三区av | 亚洲精品一区三区三区在线观看 | 欧美xxxxx精品 | 欧美国产日产一区二区 | 国产精品久久久一区二区三区 | 高潮毛片无遮挡高清免费视频 | 好男人社区资源 | 十八禁真人啪啪免费网站 | 久久久久久久人妻无码中文字幕爆 | 狠狠色色综合网站 | 久久精品中文字幕一区 | 亚洲日韩一区二区三区 | 国精产品一品二品国精品69xx | 少妇高潮喷潮久久久影院 | 四虎永久在线精品免费网址 | 狠狠色丁香久久婷婷综合五月 | 荡女精品导航 | 成人无码视频在线观看网站 | 久久精品国产大片免费观看 | 国产在线一区二区三区四区五区 | 一区二区三区高清视频一 | 无码免费一区二区三区 | 老司机亚洲精品影院 | 亚洲精品久久久久久久久久久 | 欧美成人午夜精品久久久 | 国色天香社区在线视频 | 国产精品99久久精品爆乳 | 久久久久久久久888 | 国产猛烈高潮尖叫视频免费 | 高清不卡一区二区三区 | 亚洲综合精品香蕉久久网 | 天天做天天爱天天爽综合网 | 久久aⅴ免费观看 | 欧美第一黄网免费网站 | 精品国精品国产自在久国产87 | 奇米影视7777久久精品人人爽 | 无码午夜成人1000部免费视频 | 久久精品视频在线看15 | 久久精品无码一区二区三区 | 欧美猛少妇色xxxxx | 国产av久久久久精东av | 秋霞特色aa大片 | 丰满少妇人妻久久久久久 | 精品国产国产综合精品 | а天堂中文在线官网 | 国产极品美女高潮无套在线观看 | 97资源共享在线视频 | 中国女人内谢69xxxxxa片 | 成人免费视频视频在线观看 免费 | 性欧美大战久久久久久久 | 国产精品无码一区二区桃花视频 | 大肉大捧一进一出好爽视频 | 精品一二三区久久aaa片 | √8天堂资源地址中文在线 | 久久zyz资源站无码中文动漫 | 成人女人看片免费视频放人 | 99久久人妻精品免费一区 | 国产精品亚洲五月天高清 | 5858s亚洲色大成网站www | 国产精品多人p群无码 | 亚洲国产av美女网站 | 国产精品理论片在线观看 | 色欲综合久久中文字幕网 | 日韩av无码一区二区三区 | аⅴ资源天堂资源库在线 | 三上悠亚人妻中文字幕在线 | 成人精品一区二区三区中文字幕 | 午夜肉伦伦影院 | 国产一精品一av一免费 | 四虎4hu永久免费 | 欧美老妇交乱视频在线观看 | 国产97人人超碰caoprom | 中文字幕无码免费久久99 | 国产精品久久福利网站 | 亚洲精品成人福利网站 | 久久99精品久久久久婷婷 | 97无码免费人妻超级碰碰夜夜 | 亚洲精品一区二区三区在线 | 131美女爱做视频 | 久久久无码中文字幕久... | 久久精品国产精品国产精品污 | 麻豆精品国产精华精华液好用吗 | 国产又粗又硬又大爽黄老大爷视 | 国产区女主播在线观看 | 国产偷国产偷精品高清尤物 | 露脸叫床粗话东北少妇 | 粗大的内捧猛烈进出视频 | 国内综合精品午夜久久资源 | 亚洲日韩一区二区三区 | 麻豆精产国品 | 在线观看欧美一区二区三区 | 少妇无码av无码专区在线观看 | 又紧又大又爽精品一区二区 | 国产精品沙发午睡系列 | 偷窥村妇洗澡毛毛多 | 成人欧美一区二区三区 | 欧美 丝袜 自拍 制服 另类 | 精品国产麻豆免费人成网站 | 99久久人妻精品免费一区 | 亚洲一区二区观看播放 | 乱人伦人妻中文字幕无码 | 中文精品久久久久人妻不卡 | 欧美猛少妇色xxxxx | 两性色午夜视频免费播放 | 亚洲国产午夜精品理论片 | 亚洲理论电影在线观看 | 国产成人无码一二三区视频 | 国产性生交xxxxx无码 | 欧美三级a做爰在线观看 | 日韩欧美中文字幕公布 | 久久综合给久久狠狠97色 | 少妇太爽了在线观看 | 亚洲日韩中文字幕在线播放 | 无码纯肉视频在线观看 | 亚洲精品鲁一鲁一区二区三区 | 国产偷国产偷精品高清尤物 | 丰满人妻翻云覆雨呻吟视频 | 亚洲国产av精品一区二区蜜芽 | 精品人妻人人做人人爽夜夜爽 | 无码精品人妻一区二区三区av | 在线播放免费人成毛片乱码 | 内射爽无广熟女亚洲 | 波多野结衣高清一区二区三区 | 人人澡人人透人人爽 | 少妇无套内谢久久久久 | 国内精品久久久久久中文字幕 | 欧美激情内射喷水高潮 | av小次郎收藏 | 久久久www成人免费毛片 | 狂野欧美性猛xxxx乱大交 | 欧美丰满熟妇xxxx | 狠狠色丁香久久婷婷综合五月 | 精品无码一区二区三区爱欲 | av小次郎收藏 | 超碰97人人射妻 | 在线а√天堂中文官网 | 欧美zoozzooz性欧美 | 美女扒开屁股让男人桶 | 久久久久se色偷偷亚洲精品av | 久久午夜无码鲁丝片秋霞 | 黑人巨大精品欧美黑寡妇 | 亚洲一区二区三区在线观看网站 | 久久久国产一区二区三区 | 欧美刺激性大交 | 成人性做爰aaa片免费看不忠 | 精品国产av色一区二区深夜久久 | 国内精品人妻无码久久久影院 | 女人被男人爽到呻吟的视频 | 午夜精品久久久内射近拍高清 | 亚洲色www成人永久网址 | 久久久久久九九精品久 | 亚洲aⅴ无码成人网站国产app | 成人欧美一区二区三区黑人免费 | 成年女人永久免费看片 | 精品人妻人人做人人爽 | 成人毛片一区二区 | 久久国产精品萌白酱免费 | 午夜无码人妻av大片色欲 | 99国产精品白浆在线观看免费 | 无码毛片视频一区二区本码 | 一个人免费观看的www视频 | 内射后入在线观看一区 | 国产9 9在线 | 中文 | 亚洲精品无码国产 | 亚洲中文字幕在线无码一区二区 | 夜夜影院未满十八勿进 | 51国偷自产一区二区三区 | 亚洲一区二区三区 | 激情内射日本一区二区三区 | 亚洲午夜福利在线观看 | 日本在线高清不卡免费播放 | 乱人伦中文视频在线观看 | 国产av无码专区亚洲a∨毛片 | 高潮喷水的毛片 | 日韩av无码一区二区三区不卡 | 日日干夜夜干 | 天天爽夜夜爽夜夜爽 | 欧美野外疯狂做受xxxx高潮 | 国产偷自视频区视频 | 一本久久a久久精品亚洲 | 精品无码一区二区三区的天堂 | 欧洲极品少妇 | 日本www一道久久久免费榴莲 | 久久综合给久久狠狠97色 | 久久无码中文字幕免费影院蜜桃 | 欧洲极品少妇 | 熟妇女人妻丰满少妇中文字幕 | 国产一区二区三区四区五区加勒比 | 国语精品一区二区三区 | 无码国产激情在线观看 | 国产偷抇久久精品a片69 | 久久国产自偷自偷免费一区调 | 精品成人av一区二区三区 | 久久精品国产日本波多野结衣 | 日日摸日日碰夜夜爽av | 欧美高清在线精品一区 | 精品国产一区二区三区四区 | 扒开双腿疯狂进出爽爽爽视频 | 捆绑白丝粉色jk震动捧喷白浆 | 秋霞成人午夜鲁丝一区二区三区 | 日韩欧美成人免费观看 | ass日本丰满熟妇pics | 久久zyz资源站无码中文动漫 | 国产免费久久久久久无码 | 欧美自拍另类欧美综合图片区 | 日本熟妇大屁股人妻 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 超碰97人人做人人爱少妇 | 久久综合给合久久狠狠狠97色 | 无码国模国产在线观看 | 成年女人永久免费看片 | 国产av剧情md精品麻豆 | 性色欲情网站iwww九文堂 | 伦伦影院午夜理论片 | 少妇高潮一区二区三区99 | 色综合视频一区二区三区 | 午夜熟女插插xx免费视频 | 国产精品18久久久久久麻辣 | 97精品国产97久久久久久免费 | 亚洲第一网站男人都懂 | 中文久久乱码一区二区 | 高潮毛片无遮挡高清免费 | 成熟妇人a片免费看网站 | 国产免费久久精品国产传媒 | 国产后入清纯学生妹 | 中文字幕日产无线码一区 | 人妻无码αv中文字幕久久琪琪布 | 欧美老妇交乱视频在线观看 | 大地资源网第二页免费观看 | 天干天干啦夜天干天2017 | 伊在人天堂亚洲香蕉精品区 | 中文字幕亚洲情99在线 | 在线天堂新版最新版在线8 | 曰本女人与公拘交酡免费视频 | 国产av久久久久精东av | 色婷婷av一区二区三区之红樱桃 | 国产人妻久久精品二区三区老狼 | 永久黄网站色视频免费直播 | 蜜桃臀无码内射一区二区三区 | 成人一区二区免费视频 | 日本一卡二卡不卡视频查询 | 亚洲国产精品一区二区美利坚 | 久久国产自偷自偷免费一区调 | 国产亚洲美女精品久久久2020 | 午夜成人1000部免费视频 | 亚洲精品中文字幕久久久久 | 亚洲伊人久久精品影院 | 天堂亚洲免费视频 | 性欧美疯狂xxxxbbbb | 内射欧美老妇wbb | 亚洲成熟女人毛毛耸耸多 | 曰韩少妇内射免费播放 | 欧美老妇交乱视频在线观看 | 99久久精品国产一区二区蜜芽 | 中文字幕无码视频专区 | 国产精品丝袜黑色高跟鞋 | 国产精品久久久 | 久久aⅴ免费观看 | 一个人免费观看的www视频 | 麻豆果冻传媒2021精品传媒一区下载 | 成人片黄网站色大片免费观看 | 又大又黄又粗又爽的免费视频 | 国产亚洲精品久久久久久大师 | 色婷婷香蕉在线一区二区 | 国产精品无码永久免费888 | 精品国产青草久久久久福利 | 一区二区三区乱码在线 | 欧洲 | 亚洲精品无码人妻无码 | 波多野结衣高清一区二区三区 | 中文久久乱码一区二区 | 一个人看的www免费视频在线观看 | 未满小14洗澡无码视频网站 | 亚洲国产欧美日韩精品一区二区三区 | 亚洲精品久久久久avwww潮水 | 中文精品久久久久人妻不卡 | 曰韩少妇内射免费播放 | 又湿又紧又大又爽a视频国产 | 无码纯肉视频在线观看 | 奇米影视7777久久精品 | 十八禁视频网站在线观看 | 爽爽影院免费观看 | 午夜不卡av免费 一本久久a久久精品vr综合 | 久久久婷婷五月亚洲97号色 | 麻豆国产97在线 | 欧洲 | 国产成人精品三级麻豆 | 亚洲国产精品久久久天堂 | 十八禁视频网站在线观看 | www国产亚洲精品久久久日本 | 在线精品亚洲一区二区 | 国产精品-区区久久久狼 | 荫蒂被男人添的好舒服爽免费视频 | 国产精品视频免费播放 | a在线亚洲男人的天堂 | 久久视频在线观看精品 | 日韩亚洲欧美中文高清在线 | 麻豆国产97在线 | 欧洲 | 精品久久久久香蕉网 | 欧美日本精品一区二区三区 | 在线观看国产一区二区三区 | 九九久久精品国产免费看小说 | 亚洲 日韩 欧美 成人 在线观看 | 4hu四虎永久在线观看 | 天堂а√在线地址中文在线 | 欧美日本日韩 | 中文字幕中文有码在线 | 精品 日韩 国产 欧美 视频 | 51国偷自产一区二区三区 | 中文字幕av伊人av无码av | 男女爱爱好爽视频免费看 | 国产97在线 | 亚洲 | 国产精品美女久久久久av爽李琼 | 国产激情无码一区二区 | 成人欧美一区二区三区黑人免费 | 澳门永久av免费网站 | 麻豆国产人妻欲求不满谁演的 | 婷婷五月综合激情中文字幕 | 中文无码伦av中文字幕 | 国产无遮挡吃胸膜奶免费看 | 欧美丰满老熟妇xxxxx性 | 日日摸日日碰夜夜爽av | 国产莉萝无码av在线播放 | 亚洲国产精品成人久久蜜臀 | 曰本女人与公拘交酡免费视频 | 少妇无码av无码专区在线观看 | 亚洲人成影院在线无码按摩店 | 在教室伦流澡到高潮hnp视频 | 欧美人与动性行为视频 | 免费观看又污又黄的网站 | 无码人妻丰满熟妇区五十路百度 | 国产成人精品优优av | 亚洲a无码综合a国产av中文 | 俺去俺来也在线www色官网 | 丰满少妇人妻久久久久久 | 日产精品高潮呻吟av久久 | 永久免费观看美女裸体的网站 | 亚洲色www成人永久网址 | 欧美人与动性行为视频 | 免费人成在线观看网站 | 97色伦图片97综合影院 | 亚洲 另类 在线 欧美 制服 | 亚洲男人av香蕉爽爽爽爽 | 欧美日韩亚洲国产精品 | 亚洲gv猛男gv无码男同 | 又湿又紧又大又爽a视频国产 | 国内丰满熟女出轨videos | 丰满岳乱妇在线观看中字无码 | 欧美zoozzooz性欧美 | 亚洲人成网站免费播放 | 一本色道久久综合亚洲精品不卡 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 亚洲精品国偷拍自产在线观看蜜桃 | 久久99热只有频精品8 | 午夜性刺激在线视频免费 | 中文字幕中文有码在线 | 婷婷综合久久中文字幕蜜桃三电影 | 久久综合色之久久综合 | 色狠狠av一区二区三区 | 国产亚洲精品久久久久久国模美 | 亚洲国产精品一区二区第一页 | 久久这里只有精品视频9 | 日本饥渴人妻欲求不满 | 成人免费视频一区二区 | 精品午夜福利在线观看 | 日日碰狠狠躁久久躁蜜桃 | 宝宝好涨水快流出来免费视频 | 色欲人妻aaaaaaa无码 | 久久精品中文字幕一区 | 玩弄少妇高潮ⅹxxxyw | 玩弄少妇高潮ⅹxxxyw | 亚洲娇小与黑人巨大交 | 2020久久超碰国产精品最新 | 国产精品久久国产三级国 | 精品国产麻豆免费人成网站 | 搡女人真爽免费视频大全 | 亚洲日本va午夜在线电影 | 欧洲欧美人成视频在线 | 精品国产av色一区二区深夜久久 | 少妇太爽了在线观看 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 爽爽影院免费观看 | 国产九九九九九九九a片 | 少妇性俱乐部纵欲狂欢电影 | 久精品国产欧美亚洲色aⅴ大片 | 国产免费久久精品国产传媒 | 日产精品99久久久久久 | 精品国产一区二区三区四区 | 美女毛片一区二区三区四区 | 18黄暴禁片在线观看 | 日韩无码专区 | 国产人妻大战黑人第1集 | 中文字幕av日韩精品一区二区 | 波多野结衣av一区二区全免费观看 | 日本又色又爽又黄的a片18禁 | 国产国语老龄妇女a片 | 免费无码肉片在线观看 | 亚洲乱亚洲乱妇50p | 99精品视频在线观看免费 | 无套内射视频囯产 | 亚洲精品中文字幕 | 久久久精品成人免费观看 | 我要看www免费看插插视频 | 国产色精品久久人妻 | 日本xxxx色视频在线观看免费 | 天天av天天av天天透 | 无码人妻久久一区二区三区不卡 | 精品乱子伦一区二区三区 | 欧美人与善在线com | 国产内射爽爽大片视频社区在线 | 性欧美熟妇videofreesex | 国产午夜无码精品免费看 | 国产无套粉嫩白浆在线 | 国产精品久久久久久亚洲毛片 | 成 人影片 免费观看 | 亚洲熟熟妇xxxx | 欧美一区二区三区视频在线观看 | 欧美亚洲国产一区二区三区 | 久青草影院在线观看国产 | 久久综合狠狠综合久久综合88 | а√天堂www在线天堂小说 | 久久国产劲爆∧v内射 | 波多野结衣 黑人 | 日韩av激情在线观看 | 亚洲国产精品久久人人爱 | 亚洲精品久久久久久久久久久 | 精品午夜福利在线观看 | 久久久久av无码免费网 | 久久无码专区国产精品s | 久久国产自偷自偷免费一区调 | 国产一区二区三区日韩精品 | 377p欧洲日本亚洲大胆 | 性色欲网站人妻丰满中文久久不卡 | 狠狠亚洲超碰狼人久久 | 少妇性l交大片欧洲热妇乱xxx | 亚洲日本一区二区三区在线 | 在线观看国产午夜福利片 | 2020久久香蕉国产线看观看 | 欧美老熟妇乱xxxxx | 日韩欧美群交p片內射中文 | 欧美国产日产一区二区 | 亚洲日韩av一区二区三区中文 | 国产欧美精品一区二区三区 | 宝宝好涨水快流出来免费视频 | 乱人伦人妻中文字幕无码 | 无遮无挡爽爽免费视频 | 九月婷婷人人澡人人添人人爽 | 天天拍夜夜添久久精品大 | 国产无遮挡又黄又爽又色 | 婷婷丁香六月激情综合啪 | 国产精品美女久久久网av | 亚洲色欲色欲天天天www | 精品人妻人人做人人爽夜夜爽 | 又大又紧又粉嫩18p少妇 | 大地资源网第二页免费观看 | 午夜福利电影 | 初尝人妻少妇中文字幕 | 嫩b人妻精品一区二区三区 | 狠狠综合久久久久综合网 | 国产美女精品一区二区三区 | 中国女人内谢69xxxx | 亚洲人亚洲人成电影网站色 | 成人一在线视频日韩国产 | 成人无码精品一区二区三区 | 内射老妇bbwx0c0ck | 特级做a爰片毛片免费69 | 无码帝国www无码专区色综合 | 国产亲子乱弄免费视频 | 欧美性色19p | 小泽玛莉亚一区二区视频在线 | 正在播放东北夫妻内射 | 人妻无码久久精品人妻 | 中文字幕乱码人妻二区三区 | 久久久久亚洲精品男人的天堂 | 内射后入在线观看一区 | 亚洲熟妇色xxxxx亚洲 | 97久久国产亚洲精品超碰热 | 久久久精品国产sm最大网站 | 日本精品人妻无码免费大全 | 2020久久香蕉国产线看观看 | 一区二区传媒有限公司 | 午夜丰满少妇性开放视频 | 无遮挡啪啪摇乳动态图 | 日日噜噜噜噜夜夜爽亚洲精品 | 精品厕所偷拍各类美女tp嘘嘘 | 国产乱码精品一品二品 | 红桃av一区二区三区在线无码av | 天天躁日日躁狠狠躁免费麻豆 | 水蜜桃av无码 | 图片小说视频一区二区 | 精品人人妻人人澡人人爽人人 | 欧美第一黄网免费网站 | www一区二区www免费 | 久久久久久久久888 | 精品一区二区三区波多野结衣 | 欧美日韩亚洲国产精品 | 亚洲精品欧美二区三区中文字幕 | 天堂一区人妻无码 | 色噜噜亚洲男人的天堂 | 久激情内射婷内射蜜桃人妖 | 欧美乱妇无乱码大黄a片 | 国精产品一区二区三区 | 久久综合九色综合欧美狠狠 | 久久久久免费看成人影片 | 亚洲人成网站在线播放942 | 欧美一区二区三区视频在线观看 | 在线观看欧美一区二区三区 | 国产卡一卡二卡三 | 亚洲第一无码av无码专区 | 免费国产成人高清在线观看网站 | 国产成人人人97超碰超爽8 | 精品国偷自产在线视频 | 在线天堂新版最新版在线8 | 人人爽人人澡人人人妻 | 亚洲无人区午夜福利码高清完整版 | 久久国产精品_国产精品 | 丰满妇女强制高潮18xxxx | 97色伦图片97综合影院 | 精品国产乱码久久久久乱码 | 夫妻免费无码v看片 | 国产成人无码av片在线观看不卡 | 国产人妻精品一区二区三区 | 色婷婷综合激情综在线播放 | 国产乱人伦偷精品视频 | 久久久亚洲欧洲日产国码αv | 婷婷综合久久中文字幕蜜桃三电影 | 无码成人精品区在线观看 | 国产又爽又猛又粗的视频a片 | 国产午夜手机精彩视频 | 荫蒂被男人添的好舒服爽免费视频 | 精品乱子伦一区二区三区 | 成年美女黄网站色大免费视频 | 亚洲爆乳精品无码一区二区三区 | 乌克兰少妇xxxx做受 | 国产精品亚洲五月天高清 | 久久精品女人天堂av免费观看 | 两性色午夜视频免费播放 | 亚洲精品成a人在线观看 | 中文字幕日韩精品一区二区三区 | 妺妺窝人体色www婷婷 | 免费网站看v片在线18禁无码 | 欧美人妻一区二区三区 | 最近的中文字幕在线看视频 | 久久精品女人天堂av免费观看 | √天堂中文官网8在线 | 未满成年国产在线观看 | 欧美三级a做爰在线观看 | 国内丰满熟女出轨videos | 一本久久a久久精品vr综合 | 国产精品久久久久无码av色戒 | 未满成年国产在线观看 | 日韩亚洲欧美精品综合 | 日韩人妻无码一区二区三区久久99 | 无码人妻出轨黑人中文字幕 | 精品国精品国产自在久国产87 | 亚洲精品久久久久avwww潮水 | 国产麻豆精品精东影业av网站 | 在线播放亚洲第一字幕 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 老熟妇仑乱视频一区二区 | 大肉大捧一进一出视频出来呀 | 青青久在线视频免费观看 | 男人和女人高潮免费网站 | 国语精品一区二区三区 | 中文字幕乱码中文乱码51精品 | 无码精品国产va在线观看dvd | 久久综合给久久狠狠97色 | 国产精品人人妻人人爽 | 大地资源中文第3页 | 伊人久久大香线蕉亚洲 | 色情久久久av熟女人妻网站 | 日韩精品a片一区二区三区妖精 | www国产亚洲精品久久久日本 | 婷婷综合久久中文字幕蜜桃三电影 | 国产97人人超碰caoprom | 亚洲国产成人av在线观看 | 久久这里只有精品视频9 | 国产精品高潮呻吟av久久4虎 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 亚洲一区二区三区国产精华液 | 小鲜肉自慰网站xnxx | 国产精品亚洲专区无码不卡 | 亚洲国产精品毛片av不卡在线 | 欧美猛少妇色xxxxx | 免费观看又污又黄的网站 | 亚洲男人av天堂午夜在 | 成人无码精品一区二区三区 | 日韩精品无码免费一区二区三区 | 国产激情无码一区二区 | 国产激情一区二区三区 | 久久久久se色偷偷亚洲精品av | 97久久精品无码一区二区 | 中文字幕无线码 | 久久久久久久人妻无码中文字幕爆 | 久久综合狠狠综合久久综合88 | 久久久久99精品成人片 | 日本成熟视频免费视频 | 少妇性l交大片 | 无码帝国www无码专区色综合 | 波多野结衣av在线观看 | 好屌草这里只有精品 | 欧美阿v高清资源不卡在线播放 | 亚洲精品无码国产 | 免费看少妇作爱视频 | 粗大的内捧猛烈进出视频 | а天堂中文在线官网 | 中文字幕av日韩精品一区二区 | 日韩人妻无码中文字幕视频 | 国产在线精品一区二区三区直播 | 欧美日本免费一区二区三区 | 亚洲gv猛男gv无码男同 | 狠狠噜狠狠狠狠丁香五月 | 人妻无码久久精品人妻 | 99久久精品国产一区二区蜜芽 | 国产成人精品一区二区在线小狼 | 婷婷色婷婷开心五月四房播播 | 亚洲爆乳精品无码一区二区三区 | 国产午夜无码精品免费看 | 无码午夜成人1000部免费视频 | 欧美成人免费全部网站 | 无码午夜成人1000部免费视频 | 无码帝国www无码专区色综合 | 一本久久a久久精品亚洲 | 日本在线高清不卡免费播放 | 精品久久久中文字幕人妻 | 377p欧洲日本亚洲大胆 | 亚洲无人区一区二区三区 | 夜夜高潮次次欢爽av女 | 国产精品亚洲五月天高清 | 亚洲色偷偷偷综合网 | 中文字幕日韩精品一区二区三区 | 国产成人精品无码播放 | 亚洲爆乳大丰满无码专区 | av小次郎收藏 | 自拍偷自拍亚洲精品被多人伦好爽 | 99精品视频在线观看免费 | 永久免费精品精品永久-夜色 | 免费人成在线视频无码 | 亚洲精品午夜无码电影网 | 狠狠色噜噜狠狠狠7777奇米 | 亚洲呦女专区 | 风流少妇按摩来高潮 | 久青草影院在线观看国产 | 日本乱偷人妻中文字幕 | 国产精品亚洲а∨无码播放麻豆 | 99视频精品全部免费免费观看 | 人人妻人人澡人人爽人人精品浪潮 | 亚洲国产av精品一区二区蜜芽 | 国产凸凹视频一区二区 | 国产av剧情md精品麻豆 | 欧洲熟妇色 欧美 | 奇米影视7777久久精品 | 亚洲色欲色欲天天天www | 好男人www社区 | 亚洲欧美精品aaaaaa片 | 对白脏话肉麻粗话av | 一本一道久久综合久久 | 99久久精品日本一区二区免费 | 久久久久久久女国产乱让韩 | 麻豆md0077饥渴少妇 | 国产精品亚洲综合色区韩国 | 欧美日韩久久久精品a片 | 麻豆国产人妻欲求不满谁演的 | 亚洲狠狠婷婷综合久久 | 熟妇人妻激情偷爽文 | √8天堂资源地址中文在线 | 中文字幕无码av激情不卡 | 国产亚洲精品久久久久久久 | 亚洲一区av无码专区在线观看 | 蜜桃臀无码内射一区二区三区 | 亚欧洲精品在线视频免费观看 | 亚洲成熟女人毛毛耸耸多 | 熟女少妇在线视频播放 | 人人妻人人澡人人爽欧美精品 | 西西人体www44rt大胆高清 | 国产猛烈高潮尖叫视频免费 | 国产人妻精品一区二区三区 | 日本熟妇乱子伦xxxx | 大胆欧美熟妇xx | 蜜桃视频插满18在线观看 | 国产成人无码午夜视频在线观看 | 人妻少妇被猛烈进入中文字幕 | 中文字幕乱码人妻无码久久 | 俺去俺来也www色官网 | 内射巨臀欧美在线视频 | 性色av无码免费一区二区三区 | 亚洲а∨天堂久久精品2021 | 岛国片人妻三上悠亚 | 国产办公室秘书无码精品99 | 亚洲va欧美va天堂v国产综合 | 午夜精品一区二区三区的区别 | 玩弄人妻少妇500系列视频 | 亚无码乱人伦一区二区 | 99久久久无码国产精品免费 | 狠狠亚洲超碰狼人久久 | 曰韩少妇内射免费播放 | 精品国产成人一区二区三区 | 日本一区二区三区免费播放 | 天干天干啦夜天干天2017 | а√天堂www在线天堂小说 | 欧美性生交活xxxxxdddd | 纯爱无遮挡h肉动漫在线播放 | 老子影院午夜伦不卡 | 亚洲国产精品久久久天堂 | 曰韩无码二三区中文字幕 | 国产国语老龄妇女a片 | 欧美日本精品一区二区三区 | 亚洲精品一区三区三区在线观看 | 在线 国产 欧美 亚洲 天堂 | 亚洲中文字幕av在天堂 | 久久精品一区二区三区四区 | 少妇激情av一区二区 | 内射后入在线观看一区 | 中文字幕无码免费久久9一区9 | 欧美第一黄网免费网站 | 亚洲熟妇色xxxxx欧美老妇y | 给我免费的视频在线观看 | 国产午夜手机精彩视频 | 久久天天躁狠狠躁夜夜免费观看 | 亚洲色欲色欲天天天www | 无码成人精品区在线观看 | 国产精品国产三级国产专播 | 2020久久香蕉国产线看观看 | 亚洲国产精品美女久久久久 | 久久国产精品精品国产色婷婷 | 亚洲中文字幕无码中文字在线 | 久久成人a毛片免费观看网站 | 丁香啪啪综合成人亚洲 | 无码精品人妻一区二区三区av | 欧美兽交xxxx×视频 | 欧美日本日韩 | 一个人免费观看的www视频 | 免费看男女做好爽好硬视频 | 国产成人精品视频ⅴa片软件竹菊 |