xiaorui qu / HTTPClient

Dependents:   mbed-demo-http-get-json

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