Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: mbed-demo-http-get-json
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 }
Generated on Sat Jul 16 2022 06:50:27 by
1.7.2