简体   繁体   English

使用C的原始libcurl JSON PUT请求

[英]a raw libcurl JSON PUT request using C

I am currently writing a REST-like client that only is required to do PUT requests. 我目前正在编写类似REST的客户端,只需要执行PUT请求。

Problem: 问题:
Running the program is not giving me the correct results on the URL's API and I do not know why. 运行该程序并没有在URL的API上给我正确的结果,我不知道为什么。

Using curl_easy_perform(curl) does not throw an error when called. 使用curl_easy_perform(curl)不会在调用时抛出错误。 But the expected result is not generated on the URL's API. 但是,不会在URL的API上生成预期结果。

Using curl_easy_send(curl,..,..,..) throws a : unsupported protocol error 使用curl_easy_send(curl,..,..,..)会抛出:不支持的协议错误

Assumption: 假设:
I am assuming the order in which I am using the curl_easy_opts is a problem? 我假设我使用curl_easy_opts的顺序是个问题? And I am even missing a couple of key lines? 我甚至错过了几条关键线?

I have been reading on here of how other people do PUT requests and have been using their methods. 我一直在这里阅读其他人如何做PUT请求并一直在使用他们的方法。

Summary of Program: 计划摘要:

My program prompts the user for some string/character data, and from that, I construct the strings myself such as the header and the payload. 我的程序提示用户输入一些字符串/字符数据,从中我自己构造字符串,例如标题和有效负载。 The header and payload are both in JSON format but the payload is simply a string ( in this case, a char *str = (char *)mallo.. etc). 标头和有效负载都是JSON格式,但有效负载只是一个字符串(在这种情况下,char * str =(char *)mallo ...等)。 How the header is constructed is shown below. 标题的构造方式如下所示。

My header is being constructed using 我的标题正在使用

struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept: application/json");
//there is more content being appended to the header

The CURL function calls : CURL函数调用:

    //init winsock stuff
    curl_global_init(CURL_GLOBAL_ALL);

    //get a curl handle
    curl = curl_easy_init();

if(curl){
    //append the headers
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

    //specify the target URL
    curl_easy_setopt(curl, CURLOPT_URL, url);

    //connect ( //i added this here since curl_easy_send() says it requires it. )
    curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY,1L); 

    //specify the request (PUT in our case)
    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");

    //append the payload
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload);

    res = curl_easy_perform(curl);
    //res = curl_easy_send(curl, payload, strlen(payload),&iolen);

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

    curl_easy_cleanup(curl);
}

You should not be using the CURLOPT_CONNECT_ONLY option or curl_easy_send() function, those are intended to be used for custom, non-HTTP protocols. 您不应该使用CURLOPT_CONNECT_ONLY选项或curl_easy_send()函数,这些函数旨在用于自定义的非HTTP协议。

See this page for an example of how to do a PUT request with libcurl. 有关如何使用libcurl执行PUT请求的示例,请参阅此页面 Basically, you want to enable the CURLOPT_UPLOAD and CURLOPT_PUT options to say that you're doing a PUT request and to enable uploading a body with the request, and then you set the CURLOPT_READDATA and CURLOPT_INFILESIZE_LARGE options to tell libcurl how to read the data you're uploading and how big the data is. 基本上,您希望启用CURLOPT_UPLOADCURLOPT_PUT选项来表示您正在执行PUT请求并启用上传带有请求的正文,然后设置CURLOPT_READDATACURLOPT_INFILESIZE_LARGE选项以告诉libcurl如何读取您的数据重新上传以及数据有多大。

In your case, if you already have the data in memory, then you don't need to read it out of a file, and you can just memcpy() it inside your read callback. 在您的情况下,如果您已经将数据存储在内存中,那么您不需要从文件中读取数据,并且您可以在读取回调中memcpy()它。

Example code copied below: 下面复制的示例代码:

/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) 1998 - 2012, 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 http://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.
 *
 ***************************************************************************/ 
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <curl/curl.h>

/*
 * This example shows a HTTP PUT operation. PUTs a file given as a command
 * line argument to the URL also given on the command line.
 *
 * This example also uses its own read callback.
 *
 * Here's an article on how to setup a PUT handler for Apache:
 * http://www.apacheweek.com/features/put
 */ 

static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
{
  size_t retcode;
  curl_off_t nread;

  /* in real-world cases, this would probably get this data differently
     as this fread() stuff is exactly what the library already would do
     by default internally */ 
  retcode = fread(ptr, size, nmemb, stream);

  nread = (curl_off_t)retcode;

  fprintf(stderr, "*** We read %" CURL_FORMAT_CURL_OFF_T
          " bytes from file\n", nread);

  return retcode;
}

int main(int argc, char **argv)
{
  CURL *curl;
  CURLcode res;
  FILE * hd_src ;
  struct stat file_info;

  char *file;
  char *url;

  if(argc < 3)
    return 1;

  file= argv[1];
  url = argv[2];

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

  /* get a FILE * of the same file, could also be made with
     fdopen() from the previous descriptor, but hey this is just
     an example! */ 
  hd_src = fopen(file, "rb");

  /* In windows, this will init the winsock stuff */ 
  curl_global_init(CURL_GLOBAL_ALL);

  /* get a curl handle */ 
  curl = curl_easy_init();
  if(curl) {
    /* we want to use our own read function */ 
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);

    /* enable uploading */ 
    curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);

    /* HTTP PUT please */ 
    curl_easy_setopt(curl, CURLOPT_PUT, 1L);

    /* specify target URL, and note that this URL should include a file
       name, not only a directory */ 
    curl_easy_setopt(curl, CURLOPT_URL, url);

    /* now specify which file to upload */ 
    curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);

    /* provide the size of the upload, we specicially typecast the value
       to curl_off_t since we must be sure to use the correct data size */ 
    curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,
                     (curl_off_t)file_info.st_size);

    /* Now run off and do what you've been told! */ 
    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);
  }
  fclose(hd_src); /* close the local file */ 

  curl_global_cleanup();
  return 0;
}

I agree, don't use CUSTOMREQUEST. 我同意,不要使用CUSTOMREQUEST。 One detail that is being missed on every related to PUT and CURL I've seen here is that you NEED to set the file size, otherwise you'll get HTTP error 411. Use CURLOPT_INFILESIZE or CURLOPT_INFILESIZE_LARGE for that. 我在这里看到的每一个与PUT和CURL相关的细节都是你需要设置文件大小,否则你会得到HTTP错误411.使用CURLOPT_INFILESIZE或CURLOPT_INFILESIZE_LARGE。 See more details here: 在这里查看更多详情:

How do I send long PUT data in libcurl without using file pointers? 如何在不使用文件指针的情况下在libcurl中发送长PUT数据?

I know this is a very old question, but in case somebody want to use libcurl with GLib and json-glib to send a JSON with PUT request. 我知道这是一个非常古老的问题,但是如果有人想使用带有GLib和json-glib的libcurl来发送带有PUT请求的JSON。 Code below works for me: 以下代码对我有用:

    #include <curl/curl.h>
    #include <json-glib/json-glib.h>

    //this is callback function for CURLOPT_READFUNCTION: 

    static size_t
    curlPutJson ( void *ptr, size_t size, size_t nmemb, void *_putData )
    {
            GString *putData = ( GString * ) _putData;
            size_t realsize = ( size_t ) putData->len;
            memcpy ( ptr, putData->str, realsize );
            return realsize;
    }

   /*now inside main or other function*/

   //json_to_string ( jsonNode, FALSE ) is from json-glib to stringify JSON
   //created in jsonNode

   GString *putData = g_string_new ( json_to_string ( mainNode, FALSE ) );

   //now goes curl as usual: headers, url, other options and so on
   //and 4 most important lines

   curl_easy_setopt ( curl, CURLOPT_READFUNCTION, curlPutJson );
   curl_easy_setopt ( curl, CURLOPT_UPLOAD, 1L );

   curl_easy_setopt ( curl, CURLOPT_READDATA, putData );        //GString
   curl_easy_setopt ( curl, CURLOPT_INFILESIZE, putData->len ); //type long     

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM