Here is some code I wrote for automating HTTP GETs. I haven't posted the bit that figures out the exact URLs, that would be naughty:
Code:
class HttpConnection
{
protected:
SOCKET m_socket;
bool m_connected;
const char *m_site;
bool readBytes(unsigned char *buffer, unsigned int size);
char readChar();
bool getLine(char *buffer, unsigned int buffersize);
public:
HttpConnection(const char *site);
~HttpConnection();
bool connected() const;
bool grabAndSaveFile(const char *name, const char *file);
};
bool HttpConnection::readBytes(unsigned char *buffer, unsigned int size)
{
// Then do a direct read
while (size)
{
// Find out how much is waiting
unsigned long waiting = 0;
do
{
int err = ioctlsocket(m_socket, FIONREAD, &waiting);
if(err)
return false;
if (!waiting)
Sleep(100);
}
while (!waiting);
// Clamp to the amount required
if(waiting > size)
waiting = size;
int ret = recv(m_socket, (char *)buffer, waiting, 0);
if (ret > 0)
{
buffer += ret;
size -= ret;
}
}
while(size);
return true;
}
char HttpConnection::readChar()
{
unsigned char buffer;
if (readBytes(&buffer, 1))
return buffer;
return 0;
}
bool HttpConnection::getLine(char *buffer, unsigned int buffersize)
{
int a;
unsigned int c = 0;
do
{
a = readChar();
if(isalpha(a))
a = tolower(a);
*buffer++ = (char)a;
c++;
}
while (((a == '\r') || (a != '\n')) && c < (buffersize - 1));
*buffer = 0;
return true;
}
HttpConnection::HttpConnection(const char *site)
: m_socket(INVALID_SOCKET)
, m_connected(false)
, m_site(site)
{
// Get the site details
struct hostent *hostEntry = gethostbyname(site);
if (hostEntry)
{
m_socket = socket(AF_INET, SOCK_STREAM, 0);
if (m_socket >= 0)
{
// Try opening the socket
struct sockaddr_in sockAddress;
memset((char *)&sockAddress,0,sizeof(sockAddress));
sockAddress.sin_family = AF_INET;
memcpy((char *)&sockAddress.sin_addr, hostEntry->h_addr, hostEntry->h_length);
sockAddress.sin_port = htons((short)80);
m_connected = (connect(m_socket,(struct sockaddr *)&sockAddress,16) >= 0);
}
}
}
HttpConnection::~HttpConnection()
{
if (m_socket != INVALID_SOCKET)
closesocket(m_socket);
m_socket = INVALID_SOCKET;
m_connected = false;
}
bool HttpConnection::connected() const
{
return m_connected;
}
bool HttpConnection::grabAndSaveFile(const char *name, const char *file)
{
// Generate and send the HTTP request
char str[1024];
sprintf(str, "GET /%s HTTP/1.1\r\nAccept: */*\r\nUser-Agent: Me\r\nHost: %s\r\nConnection: Keep-alive\r\n\r\n", name, m_site);
int err = send(m_socket, str, (int)strlen(str), 0);
// Iterate the lines until a blank one appears prior to the data
int header = 1;
int contentLength = 0;
int amountRead = 0;
// Receive and parse http header.
do
{
char line[1024];
getLine(line, 1024);
// Try getting the content length
if(!contentLength)
sscanf(line, "content-length: %d", &contentLength);
if(line[0]=='\n' || line[0]=='\r')
header = 0;
}
while(header);
// Grab file if we have a content length
if(contentLength)
{
unsigned char *buffer = new unsigned char [contentLength];
if (buffer)
{
readBytes(buffer, contentLength);
OutputDebugString("Grabbing ");
OutputDebugString(file);
OutputDebugString("\n");
FILE *fptr = fopen(file, "wb");
if (fptr)
{
fwrite(buffer, contentLength, 1, fptr);
fclose(fptr);
}
delete [] buffer;
}
}
return true;
}
Usage is along the lines of:
Code:
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
int err = WSAStartup(wVersionRequested, &wsaData);
if(err == 0)
{
{
// Conventional maps
HttpConnection connection(<insert hostname here>);
if (connection.connected())
{
connection.grabAndSaveFile(<urlWithoutHostname>, <filenameToSaveAs>);
// Repeat grabAndSaveFile as many times as you need.
}
}
WSACleanup();
}
Bookmarks