Change the CHUNK_SIZE, KEY_SIZE and VALUE_SIZE

Dependents:   CurrentWeatherData_W5500 EmailButton EmailButton HTTPClient_Weather ... more

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