3
* VBox frontends: Qt GUI ("VirtualBox"):
5
* Modified for VirtualBox. Original copyright below.
9
* Copyright (C) 2006-2007 innotek GmbH
11
* This file is part of VirtualBox Open Source Edition (OSE), as
12
* available from http://www.virtualbox.org. This file is free software;
13
* you can redistribute it and/or modify it under the terms of the GNU
14
* General Public License as published by the Free Software Foundation,
15
* in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
16
* distribution. VirtualBox OSE is distributed in the hope that it will
17
* be useful, but WITHOUT ANY WARRANTY of any kind.
22
* HappyHTTP - a simple HTTP library
25
* Copyright (c) 2006 Ben Campbell
27
* This software is provided 'as-is', without any express or implied
28
* warranty. In no event will the authors be held liable for any damages
29
* arising from the use of this software.
31
* Permission is granted to anyone to use this software for any purpose,
32
* including commercial applications, and to alter it and redistribute it
33
* freely, subject to the following restrictions:
35
* 1. The origin of this software must not be misrepresented; you must not
36
* claim that you wrote the original software. If you use this software in a
37
* product, an acknowledgment in the product documentation would be
38
* appreciated but is not required.
40
* 2. Altered source versions must be plainly marked as such, and must not
41
* be misrepresented as being the original software.
43
* 3. This notice may not be removed or altered from any source distribution.
48
#include "HappyHttp.h"
51
// #include <sys/types.h>
52
#include <sys/socket.h>
53
#include <netinet/in.h>
54
#include <arpa/inet.h>
55
#include <netdb.h> // for gethostbyname()
57
#include <unistd.h> // close
62
#define vsnprintf _vsnprintf
63
#define strcasecmp _stricmp
76
#include <iprt/ctype.h>
86
const char* GetWinsockErrorString( int err );
90
//---------------------------------------------------------------------
92
//---------------------------------------------------------------------
96
void BailOnSocketError( const char* context )
100
int e = WSAGetLastError();
101
const char* msg = GetWinsockErrorString( e );
103
const char* msg = strerror( errno );
105
throw Wobbly( "%s: %s", context, msg );
111
const char* GetWinsockErrorString( int err )
115
case 0: return "No error";
116
case WSAEINTR: return "Interrupted system call";
117
case WSAEBADF: return "Bad file number";
118
case WSAEACCES: return "Permission denied";
119
case WSAEFAULT: return "Bad address";
120
case WSAEINVAL: return "Invalid argument";
121
case WSAEMFILE: return "Too many open sockets";
122
case WSAEWOULDBLOCK: return "Operation would block";
123
case WSAEINPROGRESS: return "Operation now in progress";
124
case WSAEALREADY: return "Operation already in progress";
125
case WSAENOTSOCK: return "Socket operation on non-socket";
126
case WSAEDESTADDRREQ: return "Destination address required";
127
case WSAEMSGSIZE: return "Message too long";
128
case WSAEPROTOTYPE: return "Protocol wrong type for socket";
129
case WSAENOPROTOOPT: return "Bad protocol option";
130
case WSAEPROTONOSUPPORT: return "Protocol not supported";
131
case WSAESOCKTNOSUPPORT: return "Socket type not supported";
132
case WSAEOPNOTSUPP: return "Operation not supported on socket";
133
case WSAEPFNOSUPPORT: return "Protocol family not supported";
134
case WSAEAFNOSUPPORT: return "Address family not supported";
135
case WSAEADDRINUSE: return "Address already in use";
136
case WSAEADDRNOTAVAIL: return "Can't assign requested address";
137
case WSAENETDOWN: return "Network is down";
138
case WSAENETUNREACH: return "Network is unreachable";
139
case WSAENETRESET: return "Net connection reset";
140
case WSAECONNABORTED: return "Software caused connection abort";
141
case WSAECONNRESET: return "Connection reset by peer";
142
case WSAENOBUFS: return "No buffer space available";
143
case WSAEISCONN: return "Socket is already connected";
144
case WSAENOTCONN: return "Socket is not connected";
145
case WSAESHUTDOWN: return "Can't send after socket shutdown";
146
case WSAETOOMANYREFS: return "Too many references, can't splice";
147
case WSAETIMEDOUT: return "Connection timed out";
148
case WSAECONNREFUSED: return "Connection refused";
149
case WSAELOOP: return "Too many levels of symbolic links";
150
case WSAENAMETOOLONG: return "File name too long";
151
case WSAEHOSTDOWN: return "Host is down";
152
case WSAEHOSTUNREACH: return "No route to host";
153
case WSAENOTEMPTY: return "Directory not empty";
154
case WSAEPROCLIM: return "Too many processes";
155
case WSAEUSERS: return "Too many users";
156
case WSAEDQUOT: return "Disc quota exceeded";
157
case WSAESTALE: return "Stale NFS file handle";
158
case WSAEREMOTE: return "Too many levels of remote in path";
159
case WSASYSNOTREADY: return "Network system is unavailable";
160
case WSAVERNOTSUPPORTED: return "Winsock version out of range";
161
case WSANOTINITIALISED: return "WSAStartup not yet called";
162
case WSAEDISCON: return "Graceful shutdown in progress";
163
case WSAHOST_NOT_FOUND: return "Host not found";
164
case WSANO_DATA: return "No host data of that type was found";
170
#endif // RT_OS_WINDOWS
173
// return true if socket has data waiting to be read
174
bool datawaiting( int sock )
178
FD_SET( sock, &fds );
184
int r = select( sock+1, &fds, NULL, NULL, &tv);
186
BailOnSocketError( "select" );
188
if( FD_ISSET( sock, &fds ) )
195
// Try to work out address from string
197
struct in_addr *atoaddr( const char* address)
199
struct hostent *host;
200
static struct in_addr saddr;
202
// First try nnn.nnn.nnn.nnn form
203
saddr.s_addr = inet_addr(address);
204
if (saddr.s_addr != INADDR_NONE)
207
host = gethostbyname(address);
209
return (struct in_addr *) *host->h_addr_list;
220
//---------------------------------------------------------------------
224
//---------------------------------------------------------------------
227
Wobbly::Wobbly( const char* fmt, ... )
231
int n = vsnprintf( m_Message, MAXLEN, fmt, ap );
234
m_Message[MAXLEN-1] = '\0';
244
//---------------------------------------------------------------------
248
//---------------------------------------------------------------------
249
Connection::Connection( const char* host, int port ) :
250
m_ResponseBeginCB(0),
252
m_ResponseCompleteCB(0),
262
int ret = WSAStartup(MAKEWORD(1,1), &wsaData);
267
void Connection::setcallbacks(
268
ResponseBegin_CB begincb,
269
ResponseData_CB datacb,
270
ResponseComplete_CB completecb,
273
m_ResponseBeginCB = begincb;
274
m_ResponseDataCB = datacb;
275
m_ResponseCompleteCB = completecb;
276
m_UserData = userdata;
280
void Connection::connect()
282
in_addr* addr = atoaddr( m_Host.c_str() );
284
throw Wobbly( "Invalid network address" );
287
memset( (char*)&address, 0, sizeof(address) );
288
address.sin_family = AF_INET;
289
address.sin_port = htons( m_Port );
290
address.sin_addr.s_addr = addr->s_addr;
292
m_Sock = socket( AF_INET, SOCK_STREAM, 0 );
294
BailOnSocketError( "socket()" );
296
// printf("Connecting to %s on port %d.\n",inet_ntoa(*addr), port);
298
if( ::connect( m_Sock, (sockaddr const*)&address, sizeof(address) ) < 0 )
299
BailOnSocketError( "connect()" );
303
void Connection::close()
307
::closesocket( m_Sock );
314
// discard any incomplete responses
315
while( !m_Outstanding.empty() )
317
delete m_Outstanding.front();
318
m_Outstanding.pop_front();
323
Connection::~Connection()
328
void Connection::request( const char* method,
330
const char* headers[],
331
const unsigned char* body,
335
bool gotcontentlength = false; // already in headers?
337
// check headers for content-length
338
// TODO: check for "Host" and "Accept-Encoding" too
339
// and avoid adding them ourselves in putrequest()
342
const char** h = headers;
345
const char* name = *h++;
346
const char* value = *h++;
347
assert( value != 0 ); // name with no value!
349
if( 0==strcasecmp( name, "content-length" ) )
350
gotcontentlength = true;
354
putrequest( method, url );
356
if( body && !gotcontentlength )
357
putheader( "Content-Length", bodysize );
361
const char** h = headers;
364
const char* name = *h++;
365
const char* value = *h++;
366
putheader( name, value );
372
send( body, bodysize );
379
void Connection::putrequest( const char* method, const char* url )
381
if( m_State != IDLE )
382
throw Wobbly( "Request already issued" );
384
m_State = REQ_STARTED;
387
sprintf( req, "%s %s HTTP/1.1", method, url );
388
m_Buffer.push_back( req );
390
putheader( "Host", m_Host.c_str() ); // required for HTTP1.1
392
// don't want any fancy encodings please
393
putheader("Accept-Encoding", "identity");
395
// Push a new response onto the queue
396
Response *r = new Response( method, *this );
397
m_Outstanding.push_back( r );
401
void Connection::putheader( const char* header, const char* value )
403
if( m_State != REQ_STARTED )
404
throw Wobbly( "putheader() failed" );
405
m_Buffer.push_back( string(header) + ": " + string( value ) );
408
void Connection::putheader( const char* header, int numericvalue )
411
sprintf( buf, "%d", numericvalue );
412
putheader( header, buf );
415
void Connection::endheaders()
417
if( m_State != REQ_STARTED )
418
throw Wobbly( "Cannot send header" );
421
m_Buffer.push_back( "" );
424
vector< string>::const_iterator it;
425
for( it = m_Buffer.begin(); it != m_Buffer.end(); ++it )
426
msg += (*it) + "\r\n";
430
// printf( "%s", msg.c_str() );
431
send( (const unsigned char*)msg.c_str(), msg.size() );
436
void Connection::send( const unsigned char* buf, int numbytes )
438
// fwrite( buf, 1,numbytes, stdout );
443
while( numbytes > 0 )
446
int n = ::send( m_Sock, (const char*)buf, numbytes, 0 );
448
int n = ::send( m_Sock, buf, numbytes, 0 );
451
BailOnSocketError( "send()" );
458
void Connection::pump()
460
if( m_Outstanding.empty() )
461
return; // no requests outstanding
463
assert( m_Sock >0 ); // outstanding requests but no connection!
465
if( !datawaiting( m_Sock ) )
466
return; // recv will block
468
unsigned char buf[ 2048 ];
469
int a = recv( m_Sock, (char*)buf, sizeof(buf), 0 );
471
BailOnSocketError( "recv()" );
475
// connection has closed
477
Response* r = m_Outstanding.front();
478
r->notifyconnectionclosed();
479
assert( r->completed() );
481
m_Outstanding.pop_front();
483
// any outstanding requests will be discarded
489
while( used < a && !m_Outstanding.empty() )
492
Response* r = m_Outstanding.front();
493
int u = r->pump( &buf[used], a-used );
495
// delete response once completed
499
m_Outstanding.pop_front();
504
// NOTE: will lose bytes if response queue goes empty
505
// (but server shouldn't be sending anything if we don't have
506
// anything outstanding anyway)
507
assert( used == a ); // all bytes should be used up by here.
516
//---------------------------------------------------------------------
520
//---------------------------------------------------------------------
523
Response::Response( const char* method, Connection& conn ) :
524
m_State( STATUSLINE ),
525
m_Connection( conn ),
538
const char* Response::getheader( const char* name ) const
540
std::string lname( name );
541
std::transform( lname.begin(), lname.end(), lname.begin(), tolower );
543
std::map< std::string, std::string >::const_iterator it = m_Headers.find( lname );
544
if( it == m_Headers.end() )
547
return it->second.c_str();
551
int Response::getstatus() const
553
// only valid once we've got the statusline
554
assert( m_State != STATUSLINE );
559
const char* Response::getreason() const
561
// only valid once we've got the statusline
562
assert( m_State != STATUSLINE );
563
return m_Reason.c_str();
568
// Connection has closed
569
void Response::notifyconnectionclosed()
571
if( m_State == COMPLETE )
574
// eof can be valid...
575
if( m_State == BODY &&
579
Finish(); // we're all done!
583
throw Wobbly( "Connection closed unexpectedly" );
589
int Response::pump( const unsigned char* data, int datasize )
591
assert( datasize != 0 );
592
int count = datasize;
594
while( count > 0 && m_State != COMPLETE )
596
if( m_State == STATUSLINE ||
597
m_State == HEADERS ||
598
m_State == TRAILERS ||
599
m_State == CHUNKLEN ||
600
m_State == CHUNKEND )
602
// we want to accumulate a line
605
char c = (char)*data++;
609
// now got a whole line!
613
ProcessStatusLine( m_LineBuf );
616
ProcessHeaderLine( m_LineBuf );
619
ProcessTrailerLine( m_LineBuf );
622
ProcessChunkLenLine( m_LineBuf );
625
// just soak up the crlf after body and go to next state
626
assert( m_Chunked == true );
633
break; // break out of line accumulation!
637
if( c != '\r' ) // just ignore CR
642
else if( m_State == BODY )
646
bytesused = ProcessDataChunked( data, count );
648
bytesused = ProcessDataNonChunked( data, count );
654
// return number of bytes used
655
return datasize - count;
660
void Response::ProcessChunkLenLine( std::string const& line )
662
// chunklen in hex at beginning of line
663
m_ChunkLeft = strtol( line.c_str(), NULL, 16 );
665
if( m_ChunkLeft == 0 )
667
// got the whole body, now check for trailing headers
669
m_HeaderAccum.clear();
678
// handle some body data in chunked mode
679
// returns number of bytes used.
680
int Response::ProcessDataChunked( const unsigned char* data, int count )
688
// invoke callback to pass out the data
689
if( m_Connection.m_ResponseDataCB )
690
(m_Connection.m_ResponseDataCB)( this, m_Connection.m_UserData, data, n );
695
assert( m_ChunkLeft >= 0);
696
if( m_ChunkLeft == 0 )
698
// chunk completed! now soak up the trailing CRLF before next chunk
704
// handle some body data in non-chunked mode.
705
// returns number of bytes used.
706
int Response::ProcessDataNonChunked( const unsigned char* data, int count )
711
// we know how many bytes to expect
712
int remaining = m_Length - m_BytesRead;
717
// invoke callback to pass out the data
718
if( m_Connection.m_ResponseDataCB )
719
(m_Connection.m_ResponseDataCB)( this, m_Connection.m_UserData, data, n );
723
// Finish if we know we're done. Else we're waiting for connection close.
724
if( m_Length != -1 && m_BytesRead == m_Length )
731
void Response::Finish()
735
// invoke the callback
736
if( m_Connection.m_ResponseCompleteCB )
737
(m_Connection.m_ResponseCompleteCB)( this, m_Connection.m_UserData );
741
void Response::ProcessStatusLine( std::string const& line )
743
const char* p = line.c_str();
745
// skip any leading space
746
while( *p && *p == ' ' )
750
while( *p && *p != ' ' )
751
m_VersionString += *p++;
752
while( *p && *p == ' ' )
757
while( *p && *p != ' ' )
759
while( *p && *p == ' ' )
762
// rest of line is reason
766
m_Status = atoi( status.c_str() );
767
if( m_Status < 100 || m_Status > 999 )
768
throw Wobbly( "BadStatusLine (%s)", line.c_str() );
771
printf( "version: '%s'\n", m_VersionString.c_str() );
772
printf( "status: '%d'\n", m_Status );
773
printf( "reason: '%s'\n", m_Reason.c_str() );
776
if( m_VersionString == "HTTP:/1.0" )
778
else if( 0==m_VersionString.compare( 0,7,"HTTP/1." ) )
781
throw Wobbly( "UnknownProtocol (%s)", m_VersionString.c_str() );
782
// TODO: support for HTTP/0.9
785
// OK, now we expect headers!
787
m_HeaderAccum.clear();
791
// process accumulated header data
792
void Response::FlushHeader()
794
if( m_HeaderAccum.empty() )
795
return; // no flushing required
797
const char* p = m_HeaderAccum.c_str();
801
while( *p && *p != ':' )
802
header += tolower( *p++ );
809
while( *p && (*p ==' ' || *p=='\t') )
812
value = p; // rest of line is value
814
m_Headers[ header ] = value;
815
// printf("header: ['%s': '%s']\n", header.c_str(), value.c_str() );
817
m_HeaderAccum.clear();
821
void Response::ProcessHeaderLine( std::string const& line )
823
const char* p = line.c_str();
829
// HTTP code 100 handling (we ignore 'em)
830
if( m_Status == CONTINUE )
831
m_State = STATUSLINE; // reset parsing, expect new status line
833
BeginBody(); // start on body now!
839
// it's a continuation line - just add it to previous data
841
while( *p && isspace( *p ) )
844
m_HeaderAccum += ' ';
849
// begin a new header
856
void Response::ProcessTrailerLine( std::string const& line )
858
// TODO: handle trailers?
859
// (python httplib doesn't seem to!)
863
// just ignore all the trailers...
868
// OK, we've now got all the headers read in, so we're ready to start
869
// on the body. But we need to see what info we can glean from the headers
871
void Response::BeginBody()
875
m_Length = -1; // unknown
878
// using chunked encoding?
879
const char* trenc = getheader( "transfer-encoding" );
880
if( trenc && 0==strcasecmp( trenc, "chunked") )
883
m_ChunkLeft = -1; // unknown
886
m_WillClose = CheckClose();
889
const char* contentlen = getheader( "content-length" );
890
if( contentlen && !m_Chunked )
892
m_Length = atoi( contentlen );
895
// check for various cases where we expect zero-length body
896
if( m_Status == NO_CONTENT ||
897
m_Status == NOT_MODIFIED ||
898
( m_Status >= 100 && m_Status < 200 ) || // 1xx codes have no body
905
// if we're not using chunked mode, and no length has been specified,
906
// assume connection will close at end.
907
if( !m_WillClose && !m_Chunked && m_Length == -1 )
912
// Invoke the user callback, if any
913
if( m_Connection.m_ResponseBeginCB )
914
(m_Connection.m_ResponseBeginCB)( this, m_Connection.m_UserData );
917
printf("---------BeginBody()--------\n");
918
printf("Length: %d\n", m_Length );
919
printf("WillClose: %d\n", (int)m_WillClose );
920
printf("Chunked: %d\n", (int)m_Chunked );
921
printf("ChunkLeft: %d\n", (int)m_ChunkLeft );
922
printf("----------------------------\n");
924
// now start reading body data!
932
// return true if we think server will automatically close connection
933
bool Response::CheckClose()
935
if( m_Version == 11 )
938
// the connection stays open unless "connection: close" is specified.
939
const char* conn = getheader( "connection" );
940
if( conn && 0==strcasecmp( conn, "close" ) )
947
// keep-alive header indicates persistant connection
948
if( getheader( "keep-alive" ) )
951
// TODO: some special case handling for Akamai and netscape maybe?
952
// (see _check_close() in python httplib.py for details)
959
} // end namespace happyhttp