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
原创粉丝点击