|
#include <iostream.h>
#include <string.h>
#include <errno.h>
#include "http.hpp"
// for timeout management
// UNIX: Set a dummy timeout for SIGALRM (otherwise the signal
// aborts the application).
#if OS == UNIX_OS
#include <signal.h>
static void handler (int signo) { }
#endif
// -------------------------------------------------------------
// system dependent functions
// -------------------------------------------------------------
// -------------------------------------------------------------
void Http::set_timer() throw (Http_timer_error)
{
#if OS == UNIX_OS
struct sigaction new_sigalarm;
new_sigalarm.sa_handler = handler;
if (sigemptyset (&new_sigalarm.sa_mask) == -1)
{ throw Http_timer_error(); }
new_sigalarm.sa_flags = 0;
if (sigaction (SIGALRM, &new_sigalarm, NULL) == -1)
{ throw Http_timer_error(); }
#endif
#if 0
#if OS == WINDOWS_OS
if (timeout > 0)
{
int cr;
cr = setsockopt (
sock,
IPPROTO_TCP,
SO_RCVTIMEO,
(char FAR *)&timeout,
sizeof(int)
);
if (cr == SOCKET_ERROR) { throw Http_timer_error(); }
}
#endif
#endif
}
// -------------------------------------------------------------
void Http::set_alarm()
{
#if OS == UNIX_OS
if (timeout > 0) { alarm (timeout); }
#endif
}
// -------------------------------------------------------------
void Http::reset_alarm()
{
#if OS == UNIX_OS
if (timeout > 0) { alarm (0); }
#endif
}
// -------------------------------------------------------------
Http::Http()
{
port = -1;
timeout = -1;
hostname = NULL;
url = NULL;
out_file = NULL;
buffer = NULL;
buffer_size = 0;
}
// -------------------------------------------------------------
Http::Http(char* mhostname, char* mulr, int mport, char* mout_file, int mtimeout) throw (Http_memory_error)
{
set_port(mport);
set_hostname(mhostname);
set_url(mulr);
if (mout_file != NULL) { set_out_file (mout_file); }
set_timeout(mtimeout);
buffer_size = 0;
}
// -------------------------------------------------------------
Http::~Http()
{
if (hostname != NULL) { delete [] hostname; }
if (url != NULL) { delete [] url; }
if (out_file != NULL) { delete [] out_file; }
if (buffer != NULL) { delete [] buffer; }
}
// -------------------------------------------------------------
void Http::re_alloc_buffer() throw (Http_memory_error)
{
char* aux = new char[buffer_size];
if (aux == NULL) { throw Http_memory_error(); }
memcpy (aux, buffer, buffer_size);
delete [] buffer;
buffer_size *= 2;
buffer = new char[buffer_size];
if (buffer == NULL) { delete [] aux; throw Http_memory_error(); }
memcpy (buffer, aux, buffer_size/2);
delete [] aux;
}
// -------------------------------------------------------------
void Http::set_port(int mport)
{ port = mport; }
// -------------------------------------------------------------
void Http::set_timeout(const int mtimeout)
{ timeout = mtimeout; }
// -------------------------------------------------------------
void Http::set_hostname(const char *mhostname) throw (Http_memory_error)
{
if (hostname != NULL) { delete [] hostname; }
hostname = new char[strlen(mhostname)+1];
if (hostname == NULL) { throw Http_memory_error(); }
strncpy (hostname, mhostname, strlen(mhostname)+1);
}
// -------------------------------------------------------------
void Http::set_url (const char *mulr) throw (Http_memory_error)
{
if (url != NULL) { delete [] url; }
url = new char[strlen(mulr)+1];
if (url == NULL) { throw Http_memory_error(); }
strncpy (url, mulr, strlen(mulr)+1);
}
// -------------------------------------------------------------
void Http::set_out_file (const char *mout_file) throw (Http_memory_error)
{
if (out_file != NULL) { delete [] out_file; }
out_file = new char[strlen(mout_file)+1];
if (out_file == NULL) { throw Http_memory_error(); }
strncpy (out_file, mout_file, strlen(mout_file)+1);
}
// -------------------------------------------------------------
void Http::get() throw (Http_memory_error, Http_invalid_args, Http_connect_failed, Http_write_failed, Http_read_failed, Http_timer_error, Http_timeout_connect, Http_timeout_read)
{
int cr;
// -----------------------------------------------------
// Make sure that we don't have stupid args
if (
(hostname == NULL)
¦¦
(url == NULL)
¦¦
(port == -1)
) { throw Http_invalid_args(); }
// -----------------------------------------------------
// Set timers (UNIX: signal SIGALRM)
// This can throw the exception "Http_timer_error")
#if OS == UNIX_OS
set_timer();
#endif
// -----------------------------------------------------
// Try to open the connexion with the server
// Note that "set_alarm()" and "reset_alarm()" are used
// to produce a timeout under UNIX. To do that we use
// signals ... UNIX signals are not supported under Win-
// -dows, For Windows the "connect timeout" is imple-
// -mented using non blocking sockets.
set_alarm();
sock = open_tcp_connexion (&server_address, hostname, port, timeout);
reset_alarm();
if (
(sock == SCK_CREATE_ERROR)
¦¦
(sock == SCK_CONNECT_ERROR)
¦¦
(sock == SCK_GET_IP_ERROR)
¦¦
(sock == SCK_SET_NON_BLOCK_ERR)
¦¦
(sock == SCK_SET_BLOCK_ERR)
) { throw Http_connect_failed(sock); }
if (sock == SCK_TIMEOUT_CONNECT) { throw Http_timeout_connect(); }
#if OS == WINDOWS_OS
set_timer();
#endif
// -----------------------------------------------------
// "GET url".
// Please note that "GET " is 4 characters long.
// Please nothe that " HTTP/1.0" is 9 characters long.
// We alse add 2 "cariage return" at the end of the URL.
// A "cariage return" is 2 characters long "\012\015" (in octal)
// <=> characters 10 and 13 in decimal.
int request_size = strlen("GET ") +
strlen(url) +
strlen(" HTTP/1.0") +
strlen("\nUser-Agent: ApacheBench") +
strlen("\nHost: ") +
strlen(hostname) +
strlen("\nAccept: */*") +
strlen("\012\015\012\015") +
1;
char *request = new char[request_size];
if (request == NULL)
{
CLOSE_SOCKET(sock);
throw Http_memory_error();
}
request[0] = 0;
strcat (request, "GET ");
strcat (request, url);
strcat (request, " HTTP/1.0");
strcat (request, "\nUser-Agent: ApacheBench");
strcat (request, "\nHost: ");
strcat (request, hostname);
strcat (request, "\nAccept: */*");
strcat (request, "\012\015\012\015");
request [request_size-1] = 0;
// -----------------------------------------------------
cr = WRITE_TO_SOCKET(sock, request, request_size, 0);
if (cr != request_size)
{
delete [] request;
CLOSE_SOCKET(sock);
throw Http_write_failed();
}
delete [] request;
// -----------------------------------------------------
// Now get the data
if (buffer != NULL) { delete [] buffer; buffer_size = 0; }
buffer = new char[BUFFER_INIT_SIZE];
if (buffer == NULL)
{
CLOSE_SOCKET(sock);
throw Http_memory_error();
}
buffer_size = BUFFER_INIT_SIZE;
int total_lu = 0;
char *pt = buffer;
int a_lire = buffer_size - total_lu - 1;
#if OS == UNIX_OS
int err;
#endif
set_alarm();
cr = READ_FROM_SOCKET(sock, pt, a_lire, 0);
reset_alarm();
#if OS == UNIX_OS
err = errno;
#endif
if (cr == SCK_ERROR_READ)
{
delete [] buffer;
buffer = NULL;
buffer_size = -1;
CLOSE_SOCKET(sock);
#if OS == UNIX_OS
if (err == EINTR) { throw Http_timeout_read(); }
#endif
throw Http_read_failed();
}
pt[cr] = 0;
total_lu += cr;
// keep in mind that 'buffer_size' is modified by 're_alloc_buffer()'
// while (cr == a_lire)
while (cr > 0)
{
// -------------------------------------------------
// We realloc memory only if we need to ... The read
// from a socket does not necessarily return the
// requested number of bytes.
// -------------------------------------------------
if (total_lu >= buffer_size - 1)
{
try { re_alloc_buffer(); }
catch ( Http_memory_error e )
{
buffer_size = -1;
CLOSE_SOCKET(sock);
throw Http_memory_error();
}
}
pt = buffer + total_lu;
a_lire = buffer_size - total_lu - 1;
set_alarm();
cr = READ_FROM_SOCKET(sock, pt, a_lire, 0);
reset_alarm();
#if OS == UNIX_OS
err = errno;
#endif
if (cr == SCK_ERROR_READ)
{
delete [] buffer;
buffer = NULL;
buffer_size = -1;
CLOSE_SOCKET(sock);
#if OS == UNIX_OS
if (err == EINTR) { throw Http_timeout_read(); }
#endif
throw Http_read_failed();
}
if (cr == 0) { break; }
total_lu += cr;
buffer[total_lu] = 0;
}
buffer_size = total_lu;
CLOSE_SOCKET(sock);
}
// -------------------------------------------------------------
int Http::get_header(char **dest)
{
if (buffer == NULL) { *dest = NULL; return -1; }
// Apache separates the header from the body with the 4 following charaters
// "\012\015\012\015"
// Microsoft server separates the header from the body with the 4 following charaters
// "\015\012\015\012"
char *pt;
// Does it comes from a Microsoft's server ?
pt = strstr (buffer, "\015\012\015\012");
if (pt == NULL)
{
// Does it come from Apache ?
pt = strstr (buffer, "\012\015\012\015");
if (pt == NULL) { *dest = NULL; return -1; }
}
char aux = *pt;
*pt = 0;
int size = strlen(buffer);
*dest = new char[size+1];
if (*dest == NULL) { *pt = aux; *dest=NULL; return -1; }
strncpy(*dest, buffer, size);
(*dest)[size]=0;
*pt = aux;
return size;
}
// -------------------------------------------------------------
int Http::get_status(char **dest)
{
if (buffer == NULL) { *dest = NULL; return -1; }
char *start = strstr (buffer, "HTTP");
if (start == NULL) { *dest = NULL; return -1; }
char *stop = strstr (buffer, "\012");
if (stop == NULL) { *dest = NULL; return -1; }
char aux = *stop;
*stop = 0;
int size = strlen(start);
*dest = new char[size+1];
if (*dest == NULL) { *stop = aux; *dest=NULL; return -1; }
strncpy(*dest, start, size);
(*dest)[size]=0;
*stop = aux;
return size;
}
|
|