]> git.mxchange.org Git - simgear.git/blobdiff - simgear/io/HTTPClient.cxx
Ensure individual log-level setting works.
[simgear.git] / simgear / io / HTTPClient.cxx
index 7531a1011e15a62dcaabad0ed1cbec035e7f4cf0..8a48bff6386deb9e97c75cad39f44f19ae5ccca2 100644 (file)
@@ -4,6 +4,7 @@
 #include <cassert>
 #include <list>
 #include <iostream>
+#include <errno.h>
 
 #include <boost/foreach.hpp>
 #include <boost/algorithm/string/case_conv.hpp>
@@ -37,7 +38,7 @@ namespace HTTP
 
 extern const int DEFAULT_HTTP_PORT = 80;
 const char* CONTENT_TYPE_URL_ENCODED = "application/x-www-form-urlencoded";
-const int MAX_INFLIGHT_REQUESTS = 32;
+const unsigned int MAX_INFLIGHT_REQUESTS = 32;
 const int ZLIB_DECOMPRESS_BUFFER_SIZE = 32 * 1024;
 const int ZLIB_INFLATE_WINDOW_BITS = -MAX_WBITS;
   
@@ -46,7 +47,7 @@ const int ZLIB_INFLATE_WINDOW_BITS = -MAX_WBITS;
 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;
@@ -85,9 +86,26 @@ public:
     
     // 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;
@@ -130,7 +148,7 @@ public:
     {
       assert(!sentRequests.empty());
       
-      activeRequest = sentRequests.front();
+      activeRequest = sentRequests.front();      
       activeRequest->responseStart(buffer);
       state = STATE_GETTING_HEADERS;
       buffer.clear();
@@ -169,9 +187,10 @@ public:
      
       Request_ptr r = queuedRequests.front();
       requestBodyBytesToSend = r->requestBodyLength();
-    
+          
       stringstream headerData;
       string path = r->path();
+      assert(!path.empty());
       string query = r->query();
       string bodyData;
       
@@ -179,7 +198,7 @@ public:
           path = r->scheme() + "://" + r->host() + r->path();
       }
 
-      if (r->method() == "POST") {
+      if (r->requestBodyType() == CONTENT_TYPE_URL_ENCODED) {
           headerData << r->method() << " " << path << " HTTP/1.1\r\n";
           bodyData = query.substr(1); // URL-encode, drop the leading '?'
           headerData << "Content-Type:" << CONTENT_TYPE_URL_ENCODED << "\r\n";
@@ -279,25 +298,51 @@ public:
       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));
@@ -306,14 +351,14 @@ public:
           }
           
           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
             }
@@ -322,7 +367,7 @@ public:
         
         if (flags & GZIP_HEADER_COMMENT) {
           gzipHeaderSize++;
-          while (gzipHeaderSize <= reqSize) {
+          while (gzipHeaderSize <= zlib.avail_in) {
             if (zlibInflateBuffer[gzipHeaderSize-1] == 0) {
               break; // found terminating NULL character
             }
@@ -333,33 +378,16 @@ public:
           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)
@@ -386,6 +414,7 @@ public:
         case STATE_GETTING_CHUNKED_BYTES:
             setTerminator("\r\n");
             state = STATE_GETTING_CHUNKED;
+            buffer.clear();
             break;
             
 
@@ -429,7 +458,7 @@ public:
 private:
     bool connectToHost()
     {
-        SG_LOG(SG_IO, SG_INFO, "HTTP connecting to " << host << ":" << port);
+        SG_LOG(SG_IO, SG_DEBUG, "HTTP connecting to " << host << ":" << port);
         
         if (!open()) {
             SG_LOG(SG_ALL, SG_WARN, "HTTP::Connection: connectToHost: open() failed");
@@ -534,7 +563,7 @@ private:
             // blank line after chunk data
             return;
         }
-        
+                
         int chunkSize = 0;
         int semiPos = buffer.find(';');
         if (semiPos >= 0) {
@@ -657,7 +686,6 @@ void Client::update(int waitTimeout)
             _connections.erase(del);
         } else {
             if (it->second->shouldStartNext()) {
-                SG_LOG(SG_IO, SG_INFO, "should start next, hmm");
                 it->second->tryStartNextRequest();
             }