Colin Meikle / HTTPClient

Dependents:   weather HTTPClient_IFTTT_Maker_post_HelloWorld Thingspeak_over_ethernet Thingspeak_over_ethernet

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