难点补充
1
oid SendRequest(RequestContext *request_context) { if (request_context->is_running) { PRINTLNF("request already running ...."); return; } CURL *curl = curl_easy_init(); if (!curl) { request_context->curl_code = -1; return; } //参数配置 curl_easy_setopt(curl, CURLOPT_URL, request_context->url); //对于http 返回请求302 重定向做一处理 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); //这里解析文件名称 文件大小 文件!是什么 curl_easy_setopt(curl, CURLOPT_NOBODY, request_context->header_only); curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, CurlHeaderFunction); curl_easy_setopt(curl, CURLOPT_HEADERDATA, request_context); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlBodyFunction); curl_easy_setopt(curl, CURLOPT_WRITEDATA, request_context); //进度回调 if (request_context->request->progress_callback) { curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, CurlProgressFunction); curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, request_context); } //断点续传 char content_range[40]; if (request_context->range_start >= 0 && request_context->range_end >= 0) { //先下载一部分 //9223372036854775808-9223372036854775808 | 838TB snprintf(content_range, 40, "%llu-%llu", request_context->range_start, request_context->range_end); } else if (request_context->range_start >= 0) { //暂停后开始 //9223372036854775808- | 838TB snprintf(content_range, 40, "%llu-", request_context->range_start); } else if (request_context->range_end >= 0) { //-9223372036854775808 | 838TB snprintf(content_range, 40, "-%llu", request_context->range_end); } else { // no range request. content_range[0] = 0; } if (content_range[0] > 0) { PRINTLNF("content-range: %s", content_range); CURLcode code = curl_easy_setopt(curl, CURLOPT_RANGE, content_range); } curl_easy_setopt(curl, CURLOPT_CAINFO, "cacert.pem"); curl_easy_setopt(curl, CURLOPT_CAPATH, "cacert.pem"); request_context->curl = curl; request_context->is_running = 1; //请求得到返回值 调用这句话的时候 请求 request_context->curl_code = curl_easy_perform(curl); request_context->curl = NULL; request_context->is_running = 0; curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &request_context->file_size); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &request_context->response_code); // 找不到文件名 header里面没有对应的字段 解析不出来字段 就根据URL 解析 if (request_context->header_only && !request_context->output_filename) { RetrieveOutputNameFromUrl(request_context); } if (request_context->output_stream) { fclose(request_context->output_stream); request_context->output_stream = NULL; } curl_easy_cleanup(curl); }
对于断点设定就是结构体里面初始化两个变量 然后根据里面的值进行判断下载 一般就是暂停保存一下 然后开始的时候读取那个点
typedef struct RequestContext { Request *request; char *url; char *download_directory; int header_only; int64_t range_start; int64_t range_end;
还有就是多线程下载要注意的问题
RequestContext *CreateRequestContext(Request *request, const char *url, const char *directory) { CREATE_OBJECT_CLEANED(RequestContext, context); context->request = request; //复制一下为多线程做准备 url 是复制一份 以防止多线程私有栈被释放 context->url = strdup(url); context->download_directory = strdup(directory); context->file_size = 0; context->range_start = -1; context->range_end = -1; context->is_running = 0; return context; }
header中找不到字段的话去url 里面找
// 找不到文件名 header里面没有对应的字段 解析不出来字段 就根据URL 解析 if (request_context->header_only && !request_context->output_filename) { RetrieveOutputNameFromUrl(request_context); } // header 里面没有字段 就根据 url 解析 就是解析 task 里面的最后一个文件名 static int RetrieveOutputNameFromUrl(RequestContext *context) { int result = RESULT_OK; char output_filename[1024]; char const *url = context->url; // http://www.bennyhuo.com/testdata/三国演义.txt?param=1 // http://www.bennyhuo.com/testdata/三国演义.txt#chapter1 // http://www.bennyhuo.com/testdata/%E4%B8%89%E5%9B%BD%E6%BC%94%E4%B9%89.txt?param=1 url = strrchr(url, '/'); url++; int i = 0; while (*url != '\0' && *url != '?' && *url != '#') { output_filename[i++] = *url++; } output_filename[i] = '\0'; char *url_decoded_filename = curl_easy_unescape(context->curl, output_filename, 0, NULL); context->output_filename = strdup(url_decoded_filename); curl_free(url_decoded_filename); return result; }
printf("%.*s", (int) buffer_size, buffer); 传入点 * 自己设定字符串大小
在http 的url 协议中是不会自己传递 汉字的都是编码后的结果 所以拿到的都是编码后的内容 要进行解码
strdup()在内部调用了malloc()为变量分配内存,不需要使用返回的字符串时,需要用free()释放相应的内存空间,否则会造成内存泄漏。
static int RetrieveOutputNameFromUrl(RequestContext *context) { int result = RESULT_OK; char output_filename[1024]; char const *url = context->url; // http://www.bennyhuo.com/testdata/三国演义.txt?param=1 // http://www.bennyhuo.com/testdata/三国演义.txt#chapter1 // http://www.bennyhuo.com/testdata/%E4%B8%89%E5%9B%BD%E6%BC%94%E4%B9%89.txt?param=1 url = strrchr(url, '/'); url++; int i = 0; while (*url != '\0' && *url != '?' && *url != '#') { output_filename[i++] = *url++; } output_filename[i] = '\0'; char *url_decoded_filename = curl_easy_unescape(context->curl, output_filename, 0, NULL); context->output_filename = strdup(url_decoded_filename); curl_free(url_decoded_filename); return result;
如果Http 返回值是206 是支持断点续传