HTTP/HTTPS Client Library for the X-NUCLEO-IDW01M1v2 wifi board.
Dependents: HTTPClient_HelloWorld_IDW01M1 wifigianluigi HTTPClient_HelloWorld_IDW01M1_Fabio_Ricezione
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 00044 #define MAX_KEY 64 00045 #define MAX_VALUE 64 00046 00047 #include <cstring> 00048 #include "HTTPClient.h" 00049 00050 //HTTPClient::HTTPClient(NetworkStack & _m_intf) : m_intf(_m_intf) 00051 HTTPClient::HTTPClient(SpwfSAInterface & _m_intf) : m_intf(_m_intf) 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 HTTPResult HTTPClient::put(const char* url, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking 00085 { 00086 return connect(url, HTTP_PUT, (IHTTPDataOut*)&dataOut, pDataIn, timeout); 00087 } 00088 00089 HTTPResult HTTPClient::del(const char* url, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking 00090 { 00091 return connect(url, HTTP_DELETE, NULL, pDataIn, timeout); 00092 } 00093 00094 00095 int HTTPClient::getHTTPResponseCode() 00096 { 00097 return m_httpResponseCode; 00098 } 00099 00100 #define CHECK_CONN_ERR(ret) \ 00101 do{ \ 00102 if(ret) { \ 00103 m_sock.close(); \ 00104 ERR("Connection error (%d)", ret); \ 00105 return HTTP_CONN; \ 00106 } \ 00107 } while(0) 00108 00109 #define PRTCL_ERR() \ 00110 do{ \ 00111 m_sock.close(); \ 00112 ERR("Protocol error"); \ 00113 return HTTP_PRTCL; \ 00114 } while(0) 00115 00116 00117 HTTPResult HTTPClient::connect(const char* url, HTTP_METH method, IHTTPDataOut* pDataOut, IHTTPDataIn* pDataIn, int timeout) //Execute request 00118 { 00119 m_httpResponseCode = 0; //Invalidate code 00120 m_timeout = timeout; 00121 00122 pDataIn->writeReset(); 00123 if( pDataOut ) 00124 { 00125 pDataOut->readReset(); 00126 } 00127 00128 char scheme[8]; 00129 uint16_t port; 00130 char host[64]; 00131 char path[64]; 00132 //First we need to parse the url (http[s]://host[:port][/[path]]) -- HTTPS not supported (yet?) 00133 HTTPResult res = parseURL(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path)); 00134 if(res != HTTP_OK) 00135 { 00136 ERR("parseURL returned %d", res); 00137 return res; 00138 } 00139 00140 if ((strcmp ("https", scheme)) == 0 || (strcmp ("HTTPS", scheme) == 0)) { 00141 if ( port == 0) port = 443; 00142 m_intf.set_secure_mode(); 00143 } 00144 if(port == 0) //TODO do handle HTTPS->443 00145 { 00146 port = 80; 00147 } 00148 00149 DBG("Scheme: %s", scheme); 00150 DBG("Host: %s", host); 00151 DBG("Port: %d", port); 00152 DBG("Path: %s", path); 00153 // Open 00154 m_sock.open(&m_intf); 00155 m_intf.set_unsecure_mode(); 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("TCP Could not connect"); 00163 return HTTP_CONN; 00164 } 00165 DBG ("TCP connected\n\r"); 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 //Send all headers 00179 00180 //Send default headers 00181 DBG("Sending headers"); 00182 if( pDataOut != NULL ) 00183 { 00184 if( pDataOut->getIsChunked() ) 00185 { 00186 ret = send("Transfer-Encoding: chunked\r\n"); 00187 CHECK_CONN_ERR(ret); 00188 } 00189 else 00190 { 00191 snprintf(buf, sizeof(buf), "Content-Length: %d\r\n", pDataOut->getDataLen()); 00192 ret = send(buf); 00193 CHECK_CONN_ERR(ret); 00194 } 00195 char type[48]; 00196 if( pDataOut->getDataType(type, 48) == HTTP_OK ) 00197 { 00198 snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", type); 00199 ret = send(buf); 00200 CHECK_CONN_ERR(ret); 00201 } 00202 00203 //Send specific headers 00204 while( pDataOut->getHeader(buf, sizeof(buf) - 3) ) //must have space left for CRLF + 0 terminating char 00205 { 00206 size_t headerlen = strlen(buf); 00207 snprintf(buf + headerlen, sizeof(buf) - headerlen, "\r\n"); 00208 ret = send(buf); 00209 CHECK_CONN_ERR(ret); 00210 } 00211 } 00212 00213 //Send specific headers 00214 while( pDataIn->getHeader(buf, sizeof(buf) - 3) ) 00215 { 00216 size_t headerlen = strlen(buf); 00217 snprintf(buf + headerlen, sizeof(buf) - headerlen, "\r\n"); 00218 ret = send(buf); 00219 CHECK_CONN_ERR(ret); 00220 } 00221 00222 //Close headers 00223 DBG("Headers sent"); 00224 ret = send("\r\n"); 00225 CHECK_CONN_ERR(ret); 00226 00227 size_t trfLen; 00228 //Send data (if available) 00229 if( pDataOut != NULL ) 00230 { 00231 DBG("Sending data"); 00232 while(true) 00233 { 00234 00235 size_t writtenLen = 0; 00236 pDataOut->read(buf, CHUNK_SIZE, &trfLen); 00237 00238 if( pDataOut->getIsChunked() ) 00239 { 00240 //Write chunk header 00241 char chunkHeader[16]; 00242 snprintf(chunkHeader, sizeof(chunkHeader), "%X\r\n", trfLen); //In hex encoding 00243 ret = send(chunkHeader); 00244 CHECK_CONN_ERR(ret); 00245 } 00246 else if( trfLen == 0 ) 00247 { 00248 break; 00249 } 00250 if( trfLen != 0 ) 00251 { 00252 ret = send(buf, trfLen); 00253 CHECK_CONN_ERR(ret); 00254 } 00255 00256 if( pDataOut->getIsChunked() ) 00257 { 00258 ret = send("\r\n"); //Chunk-terminating CRLF 00259 CHECK_CONN_ERR(ret); 00260 } 00261 else 00262 { 00263 writtenLen += trfLen; 00264 if( writtenLen >= pDataOut->getDataLen() ) 00265 { 00266 break; 00267 } 00268 } 00269 00270 if( trfLen == 0 ) 00271 { 00272 break; 00273 } 00274 } 00275 } 00276 00277 //Receive response 00278 DBG("Receiving response"); 00279 ret = recv(buf, 1, CHUNK_SIZE - 1, &trfLen); //Read n bytes 00280 CHECK_CONN_ERR(ret); 00281 00282 buf[trfLen] = '\0'; 00283 00284 //Make sure we got the first response line 00285 char* crlfPtr = NULL; 00286 while( true ) 00287 { 00288 crlfPtr = strstr(buf, "\r\n"); 00289 if(crlfPtr == NULL) 00290 { 00291 if( trfLen < CHUNK_SIZE - 1 ) 00292 { 00293 size_t newTrfLen; 00294 ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen); 00295 trfLen += newTrfLen; 00296 buf[trfLen] = '\0'; 00297 DBG("Read %d chars; In buf: [%s]", newTrfLen, buf); 00298 CHECK_CONN_ERR(ret); 00299 continue; 00300 } 00301 else 00302 { 00303 PRTCL_ERR(); 00304 } 00305 } 00306 break; 00307 } 00308 int crlfPos = crlfPtr - buf; 00309 buf[crlfPos] = '\0'; 00310 //Parse HTTP response 00311 //if( sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 ) 00312 if(crlfPos > 13) 00313 { 00314 buf[13] = '\0'; 00315 } 00316 if( sscanf(buf, "HTTP/%*d.%*d %d", &m_httpResponseCode) != 1 ) //Kludge for newlib nano 00317 { 00318 //Cannot match string, error 00319 ERR("Not a correct HTTP answer : %s\n", buf); 00320 PRTCL_ERR(); 00321 } 00322 00323 if( (m_httpResponseCode < 200) || (m_httpResponseCode >= 300) ) 00324 { 00325 //Did not return a 2xx code; TODO fetch headers/(&data?) anyway and implement a mean of writing/reading headers 00326 WARN("Response code %d", m_httpResponseCode); 00327 PRTCL_ERR(); 00328 } 00329 00330 DBG("=======>>>> Reading headers"); 00331 00332 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well 00333 trfLen -= (crlfPos + 2); 00334 00335 size_t recvContentLength = 0; 00336 bool recvChunked = false; 00337 bool recvLengthUnknown = true; 00338 //Now get headers 00339 while( true ) 00340 { 00341 crlfPtr = strstr(buf, "\r\n"); 00342 if(crlfPtr == NULL) 00343 { 00344 if( trfLen < CHUNK_SIZE - 1 ) 00345 { 00346 size_t newTrfLen; 00347 ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen); 00348 trfLen += newTrfLen; 00349 buf[trfLen] = '\0'; 00350 DBG("Read %d chars; In buf: [%s]", newTrfLen, buf); 00351 CHECK_CONN_ERR(ret); 00352 continue; 00353 } 00354 else 00355 { 00356 PRTCL_ERR(); 00357 } 00358 } 00359 00360 crlfPos = crlfPtr - buf; 00361 00362 if(crlfPos == 0) //End of headers 00363 { 00364 DBG("Headers read"); 00365 memmove(buf, &buf[2], trfLen - 2 + 1); //Be sure to move NULL-terminating char as well 00366 trfLen -= 2; 00367 break; 00368 } 00369 00370 buf[crlfPos] = '\0'; 00371 00372 char key[MAX_KEY]; 00373 char value[MAX_VALUE]; 00374 00375 //key[31] = '\0'; 00376 //value[31] = '\0'; 00377 00378 memset(key, 0, MAX_KEY); 00379 memset(value, 0, MAX_VALUE); 00380 00381 //int n = sscanf(buf, "%31[^:]: %31[^\r\n]", key, value); 00382 00383 int n = 0; 00384 00385 char* keyEnd = strchr(buf, ':'); 00386 if(keyEnd != NULL) 00387 { 00388 *keyEnd = '\0'; 00389 if(strlen(buf) < MAX_KEY) 00390 { 00391 strcpy(key, buf); 00392 n++; 00393 char* valueStart = keyEnd + 2; 00394 if( (valueStart - buf) < crlfPos ) 00395 { 00396 if(strlen(valueStart) < MAX_VALUE) 00397 { 00398 strcpy(value, valueStart); 00399 n++; 00400 } 00401 } 00402 } 00403 } 00404 if ( n == 2 ) 00405 { 00406 DBG("Read header : %s: %s\n", key, value); 00407 if( !strcmp(key, "Content-Length") ) 00408 { 00409 sscanf(value, "%d", &recvContentLength); 00410 recvLengthUnknown = false; 00411 pDataIn->setDataLen(recvContentLength); 00412 } 00413 else if( !strcmp(key, "Transfer-Encoding") ) 00414 { 00415 if( !strcmp(value, "Chunked") || !strcmp(value, "chunked") ) 00416 { 00417 recvChunked = true; 00418 recvLengthUnknown = false; 00419 pDataIn->setIsChunked(true); 00420 } 00421 } 00422 else if( !strcmp(key, "Content-Type") ) 00423 { 00424 pDataIn->setDataType(value); 00425 } 00426 00427 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well 00428 trfLen -= (crlfPos + 2); 00429 00430 } 00431 else 00432 { 00433 ERR("Could not parse header"); 00434 PRTCL_ERR(); 00435 } 00436 00437 } 00438 00439 //Receive data 00440 DBG("Receiving data"); 00441 while(true) 00442 { 00443 size_t readLen = 0; 00444 00445 if( recvChunked ) 00446 { 00447 //Read chunk header 00448 bool foundCrlf; 00449 do 00450 { 00451 foundCrlf = false; 00452 crlfPos=0; 00453 buf[trfLen]=0; 00454 if(trfLen >= 2) 00455 { 00456 for(; crlfPos < trfLen - 2; crlfPos++) 00457 { 00458 if( buf[crlfPos] == '\r' && buf[crlfPos + 1] == '\n' ) 00459 { 00460 foundCrlf = true; 00461 break; 00462 } 00463 } 00464 } 00465 if(!foundCrlf) //Try to read more 00466 { 00467 if( trfLen < CHUNK_SIZE ) 00468 { 00469 size_t newTrfLen; 00470 ret = recv(buf + trfLen, 0, CHUNK_SIZE - trfLen - 1, &newTrfLen); 00471 trfLen += newTrfLen; 00472 CHECK_CONN_ERR(ret); 00473 continue; 00474 } 00475 else 00476 { 00477 PRTCL_ERR(); 00478 } 00479 } 00480 } while(!foundCrlf); 00481 buf[crlfPos] = '\0'; 00482 int n = sscanf(buf, "%x", &readLen); 00483 if(n!=1) 00484 { 00485 ERR("Could not read chunk length"); 00486 PRTCL_ERR(); 00487 } 00488 00489 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2)); //Not need to move NULL-terminating char any more 00490 trfLen -= (crlfPos + 2); 00491 00492 if( readLen == 0 ) 00493 { 00494 //Last chunk 00495 break; 00496 } 00497 } 00498 else 00499 { 00500 readLen = recvContentLength; 00501 } 00502 00503 DBG("Retrieving %d bytes (%d bytes in buffer)", readLen, trfLen); 00504 00505 do 00506 { 00507 if(recvLengthUnknown ) 00508 { 00509 readLen = trfLen; 00510 } 00511 pDataIn->write(buf, MIN(trfLen, readLen)); 00512 if(!recvLengthUnknown) 00513 { 00514 if( trfLen > readLen ) 00515 { 00516 memmove(buf, &buf[readLen], trfLen - readLen); 00517 trfLen -= readLen; 00518 readLen = 0; 00519 } 00520 else 00521 { 00522 readLen -= trfLen; 00523 } 00524 } 00525 else 00526 { 00527 trfLen = 0; 00528 } 00529 00530 if(readLen || recvLengthUnknown) 00531 { 00532 ret = recv(buf, 1, CHUNK_SIZE - trfLen - 1, &trfLen); 00533 if(recvLengthUnknown && (ret == HTTP_CLOSED)) 00534 { 00535 //Write and exit 00536 pDataIn->write(buf, trfLen); 00537 break; 00538 } 00539 CHECK_CONN_ERR(ret); 00540 if(recvLengthUnknown && (trfLen == 0)) 00541 { 00542 break; 00543 } 00544 } 00545 } while(readLen || recvLengthUnknown); 00546 00547 if( recvChunked ) 00548 { 00549 if(trfLen < 2) 00550 { 00551 size_t newTrfLen; 00552 //Read missing chars to find end of chunk 00553 ret = recv(buf + trfLen, 2 - trfLen, CHUNK_SIZE - trfLen - 1, &newTrfLen); 00554 CHECK_CONN_ERR(ret); 00555 trfLen += newTrfLen; 00556 } 00557 if( (buf[0] != '\r') || (buf[1] != '\n') ) 00558 { 00559 ERR("Format error"); 00560 PRTCL_ERR(); 00561 } 00562 memmove(buf, &buf[2], trfLen - 2); 00563 trfLen -= 2; 00564 } 00565 else 00566 { 00567 break; 00568 } 00569 00570 } 00571 00572 m_sock.close(); 00573 DBG("Completed HTTP transaction"); 00574 00575 return HTTP_OK; 00576 } 00577 00578 HTTPResult HTTPClient::recv(char* buf, size_t minLen, size_t maxLen, size_t* pReadLen) //0 on success, err code on failure 00579 { 00580 DBG("Trying to read between %d and %d bytes", minLen, maxLen); 00581 size_t readLen = 0; 00582 00583 #ifdef LICIO 00584 00585 #else 00586 if(!m_sock.is_connected()) 00587 { 00588 WARN("Connection was closed by server"); 00589 return HTTP_CLOSED; //Connection was closed by server 00590 } 00591 #endif 00592 int ret; 00593 while(readLen < maxLen) 00594 { 00595 if(readLen < minLen) 00596 { 00597 DBG("Trying to read at most %d bytes [Blocking]", minLen - readLen); 00598 #ifdef LICIO 00599 m_sock.set_blocking(false); 00600 ret = m_sock.recv(buf + readLen, minLen - readLen); 00601 #else 00602 m_sock.set_blocking(false, m_timeout); 00603 ret = m_sock.receive_all(buf + readLen, minLen - readLen); 00604 #endif 00605 } 00606 else 00607 { 00608 DBG("Trying to read at most %d bytes [Not blocking]", maxLen - readLen); 00609 #ifdef LICIO 00610 m_sock.set_blocking(false); 00611 ret = m_sock.recv(buf + readLen, maxLen - readLen); 00612 #else 00613 m_sock.set_blocking(false, 0); 00614 ret = m_sock.receive(buf + readLen, maxLen - readLen); 00615 #endif 00616 } 00617 00618 if( ret > 0) 00619 { 00620 readLen += ret; 00621 } 00622 else if( ret == 0 || ret == NSAPI_ERROR_WOULD_BLOCK) 00623 { 00624 break; 00625 } 00626 else 00627 { 00628 #ifdef LICIO 00629 // if (ret == NSAPI_ERROR_NO_CONNECTION) { *pReadLen = readLen; return HTTP_CONN; } 00630 #else 00631 if(!m_sock.is_connected()) 00632 { 00633 ERR("Connection error (recv returned %d)", ret); 00634 *pReadLen = readLen; 00635 return HTTP_CONN; 00636 } 00637 else 00638 { 00639 break; 00640 } 00641 #endif 00642 } 00643 #ifdef LICIO 00644 // if (ret == NSAPI_ERROR_NO_CONNECTION) { *pReadLen = readLen; return HTTP_CONN; } 00645 #else 00646 if(!m_sock.is_connected()) 00647 { 00648 break; 00649 } 00650 #endif 00651 } 00652 DBG("Read %d bytes", readLen); 00653 *pReadLen = readLen; 00654 return HTTP_OK; 00655 } 00656 00657 HTTPResult HTTPClient::send(char* buf, size_t len) //0 on success, err code on failure 00658 { 00659 if(len == 0) 00660 { 00661 len = strlen(buf); 00662 } 00663 DBG("Trying to write %d bytes", len); 00664 size_t writtenLen = 0; 00665 00666 #ifdef LICIO 00667 #else 00668 if(!m_sock.is_connected()) 00669 { 00670 WARN("Connection was closed by server"); 00671 return HTTP_CLOSED; //Connection was closed by server 00672 } 00673 #endif 00674 #ifdef LICIO 00675 m_sock.set_blocking(false); 00676 int ret = m_sock.send(buf, len); 00677 00678 #else 00679 m_sock.set_blocking(false, m_timeout); 00680 int ret = m_sock.send_all(buf, len); 00681 #endif 00682 if(ret > 0) 00683 { 00684 writtenLen += ret; 00685 } 00686 else if( ret == 0 ) 00687 { 00688 WARN("Connection was closed by server"); 00689 return HTTP_CLOSED; //Connection was closed by server 00690 } 00691 else 00692 { 00693 ERR("Connection error (send returned %d)", ret); 00694 return HTTP_CONN; 00695 } 00696 00697 DBG("Written %d bytes", writtenLen); 00698 return HTTP_OK; 00699 } 00700 00701 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 00702 { 00703 char* schemePtr = (char*) url; 00704 char* hostPtr = (char*) strstr(url, "://"); 00705 if(hostPtr == NULL) 00706 { 00707 WARN("Could not find host"); 00708 return HTTP_PARSE; //URL is invalid 00709 } 00710 00711 if( maxSchemeLen < hostPtr - schemePtr + 1 ) //including NULL-terminating char 00712 { 00713 WARN("Scheme str is too small (%d >= %d)", maxSchemeLen, hostPtr - schemePtr + 1); 00714 return HTTP_PARSE; 00715 } 00716 memcpy(scheme, schemePtr, hostPtr - schemePtr); 00717 scheme[hostPtr - schemePtr] = '\0'; 00718 00719 hostPtr+=3; 00720 00721 size_t hostLen = 0; 00722 00723 char* portPtr = strchr(hostPtr, ':'); 00724 if( portPtr != NULL ) 00725 { 00726 hostLen = portPtr - hostPtr; 00727 portPtr++; 00728 if( sscanf(portPtr, "%hu", port) != 1) 00729 { 00730 WARN("Could not find port"); 00731 return HTTP_PARSE; 00732 } 00733 } 00734 else 00735 { 00736 *port=0; 00737 } 00738 char* pathPtr = strchr(hostPtr, '/'); 00739 if( hostLen == 0 ) 00740 { 00741 hostLen = pathPtr - hostPtr; 00742 } 00743 00744 if( maxHostLen < hostLen + 1 ) //including NULL-terminating char 00745 { 00746 WARN("Host str is too small (%d >= %d)", maxHostLen, hostLen + 1); 00747 return HTTP_PARSE; 00748 } 00749 memcpy(host, hostPtr, hostLen); 00750 host[hostLen] = '\0'; 00751 00752 size_t pathLen; 00753 char* fragmentPtr = strchr(hostPtr, '#'); 00754 if(fragmentPtr != NULL) 00755 { 00756 pathLen = fragmentPtr - pathPtr; 00757 } 00758 else 00759 { 00760 pathLen = strlen(pathPtr); 00761 } 00762 00763 if( maxPathLen < pathLen + 1 ) //including NULL-terminating char 00764 { 00765 WARN("Path str is too small (%d >= %d)", maxPathLen, pathLen + 1); 00766 return HTTP_PARSE; 00767 } 00768 memcpy(path, pathPtr, pathLen); 00769 path[pathLen] = '\0'; 00770 00771 return HTTP_OK; 00772 }
Generated on Tue Jul 12 2022 21:24:56 by
1.7.2
