HTTPClient for IEEE1888 (FIAP) Gateway
Dependents: Fetch_IEEE1888_Storage IEEE1888_MULTI_SENSOR_GW
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 //Debug is disabled by default 00021 #if 0 00022 //Enable debug 00023 #include <cstdio> 00024 #define DBG(x, ...) std::printf("[HTTPClient : DBG]"x"\r\n", ##__VA_ARGS__); 00025 #define WARN(x, ...) std::printf("[HTTPClient : WARN]"x"\r\n", ##__VA_ARGS__); 00026 #define ERR(x, ...) std::printf("[HTTPClient : ERR]"x"\r\n", ##__VA_ARGS__); 00027 00028 #else 00029 //Disable debug 00030 #define DBG(x, ...) 00031 #define WARN(x, ...) 00032 #define ERR(x, ...) 00033 00034 #endif 00035 00036 #define HTTP_PORT 80 00037 00038 #define OK 0 00039 00040 #define MIN(x,y) (((x)<(y))?(x):(y)) 00041 #define MAX(x,y) (((x)>(y))?(x):(y)) 00042 00043 #define CHUNK_SIZE 256 00044 00045 #include <cstring> 00046 00047 #include "HTTPClient.h" 00048 00049 HTTPClient::HTTPClient() : 00050 m_sock(), m_basicAuthUser(NULL), m_basicAuthPassword(NULL), m_httpResponseCode(0) 00051 { 00052 00053 } 00054 00055 HTTPClient::~HTTPClient() 00056 { 00057 00058 } 00059 00060 #if 0 00061 void HTTPClient::basicAuth(const char* user, const char* password) //Basic Authentification 00062 { 00063 m_basicAuthUser = user; 00064 m_basicAuthPassword = password; 00065 } 00066 #endif 00067 00068 HTTPResult HTTPClient::get(const char* url, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking 00069 { 00070 return connect(url, HTTP_GET, NULL, pDataIn, timeout); 00071 } 00072 00073 HTTPResult HTTPClient::get(const char* url, char* result, size_t maxResultLen, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking 00074 { 00075 HTTPText str(result, maxResultLen); 00076 return get(url, &str, timeout); 00077 } 00078 00079 HTTPResult HTTPClient::post(const char* url, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking 00080 { 00081 return connect(url, HTTP_POST, (IHTTPDataOut*)&dataOut, pDataIn, timeout); 00082 } 00083 00084 //strysd add start 00085 HTTPResult HTTPClient::postXML(const char* url,const char* SOAPAction, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking 00086 { 00087 return connectExt(url, HTTP_POST, SOAPAction, (IHTTPDataOut*)&dataOut, pDataIn, timeout); 00088 } 00089 //strysd add end 00090 00091 HTTPResult HTTPClient::put(const char* url, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking 00092 { 00093 return connect(url, HTTP_PUT, (IHTTPDataOut*)&dataOut, pDataIn, timeout); 00094 } 00095 00096 HTTPResult HTTPClient::del(const char* url, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking 00097 { 00098 return connect(url, HTTP_DELETE, NULL, pDataIn, timeout); 00099 } 00100 00101 00102 int HTTPClient::getHTTPResponseCode() 00103 { 00104 return m_httpResponseCode; 00105 } 00106 00107 #define CHECK_CONN_ERR(ret) \ 00108 do{ \ 00109 if(ret) { \ 00110 m_sock.close(); \ 00111 ERR("Connection error (%d)", ret); \ 00112 return HTTP_CONN; \ 00113 } \ 00114 } while(0) 00115 00116 #define PRTCL_ERR() \ 00117 do{ \ 00118 m_sock.close(); \ 00119 ERR("Protocol error"); \ 00120 return HTTP_PRTCL; \ 00121 } while(0) 00122 00123 HTTPResult HTTPClient::connect(const char* url, HTTP_METH method, IHTTPDataOut* pDataOut, IHTTPDataIn* pDataIn, int timeout) //Execute request 00124 { 00125 m_httpResponseCode = 0; //Invalidate code 00126 m_timeout = timeout; 00127 00128 pDataIn->writeReset(); 00129 if( pDataOut ) 00130 { 00131 pDataOut->readReset(); 00132 } 00133 00134 char scheme[8]; 00135 uint16_t port; 00136 char host[64];//strysd change from 32 00137 char path[64]; 00138 //First we need to parse the url (http[s]://host[:port][/[path]]) -- HTTPS not supported (yet?) 00139 HTTPResult res = parseURL(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path)); 00140 if(res != HTTP_OK) 00141 { 00142 ERR("parseURL returned %d", res); 00143 return res; 00144 } 00145 00146 if(port == 0) //TODO do handle HTTPS->443 00147 { 00148 port = 80; 00149 } 00150 00151 DBG("Scheme: %s", scheme); 00152 DBG("Host: %s", host); 00153 DBG("Port: %d", port); 00154 DBG("Path: %s", path); 00155 00156 //Connect 00157 DBG("Connecting socket to server"); 00158 int ret = m_sock.connect(host, port); 00159 if (ret < 0) 00160 { 00161 m_sock.close(); 00162 ERR("Could not connect"); 00163 return HTTP_CONN; 00164 } 00165 00166 //Send request 00167 DBG("Sending request"); 00168 char buf[CHUNK_SIZE]; 00169 const char* meth = (method==HTTP_GET)?"GET":(method==HTTP_POST)?"POST":(method==HTTP_PUT)?"PUT":(method==HTTP_DELETE)?"DELETE":""; 00170 snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\n", meth, path, host); //Write request 00171 ret = send(buf); 00172 if(ret) 00173 { 00174 m_sock.close(); 00175 ERR("Could not write request"); 00176 return HTTP_CONN; 00177 } 00178 00179 //Send all headers 00180 00181 //Send default headers 00182 DBG("Sending headers"); 00183 if( pDataOut != NULL ) 00184 { 00185 if( pDataOut->getIsChunked() ) 00186 { 00187 ret = send("Transfer-Encoding: chunked\r\n"); 00188 CHECK_CONN_ERR(ret); 00189 } 00190 else 00191 { 00192 snprintf(buf, sizeof(buf), "Content-Length: %d\r\n", pDataOut->getDataLen()); 00193 ret = send(buf); 00194 CHECK_CONN_ERR(ret); 00195 } 00196 char type[48]; 00197 if( pDataOut->getDataType(type, 48) == HTTP_OK ) 00198 { 00199 snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", type); 00200 ret = send(buf); 00201 CHECK_CONN_ERR(ret); 00202 } 00203 } 00204 00205 //Close headers 00206 DBG("Headers sent"); 00207 ret = send("\r\n"); 00208 CHECK_CONN_ERR(ret); 00209 00210 size_t trfLen; 00211 00212 //Send data (if available) 00213 if( pDataOut != NULL ) 00214 { 00215 DBG("Sending data"); 00216 while(true) 00217 { 00218 size_t writtenLen = 0; 00219 pDataOut->read(buf, CHUNK_SIZE, &trfLen); 00220 if( pDataOut->getIsChunked() ) 00221 { 00222 //Write chunk header 00223 char chunkHeader[16]; 00224 snprintf(chunkHeader, sizeof(chunkHeader), "%X\r\n", trfLen); //In hex encoding 00225 ret = send(chunkHeader); 00226 CHECK_CONN_ERR(ret); 00227 } 00228 else if( trfLen == 0 ) 00229 { 00230 break; 00231 } 00232 if( trfLen != 0 ) 00233 { 00234 ret = send(buf, trfLen); 00235 CHECK_CONN_ERR(ret); 00236 } 00237 00238 if( pDataOut->getIsChunked() ) 00239 { 00240 ret = send("\r\n"); //Chunk-terminating CRLF 00241 CHECK_CONN_ERR(ret); 00242 } 00243 else 00244 { 00245 writtenLen += trfLen; 00246 if( writtenLen >= pDataOut->getDataLen() ) 00247 { 00248 break; 00249 } 00250 } 00251 00252 if( trfLen == 0 ) 00253 { 00254 break; 00255 } 00256 } 00257 00258 } 00259 00260 //Receive response 00261 DBG("Receiving response"); 00262 ret = recv(buf, CHUNK_SIZE - 1, CHUNK_SIZE - 1, &trfLen); //Read n bytes 00263 CHECK_CONN_ERR(ret); 00264 00265 buf[trfLen] = '\0'; 00266 00267 char* crlfPtr = strstr(buf, "\r\n"); 00268 if(crlfPtr == NULL) 00269 { 00270 PRTCL_ERR(); 00271 } 00272 00273 int crlfPos = crlfPtr - buf; 00274 buf[crlfPos] = '\0'; 00275 00276 //Parse HTTP response 00277 if( sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 ) 00278 { 00279 //Cannot match string, error 00280 ERR("Not a correct HTTP answer : %s\n", buf); 00281 PRTCL_ERR(); 00282 } 00283 00284 if( (m_httpResponseCode < 200) || (m_httpResponseCode >= 300) ) 00285 { 00286 //Did not return a 2xx code; TODO fetch headers/(&data?) anyway and implement a mean of writing/reading headers 00287 WARN("Response code %d", m_httpResponseCode); 00288 PRTCL_ERR(); 00289 } 00290 00291 DBG("Reading headers"); 00292 00293 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well 00294 trfLen -= (crlfPos + 2); 00295 00296 size_t recvContentLength = 0; 00297 bool recvChunked = false; 00298 //Now get headers 00299 while( true ) 00300 { 00301 crlfPtr = strstr(buf, "\r\n"); 00302 if(crlfPtr == NULL) 00303 { 00304 if( trfLen < CHUNK_SIZE - 1 ) 00305 { 00306 size_t newTrfLen; 00307 ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen); 00308 trfLen += newTrfLen; 00309 buf[trfLen] = '\0'; 00310 DBG("Read %d chars; In buf: [%s]", newTrfLen, buf); 00311 CHECK_CONN_ERR(ret); 00312 continue; 00313 } 00314 else 00315 { 00316 PRTCL_ERR(); 00317 } 00318 } 00319 00320 crlfPos = crlfPtr - buf; 00321 00322 if(crlfPos == 0) //End of headers 00323 { 00324 DBG("Headers read"); 00325 memmove(buf, &buf[2], trfLen - 2 + 1); //Be sure to move NULL-terminating char as well 00326 trfLen -= 2; 00327 break; 00328 } 00329 00330 buf[crlfPos] = '\0'; 00331 00332 char key[32]; 00333 char value[32]; 00334 00335 key[31] = '\0'; 00336 value[31] = '\0'; 00337 00338 int n = sscanf(buf, "%31[^:]: %31[^\r\n]", key, value); 00339 if ( n == 2 ) 00340 { 00341 DBG("Read header : %s: %s\n", key, value); 00342 if( !strcmp(key, "Content-Length") ) 00343 { 00344 sscanf(value, "%d", &recvContentLength); 00345 pDataIn->setDataLen(recvContentLength); 00346 } 00347 else if( !strcmp(key, "Transfer-Encoding") ) 00348 { 00349 if( !strcmp(value, "Chunked") || !strcmp(value, "chunked") ) 00350 { 00351 recvChunked = true; 00352 pDataIn->setIsChunked(true); 00353 } 00354 } 00355 else if( !strcmp(key, "Content-Type") ) 00356 { 00357 pDataIn->setDataType(value); 00358 } 00359 00360 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well 00361 trfLen -= (crlfPos + 2); 00362 00363 } 00364 else 00365 { 00366 ERR("Could not parse header"); 00367 PRTCL_ERR(); 00368 } 00369 00370 } 00371 00372 //Receive data 00373 DBG("Receiving data"); 00374 while(true) 00375 { 00376 size_t readLen = 0; 00377 00378 if( recvChunked ) 00379 { 00380 //Read chunk header 00381 bool foundCrlf; 00382 do 00383 { 00384 foundCrlf = false; 00385 crlfPos=0; 00386 buf[trfLen]=0; 00387 if(trfLen >= 2) 00388 { 00389 for(; crlfPos < trfLen - 2; crlfPos++) 00390 { 00391 if( buf[crlfPos] == '\r' && buf[crlfPos + 1] == '\n' ) 00392 { 00393 foundCrlf = true; 00394 break; 00395 } 00396 } 00397 } 00398 if(!foundCrlf) //Try to read more 00399 { 00400 if( trfLen < CHUNK_SIZE ) 00401 { 00402 size_t newTrfLen; 00403 ret = recv(buf + trfLen, 0, CHUNK_SIZE - trfLen - 1, &newTrfLen); 00404 trfLen += newTrfLen; 00405 CHECK_CONN_ERR(ret); 00406 continue; 00407 } 00408 else 00409 { 00410 PRTCL_ERR(); 00411 } 00412 } 00413 } while(!foundCrlf); 00414 buf[crlfPos] = '\0'; 00415 int n = sscanf(buf, "%x", &readLen); 00416 if(n!=1) 00417 { 00418 ERR("Could not read chunk length"); 00419 PRTCL_ERR(); 00420 } 00421 00422 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2)); //Not need to move NULL-terminating char any more 00423 trfLen -= (crlfPos + 2); 00424 00425 if( readLen == 0 ) 00426 { 00427 //Last chunk 00428 break; 00429 } 00430 } 00431 else 00432 { 00433 readLen = recvContentLength; 00434 } 00435 00436 DBG("Retrieving %d bytes", readLen); 00437 00438 do 00439 { 00440 pDataIn->write(buf, MIN(trfLen, readLen)); 00441 if( trfLen > readLen ) 00442 { 00443 memmove(buf, &buf[readLen], trfLen - readLen); 00444 trfLen -= readLen; 00445 readLen = 0; 00446 } 00447 else 00448 { 00449 readLen -= trfLen; 00450 } 00451 00452 if(readLen) 00453 { 00454 ret = recv(buf, 1, CHUNK_SIZE - trfLen - 1, &trfLen); 00455 CHECK_CONN_ERR(ret); 00456 } 00457 } while(readLen); 00458 00459 if( recvChunked ) 00460 { 00461 if(trfLen < 2) 00462 { 00463 size_t newTrfLen; 00464 //Read missing chars to find end of chunk 00465 ret = recv(buf + trfLen, 2 - trfLen, CHUNK_SIZE - trfLen - 1, &newTrfLen); 00466 CHECK_CONN_ERR(ret); 00467 trfLen += newTrfLen; 00468 } 00469 if( (buf[0] != '\r') || (buf[1] != '\n') ) 00470 { 00471 ERR("Format error"); 00472 PRTCL_ERR(); 00473 } 00474 memmove(buf, &buf[2], trfLen - 2); 00475 trfLen -= 2; 00476 } 00477 else 00478 { 00479 break; 00480 } 00481 00482 } 00483 00484 m_sock.close(); 00485 DBG("Completed HTTP transaction"); 00486 00487 return HTTP_OK; 00488 } 00489 00490 //strysd add this function start 00491 //mainly inherit from connect(), but some code is different, see programer name, "strysd" 00492 HTTPResult HTTPClient::connectExt(const char* url, HTTP_METH method, const char* SOAPAction, IHTTPDataOut* pDataOut, IHTTPDataIn* pDataIn, int timeout) //Execute request 00493 { 00494 m_httpResponseCode = 0; //Invalidate code 00495 m_timeout = timeout; 00496 00497 pDataIn->writeReset(); 00498 if( pDataOut ) 00499 { 00500 pDataOut->readReset(); 00501 } 00502 00503 char scheme[8]; 00504 uint16_t port; 00505 char host[64];//strysd change from 32 00506 char path[64]; 00507 //First we need to parse the url (http[s]://host[:port][/[path]]) -- HTTPS not supported (yet?) 00508 HTTPResult res = parseURL(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path)); 00509 if(res != HTTP_OK) 00510 { 00511 ERR("parseURL returned %d", res); 00512 return res; 00513 } 00514 00515 if(port == 0) //TODO do handle HTTPS->443 00516 { 00517 port = 80; 00518 } 00519 00520 DBG("Scheme: %s", scheme); 00521 DBG("Host: %s", host); 00522 DBG("Port: %d", port); 00523 DBG("Path: %s", path); 00524 00525 //Connect 00526 DBG("Connecting socket to server"); 00527 int ret = m_sock.connect(host, port); 00528 if (ret < 0) 00529 { 00530 m_sock.close(); 00531 ERR("Could not connect"); 00532 return HTTP_CONN; 00533 } 00534 00535 //Send request 00536 DBG("Sending request"); 00537 char buf[CHUNK_SIZE]; 00538 const char* meth = (method==HTTP_GET)?"GET":(method==HTTP_POST)?"POST":(method==HTTP_PUT)?"PUT":(method==HTTP_DELETE)?"DELETE":""; 00539 snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\n", meth, path, host); //Write request 00540 ret = send(buf); 00541 if(ret) 00542 { 00543 m_sock.close(); 00544 ERR("Could not write request"); 00545 return HTTP_CONN; 00546 } 00547 00548 //Send all headers 00549 00550 //Send default headers 00551 DBG("Sending headers"); 00552 if( pDataOut != NULL ) 00553 { 00554 if( pDataOut->getIsChunked() ) 00555 { 00556 ret = send("Transfer-Encoding: chunked\r\n"); 00557 CHECK_CONN_ERR(ret); 00558 } 00559 else 00560 { 00561 snprintf(buf, sizeof(buf), "Content-Length: %d\r\n", pDataOut->getDataLen()); 00562 ret = send(buf); 00563 CHECK_CONN_ERR(ret); 00564 } 00565 char type[48]; 00566 if( pDataOut->getDataType(type, 48) == HTTP_OK ) 00567 { 00568 //strysd change next line 00569 //snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", type); 00570 snprintf(buf, sizeof(buf), "Content-Type: text/xml;charset=UTF-8\r\n"); 00571 00572 ret = send(buf); 00573 CHECK_CONN_ERR(ret); 00574 //strysd add start 00575 snprintf(buf, sizeof(buf), "SOAPAction: \"%s\"\r\n", type); 00576 ret = send(buf); 00577 CHECK_CONN_ERR(ret); 00578 //strysd add end 00579 } 00580 } 00581 00582 //Close headers 00583 DBG("Headers sent"); 00584 ret = send("\r\n"); 00585 CHECK_CONN_ERR(ret); 00586 00587 size_t trfLen; 00588 00589 //Send data (if available) 00590 if( pDataOut != NULL ) 00591 { 00592 DBG("Sending data"); 00593 while(true) 00594 { 00595 size_t writtenLen = 0; 00596 pDataOut->read(buf, CHUNK_SIZE, &trfLen); 00597 if( pDataOut->getIsChunked() ) 00598 { 00599 //Write chunk header 00600 char chunkHeader[16]; 00601 snprintf(chunkHeader, sizeof(chunkHeader), "%X\r\n", trfLen); //In hex encoding 00602 ret = send(chunkHeader); 00603 CHECK_CONN_ERR(ret); 00604 } 00605 else if( trfLen == 0 ) 00606 { 00607 break; 00608 } 00609 if( trfLen != 0 ) 00610 { 00611 ret = send(buf, trfLen); 00612 CHECK_CONN_ERR(ret); 00613 } 00614 00615 if( pDataOut->getIsChunked() ) 00616 { 00617 ret = send("\r\n"); //Chunk-terminating CRLF 00618 CHECK_CONN_ERR(ret); 00619 } 00620 else 00621 { 00622 writtenLen += trfLen; 00623 if( writtenLen >= pDataOut->getDataLen() ) 00624 { 00625 break; 00626 } 00627 } 00628 00629 if( trfLen == 0 ) 00630 { 00631 break; 00632 } 00633 } 00634 00635 } 00636 00637 //Receive response 00638 DBG("Receiving response"); 00639 ret = recv(buf, CHUNK_SIZE - 1, CHUNK_SIZE - 1, &trfLen); //Read n bytes 00640 CHECK_CONN_ERR(ret); 00641 00642 buf[trfLen] = '\0'; 00643 00644 char* crlfPtr = strstr(buf, "\r\n"); 00645 if(crlfPtr == NULL) 00646 { 00647 PRTCL_ERR(); 00648 } 00649 00650 int crlfPos = crlfPtr - buf; 00651 buf[crlfPos] = '\0'; 00652 00653 //Parse HTTP response 00654 if( sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 ) 00655 { 00656 //Cannot match string, error 00657 ERR("Not a correct HTTP answer : %s\n", buf); 00658 PRTCL_ERR(); 00659 } 00660 00661 if( (m_httpResponseCode < 200) || (m_httpResponseCode >= 300) ) 00662 { 00663 //Did not return a 2xx code; TODO fetch headers/(&data?) anyway and implement a mean of writing/reading headers 00664 WARN("Response code %d", m_httpResponseCode); 00665 PRTCL_ERR(); 00666 } 00667 00668 DBG("Reading headers"); 00669 00670 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well 00671 trfLen -= (crlfPos + 2); 00672 00673 size_t recvContentLength = 0; 00674 bool recvChunked = false; 00675 //Now get headers 00676 while( true ) 00677 { 00678 crlfPtr = strstr(buf, "\r\n"); 00679 if(crlfPtr == NULL) 00680 { 00681 if( trfLen < CHUNK_SIZE - 1 ) 00682 { 00683 size_t newTrfLen; 00684 ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen); 00685 trfLen += newTrfLen; 00686 buf[trfLen] = '\0'; 00687 DBG("Read %d chars; In buf: [%s]", newTrfLen, buf); 00688 CHECK_CONN_ERR(ret); 00689 continue; 00690 } 00691 else 00692 { 00693 PRTCL_ERR(); 00694 } 00695 } 00696 00697 crlfPos = crlfPtr - buf; 00698 00699 if(crlfPos == 0) //End of headers 00700 { 00701 DBG("Headers read"); 00702 memmove(buf, &buf[2], trfLen - 2 + 1); //Be sure to move NULL-terminating char as well 00703 trfLen -= 2; 00704 break; 00705 } 00706 00707 buf[crlfPos] = '\0'; 00708 00709 char key[32]; 00710 char value[32]; 00711 00712 key[31] = '\0'; 00713 value[31] = '\0'; 00714 00715 int n = sscanf(buf, "%31[^:]: %31[^\r\n]", key, value); 00716 if ( n == 2 ) 00717 { 00718 DBG("Read header : %s: %s\n", key, value); 00719 if( !strcmp(key, "Content-Length") ) 00720 { 00721 sscanf(value, "%d", &recvContentLength); 00722 pDataIn->setDataLen(recvContentLength); 00723 } 00724 else if( !strcmp(key, "Transfer-Encoding") ) 00725 { 00726 if( !strcmp(value, "Chunked") || !strcmp(value, "chunked") ) 00727 { 00728 recvChunked = true; 00729 pDataIn->setIsChunked(true); 00730 } 00731 } 00732 else if( !strcmp(key, "Content-Type") ) 00733 { 00734 pDataIn->setDataType(value); 00735 } 00736 00737 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well 00738 trfLen -= (crlfPos + 2); 00739 00740 } 00741 else 00742 { 00743 ERR("Could not parse header"); 00744 PRTCL_ERR(); 00745 } 00746 00747 } 00748 00749 //Receive data 00750 DBG("Receiving data"); 00751 while(true) 00752 { 00753 size_t readLen = 0; 00754 00755 if( recvChunked ) 00756 { 00757 //Read chunk header 00758 bool foundCrlf; 00759 do 00760 { 00761 foundCrlf = false; 00762 crlfPos=0; 00763 buf[trfLen]=0; 00764 if(trfLen >= 2) 00765 { 00766 for(; crlfPos < trfLen - 2; crlfPos++) 00767 { 00768 if( buf[crlfPos] == '\r' && buf[crlfPos + 1] == '\n' ) 00769 { 00770 foundCrlf = true; 00771 break; 00772 } 00773 } 00774 } 00775 if(!foundCrlf) //Try to read more 00776 { 00777 if( trfLen < CHUNK_SIZE ) 00778 { 00779 size_t newTrfLen; 00780 ret = recv(buf + trfLen, 0, CHUNK_SIZE - trfLen - 1, &newTrfLen); 00781 trfLen += newTrfLen; 00782 CHECK_CONN_ERR(ret); 00783 continue; 00784 } 00785 else 00786 { 00787 PRTCL_ERR(); 00788 } 00789 } 00790 } while(!foundCrlf); 00791 buf[crlfPos] = '\0'; 00792 int n = sscanf(buf, "%x", &readLen); 00793 if(n!=1) 00794 { 00795 ERR("Could not read chunk length"); 00796 PRTCL_ERR(); 00797 } 00798 00799 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2)); //Not need to move NULL-terminating char any more 00800 trfLen -= (crlfPos + 2); 00801 00802 if( readLen == 0 ) 00803 { 00804 //Last chunk 00805 break; 00806 } 00807 } 00808 else 00809 { 00810 readLen = recvContentLength; 00811 } 00812 00813 DBG("Retrieving %d bytes", readLen); 00814 00815 do 00816 { 00817 pDataIn->write(buf, MIN(trfLen, readLen)); 00818 if( trfLen > readLen ) 00819 { 00820 memmove(buf, &buf[readLen], trfLen - readLen); 00821 trfLen -= readLen; 00822 readLen = 0; 00823 } 00824 else 00825 { 00826 readLen -= trfLen; 00827 } 00828 00829 if(readLen) 00830 { 00831 ret = recv(buf, 1, CHUNK_SIZE - trfLen - 1, &trfLen); 00832 CHECK_CONN_ERR(ret); 00833 } 00834 } while(readLen); 00835 00836 if( recvChunked ) 00837 { 00838 if(trfLen < 2) 00839 { 00840 size_t newTrfLen; 00841 //Read missing chars to find end of chunk 00842 ret = recv(buf + trfLen, 2 - trfLen, CHUNK_SIZE - trfLen - 1, &newTrfLen); 00843 CHECK_CONN_ERR(ret); 00844 trfLen += newTrfLen; 00845 } 00846 if( (buf[0] != '\r') || (buf[1] != '\n') ) 00847 { 00848 ERR("Format error"); 00849 PRTCL_ERR(); 00850 } 00851 memmove(buf, &buf[2], trfLen - 2); 00852 trfLen -= 2; 00853 } 00854 else 00855 { 00856 break; 00857 } 00858 00859 } 00860 00861 m_sock.close(); 00862 DBG("Completed HTTP transaction"); 00863 00864 return HTTP_OK; 00865 } 00866 //strysd add this function end 00867 00868 HTTPResult HTTPClient::recv(char* buf, size_t minLen, size_t maxLen, size_t* pReadLen) //0 on success, err code on failure 00869 { 00870 DBG("Trying to read between %d and %d bytes", minLen, maxLen); 00871 size_t readLen = 0; 00872 00873 if(!m_sock.is_connected()) 00874 { 00875 WARN("Connection was closed by server"); 00876 return HTTP_CLOSED; //Connection was closed by server 00877 } 00878 00879 int ret; 00880 while(readLen < maxLen) 00881 { 00882 if(readLen < minLen) 00883 { 00884 DBG("Trying to read at most %d bytes [Blocking]", minLen - readLen); 00885 m_sock.set_blocking(false, m_timeout); 00886 ret = m_sock.receive_all(buf + readLen, minLen - readLen); 00887 } 00888 else 00889 { 00890 DBG("Trying to read at most %d bytes [Not blocking]", maxLen - readLen); 00891 m_sock.set_blocking(false, 0); 00892 ret = m_sock.receive(buf + readLen, maxLen - readLen); 00893 } 00894 00895 if( ret > 0) 00896 { 00897 readLen += ret; 00898 } 00899 else if( ret == 0 ) 00900 { 00901 break; 00902 } 00903 else 00904 { 00905 if(!m_sock.is_connected()) 00906 { 00907 ERR("Connection error (recv returned %d)", ret); 00908 *pReadLen = readLen; 00909 return HTTP_CONN; 00910 } 00911 else 00912 { 00913 break; 00914 } 00915 } 00916 00917 if(!m_sock.is_connected()) 00918 { 00919 break; 00920 } 00921 } 00922 DBG("Read %d bytes", readLen); 00923 *pReadLen = readLen; 00924 return HTTP_OK; 00925 } 00926 00927 HTTPResult HTTPClient::send(char* buf, size_t len) //0 on success, err code on failure 00928 { 00929 if(len == 0) 00930 { 00931 len = strlen(buf); 00932 } 00933 DBG("Trying to write %d bytes", len); 00934 size_t writtenLen = 0; 00935 00936 if(!m_sock.is_connected()) 00937 { 00938 WARN("Connection was closed by server"); 00939 return HTTP_CLOSED; //Connection was closed by server 00940 } 00941 00942 m_sock.set_blocking(false, m_timeout); 00943 int ret = m_sock.send_all(buf, len); 00944 if(ret > 0) 00945 { 00946 writtenLen += ret; 00947 } 00948 else if( ret == 0 ) 00949 { 00950 WARN("Connection was closed by server"); 00951 return HTTP_CLOSED; //Connection was closed by server 00952 } 00953 else 00954 { 00955 ERR("Connection error (send returned %d)", ret); 00956 return HTTP_CONN; 00957 } 00958 00959 DBG("Written %d bytes", writtenLen); 00960 return HTTP_OK; 00961 } 00962 00963 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 00964 { 00965 char* schemePtr = (char*) url; 00966 char* hostPtr = (char*) strstr(url, "://"); 00967 if(hostPtr == NULL) 00968 { 00969 WARN("Could not find host"); 00970 return HTTP_PARSE; //URL is invalid 00971 } 00972 00973 if( maxSchemeLen < hostPtr - schemePtr + 1 ) //including NULL-terminating char 00974 { 00975 WARN("Scheme str is too small (%d >= %d)", maxSchemeLen, hostPtr - schemePtr + 1); 00976 return HTTP_PARSE; 00977 } 00978 memcpy(scheme, schemePtr, hostPtr - schemePtr); 00979 scheme[hostPtr - schemePtr] = '\0'; 00980 00981 hostPtr+=3; 00982 00983 size_t hostLen = 0; 00984 00985 char* portPtr = strchr(hostPtr, ':'); 00986 if( portPtr != NULL ) 00987 { 00988 hostLen = portPtr - hostPtr; 00989 portPtr++; 00990 if( sscanf(portPtr, "%hu", port) != 1) 00991 { 00992 WARN("Could not find port"); 00993 return HTTP_PARSE; 00994 } 00995 } 00996 else 00997 { 00998 *port=0; 00999 } 01000 char* pathPtr = strchr(hostPtr, '/'); 01001 if( hostLen == 0 ) 01002 { 01003 hostLen = pathPtr - hostPtr; 01004 } 01005 01006 if( maxHostLen < hostLen + 1 ) //including NULL-terminating char 01007 { 01008 WARN("Host str is too small (%d >= %d)", maxHostLen, hostLen + 1); 01009 return HTTP_PARSE; 01010 } 01011 memcpy(host, hostPtr, hostLen); 01012 host[hostLen] = '\0'; 01013 01014 size_t pathLen; 01015 char* fragmentPtr = strchr(hostPtr, '#'); 01016 if(fragmentPtr != NULL) 01017 { 01018 pathLen = fragmentPtr - pathPtr; 01019 } 01020 else 01021 { 01022 pathLen = strlen(pathPtr); 01023 } 01024 01025 if( maxPathLen < pathLen + 1 ) //including NULL-terminating char 01026 { 01027 WARN("Path str is too small (%d >= %d)", maxPathLen, pathLen + 1); 01028 return HTTP_PARSE; 01029 } 01030 memcpy(path, pathPtr, pathLen); 01031 path[pathLen] = '\0'; 01032 01033 return HTTP_OK; 01034 }
Generated on Wed Jul 13 2022 21:23:03 by 1.7.2