HTTP/HTTPS Client Library for the X-NUCLEO-IDW01M1v2 wifi board.

Dependents:   HTTPClient_HelloWorld_IDW01M1 wifigianluigi HTTPClient_HelloWorld_IDW01M1_Fabio_Ricezione

Fork of HTTPClient by ST Expansion SW Team

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 
00044 #define MAX_KEY     64
00045 #define MAX_VALUE   64
00046 
00047 #include <cstring>
00048 #include "HTTPClient.h"
00049 
00050 //HTTPClient::HTTPClient(NetworkStack  & _m_intf) : m_intf(_m_intf)
00051 HTTPClient::HTTPClient(SpwfSAInterface  & _m_intf) : m_intf(_m_intf)
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 
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[64];
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 ((strcmp ("https", scheme)) == 0 || (strcmp ("HTTPS", scheme) == 0)) {
00141       if ( port == 0) port = 443;     
00142       m_intf.set_secure_mode(); 
00143   }
00144   if(port == 0) //TODO do handle HTTPS->443
00145   {
00146     port = 80;
00147   }
00148   
00149   DBG("Scheme: %s", scheme);
00150   DBG("Host: %s", host);
00151   DBG("Port: %d", port);
00152   DBG("Path: %s", path);
00153 // Open
00154   m_sock.open(&m_intf);
00155   m_intf.set_unsecure_mode();  
00156   //Connect
00157   DBG("Connecting socket to server");
00158   int ret = m_sock.connect(host, port);
00159   if (ret < 0)
00160   {
00161     m_sock.close();
00162     ERR("TCP Could not connect");
00163     return HTTP_CONN;
00164   }
00165   DBG ("TCP connected\n\r");
00166   //Send request
00167   DBG("Sending request");
00168 //  char buf[CHUNK_SIZE];
00169   const char* meth = (method==HTTP_GET)?"GET":(method==HTTP_POST)?"POST":(method==HTTP_PUT)?"PUT":(method==HTTP_DELETE)?"DELETE":"";
00170   snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\n", meth, path, host); //Write request
00171   ret = send(buf);
00172   if(ret)
00173   {
00174     m_sock.close();
00175     ERR("Could not write request");
00176     return HTTP_CONN;
00177   }
00178   //Send all headers
00179  
00180   //Send default headers
00181   DBG("Sending headers");
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   //Send data (if available)
00229   if( pDataOut != NULL )
00230   {
00231     DBG("Sending data");
00232     while(true)
00233     {
00234               
00235       size_t writtenLen = 0;
00236       pDataOut->read(buf, CHUNK_SIZE, &trfLen);
00237 
00238       if( pDataOut->getIsChunked() )
00239       {
00240         //Write chunk header
00241         char chunkHeader[16];
00242         snprintf(chunkHeader, sizeof(chunkHeader), "%X\r\n", trfLen); //In hex encoding
00243         ret = send(chunkHeader);
00244         CHECK_CONN_ERR(ret);
00245       }
00246       else if( trfLen == 0 )
00247       {
00248         break;
00249       }
00250       if( trfLen != 0 )
00251       {
00252         ret = send(buf, trfLen);
00253         CHECK_CONN_ERR(ret);
00254       }
00255 
00256       if( pDataOut->getIsChunked()  )
00257       {
00258         ret = send("\r\n"); //Chunk-terminating CRLF
00259         CHECK_CONN_ERR(ret);
00260       }
00261       else
00262       {
00263         writtenLen += trfLen;
00264         if( writtenLen >= pDataOut->getDataLen() )
00265         {
00266           break;
00267         }
00268       }
00269 
00270       if( trfLen == 0 )
00271       {
00272         break;
00273       }
00274     }
00275   }
00276   
00277   //Receive response
00278   DBG("Receiving response");
00279   ret = recv(buf, 1, CHUNK_SIZE - 1, &trfLen); //Read n bytes
00280   CHECK_CONN_ERR(ret);
00281 
00282   buf[trfLen] = '\0';
00283 
00284   //Make sure we got the first response line
00285   char* crlfPtr = NULL;
00286   while( true )
00287   {
00288     crlfPtr = strstr(buf, "\r\n");
00289   if(crlfPtr == NULL)
00290   {
00291       if( trfLen < CHUNK_SIZE - 1 )
00292       {
00293         size_t newTrfLen;
00294         ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen);
00295         trfLen += newTrfLen;
00296         buf[trfLen] = '\0';
00297         DBG("Read %d chars; In buf: [%s]", newTrfLen, buf);
00298         CHECK_CONN_ERR(ret);
00299         continue;
00300       }
00301       else
00302       {
00303     PRTCL_ERR();
00304   }
00305     }
00306     break;
00307   }
00308   int crlfPos = crlfPtr - buf;
00309   buf[crlfPos] = '\0';
00310   //Parse HTTP response
00311   //if( sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 )
00312   if(crlfPos > 13)
00313   {
00314     buf[13] = '\0';
00315   }
00316   if( sscanf(buf, "HTTP/%*d.%*d %d", &m_httpResponseCode) != 1 ) //Kludge for newlib nano
00317   {
00318     //Cannot match string, error
00319     ERR("Not a correct HTTP answer : %s\n", buf);
00320     PRTCL_ERR();
00321   }
00322 
00323   if( (m_httpResponseCode < 200) || (m_httpResponseCode >= 300) )
00324   {
00325     //Did not return a 2xx code; TODO fetch headers/(&data?) anyway and implement a mean of writing/reading headers 
00326     WARN("Response code %d", m_httpResponseCode);
00327     PRTCL_ERR();
00328   }
00329 
00330   DBG("=======>>>>  Reading headers");
00331 
00332   memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well
00333   trfLen -= (crlfPos + 2);
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[MAX_KEY];
00373     char value[MAX_VALUE];
00374 
00375     //key[31] = '\0';
00376     //value[31] = '\0';
00377 
00378     memset(key, 0, MAX_KEY);
00379     memset(value, 0, MAX_VALUE);
00380 
00381     //int n = sscanf(buf, "%31[^:]: %31[^\r\n]", key, value);
00382     
00383     int n = 0;
00384     
00385     char* keyEnd = strchr(buf, ':');
00386     if(keyEnd != NULL)
00387     {
00388       *keyEnd = '\0';
00389       if(strlen(buf) < MAX_KEY)
00390       {
00391         strcpy(key, buf);
00392         n++;
00393         char* valueStart = keyEnd + 2;
00394         if( (valueStart - buf) < crlfPos )
00395         {
00396           if(strlen(valueStart) < MAX_VALUE)
00397           { 
00398             strcpy(value, valueStart);
00399             n++;
00400           }
00401         }
00402       }
00403     }
00404     if ( n == 2 )
00405     {
00406       DBG("Read header : %s: %s\n", key, value);
00407       if( !strcmp(key, "Content-Length") )
00408       {
00409         sscanf(value, "%d", &recvContentLength);
00410         recvLengthUnknown = false;
00411         pDataIn->setDataLen(recvContentLength);
00412       }
00413       else if( !strcmp(key, "Transfer-Encoding") )
00414       {
00415         if( !strcmp(value, "Chunked") || !strcmp(value, "chunked") )
00416         {
00417           recvChunked = true;
00418           recvLengthUnknown = false;
00419           pDataIn->setIsChunked(true);
00420         }
00421       }
00422       else if( !strcmp(key, "Content-Type") )
00423       {
00424         pDataIn->setDataType(value);
00425       }
00426 
00427       memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well
00428       trfLen -= (crlfPos + 2);
00429 
00430     }
00431     else
00432     {
00433       ERR("Could not parse header");
00434       PRTCL_ERR();
00435     }
00436 
00437   }
00438 
00439   //Receive data
00440   DBG("Receiving data");
00441   while(true)
00442   {
00443     size_t readLen = 0;
00444 
00445     if( recvChunked )
00446     {
00447       //Read chunk header
00448       bool foundCrlf;
00449       do
00450       {
00451         foundCrlf = false;
00452         crlfPos=0;
00453         buf[trfLen]=0;
00454         if(trfLen >= 2)
00455         {
00456           for(; crlfPos < trfLen - 2; crlfPos++)
00457           {
00458             if( buf[crlfPos] == '\r' && buf[crlfPos + 1] == '\n' )
00459             {
00460               foundCrlf = true;
00461               break;
00462             }
00463           }
00464         }
00465         if(!foundCrlf) //Try to read more
00466         {
00467           if( trfLen < CHUNK_SIZE )
00468           {
00469             size_t newTrfLen;
00470             ret = recv(buf + trfLen, 0, CHUNK_SIZE - trfLen - 1, &newTrfLen);
00471             trfLen += newTrfLen;
00472             CHECK_CONN_ERR(ret);
00473             continue;
00474           }
00475           else
00476           {
00477             PRTCL_ERR();
00478           }
00479         }
00480       } while(!foundCrlf);
00481       buf[crlfPos] = '\0';
00482       int n = sscanf(buf, "%x", &readLen);
00483       if(n!=1)
00484       {
00485         ERR("Could not read chunk length");
00486         PRTCL_ERR();
00487       }
00488 
00489       memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2)); //Not need to move NULL-terminating char any more
00490       trfLen -= (crlfPos + 2);
00491 
00492       if( readLen == 0 )
00493       {
00494         //Last chunk
00495         break;
00496       }
00497     }
00498     else
00499     {
00500       readLen = recvContentLength;
00501     }
00502 
00503     DBG("Retrieving %d bytes (%d bytes in buffer)", readLen, trfLen);
00504 
00505     do
00506     {
00507       if(recvLengthUnknown )
00508       {
00509         readLen = trfLen;
00510       }
00511       pDataIn->write(buf, MIN(trfLen, readLen));
00512       if(!recvLengthUnknown)
00513       {
00514         if( trfLen > readLen )
00515         {
00516           memmove(buf, &buf[readLen], trfLen - readLen);
00517           trfLen -= readLen;
00518           readLen = 0;
00519         }
00520         else
00521         {
00522           readLen -= trfLen;
00523         }
00524       }
00525       else
00526       {
00527         trfLen = 0;
00528       }
00529 
00530       if(readLen || recvLengthUnknown)
00531       {
00532         ret = recv(buf, 1, CHUNK_SIZE - trfLen - 1, &trfLen);
00533         if(recvLengthUnknown && (ret == HTTP_CLOSED))
00534         {
00535           //Write and exit
00536           pDataIn->write(buf, trfLen);
00537           break;
00538         }
00539         CHECK_CONN_ERR(ret);
00540         if(recvLengthUnknown && (trfLen == 0))
00541         {
00542           break;
00543         }
00544       }
00545     } while(readLen || recvLengthUnknown);
00546 
00547     if( recvChunked )
00548     {
00549       if(trfLen < 2)
00550       {
00551         size_t newTrfLen;
00552         //Read missing chars to find end of chunk
00553         ret = recv(buf + trfLen, 2 - trfLen, CHUNK_SIZE - trfLen - 1, &newTrfLen);
00554         CHECK_CONN_ERR(ret);
00555         trfLen += newTrfLen;
00556       }
00557       if( (buf[0] != '\r') || (buf[1] != '\n') )
00558       {
00559         ERR("Format error");
00560         PRTCL_ERR();
00561       }
00562       memmove(buf, &buf[2], trfLen - 2);
00563       trfLen -= 2;
00564     }
00565     else
00566     {
00567       break;
00568     }
00569 
00570   }
00571 
00572   m_sock.close();
00573   DBG("Completed HTTP transaction");
00574 
00575   return HTTP_OK;
00576 }
00577 
00578 HTTPResult HTTPClient::recv(char* buf, size_t minLen, size_t maxLen, size_t* pReadLen) //0 on success, err code on failure
00579 {
00580   DBG("Trying to read between %d and %d bytes", minLen, maxLen);
00581   size_t readLen = 0;
00582 
00583 #ifdef LICIO
00584 
00585 #else      
00586   if(!m_sock.is_connected())
00587   {
00588     WARN("Connection was closed by server");
00589     return HTTP_CLOSED; //Connection was closed by server 
00590   }
00591 #endif    
00592   int ret;
00593   while(readLen < maxLen)
00594   {
00595     if(readLen < minLen)
00596     {
00597       DBG("Trying to read at most %d bytes [Blocking]", minLen - readLen);
00598 #ifdef LICIO
00599       m_sock.set_blocking(false);
00600       ret = m_sock.recv(buf + readLen, minLen - readLen);
00601 #else      
00602       m_sock.set_blocking(false, m_timeout);
00603       ret = m_sock.receive_all(buf + readLen, minLen - readLen);
00604 #endif
00605     }
00606     else
00607     {
00608       DBG("Trying to read at most %d bytes [Not blocking]", maxLen - readLen);
00609 #ifdef LICIO
00610       m_sock.set_blocking(false);
00611       ret = m_sock.recv(buf + readLen, maxLen - readLen);
00612 #else      
00613       m_sock.set_blocking(false, 0);
00614       ret = m_sock.receive(buf + readLen, maxLen - readLen);
00615 #endif      
00616     }
00617     
00618     if( ret > 0)
00619     {
00620       readLen += ret;
00621     }
00622     else if( ret == 0 || ret == NSAPI_ERROR_WOULD_BLOCK)
00623     {
00624       break;
00625     }
00626     else
00627     {
00628 #ifdef LICIO      
00629 //    if (ret == NSAPI_ERROR_NO_CONNECTION) { *pReadLen = readLen; return HTTP_CONN; }
00630 #else 
00631       if(!m_sock.is_connected())
00632       {
00633         ERR("Connection error (recv returned %d)", ret);
00634         *pReadLen = readLen;
00635         return HTTP_CONN;
00636       }
00637       else
00638       {
00639         break;      
00640       }
00641 #endif
00642     }
00643 #ifdef LICIO
00644 //    if (ret == NSAPI_ERROR_NO_CONNECTION) { *pReadLen = readLen; return HTTP_CONN; }
00645 #else
00646     if(!m_sock.is_connected())
00647     {
00648       break;
00649     }
00650 #endif
00651   }
00652   DBG("Read %d bytes", readLen);
00653   *pReadLen = readLen;
00654   return HTTP_OK;
00655 }
00656 
00657 HTTPResult HTTPClient::send(char* buf, size_t len) //0 on success, err code on failure
00658 {
00659   if(len == 0)
00660   {
00661     len = strlen(buf);
00662   }
00663   DBG("Trying to write %d bytes", len);
00664   size_t writtenLen = 0;
00665 
00666 #ifdef LICIO
00667 #else
00668   if(!m_sock.is_connected())
00669   {
00670     WARN("Connection was closed by server");
00671     return HTTP_CLOSED; //Connection was closed by server 
00672   }
00673 #endif
00674 #ifdef LICIO
00675   m_sock.set_blocking(false);
00676   int ret = m_sock.send(buf, len);
00677 
00678 #else
00679   m_sock.set_blocking(false, m_timeout);
00680   int ret = m_sock.send_all(buf, len);
00681 #endif
00682   if(ret > 0)
00683   {
00684     writtenLen += ret;
00685   }
00686   else if( ret == 0 )
00687   {
00688     WARN("Connection was closed by server");
00689     return HTTP_CLOSED; //Connection was closed by server
00690   }
00691   else
00692   {
00693     ERR("Connection error (send returned %d)", ret);
00694     return HTTP_CONN;
00695   }
00696   
00697   DBG("Written %d bytes", writtenLen);
00698   return HTTP_OK;
00699 }
00700 
00701 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
00702 {
00703   char* schemePtr = (char*) url;
00704   char* hostPtr = (char*) strstr(url, "://");
00705   if(hostPtr == NULL)
00706   {
00707     WARN("Could not find host");
00708     return HTTP_PARSE; //URL is invalid
00709   }
00710 
00711   if( maxSchemeLen < hostPtr - schemePtr + 1 ) //including NULL-terminating char
00712   {
00713     WARN("Scheme str is too small (%d >= %d)", maxSchemeLen, hostPtr - schemePtr + 1);
00714     return HTTP_PARSE;
00715   }
00716   memcpy(scheme, schemePtr, hostPtr - schemePtr);
00717   scheme[hostPtr - schemePtr] = '\0';
00718 
00719   hostPtr+=3;
00720 
00721   size_t hostLen = 0;
00722 
00723   char* portPtr = strchr(hostPtr, ':');
00724   if( portPtr != NULL )
00725   {
00726     hostLen = portPtr - hostPtr;
00727     portPtr++;
00728     if( sscanf(portPtr, "%hu", port) != 1)
00729     {
00730       WARN("Could not find port");
00731       return HTTP_PARSE;
00732     }
00733   }
00734   else
00735   {
00736     *port=0;
00737   }
00738   char* pathPtr = strchr(hostPtr, '/');
00739   if( hostLen == 0 )
00740   {
00741     hostLen = pathPtr - hostPtr;
00742   }
00743 
00744   if( maxHostLen < hostLen + 1 ) //including NULL-terminating char
00745   {
00746     WARN("Host str is too small (%d >= %d)", maxHostLen, hostLen + 1);
00747     return HTTP_PARSE;
00748   }
00749   memcpy(host, hostPtr, hostLen);
00750   host[hostLen] = '\0';
00751 
00752   size_t pathLen;
00753   char* fragmentPtr = strchr(hostPtr, '#');
00754   if(fragmentPtr != NULL)
00755   {
00756     pathLen = fragmentPtr - pathPtr;
00757   }
00758   else
00759   {
00760     pathLen = strlen(pathPtr);
00761   }
00762 
00763   if( maxPathLen < pathLen + 1 ) //including NULL-terminating char
00764   {
00765     WARN("Path str is too small (%d >= %d)", maxPathLen, pathLen + 1);
00766     return HTTP_PARSE;
00767   }
00768   memcpy(path, pathPtr, pathLen);
00769   path[pathLen] = '\0';
00770 
00771   return HTTP_OK;
00772 }