A HTTP Client for the mbed networking libraries

Dependents:   HTTPClient_Wifly_HelloWorld HTTPPoster HTTPClient_HelloWorld mpod_nhk_english ... more

Fork of HTTPClientLib by Donatien Garnier

Files at this revision

API Documentation at this revision

Comitter:
donatien
Date:
Fri May 02 13:13:39 2014 +0000
Parent:
16:1f743885e7de
Child:
18:277279a1891e
Commit message:
Do not block and wait for 255 bytes

Changed in this revision

HTTPClient.cpp Show annotated file Show diff for this revision Revisions of this file
IHTTPData.h Show annotated file Show diff for this revision Revisions of this file
--- a/HTTPClient.cpp	Thu Aug 30 15:38:57 2012 +0000
+++ b/HTTPClient.cpp	Fri May 02 13:13:39 2014 +0000
@@ -193,6 +193,24 @@
       ret = send(buf);
       CHECK_CONN_ERR(ret);
     }
+    
+    //Send specific headers
+    while( pDataOut->getHeader(buf, sizeof(buf) - 3) ) //must have space left for CRLF + 0 terminating char
+    {
+      size_t headerlen = strlen(buf);
+      snprintf(buf + headerlen, sizeof(buf) - headerlen, "\r\n");
+      ret = send(buf);
+      CHECK_CONN_ERR(ret);
+    }
+  }
+  
+  //Send specific headers
+  while( pDataIn->getHeader(buf, sizeof(buf) - 3) )
+  {
+    size_t headerlen = strlen(buf);
+    snprintf(buf + headerlen, sizeof(buf) - headerlen, "\r\n");
+    ret = send(buf);
+    CHECK_CONN_ERR(ret);
   }
   
   //Close headers
@@ -247,27 +265,50 @@
         break;
       }
     }
-
   }
   
   //Receive response
   DBG("Receiving response");
-  ret = recv(buf, CHUNK_SIZE - 1, CHUNK_SIZE - 1, &trfLen); //Read n bytes
+  ret = recv(buf, 1, CHUNK_SIZE - 1, &trfLen); //Read n bytes
   CHECK_CONN_ERR(ret);
 
   buf[trfLen] = '\0';
 
-  char* crlfPtr = strstr(buf, "\r\n");
+  //Make sure we got the first response line
+  char* crlfPtr = NULL;
+  while( true )
+  {
+    crlfPtr = strstr(buf, "\r\n");
   if(crlfPtr == NULL)
   {
+      if( trfLen < CHUNK_SIZE - 1 )
+      {
+        size_t newTrfLen;
+        ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen);
+        trfLen += newTrfLen;
+        buf[trfLen] = '\0';
+        DBG("Read %d chars; In buf: [%s]", newTrfLen, buf);
+        CHECK_CONN_ERR(ret);
+        continue;
+      }
+      else
+      {
     PRTCL_ERR();
   }
+    }
+    break;
+  }
 
   int crlfPos = crlfPtr - buf;
   buf[crlfPos] = '\0';
 
   //Parse HTTP response
-  if( sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 )
+  //if( sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 )
+  if(crlfPos > 13)
+  {
+    buf[13] = '\0';
+  }
+  if( sscanf(buf, "HTTP/%*d.%*d %d", &m_httpResponseCode) != 1 ) //Kludge for newlib nano
   {
     //Cannot match string, error
     ERR("Not a correct HTTP answer : %s\n", buf);
@@ -288,6 +329,7 @@
 
   size_t recvContentLength = 0;
   bool recvChunked = false;
+  bool recvLengthUnknown = true;
   //Now get headers
   while( true )
   {
@@ -325,16 +367,41 @@
     char key[32];
     char value[32];
 
-    key[31] = '\0';
-    value[31] = '\0';
+    //key[31] = '\0';
+    //value[31] = '\0';
+
+    memset(key, 0, 32);
+    memset(value, 0, 32);
 
-    int n = sscanf(buf, "%31[^:]: %31[^\r\n]", key, value);
+    //int n = sscanf(buf, "%31[^:]: %31[^\r\n]", key, value);
+    
+    int n = 0;
+    
+    char* keyEnd = strchr(buf, ':');
+    if(keyEnd != NULL)
+    {
+      *keyEnd = '\0';
+    
+      if(sscanf(buf, "%31c", key) == 1)
+      {
+        n++;
+        char* valueStart = keyEnd + 2;
+        if( (valueStart - buf) < crlfPos )
+        {
+          if(sscanf(valueStart, "%31c", value) == 1)
+          {
+            n++;
+          }
+        }
+      }
+    }
     if ( n == 2 )
     {
       DBG("Read header : %s: %s\n", key, value);
       if( !strcmp(key, "Content-Length") )
       {
         sscanf(value, "%d", &recvContentLength);
+        recvLengthUnknown = false;
         pDataIn->setDataLen(recvContentLength);
       }
       else if( !strcmp(key, "Transfer-Encoding") )
@@ -342,6 +409,7 @@
         if( !strcmp(value, "Chunked") || !strcmp(value, "chunked") )
         {
           recvChunked = true;
+          recvLengthUnknown = false;
           pDataIn->setIsChunked(true);
         }
       }
@@ -426,28 +494,49 @@
       readLen = recvContentLength;
     }
 
-    DBG("Retrieving %d bytes", readLen);
+    DBG("Retrieving %d bytes (%d bytes in buffer)", readLen, trfLen);
 
     do
     {
+      if(recvLengthUnknown )
+      {
+        readLen = trfLen;
+      }
       pDataIn->write(buf, MIN(trfLen, readLen));
-      if( trfLen > readLen )
+      if(!recvLengthUnknown)
       {
-        memmove(buf, &buf[readLen], trfLen - readLen);
-        trfLen -= readLen;
-        readLen = 0;
+        if( trfLen > readLen )
+        {
+          memmove(buf, &buf[readLen], trfLen - readLen);
+          trfLen -= readLen;
+          readLen = 0;
+        }
+        else
+        {
+          readLen -= trfLen;
+        }
       }
       else
       {
-        readLen -= trfLen;
+        trfLen = 0;
       }
 
-      if(readLen)
+      if(readLen || recvLengthUnknown)
       {
         ret = recv(buf, 1, CHUNK_SIZE - trfLen - 1, &trfLen);
+        if(recvLengthUnknown && (ret == HTTP_CLOSED))
+        {
+          //Write and exit
+          pDataIn->write(buf, trfLen);
+          break;
+        }
         CHECK_CONN_ERR(ret);
+        if(recvLengthUnknown && (trfLen == 0))
+        {
+          break;
+        }
       }
-    } while(readLen);
+    } while(readLen || recvLengthUnknown);
 
     if( recvChunked )
     {
--- a/IHTTPData.h	Thu Aug 30 15:38:57 2012 +0000
+++ b/IHTTPData.h	Fri May 02 13:13:39 2014 +0000
@@ -24,8 +24,17 @@
 
 using std::size_t;
 
+class IHTTPData
+{
+  protected:
+  /** Get a specific header
+  *
+  */
+  virtual bool getHeader(char* header, size_t maxHeaderLen) { return false; }
+};
+
 ///This is a simple interface for HTTP data storage (impl examples are Key/Value Pairs, File, etc...)
-class IHTTPDataOut
+class IHTTPDataOut : public IHTTPData
 {
 protected:
   friend class HTTPClient;
@@ -60,7 +69,7 @@
 };
 
 ///This is a simple interface for HTTP data storage (impl examples are Key/Value Pairs, File, etc...)
-class IHTTPDataIn
+class IHTTPDataIn : public IHTTPData
 {
 protected:
   friend class HTTPClient;