Download a file from the internet, with C++

Discussion in 'Mac Programming' started by ruimac, Sep 25, 2014.

  1. ruimac macrumors newbie

    Joined:
    Sep 24, 2014
    #1
    In my site, I created a folder where I store registration files. I protected that folder with a username/password so that only I can access it.
    I want to insert code in my application that would access that protected folder to check if there was a file there.
    So, how can I access a file in the net that is inside a protected folder, using C++?
    It also needs to be cross platform because I develop in Xcode but then I send my source code to Visual Studio and compile Win32 and Win64 versions (this is for plugin development, not standalone apps).
    I already solved this using python (it is sooooo easy, with python) but some of my plugins are coded in C++ and I wanted to do the same with C++.
    But it seems to be rather complicated with C++ :-(
    Does anyone have a solution for this?
     
  2. ruimac thread starter macrumors newbie

    Joined:
    Sep 24, 2014
    #2
    Let me add that I don't want to download the file into a file.
    I just want to read the content of the file. It is simply a small .txt file that I want to read from. Just 10 characters.
     
  3. ruimac thread starter macrumors newbie

    Joined:
    Sep 24, 2014
    #3
    This is so extremely simple in python. This is my python code:

    import urllib2
    from urllib2 import URLError, HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, install_opener, build_opener

    def check_online(url,username,password):

    try:
    password_mgr.add_password(None, url, username, password)
    opener = build_opener(HTTPBasicAuthHandler(password_mgr))
    file = opener.open(url+"/myfile.txt")
    content=file.read()
    file.close()

    except:
    content=""

    return content

    Why is it so complicated in C++?!?
     
  4. balamw Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #4
  5. ruimac, Sep 25, 2014
    Last edited by a moderator: Sep 25, 2014

    ruimac thread starter macrumors newbie

    Joined:
    Sep 24, 2014
    #5
    Well, I reached as far as:

    Code:
    	CURL *curl;
    	CURLcode res;
    	char* usrpass="my_username:my_password";
    	char* pointer="1234567890";
    	
    	curl = curl_easy_init();
    	if(curl) {
    		curl_easy_setopt(curl, CURLOPT_URL, "http://my_url_pointing_to_the_file");
    		curl_easy_setopt(curl, CURLOPT_USERPWD , usrpass);
    
    		curl_easy_setopt(curl, CURLOPT_READDATA, pointer); 
    		curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
    		
    		/* 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);
    	}
    
    But, when building, I get:

    Code:
    Undefined symbols for architecture x86_64:
      "_curl_easy_init", referenced from:
          PluginStart() in main.o
      "_curl_easy_setopt", referenced from:
          PluginStart() in main.o
      "_curl_easy_perform", referenced from:
          PluginStart() in main.o
      "_curl_easy_strerror", referenced from:
          PluginStart() in main.o
      "_curl_easy_cleanup", referenced from:
          PluginStart() in main.o
    ld: symbol(s) not found for architecture x86_64
     
  6. lloyddean macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
    #6
    Did you link to the 'curl' library, which is already installed on the system, at -

    </usr/lib/libcurl.dylib>
     
  7. ruimac thread starter macrumors newbie

    Joined:
    Sep 24, 2014
    #7
    Nope... how do I do that?
    Sorry for being so "stupid" but I'm really not a professional programmer.
     
  8. Madd the Sane macrumors 6502a

    Madd the Sane

    Joined:
    Nov 8, 2010
    Location:
    Utah
    #8
    For the quick and dirty answer, add the following to your linker arguments:
    Code:
    -lcurl
    Are you building your source in Xcode?
     
  9. ruimac thread starter macrumors newbie

    Joined:
    Sep 24, 2014
    #9
    Yes, my source code is being typed in Xcode.
    After it runs ok on Mac (it is a plugin for Cinema 4D), I take it to Visual Studio and compile it for Win32 and Win64.
     
  10. ruimac thread starter macrumors newbie

    Joined:
    Sep 24, 2014
    #10
    From what I found in the internet, I should add -lcurl to the Other Linker Flags.
    However, I already have stuff in there that is required for the Cinema 4D plugin project, namely:

    For Debug: $(C4D_ROOTDIR)/resource/_api_lib/lib_api_debug.a
    For Release: $(C4D_ROOTDIR)/resource/_api_lib/lib_api_release.a

    This means that in Other Linker Flags I have <Multiple Values>

    How can I add that library, then?

    Oh, by the way, I'm using Xcode 4.6.3
    I have to use that version for developing the plugins.
     
  11. ruimac thread starter macrumors newbie

    Joined:
    Sep 24, 2014
    #11
    Definitely, in python is easier ;-)
    But I still need to do it in C++.
    So, any help is greatly appreciated.
     
  12. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #12
    You've got this a bit backwards. Guido wanted to know why C/C++ (and everything else) was so damn complicated so he made Python. C++ was first released in 1983 while Python didn't appear until 1991.

    ... Python is older than I am. That is weird.
     
  13. Madd the Sane, Sep 25, 2014
    Last edited: Sep 25, 2014

    Madd the Sane macrumors 6502a

    Madd the Sane

    Joined:
    Nov 8, 2010
    Location:
    Utah
    #13
    Are the Other Linker Flags for the target bolded? If not, you can double-click on it and change it to this:
    Code:
    -lcurl $(inherited)
    If it is, then it'll be a bit more complicated: you'll need to click on the disclosure triangle and add -lcurl at the end of the list of Other Linker Flags.
    Another option is going into "Build Phases", expand "Link Binary With Libraries", click the add button, search for libcurl, and add "libcurl.dylib".
     
  14. ruimac, Sep 26, 2014
    Last edited by a moderator: Sep 27, 2014

    ruimac thread starter macrumors newbie

    Joined:
    Sep 24, 2014
    #14
    Thank you sooooo much.
    I finally was able to compile it :)

    However, the code still doesn't download the content of the file.
    I even tried with a simple URL that does not require any username/password and it seems not to be working.
    This is my current code:

    Code:
    CURL *curl;
    CURLcode res;
    char* value="1234567890"; // since I need to download just 10 characters
    	
    curl = curl_easy_init();
    if(curl) {
    	curl_easy_setopt(curl, CURLOPT_URL, "http://www.ruimac.com/files/count.txt");
    		
    	curl_easy_setopt(curl, CURLOPT_READDATA, *value); 
    	curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
    		
    	res = curl_easy_perform(curl);
    	/* Check for errors */ 
    	if(res != CURLE_OK) GePrint ("Error!");
    		
    	/* always cleanup */ 
    	curl_easy_cleanup(curl);
    		
    	GePrint(value);
    }
    What I get is an output in the Console that reads: 1234567890
    This means that the value variable was not affected and, I assume, nothing was read. But the res variable returns CURLE_OK
     
  15. ruimac thread starter macrumors newbie

    Joined:
    Sep 24, 2014
    #15
    YES!!!
    Found it!!!!
    It is here:

    http://curl.haxx.se/libcurl/c/getinmemory.html

    What was preventing me to find out sooner was the fact that I wanted to READ the content of a file from the net and, weirdly, what was needed was CURLOPT WRITEDATA and CURLOPT_WRITEFUNCTION.
    Not very obvious.
     
  16. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #16
    For libcurl, a download from a remote host uses the WRITEDATA and WRITEFUNCTION options. The READDATA and READFUNCTION options are for uploads (e.g. an HTTP POST).

    See this example:
    http://curl.haxx.se/libcurl/c/getinmemory.html

    That example is linked to from the WRITEDATA doc page:
    http://curl.haxx.se/libcurl/c/CURLOPT_WRITEDATA.html

    EDIT: I see you found the correct example.

    I recommend trying the example exactly as given in the curl examples, including the use of the example.com URL. That URL is valid; it's an IETF example website, and you can check it in any browser.

    After the exact original example is confirmed to work, change only the URL being retrieved. Confirm it still works as expected using your non-password-protected URL. Then you can modify the working code one step at a time, compile it, test it, and make sure it continues working after every step. If it stops working, then you know that the change you just made is what broke it.

    If you can't figure out why the code stops working, then post the last working code, and the non-working code.

    Finally, please use code tags.
     
  17. mrichmon macrumors 6502a

    Joined:
    Jun 17, 2003
    #17
    The curl command will generate C code that implements the curl command-line. You can then link this C code into your C++, or refactor the C code into C++ to suit your needs.

    For example, assuming the command "curl http://www.macrumors.com" retrieves the URL you want to access, then the command "curl http://www.macrumors.com --libcurl foo.c" will generate code in the foo.c file that implements the HTTP GET.
     
  18. ruimac thread starter macrumors newbie

    Joined:
    Sep 24, 2014
    #18
    I managed to make it work (at least for Mac OS).
    But it is good to know that.
    Thank you.
     

Share This Page