cur 以post的方式进行http上传文件(自定义http head)
来源:互联网 发布:软件平台租用合同 编辑:程序博客网 时间:2024/06/06 13:03
最近在项目中需要在嵌入式终端上传录音文件,最后选择了curl来支持该项目,网上现有的一些资源比较简单,并没能满足需求,自己结合curl的example做了改进,具备一下功能:
(1)以post的方式上传文件,并对http head进行了自定义;
(2)文件名封装在附加的文件头里面。
该代码已经测试通过。
/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************//* <DESC> * Issue an HTTP POST and provide the data through the read callback. * </DESC> */#include <stdio.h>#include <string.h>#include <curl/curl.h>typedef enum file_part{ FILE_HEAD_PART = 0, FILE_CONTENT_PART, FILE_END_PART, FILE_TRANSFER_FINISH,}E_FilePart;typedef struct http_upload{ FILE* rFile; // 上传的文件 size_t fileSizeLeft; // 文件剩余字节 size_t filePos; // 文件内容位置 char *headerPtr; // 附加的文件起始头,主要用于(1)告知服务器上传文件的名字;(2)一些自定义参数 size_t headerSizeLeft; // 附加的文件起始头剩余字节 char *endPtr; // 附加的文件结束尾 size_t endSizeLeft; // 附加的文件结束尾剩余字节 E_FilePart filePart; // 0 传输HeaderInfo, 1 传输文件, 2 传输EndInfo, -1则结束 size_t totalSize; // 总共传输的字节数,附加的文件起始头+文件+附加的文件结束尾}T_HttpUpload;#define HTTP_HEAD_MAX_SIZE (256)#define HTTP_END_MAX_SIZE (1024)const char BOUNDARY[] = {"---WebKitFormBoundary"}; // 自定义的附加文件起始头static char sHeaderInfo[HTTP_HEAD_MAX_SIZE];static char sEndInfo[HTTP_END_MAX_SIZE];static size_t read_callback(void *dest, size_t size, size_t nmemb, void *userp){ T_HttpUpload *httpUpload = (T_HttpUpload *)userp; size_t bufferSize = size*nmemb; size_t copyThisMuch; printf("file left %zu, %zu, %zu, size*nmemb = %zu, filePart = %d, totalSize = %zu\n", httpUpload->headerSizeLeft, httpUpload->fileSizeLeft, httpUpload->endSizeLeft, bufferSize, httpUpload->filePart, httpUpload->totalSize); if(FILE_HEAD_PART == httpUpload->filePart) { copyThisMuch = httpUpload->headerSizeLeft; if(copyThisMuch > bufferSize) copyThisMuch = bufferSize; memcpy(dest, httpUpload->headerPtr, copyThisMuch); httpUpload->headerPtr += copyThisMuch; httpUpload->headerSizeLeft -= copyThisMuch; if(httpUpload->headerSizeLeft <= 0) { httpUpload->filePart = FILE_CONTENT_PART; } httpUpload->totalSize += copyThisMuch; return copyThisMuch; } else if(FILE_CONTENT_PART == httpUpload->filePart) { copyThisMuch = httpUpload->fileSizeLeft; if(copyThisMuch > bufferSize) copyThisMuch = bufferSize; copyThisMuch = fread(dest, 1, copyThisMuch, httpUpload->rFile); httpUpload->filePos += copyThisMuch; httpUpload->fileSizeLeft -= copyThisMuch; if(httpUpload->fileSizeLeft <= 0) { httpUpload->filePart = FILE_END_PART; } httpUpload->totalSize += copyThisMuch; return copyThisMuch; } else if(FILE_END_PART == httpUpload->filePart) { copyThisMuch = httpUpload->endSizeLeft; if(copyThisMuch > bufferSize) copyThisMuch = bufferSize; memcpy(dest, httpUpload->endPtr, copyThisMuch); httpUpload->endPtr += copyThisMuch; httpUpload->endSizeLeft -= copyThisMuch; if(httpUpload->endSizeLeft <= 0) { httpUpload->filePart = FILE_TRANSFER_FINISH; } httpUpload->totalSize += copyThisMuch; return copyThisMuch; } else { printf("file transfer finish, totalSize = %zu .............\n", httpUpload->totalSize); } return 0;}int HttpUploadFile(const char* url, const char* fileName){ CURL *curl; CURLcode res; char chunkString[256]; size_t totalSize; /* In windows, this will init the winsock stuff */ res = curl_global_init(CURL_GLOBAL_DEFAULT); /* Check for errors */ if(res != CURLE_OK) { fprintf(stderr, "curl_global_init() failed: %s\n", curl_easy_strerror(res)); return 1; } /* get a curl handle */ curl = curl_easy_init(); if(curl) { T_HttpUpload httpUpload; memset(&httpUpload, sizeof(httpUpload), 0); httpUpload.filePart = FILE_HEAD_PART; httpUpload.totalSize = 0; memset(sHeaderInfo, 0 , HTTP_HEAD_MAX_SIZE); // 设置起始文件头 sprintf(sHeaderInfo, "%s%s%s%s%s%s%s%s%s%s", "--", BOUNDARY, "\r\n", "Content-Disposition: form-data; name=\"", "file", "\"; filename=\"", fileName, "\"", "\r\n", "\r\n"); httpUpload.headerPtr = sHeaderInfo; httpUpload.headerSizeLeft = strlen(httpUpload.headerPtr); // 设置结束文件信息 memset(sEndInfo, 0 , HTTP_END_MAX_SIZE); sprintf(sEndInfo, "%s%s%s","\r\n--", BOUNDARY, "--\r\n" ); httpUpload.endPtr = sEndInfo; httpUpload.endSizeLeft = strlen(httpUpload.endPtr); printf("\n\nHeaderInfo = :%s\n", httpUpload.headerPtr); printf("HeaderInfo End\n"); printf("\nEndInfo = :%s\n", httpUpload.endPtr); printf("EndInfo End\n"); //获取要上传的文件指针 httpUpload.rFile = fopen(fileName, "rb"); if (0 == httpUpload.rFile) { printf("the file %s that you will read is not exist", fileName); return -1; } // 获取文件大小 fseek(httpUpload.rFile, 0, 2); httpUpload.filePos = 0; httpUpload.fileSizeLeft = ftell(httpUpload.rFile); rewind(httpUpload.rFile); /* First set the URL that is about to receive our POST. */ curl_easy_setopt(curl, CURLOPT_URL, url); struct curl_slist *chunk=NULL; /* Remove a header curl would otherwise add by itself */ //chunk = curl_slist_append(chunk, "Accept:"); /* Add a custom header */ //chunk = curl_slist_append(chunk, "Another: yes"); sprintf(chunkString, "%s%s%s", "Content-Type: ", "multipart/form-data; boundary=", BOUNDARY); // 重新设置Content-Type chunk = curl_slist_append(chunk, chunkString); // 上传的文件总长度, 服务器需要剥离附加文件头,以及附加文件尾,中间部分才是文件的实际内容;服务器可以通过文件的文件头解析出文件名字 totalSize = httpUpload.headerSizeLeft + httpUpload.fileSizeLeft + httpUpload.endSizeLeft; sprintf(chunkString, "%s%zu","Content-Length: ", totalSize); chunk = curl_slist_append(chunk, chunkString); /* Modify a header curl otherwise adds differently */ //chunk = curl_slist_append(chunk, "Host: example.com"); /* Add a header with "blank" contents to the right of the colon. Note that we're then using a semicolon in the string we pass to curl! */ //chunk = curl_slist_append(chunk, "X-silly-header;"); /* set our custom set of headers */ res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); /* Now specify we want to POST data */ curl_easy_setopt(curl, CURLOPT_POST, 1L); /* we want to use our own read function */ curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); /* pointer to pass to our read function */ curl_easy_setopt(curl, CURLOPT_READDATA, &httpUpload); /* get verbose debug output please */ curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); /* If you use POST to a HTTP 1.1 server, you can send data without knowing the size before starting the POST if you use chunked encoding. You enable this by adding a header like "Transfer-Encoding: chunked" with CURLOPT_HTTPHEADER. With HTTP 1.0 or without chunked transfer, you must specify the size in the request. */ /* Set the expected POST size. If you want to POST large amounts of data, consider CURLOPT_POSTFIELDSIZE_LARGE */ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)(httpUpload.headerSizeLeft + httpUpload.fileSizeLeft + httpUpload.endSizeLeft)); /* Perform the request, res will get the return code */ res = curl_easy_perform(curl); /* Check for errors */ if(res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); /* always cleanup */ curl_easy_cleanup(curl); } curl_global_cleanup(); return 0;}int main(int argc, char *argv[]){ if(argc < 2) { printf("no input file name ...... \n"); return -1; } if(HttpUploadFile("换成自己的URL地址", argv[1]) != 0) { printf("HttpUploadFile failed\n"); } return 0;}
阅读全文
0 0
- cur 以post的方式进行http上传文件(自定义http head)
- http post方式上传文件
- 关于通过http post进行文件上传的问题
- vc中如何通过http的post方式上传文件
- http以post方式上传一个文件,构造其请求头和消息报文(转载)
- http以post方式上传一个文件,构造其请求头和消息报文
- http以post方式上传一个文件,构造其请求头和消息报文
- [转载]http以post方式上传一个文件,构造其请求头和消息报文
- http以post方式上传一个文件,构造其请求头和消息报文
- http以post方式上传一个文件,构造其请求头和消息报文
- http post 上传文件
- HTTP POST上传文件
- HTTP POST的文件上传问题
- 基于 HTTP POST multipart 的文件上传
- HTTP POST上传文件的格式说明
- HTTP POST上传文件的格式示范
- 安卓使用HttpClient进行Http Post文件上传
- http post 文件上传解析
- 输入法遮挡登录按钮及输入框问题
- Eclipes:设置显示代码行号Show line mumber
- 7. DMA模块初见(ADC模块深入实践)
- Java 算法练习 ——— CodeWar Day 2
- IOS APP中,使用h5播放器,默认打开网页的时候,会自动全屏,解决方法webkit-playsinline
- cur 以post的方式进行http上传文件(自定义http head)
- 不知道何时开始的程序员之路
- 再谈Qt实现Rasdial拨号问题(说说项目中遇到的问题和解决方案)
- FTP客户端的代码实现
- Git pull避免用户名和密码方法
- 干货丨一文读懂深度学习(附学习资源,据说点赞2W+)
- 深度丨AI挑战人类情感!机器人写诗出书背后透露了什么?
- CSS 黑魔法小技巧,让你少写不必要的JS,代码更优雅
- Bootstrap 之Table样式