如何将libcurl用于HTTP PUT Xively

时间:2014-10-13 23:06:34

标签: linux http libcurl

我想让HTTPS PUT请求放一个csv文件。下面是用于将数据上传到Xively的代码。早些时候我得到411长度要求的错误。我提到了这里可用的代码(Send string in PUT request with libcurl)来解决这个问题,其中进行了CURLOPT_CUSTOMREQUEST。现在我收到HTTP 500内部服务器错误。

void upload()
{
   CURL *curl;
   CURLcode res;
   FILE * hd_src;
   struct stat file_info;
   struct curl_slist* header  = NULL;
   char * csvfile = "123.csv";

   /* get the file size */
   stat(csvfile, &file_info);

   hd_src = fopen("123.csv","rb");

   curl_global_init(CURL_GLOBAL_ALL);

   curl = curl_easy_init();

   if(curl)
   {

        header  = curl_slist_append(header,"X-ApiKey: 123123123"); /* API KEY HERE - sample only*/
        header = curl_slist_append(header,"Accept: text/csv");
        header = curl_slist_append(header, "Host: api.xively.com"); 

        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

        /* Actual Xively feed  is here. For demonstration purpose the feed is listed as 123 */
        curl_easy_setopt(curl, CURLOPT_URL, "https://api.xively.com/v2/feeds/123.csv");

        curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);
        curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);

        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT" );
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, hd_src);

        res = curl_easy_perform(curl); 

        if(res != CURLE_OK)
        {
            fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
        }
        curl_easy_cleanup(curl);        
   }
   fclose(hd_src);   
   curl_slist_free_all(header);
   curl_global_cleanup();
}

有人可以提出建议吗?如果我删除curl_easy_setopt(curl,CURLOPT_POSTFIELDS,hd_src),我将得到411长度所需的错误。我删除了这个并使用file_info.st_size将Content-Length添加到标头中。再次收到411长度要求的错误。使用curl_easy_setopt(curl,CURLOPT_POSTFIELDS,hd_src)411已解决,但Xively提供500内部服务器错误。

提前致谢。

1 个答案:

答案 0 :(得分:1)

请尝试使用CURLOPT_UPLOAD,例如documentation说:

  

CURLOPT_PUT - 发出HTTP PUT请求
  ...
  自版本7.12.1起不推荐使用此选项。使用CURLOPT_UPLOAD!

  

CURLOPT_UPLOAD - 启用数据上传
  ...
  如果协议是HTTP,则上传意味着使用PUT请求,除非您告诉libcurl

你必须非常小心CURLOPT_CUSTOMREQUEST

  

CURLOPT_CUSTOMREQUEST - 请求的自定义字符串
  ...
  当您通过将CURLOPT_CUSTOMREQUEST设置为某个更改请求方法时,您实际上并未更改libcurl对特定请求方法的行为或行为方式,它只会更改请求中发送的实际字符串
  ...
  许多人错误地使用此选项用自己的请求替换整个请求,包括多个标头和POST内容。虽然在许多情况下这可能会起作用,但它会导致libcurl发送无效请求,并且可能会严重混淆远程服务器。

您也没有发送Content-Type标头,而是发送Accept标头。 Content-Type告诉服务器您要发送的数据类型。 Accept告诉服务器您愿意收到哪些类型的数据。

最后,您没有在stat()fopen()上进行错误处理。

请改为尝试:

void upload()
{
    CURL *curl;
    CURLcode res;
    FILE * hd_src;
    struct stat file_info = {0};
    struct curl_slist* header = NULL;
    char * csvfile = "C:\\full path to\\123.csv";

    /* get the file size */
    if (stat(csvfile, &file_info) == -1)
    {
        fprintf(stderr, "stat() failed: %s\n", strerror(errno));
        return;
    }

    hd_src = fopen(csvfile, "rb");
    if (!hd_src)
    {
        fprintf(stderr, "fopen() failed: %s\n", strerror(errno));
        return;
    }  

    curl_global_init(CURL_GLOBAL_ALL);

    curl = curl_easy_init();
    if (!curl)
    {
        fprintf(stderr, "curl_easy_init() failed\n");
    }
    else
    {
        header = curl_slist_append(header, "X-ApiKey: 123123123"); /* API KEY HERE - sample only*/
        header = curl_slist_append(header, "Content-Type: text/csv");

        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

        /* Actual Xively feed  is here. For demonstration purpose the feed is listed as 123 */
        curl_easy_setopt(curl, CURLOPT_URL, "https://api.xively.com/v2/feeds/123.csv");

        curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);
        curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);

        curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L );

        res = curl_easy_perform(curl); 
        if (res != CURLE_OK)
            fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));

        curl_slist_free_all(header);
        curl_easy_cleanup(curl);        
    }

    fclose(hd_src);   

    curl_global_cleanup();
}