#include <cassert>
#include <list>
#include <iostream>
+#include <errno.h>
#include <boost/foreach.hpp>
#include <boost/algorithm/string/case_conv.hpp>
const int GZIP_HEADER_ID1 = 31;
const int GZIP_HEADER_ID2 = 139;
const int GZIP_HEADER_METHOD_DEFLATE = 8;
-const int GZIP_HEADER_SIZE = 10;
+const unsigned int GZIP_HEADER_SIZE = 10;
const int GZIP_HEADER_FEXTRA = 1 << 2;
const int GZIP_HEADER_FNAME = 1 << 3;
const int GZIP_HEADER_COMMENT = 1 << 4;
// socket-level errors
virtual void handleError(int error)
- {
+ {
+ if (error == ENOENT) {
+ // name lookup failure
+ // we won't have an active request yet, so the logic below won't
+ // fire to actually call setFailure. Let's fail all of the requests
+ BOOST_FOREACH(Request_ptr req, sentRequests) {
+ req->setFailure(error, "hostname lookup failure");
+ }
+
+ BOOST_FOREACH(Request_ptr req, queuedRequests) {
+ req->setFailure(error, "hostname lookup failure");
+ }
+
+ // name lookup failure, abandon all requests on this connection
+ sentRequests.clear();
+ queuedRequests.clear();
+ }
+
NetChat::handleError(error);
- if (activeRequest) {
+ if (activeRequest) {
SG_LOG(SG_IO, SG_INFO, "HTTP socket error");
activeRequest->setFailure(error, "socket error");
activeRequest = NULL;
zlib.next_out = zlibOutputBuffer;
zlib.avail_out = ZLIB_DECOMPRESS_BUFFER_SIZE;
- if (contentGZip) {
+ if (contentGZip && !handleGZipHeader()) {
+ return;
+ }
+
+ int writtenSize = 0;
+ do {
+ int result = inflate(&zlib, Z_NO_FLUSH);
+ if (result == Z_OK || result == Z_STREAM_END) {
+ // nothing to do
+ } else {
+ SG_LOG(SG_IO, SG_WARN, "got Zlib error:" << result);
+ return;
+ }
+
+ writtenSize = ZLIB_DECOMPRESS_BUFFER_SIZE - zlib.avail_out;
+ if (result == Z_STREAM_END) {
+ break;
+ }
+ } while ((writtenSize == 0) && (zlib.avail_in > 0));
+
+ if (writtenSize > 0) {
+ activeRequest->processBodyBytes((const char*) zlibOutputBuffer, writtenSize);
+ }
+ }
+
+ bool handleGZipHeader()
+ {
// we clear this down to contentDeflate once the GZip header has been seen
- if (reqSize < GZIP_HEADER_SIZE) {
- return; // need more header bytes
+ if (zlib.avail_in < GZIP_HEADER_SIZE) {
+ return false; // need more header bytes
}
if ((zlibInflateBuffer[0] != GZIP_HEADER_ID1) ||
(zlibInflateBuffer[1] != GZIP_HEADER_ID2) ||
(zlibInflateBuffer[2] != GZIP_HEADER_METHOD_DEFLATE))
{
- return; // invalid GZip header
+ return false; // invalid GZip header
}
char flags = zlibInflateBuffer[3];
int gzipHeaderSize = GZIP_HEADER_SIZE;
if (flags & GZIP_HEADER_FEXTRA) {
gzipHeaderSize += 2;
- if (reqSize < gzipHeaderSize) {
- return; // need more header bytes
+ if (zlib.avail_in < gzipHeaderSize) {
+ return false; // need more header bytes
}
unsigned short extraHeaderBytes = *(reinterpret_cast<unsigned short*>(zlibInflateBuffer + GZIP_HEADER_FEXTRA));
}
gzipHeaderSize += extraHeaderBytes;
- if (reqSize < gzipHeaderSize) {
- return; // need more header bytes
+ if (zlib.avail_in < gzipHeaderSize) {
+ return false; // need more header bytes
}
}
if (flags & GZIP_HEADER_FNAME) {
gzipHeaderSize++;
- while (gzipHeaderSize <= reqSize) {
+ while (gzipHeaderSize <= zlib.avail_in) {
if (zlibInflateBuffer[gzipHeaderSize-1] == 0) {
break; // found terminating NULL character
}
if (flags & GZIP_HEADER_COMMENT) {
gzipHeaderSize++;
- while (gzipHeaderSize <= reqSize) {
+ while (gzipHeaderSize <= zlib.avail_in) {
if (zlibInflateBuffer[gzipHeaderSize-1] == 0) {
break; // found terminating NULL character
}
gzipHeaderSize += 2;
}
- if (reqSize < gzipHeaderSize) {
- return; // need more header bytes
+ if (zlib.avail_in < gzipHeaderSize) {
+ return false; // need more header bytes
}
zlib.next_in += gzipHeaderSize;
- zlib.avail_in = reqSize - gzipHeaderSize;
+ zlib.avail_in -= gzipHeaderSize;
// now we've processed the GZip header, can decode as deflate
contentGZip = false;
contentDeflate = true;
- }
-
- int writtenSize = 0;
- do {
- int result = inflate(&zlib, Z_NO_FLUSH);
- if (result == Z_OK || result == Z_STREAM_END) {
-
- } else {
- SG_LOG(SG_IO, SG_WARN, "got Zlib error:" << result);
- return;
- }
-
- writtenSize = ZLIB_DECOMPRESS_BUFFER_SIZE - zlib.avail_out;
- } while ((writtenSize == 0) && (zlib.avail_in > 0));
-
- if (writtenSize > 0) {
- activeRequest->processBodyBytes((const char*) zlibOutputBuffer, writtenSize);
- }
+ return true;
}
virtual void foundTerminator(void)
case STATE_GETTING_CHUNKED_BYTES:
setTerminator("\r\n");
state = STATE_GETTING_CHUNKED;
+ buffer.clear();
break;
// blank line after chunk data
return;
}
-
+
int chunkSize = 0;
int semiPos = buffer.find(';');
if (semiPos >= 0) {