Skip to main content
GameDev.net gamedev.net
🔒 Locked

GET or POST url in any language

Started by Glass_Knife Mar 23, 2007 at 9:48 PM 3 replies 1.5k views
Original Post
Glass_Knife
Glass_Knife
Recently I have been looking at the different ways to create a web service. I am not talking about a web page service, but a service that could be used by an application, like when you put a CD in your computer and it downloads the track names. I have looked at rcp, xml-rpc, SOAP, REST, JSON-RPC, and custom peer-to-peer. Of all these choices, the RESTful web-service is the most interesting. An example of getting some information from java looks like this...

import java.io.BufferedInputStream;
import java.io.StringWriter;
import java.net.URL;
import java.net.URLConnection;

public class UrlTest {

    public static void main( String[] args ) throws Exception {
        URLConnection conn = new URL("http://www.gamedev.net").openConnection();
        BufferedInputStream in = new BufferedInputStream(conn.getInputStream());
        StringWriter out = new StringWriter();
        int read;
        while((read = in.read()) != -1) {
            out.write(read);
        }
        System.out.println(out.toString());
    }

}

It is amazing that you can get information in this way without messing with connections, ports, sockets, threads, etc... Now I realize that getting the webpage is a neat trick, but if that URL returned some data in xml, you have a service. So my question is, does anyone out there know how do this in C++. I spent some time looking at libraries, but I could not find one that I liked. I am sure the right library is out there, I just don't know what it is. If you have ever done this in C++, please share it with us. Thanks
drowner
drowner
libcurl

Quote:

libcurl is a free and easy-to-use client-side URL transfer library, supporting FTP, FTPS, HTTP, HTTPS, SCP, SFTP, TFTP, TELNET, DICT, FILE and LDAP. libcurl supports SSL certificates, HTTP POST, HTTP PUT, FTP uploading, HTTP form based upload, proxies, cookies, user+password authentication (Basic, Digest, NTLM, Negotiate, Kerberos4), file transfer resume, http proxy tunneling and more!

libcurl is highly portable, it builds and works identically on numerous platforms, including Solaris, NetBSD, FreeBSD, OpenBSD, Darwin, HPUX, IRIX, AIX, Tru64, Linux, UnixWare, HURD, Windows, Amiga, OS/2, BeOs, Mac OS X, Ultrix, QNX, OpenVMS, RISC OS, Novell NetWare, DOS and more...

libcurl is free, thread-safe, IPv6 compatible, feature rich, well supported, fast, thoroughly documented and is already used by many known, big and successful companies and numerous applications.


and I suppose a sample couldn't hurt...

 #include <stdio.h> #include <curl/curl.h>  int main(void) {   CURL *curl;   CURLcode res;    curl = curl_easy_init();   if(curl) {     curl_easy_setopt(curl, CURLOPT_URL, "curl.haxx.se");     res = curl_easy_perform(curl);      /* always cleanup */     curl_easy_cleanup(curl);   }   return 0; } 
------------------------------------------------------------// TODO: Insert clever comment here.
DJHoy
DJHoy
Well, it's certainly doable, but a total pain in the butt using straight C++ - libcurl is certainly an easier alternative... BUT - if you want a straight implementation - here's a win32 version (I also have a linux version if you want that also):

#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <winsock2.h>#include <errno.h>/** be sure to include wsock32.lib library! **/#pragma comment (lib, "wsock32.lib")/** function prototypes **/char *extendString(char *currentString, int numExtra);char *getRequest(char *host, char *request, char *username, char *password);/** * a simple main to test the code */void main() {  // you need to startup the winsock library!  WSAData wsaData;  WSAStartup(MAKEWORD(2,2), &wsaData);  char *retText=getRequest("www.test.com", "index.html");  if (retText) {    printf("OK:\nText: %s\n\n", retText);    delete retText;  } else {    printf("Error retrieving text!\n";  }  // and cleanup the winsock library...  WSACleanup();}/** * Extends the string by numExtra bytes and returns a new string */char *extendString(char *currentString, int numExtra) {  // make sure we have proper parameters  if (!currentString || (numExtra < 1)) return NULL;  // get the new string allocation length  int currentLen=strlen(currentString);  int newLen=currentLen+numExtra+1;  // create the new string  char *newString=new char[newLen];  if (!newString) return NULL;  // copy the old string into the new one  sprintf(newString, "%s\0", currentString);  return newString;}/** * our main function: * takes a host and the request line * and fetches the data from the server. * * returns NULL on failure. */char *getRequest(char *host, char *request) {  // ensure we have valid parameters  if (!host || !request)  return NULL;  // open a connection to the host  int socketID;  struct sockaddr_in serverSocket;  struct hostent *serverIP;  memset ((char *) &serverSocket, 0, sizeof (serverSocket));  // make sure we can get the host's IP address  if ((serverIP = gethostbyname (host))==NULL) return NULL;  // setup our socket parameters  serverSocket.sin_family = AF_INET;  memcpy (&(serverSocket.sin_addr.s_addr), serverIP->h_addr_list[0], serverIP->h_length);  // set our socket for port 80  serverSocket.sin_port = htons (80);  // create the socket  if ((socketID = socket (AF_INET, SOCK_STREAM, 0)) < 0) return NULL;  // connect to the HTTP server  if (connect (socketID, (struct sockaddr *) &serverSocket, sizeof (serverSocket)) < 0) return NULL;  // create our return char[]  // and initialize it with nothing  char *retVal=new char[1];  retVal[0]=0;  // keep a counter of how many bytes we've allocated...  int currentRetValAlloc=1;  // create our GET command  // make sure to use the "Host:" command if there's the  // possibility of the website hosted with virtual hosting  // and and emulate Mozilla 4.0 compatibility  char getCmd[2048];  sprintf(getCmd, "GET %s HTTP/1.1\nHost: %s:80\nUser-Agent: Mozilla/4.0 (compatible)\n\n", request, host);  // send our GET command  if (sendto (socketID, getCmd, strlen(getCmd), 0, (struct sockaddr *) &serverSocket, sizeof(serverSocket)) < 0) {     closesocket(socketID);     delete retVal;    return NULL;  }  // get the response  // header and all  // create a temp buffer to read into  char tmpReadBuffer[8192];  memset(tmpReadBuffer, 0, 8192);  int nread=0;  // our read loop  while ((nread = recvfrom (socketID, tmpReadBuffer, 8192, 0, NULL, NULL)) > 0) {  // get the length of the current string  // to see if we need to extend it    int currentLen=strlen(retVal);    if ((currentLen+nread) > (currentRetValAlloc-1)) {       // yes - extend it...      char *tmpExtent=extendString(retVal, nread);      if (!tmpExtent) {         // error - abort.           closesocket(socketID);           delete retVal;           return NULL;       }      // replace the old one with the new  delete retVal;  retVal=tmpExtent;  // and add our additional length to the counter  currentRetValAlloc+=nread;}    // concatenate the new string to the end    strncat(retVal, tmpReadBuffer, nread);    // clear our buffer (just in case)    memset(tmpReadBuffer, 0, 8192);  }  // close the socket  closesocket(socketID);  // return the buffer - caller is responsible  // for deleting the return value  return retVal;}

Sneftel
Sneftel
Yikes. A lot of allocation errors in that one. Why, oh why not use the STL?
Glass_Knife
Glass_Knife
Quote:
Original post by DJHoy
Well, it's certainly doable, but a total pain in the butt using straight C++ - libcurl is certainly an easier alternative...


Using the pure C++ code is realy a pain, isn't it. RESTful web services don't look so great if it is not easy to call them.

Quote:
Original post by drowner
and I suppose a sample couldn't hurt...


Thats what I was looking for. A simple C++ wrapper around that library and it could be really easy.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.