smd.iotkit2.ch / Mbed 2 deprecated 2-10-02-Uebung

Dependencies:   EthernetInterface MbedJSONValue NTPClient mbed-rtos mbed

Fork of SunriseSunset by smd.iotkit2.ch

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