cURL / Mailing Lists / curl-library / Single Mail

curl-library

Problem with curl_formadd()

From: Byrial Jensen <byrial_at_vip.cybercity.dk>
Date: Tue, 23 Jul 2013 21:34:03 +0200

Hi,

I am writing a bot to edit www.wikidata.org using libcurl.

I have a problem with curl_formadd() which I suspect is a bug:

My statement of the form

   curl_formadd (&post, &last, CURLFORM_PTRNAME, name,
                 CURLFORM_FILECONTENT, "file.txt", CURLFORM_END)

fails with CURLcode 2 (CURLE_FAILED_INIT) which I do not understand. I
have sample program to demonstrate the problem. It will do a simple
query about site information with a multipart/form-data:

$ cat curltest.c
#include <curl/curl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char *buffer = 0;
size_t buffer_len = 0;

void print_curl_error_and_exit (CURLcode code, const char *text)
{
    printf ("libcurl error %d: %s: %s\n",
           code, text, curl_easy_strerror (code));
    exit (1);
}

size_t write_callback (char *ptr, size_t size, size_t nmemb, void *userdata)
{
    size *= nmemb;
    buffer = realloc (buffer, buffer_len + size);
    if (! buffer)
      {
        printf ("Could allocate memory for buffer.\n");
        exit (1);
      }
    strncpy (buffer + buffer_len, ptr, size);
    buffer_len += size;
    return size;
}

int main (int argc, char * const argv[])
{
    FILE *fp = fopen ("file.txt", "w");
    fprintf (fp, "general");
    fclose (fp);

    int use_copy = (argc > 1 && strcmp (argv[1], "usecopy") == 0);

    CURLcode ret;
    if ((ret = curl_global_init (CURL_GLOBAL_ALL)))
      print_curl_error_and_exit (ret, "curl_global_init () failed.");

    CURL *curl = curl_easy_init ();
    if (! curl)
      {
        printf ("curl_easy_init () failed.\n");
        exit (1);
      }

    if ((ret = curl_easy_setopt (curl, CURLOPT_URL,
"http://www.wikidata.org/w/api.php")))
      print_curl_error_and_exit (ret, "Setting URL failed.");

    if ((ret = curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION,
write_callback)))
      print_curl_error_and_exit (ret, "Setting WRITEFUNCTION failed");

    struct curl_httppost *post = NULL;
    struct curl_httppost *last = NULL;

    if ((ret = curl_formadd (&post, &last,
                            CURLFORM_PTRNAME, "action", CURLFORM_PTRCONTENTS, "query",
                            CURLFORM_END)))
      print_curl_error_and_exit (ret, "curl_formadd action failed");
    if ((ret = curl_formadd (&post, &last,
                            CURLFORM_PTRNAME, "meta", CURLFORM_PTRCONTENTS, "siteinfo",
                            CURLFORM_END)))
      print_curl_error_and_exit (ret, "curl_formadd meta failed");
    if ((ret = curl_formadd (&post, &last,
                            CURLFORM_PTRNAME, "format", CURLFORM_PTRCONTENTS, "xml",
                            CURLFORM_END)))
      print_curl_error_and_exit (ret, "curl_formadd summary failed");

    if ((ret = curl_formadd (&post, &last,
                            use_copy ? CURLFORM_COPYNAME : CURLFORM_PTRNAME, "siprop",
                            CURLFORM_FILECONTENT, "file.txt",
                            CURLFORM_END)))
      print_curl_error_and_exit (ret, "curl_formadd siprop failed");

    if ((ret = curl_easy_setopt (curl, CURLOPT_HTTPPOST, post)))
      print_curl_error_and_exit (ret, "curl_easy_setopt HTTPPOST failed");

    struct curl_slist *list = curl_slist_append (NULL, "Expect:");
    if ((ret = curl_easy_setopt (curl, CURLOPT_HTTPHEADER, list)))
      print_curl_error_and_exit (ret, "curl_easy_setopt HTTPHEADER failed");

    if ((ret = curl_easy_perform (curl)))
      print_curl_error_and_exit (ret, "curl_easy_perform failed");

    printf ("Received reply: %*s\n", buffer_len, buffer);
}
$ make
gcc -g -Wall -Wextra -O2 curltest.o -o curltest
-L/usr/lib/i386-linux-gnu -lcurl -Wl,-Bsymbolic-functions -Wl,-z,relro
$ ./curltest
libcurl error 2: curl_formadd siprop failed: Failed initialization
$ ./curltest usecopy
Received reply: <?xml version="1.0"?><api><query><general
mainpage="Wikidata:Main Page"
base="http://www.wikidata.org/wiki/Wikidata:Main_Page"
sitename="Wikidata" generator="MediaWiki 1.22wmf11"
phpversion="5.3.10-1ubuntu3.6+wmf1" phpsapi="apache2handler"
dbtype="mysql" dbversion="5.5.30-MariaDB-mariadb1~precise-log"
imagewhitelistenabled="" langconversion="" titleconversion=""
linkprefix="" linktrail="/^([a-z]+)(.*)$/sD"
git-hash="ab0ce3585411601379f73cf7562aee8eb836a36f" case="first-letter"
rights="Creative Commons Attribution-Share Alike 3.0 Unported" lang="en"
fallback8bitEncoding="windows-1252" writeapi="" timezone="UTC"
timeoffset="0" articlepath="/wiki/$1" scriptpath="/w"
script="/w/index.php" variantarticlepath="" server="//www.wikidata.org"
wikiid="wikidatawiki" time="2013-07-23T19:21:34Z" misermode=""
maxuploadsize="524288000"><fallback /></general></query></api>
$ curl --version
curl 7.22.0 (i686-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1
zlib/1.2.3.4 libidn/1.23 librtmp/2.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap pop3
pop3s rtmp rtsp smtp smtps telnet tftp
Features: GSS-Negotiate IDN IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP

As you see if I use CURLFORM_COPYNAME instead of CURLFORM_PTRNAME, it
works fine. I do not understand why, and I think it is silly to have to
copy a constant string.

Is this a bug or did I do something wrong?

Thank you for your time.
Regards,
Byrial
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html
Received on 2013-07-23