Thread: HTTP File Upload Libcurl

  1. #16
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    I'm still seeing this in your code
    Code:
    char *REMOTE_URL = "http://iss.netii.net/projects/message/";
    and I really think I shouldn't be.

  2. #17
    Registered User
    Join Date
    Dec 2007
    Posts
    2,675
    You're trying to do an HTTP PUT to an Apache server. I don't believe that Apache supports PUT out of the box, hence the "Method not allowed" error. You need to properly configure Apache to support PUT. Here's one link to that end.

  3. #18
    Registered User
    Join Date
    Mar 2011
    Posts
    216
    Quote Originally Posted by tabstop View Post
    I'm still seeing this in your code
    Code:
    char *REMOTE_URL = "http://iss.netii.net/projects/message/";
    and I really think I shouldn't be.
    No this is the new code.

    Code:
    #include <stdio.h>
    #include <string.h>
     
    #include <curl/curl.h>
    #include <curl/types.h> 
    #include <curl/easy.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <errno.h>
    #ifdef WIN32
    #include <io.h>
    #else
    #include <unistd.h>
    #endif
     
    /*
     * This example shows an FTP upload, with a rename of the file just after
     * a successful upload.
     *
     * Example based on source code provided by Erick Nuwendam. Thanks!
     */ 
     
    #define LOCAL_FILE      "feed.txt"
    #define RENAME_FILE_TO  "feed.zip"
    #define UPLOAD_FILE_AS  "feed.txt"
    
     
    /* NOTE: if you want this example to work on Windows with libcurl as a
       DLL, you MUST also provide a read callback with CURLOPT_READFUNCTION.
       Failing to do so will give you a crash since a DLL may not use the
       variable's memory when passed in to it from an app like this. */ 
    static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
    {
      /* 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 */ 
      size_t retcode = fread(ptr, size, nmemb, stream);
     
      printf("*** We read %d bytes from file\n", retcode);
      return retcode;
    }
     
    int main(void)
    {
      CURL *curl;
      CURLcode res;
      FILE *hd_src;
      struct stat file_info;
      curl_off_t fsize;
      
      char *REMOTE_URL = "ftp://iss.netii.net/projects/message/";
     
      struct curl_slist *headerlist=NULL;
      static const char buf_1 [] = "RNFR " UPLOAD_FILE_AS;
      static const char buf_2 [] = "RNTO " RENAME_FILE_TO;
     
      /* get the file size of the local file */ 
      if(stat(LOCAL_FILE, &file_info)) {
        printf("Couldnt open '%s': %s\n", LOCAL_FILE, strerror(errno));
        return 1;
      }
      fsize = (curl_off_t)file_info.st_size;
     
      printf("Local file size: %" CURL_FORMAT_CURL_OFF_T " bytes.\n", fsize);
     
      /* get a FILE * of the same file */ 
      hd_src = fopen(LOCAL_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) {
        /* build a list of commands to pass to libcurl */ 
        headerlist = curl_slist_append(headerlist, buf_1);
        headerlist = curl_slist_append(headerlist, buf_2);
     
        /* 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);
     
        /* specify target */ 
        curl_easy_setopt(curl,CURLOPT_URL, REMOTE_URL);
     
        /* pass in that last of FTP commands to run after the transfer */ 
        curl_easy_setopt(curl, CURLOPT_POSTQUOTE, headerlist);
     
        /* now specify which file to upload */ 
        curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);
        
        /* specify username and password for ftp */
        curl_easy_setopt(curl, CURLOPT_USERNAME, "username");
        curl_easy_setopt(curl, CURLOPT_PASSWORD, "password");
     
        /* Set the size of the file to upload (optional).  If you give a *_LARGE
           option you MUST make sure that the type of the passed-in argument is a
           curl_off_t. If you use CURLOPT_INFILESIZE (without _LARGE) you must
           make sure that to pass in a type 'long' argument. */ 
        curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,
                         (curl_off_t)fsize);
     
        /* Now run off and do what you've been told! */ 
        res = curl_easy_perform(curl);
     
        /* clean up the FTP commands list */ 
        curl_slist_free_all (headerlist);
     
        /* always cleanup */ 
        curl_easy_cleanup(curl);
      }
      fclose(hd_src); /* close the local file */ 
      getchar();
      curl_global_cleanup();
      return 0;
    }
    See, the code seems fine, but it's my server permissions that are messed up.

    In regards to the above post, this is just a free server I'm using for testing purposes. I don't have full access to the Apache server, as it's from 000webhost. (but I do have .htaccess support)

    How can I get around this problem?
    Last edited by binks; 07-21-2011 at 12:26 PM.

  4. #19
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    To be frank here, you aren't doing the greatest job of "earning" our help. You really don't seem to be making an effort to understand FTP or curl. You're just scoop-and-pooping the curl example, and when it doesn't work, you post here and say "please fix", without giving us any details of how you're supposed to connect. There is nothing wrong with your C code, or your overall use of libcurl. Your problem is that you don't understand FTP or how the server is set up. To figure out how it is set up, you have to check with whoever hosts your website (000webhost?). They should have some documentation on how to upload files for your free website. That should tell you the connection details for FTP (and HTTP if it's supported). At the very least, they should have a web form or email address for contacting support. Their site/support team should get you going on what specific curl options you need to set.

    Considering this is just a free server you're using for testing, what works here might not work on your production server, so you definitely need to understand how to use HTTP and/or FTP thoroughly so you can easily convert your code to work with your production server, come time.

    As for help with your specific, current problem, why don't you try turning verbose output back on, and try Googling whatever error message curl spits out when it tells you you failed. I'd bet good money you're not the first person to ever come across that error, and that your question has been asked and answered a number of times in a number of different forums, and recorded for posterity. An incredibly important part of being a programming is learning how to research your problem and look through existing documentation, tutorials, forums, etc and apply that knowledge to your own solution.

    Please, don't post back here until you have the connection info for uploading files to your web site and have made some effort to figure this out on your own (beyond copying a tutorial).

  5. #20
    Registered User
    Join Date
    Mar 2011
    Posts
    216
    I got it working, and I found out thanks to your advice of enabling verbose tracing! I love you for that!!

    Here is the final code, and output, for anyone else facing this issue.

    Code:
    #include <stdio.h>
    #include <string.h>
     
    #include <curl/curl.h>
    #include <curl/types.h> 
    #include <curl/easy.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <errno.h>
    #ifdef WIN32
    #include <io.h>
    #else
    #include <unistd.h>
    #endif
     
    /*
     * This example shows an FTP upload, with a rename of the file just after
     * a successful upload.
     *
     * Example based on source code provided by Erick Nuwendam. Thanks!
     */ 
     
    #define LOCAL_FILE      "feed.txt"
    #define RENAME_FILE_TO  "feed.zip"
    #define UPLOAD_FILE_AS  "feed.txt"
    
     
    /* NOTE: if you want this example to work on Windows with libcurl as a
       DLL, you MUST also provide a read callback with CURLOPT_READFUNCTION.
       Failing to do so will give you a crash since a DLL may not use the
       variable's memory when passed in to it from an app like this. */ 
    static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
    {
      /* 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 */ 
      size_t retcode = fread(ptr, size, nmemb, stream);
     
      printf("*** We read %d bytes from file\n", retcode);
      return retcode;
    }
     
    int main(void)
    {
      CURL *curl;
      CURLcode res;
      FILE *hd_src;
      struct stat file_info;
      double speed_upload, total_time;
      curl_off_t fsize;
      // I had to add public_html as a folder, because it said there was no projects directory.  As well as add the filename to the final URL below
      char *REMOTE_URL = "ftp://iss.netii.net/public_html/projects/message/feed.zip";
     
      struct curl_slist *headerlist=NULL;
      static const char buf_1 [] = "RNFR " UPLOAD_FILE_AS;
      static const char buf_2 [] = "RNTO " RENAME_FILE_TO;
     
      /* get the file size of the local file */ 
      if(stat(LOCAL_FILE, &file_info)) {
        printf("Couldnt open '%s': %s\n", LOCAL_FILE, strerror(errno));
        return 1;
      }
      fsize = (curl_off_t)file_info.st_size;
     
      printf("Local file size: %" CURL_FORMAT_CURL_OFF_T " bytes.\n", fsize);
     
      /* get a FILE * of the same file */ 
      hd_src = fopen(LOCAL_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) {
        /* build a list of commands to pass to libcurl */ 
        headerlist = curl_slist_append(headerlist, buf_1);
        headerlist = curl_slist_append(headerlist, buf_2);
     
        /* 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);
     
        /* specify target */ 
        curl_easy_setopt(curl,CURLOPT_URL, REMOTE_URL);
     
        /* pass in that last of FTP commands to run after the transfer */ 
        curl_easy_setopt(curl, CURLOPT_POSTQUOTE, headerlist);
     
        /* now specify which file to upload */ 
        curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);
        
        /* specify username and password for ftp */
        curl_easy_setopt(curl, CURLOPT_USERNAME, "username");
        curl_easy_setopt(curl, CURLOPT_PASSWORD, "password");
     
        /* Set the size of the file to upload (optional).  If you give a *_LARGE
           option you MUST make sure that the type of the passed-in argument is a
           curl_off_t. If you use CURLOPT_INFILESIZE (without _LARGE) you must
           make sure that to pass in a type 'long' argument. */ 
        curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,
                         (curl_off_t)fsize);
                         
        /* enable verbose for easier tracing */ 
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
     
        /* Now run off and do what you've been told! */ 
        res = curl_easy_perform(curl);
        
        /* now extract transfer info */ 
        curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &speed_upload);
        curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time);
     
        printf("Speed: %.3f bytes/sec during %.3f seconds\n", speed_upload, total_time);
     
        /* clean up the FTP commands list */ 
        curl_slist_free_all (headerlist);
     
        /* always cleanup */ 
        curl_easy_cleanup(curl);
      }
      fclose(hd_src); /* close the local file */ 
      getchar();
      curl_global_cleanup();
      return 0;
    }
    And the output

    HTTP File Upload Libcurl-log4-success-jpg

    libcurl did the rest, as it found it was passive mode, among other things.

    Thank you so much for your help!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 03-30-2011, 10:39 AM
  2. libcurl to file
    By starternewb in forum C Programming
    Replies: 1
    Last Post: 03-15-2011, 07:45 AM
  3. file upload form in c++
    By Yarin in forum A Brief History of Cprogramming.com
    Replies: 1
    Last Post: 10-17-2008, 01:13 PM
  4. File Upload with libcurl
    By Tonto in forum Networking/Device Communication
    Replies: 4
    Last Post: 03-15-2006, 06:11 PM
  5. Anyone know a good file upload routine.
    By bjdea1 in forum C Programming
    Replies: 2
    Last Post: 12-08-2001, 12:04 PM

Tags for this Thread