AerCloud / HTTPClient_AerCloud

Dependents:   AerCloud_C027_Sample

Fork of HTTPClient by Donatien Garnier

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HTTPClient.cpp Source File

HTTPClient.cpp

00001 /* HTTPClient.cpp */
00002 /* Copyright (C) 2012 mbed.org, MIT License
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00005  * and associated documentation files (the "Software"), to deal in the Software without restriction,
00006  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
00007  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
00008  * furnished to do so, subject to the following conditions:
00009  *
00010  * The above copyright notice and this permission notice shall be included in all copies or
00011  * substantial portions of the Software.
00012  *
00013  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00014  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00015  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00016  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00017  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00018  */
00019 
00020 //Debug is disabled by default
00021 #if 0
00022 //Enable debug
00023 #include <cstdio>
00024 #define DBG(x, ...) std::printf("[HTTPClient : DBG]"x"\r\n", ##__VA_ARGS__); 
00025 #define WARN(x, ...) std::printf("[HTTPClient : WARN]"x"\r\n", ##__VA_ARGS__); 
00026 #define ERR(x, ...) std::printf("[HTTPClient : ERR]"x"\r\n", ##__VA_ARGS__); 
00027 
00028 #else
00029 //Disable debug
00030 #define DBG(x, ...) 
00031 #define WARN(x, ...)
00032 #define ERR(x, ...) 
00033 
00034 #endif
00035 
00036 #define HTTP_PORT 80
00037 
00038 #define OK 0
00039 
00040 #define MIN(x,y) (((x)<(y))?(x):(y))
00041 #define MAX(x,y) (((x)>(y))?(x):(y))
00042 
00043 #define CHUNK_SIZE 256
00044 
00045 #include <cstring>
00046 
00047 #include "HTTPClient.h"
00048 
00049 HTTPClient::HTTPClient() :
00050 m_sock(), m_basicAuthUser(NULL), m_basicAuthPassword(NULL), m_httpResponseCode(0)
00051 {
00052 
00053 }
00054 
00055 HTTPClient::~HTTPClient()
00056 {
00057 
00058 }
00059 
00060 #if 0
00061 void HTTPClient::basicAuth(const char* user, const char* password) //Basic Authentification
00062 {
00063   m_basicAuthUser = user;
00064   m_basicAuthPassword = password;
00065 }
00066 #endif
00067 
00068 HTTPResult HTTPClient::get(const char* url, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
00069 {
00070   return connect(url, HTTP_GET, NULL, pDataIn, timeout);
00071 }
00072 
00073 HTTPResult HTTPClient::get(const char* url, char* result, size_t maxResultLen, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
00074 {
00075   HTTPText str(result, maxResultLen);
00076   return get(url, &str, timeout);
00077 }
00078 
00079 HTTPResult HTTPClient::post(const char* url, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
00080 {
00081   return connect(url, HTTP_POST, (IHTTPDataOut*)&dataOut, pDataIn, timeout);
00082 }
00083 
00084 HTTPResult HTTPClient::put(const char* url, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
00085 {
00086   return connect(url, HTTP_PUT, (IHTTPDataOut*)&dataOut, pDataIn, timeout);
00087 }
00088 
00089 HTTPResult HTTPClient::del(const char* url, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
00090 {
00091   return connect(url, HTTP_DELETE, NULL, pDataIn, timeout);
00092 }
00093 
00094 
00095 int HTTPClient::getHTTPResponseCode()
00096 {
00097   return m_httpResponseCode;
00098 }
00099 
00100 #define CHECK_CONN_ERR(ret) \
00101   do{ \
00102     if(ret) { \
00103       m_sock.close(); \
00104       ERR("Connection error (%d)", ret); \
00105       return HTTP_CONN; \
00106     } \
00107   } while(0)
00108 
00109 #define PRTCL_ERR() \
00110   do{ \
00111     m_sock.close(); \
00112     ERR("Protocol error"); \
00113     return HTTP_PRTCL; \
00114   } while(0)
00115 
00116 HTTPResult HTTPClient::connect(const char* url, HTTP_METH method, IHTTPDataOut* pDataOut, IHTTPDataIn* pDataIn, int timeout) //Execute request
00117 { 
00118   m_httpResponseCode = 0; //Invalidate code
00119   m_timeout = timeout;
00120   
00121   pDataIn->writeReset();
00122   if( pDataOut )
00123   {
00124     pDataOut->readReset();
00125   }
00126 
00127   char scheme[8];
00128   uint16_t port;
00129   char host[32];
00130   char path[124];
00131   //First we need to parse the url (http[s]://host[:port][/[path]]) -- HTTPS not supported (yet?)
00132   HTTPResult res = parseURL(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path));
00133   if(res != HTTP_OK)
00134   {
00135     ERR("parseURL returned %d", res);
00136     return res;
00137   }
00138 
00139   if(port == 0) //TODO do handle HTTPS->443
00140   {
00141     port = 80;
00142   }
00143 
00144   DBG("Scheme: %s", scheme);
00145   DBG("Host: %s", host);
00146   DBG("Port: %d", port);
00147   DBG("Path: %s", path);
00148 
00149   //Connect
00150   DBG("Connecting socket to server");
00151   int ret = m_sock.connect(host, port);
00152   if (ret < 0)
00153   {
00154     m_sock.close();
00155     ERR("Could not connect");
00156     return HTTP_CONN;
00157   }
00158 
00159   //Send request
00160   DBG("Sending request");
00161   char buf[CHUNK_SIZE];
00162   const char* meth = (method==HTTP_GET)?"GET":(method==HTTP_POST)?"POST":(method==HTTP_PUT)?"PUT":(method==HTTP_DELETE)?"DELETE":"";
00163   snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\n", meth, path, host); //Write request
00164   ret = send(buf);
00165   if(ret)
00166   {
00167     m_sock.close();
00168     ERR("Could not write request");
00169     return HTTP_CONN;
00170   }
00171 
00172   //Send all headers
00173 
00174   //Send default headers
00175   DBG("Sending headers");
00176   if( pDataOut != NULL )
00177   {
00178     if( pDataOut->getIsChunked() )
00179     {
00180       ret = send("Transfer-Encoding: chunked\r\n");
00181       CHECK_CONN_ERR(ret);
00182     }
00183     else
00184     {
00185       snprintf(buf, sizeof(buf), "Content-Length: %d\r\n", pDataOut->getDataLen());
00186       ret = send(buf);
00187       CHECK_CONN_ERR(ret);
00188       
00189       snprintf(buf, sizeof(buf), "Accept:application/json\r\n");
00190       ret = send(buf);
00191       CHECK_CONN_ERR(ret);
00192     }
00193     char type[48];
00194     if( pDataOut->getDataType(type, 48) == HTTP_OK )
00195     {
00196       snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", type);
00197       ret = send(buf);
00198       CHECK_CONN_ERR(ret);
00199     }
00200     
00201     //Send specific headers
00202     while( pDataOut->getHeader(buf, sizeof(buf) - 3) ) //must have space left for CRLF + 0 terminating char
00203     {
00204       size_t headerlen = strlen(buf);
00205       snprintf(buf + headerlen, sizeof(buf) - headerlen, "\r\n");
00206       ret = send(buf);
00207       CHECK_CONN_ERR(ret);
00208     }
00209   }
00210   
00211   //Send specific headers
00212   while( pDataIn->getHeader(buf, sizeof(buf) - 3) )
00213   {
00214     size_t headerlen = strlen(buf);
00215     snprintf(buf + headerlen, sizeof(buf) - headerlen, "\r\n");
00216     ret = send(buf);
00217     CHECK_CONN_ERR(ret);
00218   }
00219   
00220   //Close headers
00221   DBG("Headers sent");
00222   ret = send("\r\n");
00223   CHECK_CONN_ERR(ret);
00224 
00225   size_t trfLen;
00226   
00227   //Send data (if available)
00228   if( pDataOut != NULL )
00229   {
00230     DBG("Sending data");
00231     while(true)
00232     {
00233       size_t writtenLen = 0;
00234       pDataOut->read(buf, CHUNK_SIZE, &trfLen);
00235       if( pDataOut->getIsChunked() )
00236       {
00237         //Write chunk header
00238         char chunkHeader[16];
00239         snprintf(chunkHeader, sizeof(chunkHeader), "%X\r\n", trfLen); //In hex encoding
00240         ret = send(chunkHeader);
00241         CHECK_CONN_ERR(ret);
00242       }
00243       else if( trfLen == 0 )
00244       {
00245         break;
00246       }
00247       if( trfLen != 0 )
00248       {
00249         ret = send(buf, trfLen);
00250         CHECK_CONN_ERR(ret);
00251       }
00252 
00253       if( pDataOut->getIsChunked()  )
00254       {
00255         ret = send("\r\n"); //Chunk-terminating CRLF
00256         CHECK_CONN_ERR(ret);
00257       }
00258       else
00259       {
00260         writtenLen += trfLen;
00261         if( writtenLen >= pDataOut->getDataLen() )
00262         {
00263           break;
00264         }
00265       }
00266 
00267       if( trfLen == 0 )
00268       {
00269         break;
00270       }
00271     }
00272   }
00273   
00274   //Receive response
00275   DBG("Receiving response");
00276   ret = recv(buf, 1, CHUNK_SIZE - 1, &trfLen); //Read n bytes
00277   CHECK_CONN_ERR(ret);
00278 
00279   buf[trfLen] = '\0';
00280 
00281   //Make sure we got the first response line
00282   char* crlfPtr = NULL;
00283   while( true )
00284   {
00285     crlfPtr = strstr(buf, "\r\n");
00286   if(crlfPtr == NULL)
00287   {
00288       if( trfLen < CHUNK_SIZE - 1 )
00289       {
00290         size_t newTrfLen;
00291         ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen);
00292         trfLen += newTrfLen;
00293         buf[trfLen] = '\0';
00294         DBG("Read %d chars; In buf: [%s]", newTrfLen, buf);
00295         CHECK_CONN_ERR(ret);
00296         continue;
00297       }
00298       else
00299       {
00300     PRTCL_ERR();
00301   }
00302     }
00303     break;
00304   }
00305 
00306   int crlfPos = crlfPtr - buf;
00307   buf[crlfPos] = '\0';
00308 
00309   //Parse HTTP response
00310   //if( sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 )
00311   if(crlfPos > 13)
00312   {
00313     buf[13] = '\0';
00314   }
00315   if( sscanf(buf, "HTTP/%*d.%*d %d", &m_httpResponseCode) != 1 ) //Kludge for newlib nano
00316   {
00317     //Cannot match string, error
00318     ERR("Not a correct HTTP answer : %s\n", buf);
00319     PRTCL_ERR();
00320   }
00321 
00322   if( (m_httpResponseCode < 200) || (m_httpResponseCode >= 300) )
00323   {
00324     //Did not return a 2xx code; TODO fetch headers/(&data?) anyway and implement a mean of writing/reading headers 
00325     WARN("Response code %d", m_httpResponseCode);
00326     PRTCL_ERR();
00327   }
00328 
00329   DBG("Reading headers");
00330 
00331   memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well
00332   trfLen -= (crlfPos + 2);
00333 
00334   size_t recvContentLength = 0;
00335   bool recvChunked = false;
00336   bool recvLengthUnknown = true;
00337   //Now get headers
00338   while( true )
00339   {
00340     crlfPtr = strstr(buf, "\r\n");
00341     if(crlfPtr == NULL)
00342     {
00343       if( trfLen < CHUNK_SIZE - 1 )
00344       {
00345         size_t newTrfLen;
00346         ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen);
00347         trfLen += newTrfLen;
00348         buf[trfLen] = '\0';
00349         DBG("Read %d chars; In buf: [%s]", newTrfLen, buf);
00350         CHECK_CONN_ERR(ret);
00351         continue;
00352       }
00353       else
00354       {
00355         PRTCL_ERR();
00356       }
00357     }
00358 
00359     crlfPos = crlfPtr - buf;
00360 
00361     if(crlfPos == 0) //End of headers
00362     {
00363       DBG("Headers read");
00364       memmove(buf, &buf[2], trfLen - 2 + 1); //Be sure to move NULL-terminating char as well
00365       trfLen -= 2;
00366       break;
00367     }
00368 
00369     buf[crlfPos] = '\0';
00370 
00371     char key[32];
00372     char value[32];
00373 
00374     //key[31] = '\0';
00375     //value[31] = '\0';
00376 
00377     memset(key, 0, 32);
00378     memset(value, 0, 32);
00379 
00380     //int n = sscanf(buf, "%31[^:]: %31[^\r\n]", key, value);
00381     
00382     int n = 0;
00383     
00384     char* keyEnd = strchr(buf, ':');
00385     if(keyEnd != NULL)
00386     {
00387       *keyEnd = '\0';
00388       if(strlen(buf) < 32)
00389       {
00390         strcpy(key, buf);
00391         n++;
00392         char* valueStart = keyEnd + 2;
00393         if( (valueStart - buf) < crlfPos )
00394         {
00395           if(strlen(valueStart) < 32)
00396           { 
00397             strcpy(value, valueStart);
00398             n++;
00399           } else {
00400               // Value is too long, truncate it
00401               strncpy(value, valueStart, 31);
00402               value[31] = '\0';
00403               n++;
00404           }
00405         }
00406       }
00407     }
00408     if ( n == 2 )
00409     {
00410       DBG("Read header : %s: %s\n", key, value);
00411       if( !strcmp(key, "Content-Length") )
00412       {
00413         sscanf(value, "%d", &recvContentLength);
00414         recvLengthUnknown = false;
00415         pDataIn->setDataLen(recvContentLength);
00416       }
00417       else if( !strcmp(key, "Transfer-Encoding") )
00418       {
00419         if( !strcmp(value, "Chunked") || !strcmp(value, "chunked") )
00420         {
00421           recvChunked = true;
00422           recvLengthUnknown = false;
00423           pDataIn->setIsChunked(true);
00424         }
00425       }
00426       else if( !strcmp(key, "Content-Type") )
00427       {
00428         pDataIn->setDataType(value);
00429       }
00430 
00431       memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well
00432       trfLen -= (crlfPos + 2);
00433 
00434     }
00435     else
00436     {
00437       ERR("Could not parse header");
00438       PRTCL_ERR();
00439     }
00440 
00441   }
00442 
00443   //Receive data
00444   DBG("Receiving data");
00445   while(true)
00446   {
00447     size_t readLen = 0;
00448 
00449     if( recvChunked )
00450     {
00451       //Read chunk header
00452       bool foundCrlf;
00453       do
00454       {
00455         foundCrlf = false;
00456         crlfPos=0;
00457         buf[trfLen]=0;
00458         if(trfLen >= 2)
00459         {
00460           for(; crlfPos < trfLen - 2; crlfPos++)
00461           {
00462             if( buf[crlfPos] == '\r' && buf[crlfPos + 1] == '\n' )
00463             {
00464               foundCrlf = true;
00465               break;
00466             }
00467           }
00468         }
00469         if(!foundCrlf) //Try to read more
00470         {
00471           if( trfLen < CHUNK_SIZE )
00472           {
00473             size_t newTrfLen;
00474             ret = recv(buf + trfLen, 0, CHUNK_SIZE - trfLen - 1, &newTrfLen);
00475             trfLen += newTrfLen;
00476             CHECK_CONN_ERR(ret);
00477             continue;
00478           }
00479           else
00480           {
00481             PRTCL_ERR();
00482           }
00483         }
00484       } while(!foundCrlf);
00485       buf[crlfPos] = '\0';
00486       int n = sscanf(buf, "%x", &readLen);
00487       if(n!=1)
00488       {
00489         ERR("Could not read chunk length");
00490         PRTCL_ERR();
00491       }
00492 
00493       memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2)); //Not need to move NULL-terminating char any more
00494       trfLen -= (crlfPos + 2);
00495 
00496       if( readLen == 0 )
00497       {
00498         //Last chunk
00499         break;
00500       }
00501     }
00502     else
00503     {
00504       readLen = recvContentLength;
00505     }
00506 
00507     DBG("Retrieving %d bytes (%d bytes in buffer)", readLen, trfLen);
00508 
00509     do
00510     {
00511       if(recvLengthUnknown )
00512       {
00513         readLen = trfLen;
00514       }
00515       pDataIn->write(buf, MIN(trfLen, readLen));
00516       if(!recvLengthUnknown)
00517       {
00518         if( trfLen > readLen )
00519         {
00520           memmove(buf, &buf[readLen], trfLen - readLen);
00521           trfLen -= readLen;
00522           readLen = 0;
00523         }
00524         else
00525         {
00526           readLen -= trfLen;
00527         }
00528       }
00529       else
00530       {
00531         trfLen = 0;
00532       }
00533 
00534       if(readLen || recvLengthUnknown)
00535       {
00536         ret = recv(buf, 1, CHUNK_SIZE - trfLen - 1, &trfLen);
00537         if(recvLengthUnknown && (ret == HTTP_CLOSED))
00538         {
00539           //Write and exit
00540           pDataIn->write(buf, trfLen);
00541           break;
00542         }
00543         CHECK_CONN_ERR(ret);
00544         if(recvLengthUnknown && (trfLen == 0))
00545         {
00546           break;
00547         }
00548       }
00549     } while(readLen || recvLengthUnknown);
00550 
00551     if( recvChunked )
00552     {
00553       if(trfLen < 2)
00554       {
00555         size_t newTrfLen;
00556         //Read missing chars to find end of chunk
00557         ret = recv(buf + trfLen, 2 - trfLen, CHUNK_SIZE - trfLen - 1, &newTrfLen);
00558         CHECK_CONN_ERR(ret);
00559         trfLen += newTrfLen;
00560       }
00561       if( (buf[0] != '\r') || (buf[1] != '\n') )
00562       {
00563         ERR("Format error");
00564         PRTCL_ERR();
00565       }
00566       memmove(buf, &buf[2], trfLen - 2);
00567       trfLen -= 2;
00568     }
00569     else
00570     {
00571       break;
00572     }
00573 
00574   }
00575 
00576   m_sock.close();
00577   DBG("Completed HTTP transaction");
00578 
00579   return HTTP_OK;
00580 }
00581 
00582 HTTPResult HTTPClient::recv(char* buf, size_t minLen, size_t maxLen, size_t* pReadLen) //0 on success, err code on failure
00583 {
00584   DBG("Trying to read between %d and %d bytes", minLen, maxLen);
00585   size_t readLen = 0;
00586       
00587   if(!m_sock.is_connected())
00588   {
00589     WARN("Connection was closed by server");
00590     return HTTP_CLOSED; //Connection was closed by server 
00591   }
00592     
00593   int ret;
00594   while(readLen < maxLen)
00595   {
00596     if(readLen < minLen)
00597     {
00598       DBG("Trying to read at most %d bytes [Blocking]", minLen - readLen);
00599       m_sock.set_blocking(false, m_timeout);
00600       ret = m_sock.receive_all(buf + readLen, minLen - readLen);
00601     }
00602     else
00603     {
00604       DBG("Trying to read at most %d bytes [Not blocking]", maxLen - readLen);
00605       m_sock.set_blocking(false, 0);
00606       ret = m_sock.receive(buf + readLen, maxLen - readLen);
00607     }
00608     
00609     if( ret > 0)
00610     {
00611       readLen += ret;
00612     }
00613     else if( ret == 0 )
00614     {
00615       break;
00616     }
00617     else
00618     {
00619       if(!m_sock.is_connected())
00620       {
00621         ERR("Connection error (recv returned %d)", ret);
00622         *pReadLen = readLen;
00623         return HTTP_CONN;
00624       }
00625       else
00626       {
00627         break;      
00628       }
00629     }
00630     
00631     if(!m_sock.is_connected())
00632     {
00633       break;
00634     }
00635   }
00636   DBG("Read %d bytes", readLen);
00637   *pReadLen = readLen;
00638   return HTTP_OK;
00639 }
00640 
00641 HTTPResult HTTPClient::send(char* buf, size_t len) //0 on success, err code on failure
00642 {
00643   if(len == 0)
00644   {
00645     len = strlen(buf);
00646   }
00647   DBG("Trying to write %d bytes", len);
00648   size_t writtenLen = 0;
00649     
00650   if(!m_sock.is_connected())
00651   {
00652     WARN("Connection was closed by server");
00653     return HTTP_CLOSED; //Connection was closed by server 
00654   }
00655   
00656   m_sock.set_blocking(false, m_timeout);
00657   int ret = m_sock.send_all(buf, len);
00658   if(ret > 0)
00659   {
00660     writtenLen += ret;
00661   }
00662   else if( ret == 0 )
00663   {
00664     WARN("Connection was closed by server");
00665     return HTTP_CLOSED; //Connection was closed by server
00666   }
00667   else
00668   {
00669     ERR("Connection error (send returned %d)", ret);
00670     return HTTP_CONN;
00671   }
00672   
00673   DBG("Written %d bytes", writtenLen);
00674   return HTTP_OK;
00675 }
00676 
00677 HTTPResult HTTPClient::parseURL(const char* url, char* scheme, size_t maxSchemeLen, char* host, size_t maxHostLen, uint16_t* port, char* path, size_t maxPathLen) //Parse URL
00678 {
00679   char* schemePtr = (char*) url;
00680   char* hostPtr = (char*) strstr(url, "://");
00681   if(hostPtr == NULL)
00682   {
00683     WARN("Could not find host");
00684     return HTTP_PARSE; //URL is invalid
00685   }
00686 
00687   if( maxSchemeLen < hostPtr - schemePtr + 1 ) //including NULL-terminating char
00688   {
00689     WARN("Scheme str is too small (%d >= %d)", maxSchemeLen, hostPtr - schemePtr + 1);
00690     return HTTP_PARSE;
00691   }
00692   memcpy(scheme, schemePtr, hostPtr - schemePtr);
00693   scheme[hostPtr - schemePtr] = '\0';
00694 
00695   hostPtr+=3;
00696 
00697   size_t hostLen = 0;
00698 
00699   char* portPtr = strchr(hostPtr, ':');
00700   if( portPtr != NULL )
00701   {
00702     hostLen = portPtr - hostPtr;
00703     portPtr++;
00704     if( sscanf(portPtr, "%hu", port) != 1)
00705     {
00706       WARN("Could not find port");
00707       return HTTP_PARSE;
00708     }
00709   }
00710   else
00711   {
00712     *port=0;
00713   }
00714   char* pathPtr = strchr(hostPtr, '/');
00715   if( hostLen == 0 )
00716   {
00717     hostLen = pathPtr - hostPtr;
00718   }
00719 
00720   if( maxHostLen < hostLen + 1 ) //including NULL-terminating char
00721   {
00722     WARN("Host str is too small (%d >= %d)", maxHostLen, hostLen + 1);
00723     return HTTP_PARSE;
00724   }
00725   memcpy(host, hostPtr, hostLen);
00726   host[hostLen] = '\0';
00727 
00728   size_t pathLen;
00729   char* fragmentPtr = strchr(hostPtr, '#');
00730   if(fragmentPtr != NULL)
00731   {
00732     pathLen = fragmentPtr - pathPtr;
00733   }
00734   else
00735   {
00736     pathLen = strlen(pathPtr);
00737   }
00738 
00739   if( maxPathLen < pathLen + 1 ) //including NULL-terminating char
00740   {
00741     WARN("Path str is too small (%d >= %d)", maxPathLen, pathLen + 1);
00742     return HTTP_PARSE;
00743   }
00744   memcpy(path, pathPtr, pathLen);
00745   path[pathLen] = '\0';
00746 
00747   return HTTP_OK;
00748 }