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: Sample_HTTPClient Sample_HTTPClient LWM2M_NanoService_Ethernet LWM2M_NanoService_Ethernet ... more
Fork of HTTPClient by
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) && !defined(TARGET_LPC11U24)) 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() : 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 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 ret = m_sock.connect(host, port); 00225 if (ret < 0) { 00226 m_sock.close(); 00227 ERR("Could not connect"); 00228 return HTTP_CONN; 00229 } 00230 00231 // Send request 00232 DBG("Sending request"); 00233 const char* meth = (method==HTTP_GET)?"GET":(method==HTTP_POST)?"POST":(method==HTTP_PUT)?"PUT":(method==HTTP_DELETE)?"DELETE":""; 00234 snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s:%d\r\n", meth, path, host, port); //Write request 00235 INFO(" buf{%s}", buf); 00236 ret = send(buf); 00237 if (ret) { 00238 m_sock.close(); 00239 ERR("Could not write request"); 00240 return HTTP_CONN; 00241 } 00242 00243 // send authorization 00244 INFO("send auth (if defined)"); 00245 if (m_basicAuthUser && m_basicAuthPassword) { 00246 strcpy(buf, "Authorization: Basic "); 00247 createauth(m_basicAuthUser, m_basicAuthPassword, buf+strlen(buf), sizeof(buf)-strlen(buf)); 00248 strcat(buf, "\r\n"); 00249 INFO(" (%s,%s) => (%s)", m_basicAuthUser, m_basicAuthPassword, buf); 00250 ret = send(buf); 00251 INFO(" ret = %d", ret); 00252 if(ret) { 00253 m_sock.close(); 00254 ERR("Could not write request"); 00255 return HTTP_CONN; 00256 } 00257 } 00258 00259 // Send all headers 00260 INFO("Send custom header(s) %d (if any)", m_nCustomHeaders); 00261 for (size_t nh = 0; nh < m_nCustomHeaders * 2; nh+=2) { 00262 INFO("hdr[%2d] %s: %s", nh, m_customHeaders[nh], m_customHeaders[nh+1]); 00263 snprintf(buf, sizeof(buf), "%s: %s\r\n", m_customHeaders[nh], m_customHeaders[nh+1]); 00264 ret = send(buf); 00265 if (ret) { 00266 ERR("closing"); 00267 wait_ms(50); 00268 m_sock.close(); 00269 ERR("Could not write request"); 00270 return HTTP_CONN; 00271 } 00272 INFO(" send() returned %d", ret); 00273 } 00274 00275 //Send default headers 00276 DBG("Sending headers"); 00277 if( pDataOut != NULL ) { 00278 if( pDataOut->getIsChunked() ) { 00279 ret = send("Transfer-Encoding: chunked\r\n"); 00280 CHECK_CONN_ERR(ret); 00281 } else { 00282 snprintf(buf, sizeof(buf), "Content-Length: %d\r\n", pDataOut->getDataLen()); 00283 ret = send(buf); 00284 CHECK_CONN_ERR(ret); 00285 } 00286 char type[48]; 00287 if( pDataOut->getDataType(type, 48) == HTTP_OK ) { 00288 snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", type); 00289 ret = send(buf); 00290 CHECK_CONN_ERR(ret); 00291 } 00292 } 00293 00294 //Close headers 00295 DBG("Headers sent"); 00296 ret = send("\r\n"); 00297 CHECK_CONN_ERR(ret); 00298 00299 //Send data (if available) 00300 if( pDataOut != NULL ) { 00301 DBG("Sending data [%s]", buf); 00302 while(true) { 00303 size_t writtenLen = 0; 00304 pDataOut->read(buf, CHUNK_SIZE, &trfLen); 00305 DBG(" trfLen: %d", trfLen); 00306 if( pDataOut->getIsChunked() ) { 00307 //Write chunk header 00308 char chunkHeader[16]; 00309 snprintf(chunkHeader, sizeof(chunkHeader), "%X\r\n", trfLen); //In hex encoding 00310 ret = send(chunkHeader); 00311 CHECK_CONN_ERR(ret); 00312 } else if( trfLen == 0 ) { 00313 break; 00314 } 00315 if( trfLen != 0 ) { 00316 ret = send(buf, trfLen); 00317 CHECK_CONN_ERR(ret); 00318 } 00319 00320 if( pDataOut->getIsChunked() ) { 00321 ret = send("\r\n"); //Chunk-terminating CRLF 00322 CHECK_CONN_ERR(ret); 00323 } else { 00324 writtenLen += trfLen; 00325 if( writtenLen >= pDataOut->getDataLen() ) { 00326 break; 00327 } 00328 } 00329 00330 if( trfLen == 0 ) { 00331 break; 00332 } 00333 } 00334 00335 } 00336 00337 //Receive response 00338 DBG("Receiving response"); 00339 //ret = recv(buf, CHUNK_SIZE - 1, CHUNK_SIZE - 1, &trfLen); //Read n bytes 00340 ret = recv(buf, 1, CHUNK_SIZE - 1, &trfLen); // recommended by Rob Noble to avoid timeout wait 00341 CHECK_CONN_ERR(ret); 00342 buf[trfLen] = '\0'; 00343 INFO("Received \r\n(%s\r\n)", buf); 00344 00345 char* crlfPtr = strstr(buf, "\r\n"); 00346 if( crlfPtr == NULL) { 00347 PRTCL_ERR(); 00348 } 00349 00350 crlfPos = crlfPtr - buf; 00351 buf[crlfPos] = '\0'; 00352 00353 //Parse HTTP response 00354 if( sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 ) { 00355 //Cannot match string, error 00356 ERR("Not a correct HTTP answer : {%s}\n", buf); 00357 PRTCL_ERR(); 00358 } 00359 00360 if( (m_httpResponseCode < 200) || (m_httpResponseCode >= 400) ) { 00361 //Did not return a 2xx code; TODO fetch headers/(&data?) anyway and implement a mean of writing/reading headers 00362 WARN("Response code %d", m_httpResponseCode); 00363 PRTCL_ERR(); 00364 } 00365 00366 DBG("Reading headers"); 00367 00368 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well 00369 trfLen -= (crlfPos + 2); 00370 00371 recvContentLength = 0; 00372 recvChunked = false; 00373 //Now get headers 00374 while( true ) { 00375 crlfPtr = strstr(buf, "\r\n"); 00376 if(crlfPtr == NULL) { 00377 if( trfLen < CHUNK_SIZE - 1 ) { 00378 size_t newTrfLen = 0; 00379 ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen); 00380 trfLen += newTrfLen; 00381 buf[trfLen] = '\0'; 00382 DBG("Read %d chars; In buf: [%s]", newTrfLen, buf); 00383 CHECK_CONN_ERR(ret); 00384 continue; 00385 } else { 00386 PRTCL_ERR(); 00387 } 00388 } 00389 00390 crlfPos = crlfPtr - buf; 00391 00392 if(crlfPos == 0) { //End of headers 00393 DBG("Headers read"); 00394 memmove(buf, &buf[2], trfLen - 2 + 1); //Be sure to move NULL-terminating char as well 00395 trfLen -= 2; 00396 break; 00397 } 00398 00399 buf[crlfPos] = '\0'; 00400 00401 char key[61]; 00402 char value[MAXLEN_VALUE]; 00403 00404 key[31] = '\0'; 00405 value[MAXLEN_VALUE - 1] = '\0'; 00406 00407 int n = sscanf(buf, "%60[^:]: %160[^\r\n]", key, value); 00408 if ( n == 2 ) { 00409 DBG("Read header : %s: %s", key, value); 00410 if( !strcmp(key, "Content-Length") ) { 00411 sscanf(value, "%d", &recvContentLength); 00412 pDataIn->setDataLen(recvContentLength); 00413 } else if( !strcmp(key, "Transfer-Encoding") ) { 00414 if( !strcmp(value, "Chunked") || !strcmp(value, "chunked") ) { 00415 recvChunked = true; 00416 pDataIn->setIsChunked(true); 00417 } 00418 } else if( !strcmp(key, "Content-Type") ) { 00419 pDataIn->setDataType(value); 00420 } else if ( !strcmp(key, "Location") ) { 00421 if (m_location) { 00422 swFree(m_location); 00423 } 00424 m_location = (char *)swMalloc(strlen(value)+1); 00425 if (m_location) { 00426 strcpy(m_location,value); 00427 url = m_location; 00428 INFO("Following redirect[%d] to [%s]", maxRedirect, url); 00429 m_sock.close(); 00430 takeRedirect = true; 00431 break; // exit the while(true) header to follow the redirect 00432 } else { 00433 ERR("Could not allocate memory for %s", key); 00434 } 00435 } 00436 00437 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well 00438 trfLen -= (crlfPos + 2); 00439 } else { 00440 ERR("Could not parse header"); 00441 PRTCL_ERR(); 00442 } 00443 00444 } // while(true) // get headers 00445 if (!takeRedirect) 00446 break; 00447 } // while (maxRedirect) 00448 00449 //Receive data 00450 DBG("Receiving data"); 00451 while(true) { 00452 size_t readLen = 0; 00453 00454 if( recvChunked ) { 00455 //Read chunk header 00456 bool foundCrlf; 00457 do { 00458 foundCrlf = false; 00459 crlfPos=0; 00460 buf[trfLen]=0; 00461 if(trfLen >= 2) { 00462 for(; crlfPos < trfLen - 2; crlfPos++) { 00463 if( buf[crlfPos] == '\r' && buf[crlfPos + 1] == '\n' ) { 00464 foundCrlf = true; 00465 break; 00466 } 00467 } 00468 } 00469 if(!foundCrlf) { //Try to read more 00470 if( trfLen < CHUNK_SIZE ) { 00471 size_t newTrfLen = 0; 00472 ret = recv(buf + trfLen, 0, CHUNK_SIZE - trfLen - 1, &newTrfLen); 00473 trfLen += newTrfLen; 00474 CHECK_CONN_ERR(ret); 00475 continue; 00476 } else { 00477 PRTCL_ERR(); 00478 } 00479 } 00480 } while(!foundCrlf); 00481 buf[crlfPos] = '\0'; 00482 int n = sscanf(buf, "%x", &readLen); 00483 if(n!=1) { 00484 ERR("Could not read chunk length"); 00485 PRTCL_ERR(); 00486 } 00487 00488 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2)); //Not need to move NULL-terminating char any more 00489 trfLen -= (crlfPos + 2); 00490 00491 if( readLen == 0 ) { 00492 //Last chunk 00493 break; 00494 } 00495 } else { 00496 readLen = recvContentLength; 00497 } 00498 00499 DBG("Retrieving %d bytes", readLen); 00500 00501 do { 00502 INFO("write %d,%d: %s", trfLen, readLen, buf); 00503 pDataIn->write(buf, MIN(trfLen, readLen)); 00504 if( trfLen > readLen ) { 00505 memmove(buf, &buf[readLen], trfLen - readLen); 00506 trfLen -= readLen; 00507 readLen = 0; 00508 } else { 00509 readLen -= trfLen; 00510 } 00511 00512 if(readLen) { 00513 ret = recv(buf, 1, CHUNK_SIZE - trfLen - 1, &trfLen); 00514 CHECK_CONN_ERR(ret); 00515 INFO("recv'd next chunk ret: %d", ret); 00516 } 00517 } while(readLen); 00518 00519 if( recvChunked ) { 00520 if(trfLen < 2) { 00521 size_t newTrfLen; 00522 //Read missing chars to find end of chunk 00523 INFO("read chunk"); 00524 ret = recv(buf + trfLen, 2 - trfLen, CHUNK_SIZE - trfLen - 1, &newTrfLen); 00525 CHECK_CONN_ERR(ret); 00526 trfLen += newTrfLen; 00527 INFO("recv'd next chunk ret: %d", ret); 00528 } 00529 if( (buf[0] != '\r') || (buf[1] != '\n') ) { 00530 ERR("Format error"); 00531 PRTCL_ERR(); 00532 } 00533 memmove(buf, &buf[2], trfLen - 2); 00534 trfLen -= 2; 00535 } else { 00536 break; 00537 } 00538 } 00539 m_sock.close(); 00540 DBG("Completed HTTP transaction"); 00541 return HTTP_OK; 00542 } 00543 00544 HTTPResult HTTPClient::recv(char* buf, size_t minLen, size_t maxLen, size_t* pReadLen) //0 on success, err code on failure 00545 { 00546 DBG("Trying to read between %d and %d bytes", minLen, maxLen); 00547 size_t readLen = 0; 00548 00549 if (!m_sock.is_connected()) { 00550 WARN("Connection was closed by server"); 00551 return HTTP_CLOSED; //Connection was closed by server 00552 } 00553 00554 int ret; 00555 while (readLen < maxLen) { 00556 if (readLen < minLen) { 00557 DBG("Trying to read at most %4d bytes [not Blocking, %d] %d,%d", minLen - readLen, 00558 m_timeout, minLen, readLen); 00559 m_sock.set_blocking(false, m_timeout); 00560 ret = m_sock.receive_all(buf + readLen, minLen - readLen); 00561 } else { 00562 DBG("Trying to read at most %4d bytes [Not blocking, %d] %d,%d", maxLen - readLen, 00563 0, maxLen, readLen); 00564 m_sock.set_blocking(false, 0); 00565 ret = m_sock.receive(buf + readLen, maxLen - readLen); 00566 } 00567 00568 if (ret > 0) { 00569 readLen += ret; 00570 } else if ( ret == 0 ) { 00571 break; 00572 } else { 00573 if (!m_sock.is_connected()) { 00574 ERR("Connection error (recv returned %d)", ret); 00575 *pReadLen = readLen; 00576 return HTTP_CONN; 00577 } else { 00578 break; 00579 } 00580 } 00581 if (!m_sock.is_connected()) { 00582 break; 00583 } 00584 } 00585 DBG("Read %d bytes", readLen); 00586 buf[readLen] = '\0'; // DS makes it easier to see what's new. 00587 *pReadLen = readLen; 00588 return HTTP_OK; 00589 } 00590 00591 HTTPResult HTTPClient::send(char* buf, size_t len) //0 on success, err code on failure 00592 { 00593 if(len == 0) { 00594 len = strlen(buf); 00595 } 00596 DBG("send(\r\n%s,%d)", buf, len); 00597 size_t writtenLen = 0; 00598 00599 if(!m_sock.is_connected()) { 00600 WARN("Connection was closed by server"); 00601 return HTTP_CLOSED; //Connection was closed by server 00602 } 00603 DBG("a"); 00604 m_sock.set_blocking(false, m_timeout); 00605 DBG("b"); 00606 int ret = m_sock.send_all(buf, len); 00607 if(ret > 0) { 00608 writtenLen += ret; 00609 } else if( ret == 0 ) { 00610 WARN("Connection was closed by server"); 00611 return HTTP_CLOSED; //Connection was closed by server 00612 } else { 00613 ERR("Connection error (send returned %d)", ret); 00614 return HTTP_CONN; 00615 } 00616 DBG("Written %d bytes", writtenLen); 00617 return HTTP_OK; 00618 } 00619 00620 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 00621 { 00622 char* schemePtr = (char*) url; 00623 char* hostPtr = (char*) strstr(url, "://"); 00624 INFO("parseURL(%s,%p,%d,%s,%d,%d,%p,%d", 00625 url, scheme, maxSchemeLen, host, maxHostLen, *port, path, maxPathLen); 00626 if (hostPtr == NULL) { 00627 WARN("Could not find host"); 00628 return HTTP_PARSE; //URL is invalid 00629 } 00630 00631 if ( (uint16_t)maxSchemeLen < hostPtr - schemePtr + 1 ) { //including NULL-terminating char 00632 WARN("Scheme str is too small (%d >= %d)", maxSchemeLen, hostPtr - schemePtr + 1); 00633 return HTTP_PARSE; 00634 } 00635 memcpy(scheme, schemePtr, hostPtr - schemePtr); 00636 scheme[hostPtr - schemePtr] = '\0'; 00637 00638 hostPtr+=3; 00639 00640 size_t hostLen = 0; 00641 00642 char* portPtr = strchr(hostPtr, ':'); 00643 if( portPtr != NULL ) { 00644 hostLen = portPtr - hostPtr; 00645 portPtr++; 00646 if( sscanf(portPtr, "%hu", port) != 1) { 00647 WARN("Could not find port"); 00648 return HTTP_PARSE; 00649 } 00650 } else { 00651 *port=0; 00652 } 00653 INFO(" hostPtr: %s", hostPtr); 00654 INFO(" hostLen: %d", hostLen); 00655 char* pathPtr = strchr(hostPtr, '/'); 00656 if( hostLen == 0 ) { 00657 hostLen = pathPtr - hostPtr; 00658 } 00659 00660 if( maxHostLen < hostLen + 1 ) { //including NULL-terminating char 00661 WARN("Host str is too small (%d >= %d)", maxHostLen, hostLen + 1); 00662 return HTTP_PARSE; 00663 } 00664 memcpy(host, hostPtr, hostLen); 00665 host[hostLen] = '\0'; 00666 00667 size_t pathLen; 00668 char* fragmentPtr = strchr(hostPtr, '#'); 00669 if(fragmentPtr != NULL) { 00670 pathLen = fragmentPtr - pathPtr; 00671 } else { 00672 pathLen = strlen(pathPtr); 00673 } 00674 00675 if( maxPathLen < pathLen + 1 ) { //including NULL-terminating char 00676 WARN("Path str is too small (%d >= %d)", maxPathLen, pathLen + 1); 00677 return HTTP_PARSE; 00678 } 00679 memcpy(path, pathPtr, pathLen); 00680 path[pathLen] = '\0'; 00681 00682 return HTTP_OK; 00683 } 00684 00685 void HTTPClient::createauth (const char *user, const char *pwd, char *buf, int len) 00686 { 00687 char tmp[80]; 00688 00689 snprintf(tmp, sizeof(tmp), "%s:%s", user, pwd); 00690 base64enc(tmp, strlen(tmp), &buf[strlen(buf)], len - strlen(buf)); 00691 } 00692 00693 // Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) 00694 int HTTPClient::base64enc(const char *input, unsigned int length, char *output, int len) 00695 { 00696 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 00697 unsigned int c, c1, c2, c3; 00698 00699 if ((uint16_t)len < ((((length-1)/3)+1)<<2)) return -1; 00700 for(unsigned int i = 0, j = 0; i<length; i+=3,j+=4) { 00701 c1 = ((((unsigned char)*((unsigned char *)&input[i])))); 00702 c2 = (length>i+1)?((((unsigned char)*((unsigned char *)&input[i+1])))):0; 00703 c3 = (length>i+2)?((((unsigned char)*((unsigned char *)&input[i+2])))):0; 00704 00705 c = ((c1 & 0xFC) >> 2); 00706 output[j+0] = base64[c]; 00707 c = ((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4); 00708 output[j+1] = base64[c]; 00709 c = ((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6); 00710 output[j+2] = (length>i+1)?base64[c]:'='; 00711 c = (c3 & 0x3F); 00712 output[j+3] = (length>i+2)?base64[c]:'='; 00713 } 00714 output[(((length-1)/3)+1)<<2] = '\0'; 00715 return 0; 00716 }
Generated on Tue Jul 12 2022 17:30:35 by
1.7.2
