难点补充
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 是支持断点续传