Plantus / HTTPClient

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