This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

 

  HTTP Client Class
  Submitted by



This submission is a very quick-n-easy HTTP client class. With it, you can submit a URL to the web at large, and receive a string containing the contents of the web page.

Naturally, it doesn't load pictures or anything like that. My purpose in writing this was to have a high score CGI program and a News Update CGI program residing on my server-- I simply submit the url with a request code, and down comes the string with the requested data. Works well, so far. I am currently implementing a Battle.Net style lobby to work with this class, making an inexpensive game lobby that can reside on most ISPs. To implement, just do this:
HTTPClient Client;
Client.Request("microsoft.com","/index.html");
while (C.Wait(10000)==FALSE) {}
 if (C.result==HTTP_ERROR) {
  MessageBox(0,C.buffer,"Error",MB_OK);
  }
 else MessageBox(0,C.buffer,"RESULT String",MB_OK); 



Essentially, you call HTTPClient::Request and then watch the status of HTTPClient::result to wait for a result. While the request is pending, its status will be HTTP_WAITING. Other values are HTTP_CANCEL (if you cancelled the request), HTTP_TIMEOUT (if the time specified in HTTPClient::Wait elapses) or HTTP_OK, which means that the contents of the web page are now sitting in HTTPClient::buffer.

HTTPClient::Client.Request(host, path)
Requests a web page from a web server. If the url is www.microsoft.com/index.html then the host is "microsoft.com" and the path is "/index.html". HTTPClient::Wait(seconds)
Just a helper function if you want to sit and wait for the page response. It will put HTTP_TIMEOUT in HTTPClient::result if the 'seconds' has elapsed without a response. HTTPClient:Cancel()
Cancels any current requests. Happens automatically if you re-request when a request is pending. So, when you run this, you'll get the "source" of www.microsoft.com/index.html in a message box. Unless there's an error-- in that case, you'll get the string of the error in the message box. Note that the client itself is multithreaded-- you can submit a request when your program starts up, and then come back later to see if anything has come back. This is what I did for my news ticker: When the program starts up, it submits a quickie request to the server to see if there is any news or program updates. Later, when the menu screen comes up, if news has arrived, a news button is "enabled," and the user can click on the button to be taken to the news webpage with their default browser. If you want it to operate in the background, just eliminate the C.Wait() loop. Note that the request you make depends on whether your ISP has a proxy server handling your account. For a dedicated server, you just send a hostname and directory path (like the microsoft example above). If you are on a proxy server, your request should look like this: Client.Request("mysite.com","http://www.mysite.com/mypath.html"); It also works with CGI-BIN code (which is how I'm using it). If you'd like the source to a small CGI-BIN program that it can work with, e-mail me at John@Raptisoft.com. To use this code, you need to link in WSOCK32.LIB.

Currently browsing [HTTPClient.zip] (1,969 bytes) - [HTTPClient.h] - (1,296 bytes)

// HTTPClient.h: interface for the HTTPClient class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_HTTPCLIENT_H__2A78F088_AB6C_4971_BF0F_F9DC0C5B80AD__INCLUDED_)
#define AFX_HTTPCLIENT_H__2A78F088_AB6C_4971_BF0F_F9DC0C5B80AD__INCLUDED_

#if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include <winsock2.h>

#define MAX_RECEIVABLE 80000 #define MAX_URL_LENGTH 256

#define HTTP 0

typedef struct { int protocol; int port;

char host[MAX_URL_LENGTH]; char url[MAX_URL_LENGTH]; } CONNECTSTRUCT, *LPCONNECTSTRUCT;

#define HTTP_WAITING 0 #define HTTP_OK 1 #define HTTP_ERROR 2 #define HTTP_CANCEL 3 #define HTTP_TIMEOUT 4 #define MAX_RECEIVABLE 80000

class HTTPClient { public: void Request(char *host, char *url); HTTPClient(); virtual ~HTTPClient();

WSADATA WSAData;

struct sockaddr_in server_addr; struct hostent *hostent; //CONNECTSTRUCT connect; BOOL ready; int HTTPsocket; HANDLE RecvThread; DWORD ThreadID; long basetime;

public: BOOL Wait(int time); void Cancel(void); int result; char buffer[MAX_RECEIVABLE+1]; };

#endif // !defined(AFX_HTTPCLIENT_H__2A78F088_AB6C_4971_BF0F_F9DC0C5B80AD__INCLUDED_)

Currently browsing [HTTPClient.zip] (1,969 bytes) - [HTTPClient.cpp] - (3,232 bytes)

// HTTPClient.cpp: implementation of the HTTPClient class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "HTTPClient.h"

DWORD WINAPI RecvProc(LPVOID lpParameter) { HTTPClient *c=(HTTPClient*)lpParameter;

int returncode=recv(c->HTTPsocket,c->buffer,MAX_RECEIVABLE,0); if (returncode<0) { closesocket(c->HTTPsocket); c->result=HTTP_ERROR; strcpy(c->buffer,"Could not receive server response"); return TRUE; }

c->result=HTTP_OK; closesocket(c->HTTPsocket); return TRUE; }

////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// HTTPClient::HTTPClient() { hostent=NULL; ready=FALSE; HTTPsocket=-1;

if (WSAStartup(MAKEWORD(1,1),&WSAData)!=0) { char szError[1024]; wsprintf(szError,TEXT("WSAStartup failed. Error: %d"),WSAGetLastError()); MessageBox (NULL, szError, TEXT("Error"), MB_OK); return; }

ready=TRUE; }

HTTPClient::~HTTPClient() { if (hostent!=NULL) delete hostent; if (ready==TRUE) WSACleanup(); } void HTTPClient::Request(char *host, char *url) { if (result==HTTP_WAITING) Cancel();

if (hostent!=NULL) delete hostent; if (ready==FALSE) { result=HTTP_ERROR; strcpy(buffer,"Winsock did not start up correctly"); return; }

if (strlen(url)>MAX_URL_LENGTH || strlen(host)>MAX_URL_LENGTH) { result=HTTP_ERROR; strcpy(buffer,"Host or URL string is too long."); return; }

hostent=gethostbyname(host); if (hostent==NULL) { result=HTTP_ERROR; strcpy(buffer,"Host was not found."); return; }

char *temp=(char *)inet_ntoa(*((struct in_addr *)hostent->h_addr)); int IPInteger=inet_addr(temp);

HTTPsocket=socket(AF_INET,SOCK_STREAM,0); if (HTTPsocket<0) { result=HTTP_ERROR; strcpy(buffer,"Could not create HTTP socket"); return; }

server_addr.sin_family=AF_INET; server_addr.sin_port=htons(80); server_addr.sin_addr.s_addr=IPInteger; ZeroMemory(&server_addr.sin_zero,8);

int addrlen = sizeof(struct sockaddr); int returncode=connect(HTTPsocket,(struct sockaddr*)&server_addr,sizeof(struct sockaddr)); if (returncode<0) { closesocket(HTTPsocket); result=HTTP_ERROR; strcpy(buffer,"Could not connect to server"); return; }

buffer[0]=0; strcat(buffer,"GET "); strcat(buffer,url); strcat(buffer," HTTP/1.0"); strcat(buffer,"\015\012\000"); // CRLF strcat(buffer,"User-Agent:CustomClient/1.0"); strcat(buffer,"\015\012\000"); // CRLF strcat(buffer,"\015\012\000"); // CRFL result=HTTP_WAITING;

int bytes_sent=send(HTTPsocket,buffer,strlen(buffer),0); if (bytes_sent<0) { closesocket(HTTPsocket); result=HTTP_ERROR; strcpy(buffer,"Could not send URL request"); return; }

basetime=GetTickCount(); RecvThread=CreateThread(NULL,NULL,RecvProc,this,0,&ThreadID); }

void HTTPClient::Cancel() { result=HTTP_CANCEL; TerminateThread(RecvThread,0); }

BOOL HTTPClient::Wait(int time) { if ((long)GetTickCount()>(basetime+time)) result=HTTP_TIMEOUT; if (result!=HTTP_WAITING) return TRUE; return FALSE; }

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

 

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.