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

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[64];
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     char type[48];
00190     if( pDataOut->getDataType(type, 48) == HTTP_OK )
00191     {
00192       snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", type);
00193       ret = send(buf);
00194       CHECK_CONN_ERR(ret);
00195     }
00196     
00197     //Send specific headers
00198     while( pDataOut->getHeader(buf, sizeof(buf) - 3) ) //must have space left for CRLF + 0 terminating char
00199     {
00200       size_t headerlen = strlen(buf);
00201       snprintf(buf + headerlen, sizeof(buf) - headerlen, "\r\n");
00202       ret = send(buf);
00203       CHECK_CONN_ERR(ret);
00204     }
00205   }
00206   
00207   //Send specific headers
00208   while( pDataIn->getHeader(buf, sizeof(buf) - 3) )
00209   {
00210     size_t headerlen = strlen(buf);
00211     snprintf(buf + headerlen, sizeof(buf) - headerlen, "\r\n");
00212     ret = send(buf);
00213     CHECK_CONN_ERR(ret);
00214   }
00215   
00216   //Close headers
00217   DBG("Headers sent");
00218   ret = send("\r\n");
00219   CHECK_CONN_ERR(ret);
00220 
00221   size_t trfLen;
00222   
00223   //Send data (if available)
00224   if( pDataOut != NULL )
00225   {
00226     DBG("Sending data");
00227     while(true)
00228     {
00229       size_t writtenLen = 0;
00230       pDataOut->read(buf, CHUNK_SIZE, &trfLen);
00231       if( pDataOut->getIsChunked() )
00232       {
00233         //Write chunk header
00234         char chunkHeader[16];
00235         snprintf(chunkHeader, sizeof(chunkHeader), "%X\r\n", trfLen); //In hex encoding
00236         ret = send(chunkHeader);
00237         CHECK_CONN_ERR(ret);
00238       }
00239       else if( trfLen == 0 )
00240       {
00241         break;
00242       }
00243       if( trfLen != 0 )
00244       {
00245         ret = send(buf, trfLen);
00246         CHECK_CONN_ERR(ret);
00247       }
00248 
00249       if( pDataOut->getIsChunked()  )
00250       {
00251         ret = send("\r\n"); //Chunk-terminating CRLF
00252         CHECK_CONN_ERR(ret);
00253       }
00254       else
00255       {
00256         writtenLen += trfLen;
00257         if( writtenLen >= pDataOut->getDataLen() )
00258         {
00259           break;
00260         }
00261       }
00262 
00263       if( trfLen == 0 )
00264       {
00265         break;
00266       }
00267     }
00268   }
00269   
00270   //Receive response
00271   DBG("Receiving response");
00272   ret = recv(buf, 1, CHUNK_SIZE - 1, &trfLen); //Read n bytes
00273   CHECK_CONN_ERR(ret);
00274 
00275   buf[trfLen] = '\0';
00276 
00277   //Make sure we got the first response line
00278   char* crlfPtr = NULL;
00279   while( true )
00280   {
00281     crlfPtr = strstr(buf, "\r\n");
00282   if(crlfPtr == NULL)
00283   {
00284       if( trfLen < CHUNK_SIZE - 1 )
00285       {
00286         size_t newTrfLen;
00287         ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen);
00288         trfLen += newTrfLen;
00289         buf[trfLen] = '\0';
00290         DBG("Read %d chars; In buf: [%s]", newTrfLen, buf);
00291         CHECK_CONN_ERR(ret);
00292         continue;
00293       }
00294       else
00295       {
00296     PRTCL_ERR();
00297   }
00298     }
00299     break;
00300   }
00301 
00302   int crlfPos = crlfPtr - buf;
00303   buf[crlfPos] = '\0';
00304 
00305   //Parse HTTP response
00306   //if( sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 )
00307   if(crlfPos > 13)
00308   {
00309     buf[13] = '\0';
00310   }
00311   if( sscanf(buf, "HTTP/%*d.%*d %d", &m_httpResponseCode) != 1 ) //Kludge for newlib nano
00312   {
00313     //Cannot match string, error
00314     ERR("Not a correct HTTP answer : %s\n", buf);
00315     PRTCL_ERR();
00316   }
00317 
00318   if( (m_httpResponseCode < 200) || (m_httpResponseCode >= 300) )
00319   {
00320     //Did not return a 2xx code; TODO fetch headers/(&data?) anyway and implement a mean of writing/reading headers 
00321     WARN("Response code %d", m_httpResponseCode);
00322     PRTCL_ERR();
00323   }
00324 
00325   DBG("Reading headers");
00326 
00327   memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well
00328   trfLen -= (crlfPos + 2);
00329 
00330   size_t recvContentLength = 0;
00331   bool recvChunked = false;
00332   bool recvLengthUnknown = true;
00333   //Now get headers
00334   while( true )
00335   {
00336     crlfPtr = strstr(buf, "\r\n");
00337     if(crlfPtr == NULL)
00338     {
00339       if( trfLen < CHUNK_SIZE - 1 )
00340       {
00341         size_t newTrfLen;
00342         ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen);
00343         trfLen += newTrfLen;
00344         buf[trfLen] = '\0';
00345         DBG("Read %d chars; In buf: [%s]", newTrfLen, buf);
00346         CHECK_CONN_ERR(ret);
00347         continue;
00348       }
00349       else
00350       {
00351         PRTCL_ERR();
00352       }
00353     }
00354 
00355     crlfPos = crlfPtr - buf;
00356 
00357     if(crlfPos == 0) //End of headers
00358     {
00359       DBG("Headers read");
00360       memmove(buf, &buf[2], trfLen - 2 + 1); //Be sure to move NULL-terminating char as well
00361       trfLen -= 2;
00362       break;
00363     }
00364 
00365     buf[crlfPos] = '\0';
00366 
00367     char key[32];
00368     char value[32];
00369 
00370     //key[31] = '\0';
00371     //value[31] = '\0';
00372 
00373     memset(key, 0, 32);
00374     memset(value, 0, 32);
00375 
00376     //int n = sscanf(buf, "%31[^:]: %31[^\r\n]", key, value);
00377     
00378     int n = 0;
00379     
00380     char* keyEnd = strchr(buf, ':');
00381     if(keyEnd != NULL)
00382     {
00383       *keyEnd = '\0';
00384       if(strlen(buf) < 32)
00385       {
00386         strcpy(key, buf);
00387         n++;
00388         char* valueStart = keyEnd + 2;
00389         if( (valueStart - buf) < crlfPos )
00390         {
00391           if(strlen(valueStart) < 32)
00392           { 
00393             strcpy(value, valueStart);
00394             n++;
00395           }
00396         }
00397       }
00398     }
00399     if ( n == 2 )
00400     {
00401       DBG("Read header : %s: %s\n", key, value);
00402       if( !strcmp(key, "Content-Length") )
00403       {
00404         sscanf(value, "%d", &recvContentLength);
00405         recvLengthUnknown = false;
00406         pDataIn->setDataLen(recvContentLength);
00407       }
00408       else if( !strcmp(key, "Transfer-Encoding") )
00409       {
00410         if( !strcmp(value, "Chunked") || !strcmp(value, "chunked") )
00411         {
00412           recvChunked = true;
00413           recvLengthUnknown = false;
00414           pDataIn->setIsChunked(true);
00415         }
00416       }
00417       else if( !strcmp(key, "Content-Type") )
00418       {
00419         pDataIn->setDataType(value);
00420       }
00421 
00422       memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well
00423       trfLen -= (crlfPos + 2);
00424 
00425     }
00426     else
00427     {
00428       ERR("Could not parse header");
00429       PRTCL_ERR();
00430     }
00431 
00432   }
00433 
00434   //Receive data
00435   DBG("Receiving data");
00436   while(true)
00437   {
00438     size_t readLen = 0;
00439 
00440     if( recvChunked )
00441     {
00442       //Read chunk header
00443       bool foundCrlf;
00444       do
00445       {
00446         foundCrlf = false;
00447         crlfPos=0;
00448         buf[trfLen]=0;
00449         if(trfLen >= 2)
00450         {
00451           for(; crlfPos < trfLen - 2; crlfPos++)
00452           {
00453             if( buf[crlfPos] == '\r' && buf[crlfPos + 1] == '\n' )
00454             {
00455               foundCrlf = true;
00456               break;
00457             }
00458           }
00459         }
00460         if(!foundCrlf) //Try to read more
00461         {
00462           if( trfLen < CHUNK_SIZE )
00463           {
00464             size_t newTrfLen;
00465             ret = recv(buf + trfLen, 0, CHUNK_SIZE - trfLen - 1, &newTrfLen);
00466             trfLen += newTrfLen;
00467             CHECK_CONN_ERR(ret);
00468             continue;
00469           }
00470           else
00471           {
00472             PRTCL_ERR();
00473           }
00474         }
00475       } while(!foundCrlf);
00476       buf[crlfPos] = '\0';
00477       int n = sscanf(buf, "%x", &readLen);
00478       if(n!=1)
00479       {
00480         ERR("Could not read chunk length");
00481         PRTCL_ERR();
00482       }
00483 
00484       memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2)); //Not need to move NULL-terminating char any more
00485       trfLen -= (crlfPos + 2);
00486 
00487       if( readLen == 0 )
00488       {
00489         //Last chunk
00490         break;
00491       }
00492     }
00493     else
00494     {
00495       readLen = recvContentLength;
00496     }
00497 
00498     DBG("Retrieving %d bytes (%d bytes in buffer)", readLen, trfLen);
00499 
00500     do
00501     {
00502       if(recvLengthUnknown )
00503       {
00504         readLen = trfLen;
00505       }
00506       pDataIn->write(buf, MIN(trfLen, readLen));
00507       if(!recvLengthUnknown)
00508       {
00509         if( trfLen > readLen )
00510         {
00511           memmove(buf, &buf[readLen], trfLen - readLen);
00512           trfLen -= readLen;
00513           readLen = 0;
00514         }
00515         else
00516         {
00517           readLen -= trfLen;
00518         }
00519       }
00520       else
00521       {
00522         trfLen = 0;
00523       }
00524 
00525       if(readLen || recvLengthUnknown)
00526       {
00527         ret = recv(buf, 1, CHUNK_SIZE - trfLen - 1, &trfLen);
00528         if(recvLengthUnknown && (ret == HTTP_CLOSED))
00529         {
00530           //Write and exit
00531           pDataIn->write(buf, trfLen);
00532           break;
00533         }
00534         CHECK_CONN_ERR(ret);
00535         if(recvLengthUnknown && (trfLen == 0))
00536         {
00537           break;
00538         }
00539       }
00540     } while(readLen || recvLengthUnknown);
00541 
00542     if( recvChunked )
00543     {
00544       if(trfLen < 2)
00545       {
00546         size_t newTrfLen;
00547         //Read missing chars to find end of chunk
00548         ret = recv(buf + trfLen, 2 - trfLen, CHUNK_SIZE - trfLen - 1, &newTrfLen);
00549         CHECK_CONN_ERR(ret);
00550         trfLen += newTrfLen;
00551       }
00552       if( (buf[0] != '\r') || (buf[1] != '\n') )
00553       {
00554         ERR("Format error");
00555         PRTCL_ERR();
00556       }
00557       memmove(buf, &buf[2], trfLen - 2);
00558       trfLen -= 2;
00559     }
00560     else
00561     {
00562       break;
00563     }
00564 
00565   }
00566 
00567   m_sock.close();
00568   DBG("Completed HTTP transaction");
00569 
00570   return HTTP_OK;
00571 }
00572 
00573 HTTPResult HTTPClient::recv(char* buf, size_t minLen, size_t maxLen, size_t* pReadLen) //0 on success, err code on failure
00574 {
00575   DBG("Trying to read between %d and %d bytes", minLen, maxLen);
00576   size_t readLen = 0;
00577       
00578   if(!m_sock.is_connected())
00579   {
00580     WARN("Connection was closed by server");
00581     return HTTP_CLOSED; //Connection was closed by server 
00582   }
00583     
00584   int ret;
00585   while(readLen < maxLen)
00586   {
00587     if(readLen < minLen)
00588     {
00589       DBG("Trying to read at most %d bytes [Blocking]", minLen - readLen);
00590       m_sock.set_blocking(false, m_timeout);
00591       ret = m_sock.receive_all(buf + readLen, minLen - readLen);
00592     }
00593     else
00594     {
00595       DBG("Trying to read at most %d bytes [Not blocking]", maxLen - readLen);
00596       m_sock.set_blocking(false, 0);
00597       ret = m_sock.receive(buf + readLen, maxLen - readLen);
00598     }
00599     
00600     if( ret > 0)
00601     {
00602       readLen += ret;
00603     }
00604     else if( ret == 0 )
00605     {
00606       break;
00607     }
00608     else
00609     {
00610       if(!m_sock.is_connected())
00611       {
00612         ERR("Connection error (recv returned %d)", ret);
00613         *pReadLen = readLen;
00614         return HTTP_CONN;
00615       }
00616       else
00617       {
00618         break;      
00619       }
00620     }
00621     
00622     if(!m_sock.is_connected())
00623     {
00624       break;
00625     }
00626   }
00627   DBG("Read %d bytes", readLen);
00628   *pReadLen = readLen;
00629   return HTTP_OK;
00630 }
00631 
00632 HTTPResult HTTPClient::send(char* buf, size_t len) //0 on success, err code on failure
00633 {
00634   if(len == 0)
00635   {
00636     len = strlen(buf);
00637   }
00638   DBG("Trying to write %d bytes", len);
00639   size_t writtenLen = 0;
00640     
00641   if(!m_sock.is_connected())
00642   {
00643     WARN("Connection was closed by server");
00644     return HTTP_CLOSED; //Connection was closed by server 
00645   }
00646   
00647   m_sock.set_blocking(false, m_timeout);
00648   int ret = m_sock.send_all(buf, len);
00649   if(ret > 0)
00650   {
00651     writtenLen += ret;
00652   }
00653   else if( ret == 0 )
00654   {
00655     WARN("Connection was closed by server");
00656     return HTTP_CLOSED; //Connection was closed by server
00657   }
00658   else
00659   {
00660     ERR("Connection error (send returned %d)", ret);
00661     return HTTP_CONN;
00662   }
00663   
00664   DBG("Written %d bytes", writtenLen);
00665   return HTTP_OK;
00666 }
00667 
00668 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
00669 {
00670   char* schemePtr = (char*) url;
00671   char* hostPtr = (char*) strstr(url, "://");
00672   if(hostPtr == NULL)
00673   {
00674     WARN("Could not find host");
00675     return HTTP_PARSE; //URL is invalid
00676   }
00677 
00678   if( maxSchemeLen < hostPtr - schemePtr + 1 ) //including NULL-terminating char
00679   {
00680     WARN("Scheme str is too small (%d >= %d)", maxSchemeLen, hostPtr - schemePtr + 1);
00681     return HTTP_PARSE;
00682   }
00683   memcpy(scheme, schemePtr, hostPtr - schemePtr);
00684   scheme[hostPtr - schemePtr] = '\0';
00685 
00686   hostPtr+=3;
00687 
00688   size_t hostLen = 0;
00689 
00690   char* portPtr = strchr(hostPtr, ':');
00691   if( portPtr != NULL )
00692   {
00693     hostLen = portPtr - hostPtr;
00694     portPtr++;
00695     if( sscanf(portPtr, "%hu", port) != 1)
00696     {
00697       WARN("Could not find port");
00698       return HTTP_PARSE;
00699     }
00700   }
00701   else
00702   {
00703     *port=0;
00704   }
00705   char* pathPtr = strchr(hostPtr, '/');
00706   if( hostLen == 0 )
00707   {
00708     hostLen = pathPtr - hostPtr;
00709   }
00710 
00711   if( maxHostLen < hostLen + 1 ) //including NULL-terminating char
00712   {
00713     WARN("Host str is too small (%d >= %d)", maxHostLen, hostLen + 1);
00714     return HTTP_PARSE;
00715   }
00716   memcpy(host, hostPtr, hostLen);
00717   host[hostLen] = '\0';
00718 
00719   size_t pathLen;
00720   char* fragmentPtr = strchr(hostPtr, '#');
00721   if(fragmentPtr != NULL)
00722   {
00723     pathLen = fragmentPtr - pathPtr;
00724   }
00725   else
00726   {
00727     pathLen = strlen(pathPtr);
00728   }
00729 
00730   if( maxPathLen < pathLen + 1 ) //including NULL-terminating char
00731   {
00732     WARN("Path str is too small (%d >= %d)", maxPathLen, pathLen + 1);
00733     return HTTP_PARSE;
00734   }
00735   memcpy(path, pathPtr, pathLen);
00736   path[pathLen] = '\0';
00737 
00738   return HTTP_OK;
00739 }