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.
HTTPClient.cpp
00001 00002 /* 00003 Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) 00004 00005 Permission is hereby granted, free of charge, to any person obtaining a copy 00006 of this software and associated documentation files (the "Software"), to deal 00007 in the Software without restriction, including without limitation the rights 00008 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00009 copies of the Software, and to permit persons to whom the Software is 00010 furnished to do so, subject to the following conditions: 00011 00012 The above copyright notice and this permission notice shall be included in 00013 all copies or substantial portions of the Software. 00014 00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00018 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00019 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00020 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00021 THE SOFTWARE. 00022 */ 00023 00024 #include "core/netservice.h" 00025 #include "HTTPClient.h" 00026 #include "../util/base64.h" 00027 #include "../util/url.h" 00028 00029 //#define __DEBUG 00030 #include "dbg/dbg.h" 00031 00032 #define HTTP_REQUEST_TIMEOUT 30000//15000 00033 #define HTTP_PORT 80 00034 00035 #define CHUNK_SIZE 256 00036 00037 HTTPClient::HTTPClient() : NetService(false) /*Not owned by the pool*/, m_meth(HTTP_GET), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL), 00038 m_watchdog(), m_timeout(0), m_pDnsReq(NULL), m_server(), m_path(), 00039 m_closed(true), m_proxy(false), m_state(HTTP_CLOSED), 00040 m_pDataOut(NULL), m_pDataIn(NULL), m_dataChunked(false), m_dataPos(0), m_dataLen(0), m_httpResponseCode(0), m_blockingResult(HTTP_PROCESSING) 00041 00042 { 00043 setTimeout(HTTP_REQUEST_TIMEOUT); 00044 m_buf = new char[CHUNK_SIZE]; 00045 DBG("New HTTPClient %p\n",this); 00046 } 00047 00048 HTTPClient::~HTTPClient() 00049 { 00050 close(); 00051 delete[] m_buf; 00052 } 00053 00054 void HTTPClient::basicAuth(const char* user, const char* password) //Basic Authentification 00055 { 00056 if(user==NULL) 00057 { 00058 m_reqHeaders.erase("Authorization"); //Remove auth str 00059 return; 00060 } 00061 string auth = "Basic "; 00062 string decStr = user; 00063 decStr += ":"; 00064 decStr += password; 00065 auth.append( Base64::encode(decStr) ); 00066 DBG("Auth str is %s\n", auth.c_str()); 00067 m_reqHeaders["Authorization"] = auth; 00068 } 00069 00070 //High Level setup functions 00071 HTTPResult HTTPClient::get(const char* uri, HTTPData* pDataIn) //Blocking 00072 { 00073 doGet(uri, pDataIn); 00074 return blockingProcess(); 00075 } 00076 00077 HTTPResult HTTPClient::get(const char* uri, HTTPData* pDataIn, void (*pMethod)(HTTPResult)) //Non blocking 00078 { 00079 setOnResult(pMethod); 00080 doGet(uri, pDataIn); 00081 return HTTP_PROCESSING; 00082 } 00083 00084 #if 0 //For info only 00085 template<class T> 00086 HTTPResult HTTPClient::get(const char* uri, HTTPData* pDataIn, T* pItem, void (T::*pMethod)(HTTPResult)) //Non blocking 00087 { 00088 setOnResult(pItem, pMethod); 00089 doGet(uri, pDataIn); 00090 return HTTP_PROCESSING; 00091 } 00092 #endif 00093 00094 HTTPResult HTTPClient::post(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn) //Blocking 00095 { 00096 doPost(uri, dataOut, pDataIn); 00097 return blockingProcess(); 00098 } 00099 00100 HTTPResult HTTPClient::post(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn, void (*pMethod)(HTTPResult)) //Non blocking 00101 { 00102 setOnResult(pMethod); 00103 doPost(uri, dataOut, pDataIn); 00104 return HTTP_PROCESSING; 00105 } 00106 00107 #if 0 //For info only 00108 template<class T> 00109 HTTPResult HTTPClient::post(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn, T* pItem, void (T::*pMethod)(HTTPResult)) //Non blocking 00110 { 00111 setOnResult(pItem, pMethod); 00112 doPost(uri, dataOut, pDataIn); 00113 return HTTP_PROCESSING; 00114 } 00115 #endif 00116 00117 void HTTPClient::doGet(const char* uri, HTTPData* pDataIn) 00118 { 00119 m_meth = HTTP_GET; 00120 setup(uri, NULL, pDataIn); 00121 } 00122 00123 void HTTPClient::doPost(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn) 00124 { 00125 m_meth = HTTP_POST; 00126 setup(uri, (HTTPData*) &dataOut, pDataIn); 00127 } 00128 00129 void HTTPClient::setOnResult( void (*pMethod)(HTTPResult) ) 00130 { 00131 m_pCb = pMethod; 00132 m_pCbItem = NULL; 00133 m_pCbMeth = NULL; 00134 } 00135 00136 #if 0 //For info only 00137 template<class T> 00138 void HTTPClient::setOnResult( T* pItem, void (T::*pMethod)(NtpResult) ) 00139 { 00140 m_pCb = NULL; 00141 m_pCbItem = (CDummy*) pItem; 00142 m_pCbMeth = (void (CDummy::*)(NtpResult)) pMethod; 00143 } 00144 #endif 00145 00146 void HTTPClient::setTimeout(int ms) 00147 { 00148 m_timeout = ms; 00149 //resetTimeout(); 00150 } 00151 00152 void HTTPClient::poll() //Called by NetServices 00153 { 00154 if(m_closed) 00155 { 00156 return; 00157 } 00158 if(m_watchdog.read_ms()>m_timeout) 00159 { 00160 onTimeout(); 00161 } 00162 else if(m_state == HTTP_READ_DATA_INCOMPLETE) 00163 { 00164 readData(); //Try to read more data 00165 if( m_state == HTTP_DONE ) 00166 { 00167 //All data has been read, close w/ success :) 00168 DBG("Done :)!\n"); 00169 onResult(HTTP_OK); 00170 close(); 00171 } 00172 } 00173 00174 } 00175 00176 int HTTPClient::getHTTPResponseCode() 00177 { 00178 return m_httpResponseCode; 00179 } 00180 00181 void HTTPClient::setRequestHeader(const string& header, const string& value) 00182 { 00183 m_reqHeaders[header] = value; 00184 } 00185 00186 string& HTTPClient::getResponseHeader(const string& header) 00187 { 00188 return m_respHeaders[header]; 00189 } 00190 00191 void HTTPClient::resetRequestHeaders() 00192 { 00193 m_reqHeaders.clear(); 00194 } 00195 00196 void HTTPClient::resetTimeout() 00197 { 00198 m_watchdog.reset(); 00199 m_watchdog.start(); 00200 } 00201 00202 void HTTPClient::init() //Create and setup socket if needed 00203 { 00204 close(); //Remove previous elements 00205 if(!m_closed) //Already opened 00206 return; 00207 m_state = HTTP_WRITE_HEADERS; 00208 m_pTCPSocket = new TCPSocket; 00209 m_pTCPSocket->setOnEvent(this, &HTTPClient::onTCPSocketEvent); 00210 m_closed = false; 00211 m_httpResponseCode = 0; 00212 } 00213 00214 void HTTPClient::close() 00215 { 00216 if(m_closed) 00217 return; 00218 m_state = HTTP_CLOSED; 00219 //Now Request headers are kept btw requests unless resetRequestHeaders() is called 00220 //m_reqHeaders.clear(); //Clear headers for next requests 00221 m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else 00222 m_watchdog.stop(); //Stop timeout 00223 m_watchdog.reset(); 00224 m_pTCPSocket->resetOnEvent(); 00225 m_pTCPSocket->close(); 00226 delete m_pTCPSocket; 00227 m_pTCPSocket = NULL; 00228 if( m_pDnsReq ) 00229 { 00230 m_pDnsReq->close(); 00231 delete m_pDnsReq; 00232 m_pDnsReq = NULL; 00233 } 00234 } 00235 00236 void HTTPClient::setup(const char* uri, HTTPData* pDataOut, HTTPData* pDataIn) //Setup request, make DNS Req if necessary 00237 { 00238 init(); //Initialize client in known state, create socket 00239 m_pDataOut = pDataOut; 00240 m_pDataIn = pDataIn; 00241 resetTimeout(); 00242 00243 //Erase previous headers 00244 //Do NOT clear m_reqHeaders as they might have already set before connecting 00245 m_respHeaders.clear(); 00246 00247 //Erase response buffer 00248 if(m_pDataIn) 00249 m_pDataIn->clear(); 00250 00251 //Assert that buffers are initialized properly 00252 m_dataLen = 0; 00253 m_bufRemainingLen = 0; 00254 00255 if ( m_proxy ) 00256 { 00257 // m_server is the proxy server, no need to parse the URL 00258 DBG("Using proxy\r\nHost: %s\r\nPort: %d\r\nURL: %s\n", m_server.getName().c_str(), m_server.getPort(), uri); 00259 // use the full URL as the request path 00260 m_path = uri; 00261 connect(); 00262 } 00263 else 00264 { 00265 // parse the server to connect to from the URL 00266 Url url; 00267 url.fromString(uri); 00268 00269 m_path = url.getPath(); 00270 00271 m_server.setName(url.getHost().c_str()); 00272 00273 if( url.getPort() > 0 ) 00274 { 00275 m_server.setPort( url.getPort() ); 00276 } 00277 else 00278 { 00279 m_server.setPort( HTTP_PORT ); 00280 } 00281 DBG("URL parsed,\r\nHost: %s\r\nPort: %d\r\nPath: %s\n", url.getHost().c_str(), url.getPort(), url.getPath().c_str()); 00282 IpAddr ip; 00283 if( url.getHostIp(&ip) ) 00284 { 00285 m_server.setIp(ip); 00286 connect(); 00287 } 00288 else 00289 { 00290 DBG("DNS Query...\n"); 00291 m_pDnsReq = new DNSRequest(); 00292 m_pDnsReq->setOnReply(this, &HTTPClient::onDNSReply); 00293 m_pDnsReq->resolve(&m_server); 00294 DBG("HTTPClient : DNSRequest %p\n", m_pDnsReq); 00295 // onDNSReply will call connect() 00296 } 00297 } 00298 } 00299 00300 void HTTPClient::connect() //Start Connection 00301 { 00302 resetTimeout(); 00303 DBG("Connecting...\n"); 00304 m_pTCPSocket->connect(m_server); 00305 } 00306 00307 #define MIN(a,b) ((a)<(b)?(a):(b)) 00308 #define ABS(a) (((a)>0)?(a):0) 00309 int HTTPClient::tryRead() //Try to read data from tcp packet and put in the HTTPData object 00310 { 00311 int len = 0; 00312 int readLen; 00313 do 00314 { 00315 if(m_state == HTTP_READ_DATA_INCOMPLETE) //First try to complete buffer copy 00316 { 00317 readLen = m_bufRemainingLen; 00318 /* if (readLen == 0) 00319 { 00320 m_state = HTTP_READ_DATA; 00321 continue; 00322 }*/ 00323 } 00324 else 00325 { 00326 readLen = m_pTCPSocket->recv(m_buf, MIN(ABS(m_dataLen-m_dataPos),CHUNK_SIZE)); 00327 if(readLen < 0) //Error 00328 { 00329 return readLen; 00330 } 00331 00332 DBG("%d bytes read\n", readLen); 00333 00334 m_pBufRemaining = m_buf; 00335 } 00336 if (readLen == 0) 00337 { 00338 m_state = HTTP_READ_DATA; 00339 return len; 00340 } 00341 00342 DBG("Trying to write %d bytes\n", readLen); 00343 00344 int writtenLen = m_pDataIn->write(m_pBufRemaining, readLen); 00345 m_dataPos += writtenLen; 00346 00347 DBG("%d bytes written\n", writtenLen); 00348 00349 if(writtenLen<readLen) //Data was not completely written 00350 { 00351 m_pBufRemaining += writtenLen; 00352 m_bufRemainingLen = readLen - writtenLen; 00353 m_state = HTTP_READ_DATA_INCOMPLETE; 00354 return len + writtenLen; 00355 } 00356 else 00357 { 00358 m_state = HTTP_READ_DATA; 00359 } 00360 len += readLen; 00361 } while(readLen>0); 00362 00363 return len; 00364 } 00365 00366 void HTTPClient::readData() //Data has been read 00367 { 00368 if(m_pDataIn == NULL) //Nothing to read (in HEAD for instance, not supported now) 00369 { 00370 m_state = HTTP_DONE; 00371 return; 00372 } 00373 DBG("Reading response...\n"); 00374 int len = 0; 00375 do 00376 { 00377 if(m_dataChunked && (m_state != HTTP_READ_DATA_INCOMPLETE)) 00378 { 00379 if(m_dataLen==0) 00380 { 00381 DBG("Reading chunk length...\n"); 00382 //New block 00383 static char chunkHeader[16]; 00384 //We use m_dataPos to retain the read position in chunkHeader, it has been set to 0 before the first call of readData() 00385 m_dataPos += readLine(chunkHeader + m_dataPos, ABS(16 - m_dataPos)); 00386 if( m_dataPos > 0 ) 00387 { 00388 if( chunkHeader[strlen(chunkHeader)-1] == 0x0d ) 00389 { 00390 sscanf(chunkHeader, "%x%*[^\r\n]", &m_dataLen); 00391 DBG("Chunk length is %d\n", m_dataLen); 00392 m_dataPos = 0; 00393 } 00394 else 00395 { 00396 //Wait for end of line 00397 DBG("Wait for CRLF\n"); 00398 return; 00399 } 00400 } 00401 else 00402 { 00403 DBG("Wait for data\n"); 00404 //Wait for data 00405 return; 00406 } 00407 } 00408 } 00409 00410 //Proper data recovery 00411 len = tryRead(); 00412 if(len<0) //Error 00413 { 00414 onResult(HTTP_CONN); 00415 return; 00416 } 00417 00418 if(len>0) 00419 resetTimeout(); 00420 00421 if(m_state == HTTP_READ_DATA_INCOMPLETE) 00422 return; 00423 00424 //Chunk Tail 00425 if(m_dataChunked) 00426 { 00427 if(m_dataPos >= m_dataLen) 00428 { 00429 DBG("Chunk read, wait for CRLF\n"); 00430 char chunkTail[3]; 00431 m_dataPos += readLine(chunkTail, 3); 00432 } 00433 00434 if(m_dataPos >= m_dataLen + 1) //1 == strlen("\n"), 00435 { 00436 DBG("End of chunk\n"); 00437 if(m_dataLen==0) 00438 { 00439 DBG("End of file\n"); 00440 //End of file 00441 m_state = HTTP_DONE; //Done 00442 } 00443 m_dataLen = 0; 00444 m_dataPos = 0; 00445 } 00446 } 00447 00448 } while(len>0); 00449 00450 00451 if(!m_dataChunked && (m_dataPos >= m_dataLen)) //All Data has been received 00452 { 00453 DBG("End of file\n"); 00454 m_state = HTTP_DONE; //Done 00455 } 00456 } 00457 00458 void HTTPClient::writeData() //Data has been written & buf is free 00459 { 00460 if(m_pDataOut == NULL) //Nothing to write (in POST for instance) 00461 { 00462 m_dataLen = 0; //Reset Data Length 00463 m_state = HTTP_READ_HEADERS; 00464 return; 00465 } 00466 int len = m_pDataOut->read(m_buf, CHUNK_SIZE); 00467 if( m_dataChunked ) 00468 { 00469 //Write chunk header 00470 char chunkHeader[16]; 00471 sprintf(chunkHeader, "%d\r\n", len); 00472 int ret = m_pTCPSocket->send(chunkHeader, strlen(chunkHeader)); 00473 if(ret < 0)//Error 00474 { 00475 onResult(HTTP_CONN); 00476 return; 00477 } 00478 } 00479 m_pTCPSocket->send(m_buf, len); 00480 m_dataPos+=len; 00481 if( m_dataChunked ) 00482 { 00483 m_pTCPSocket->send("\r\n", 2); //Chunk-terminating CRLF 00484 } 00485 if( ( !m_dataChunked && (m_dataPos >= m_dataLen) ) 00486 || ( m_dataChunked && !len ) ) //All Data has been sent 00487 { 00488 m_dataLen = 0; //Reset Data Length 00489 m_state = HTTP_READ_HEADERS; //Wait for resp 00490 } 00491 } 00492 00493 void HTTPClient::onTCPSocketEvent(TCPSocketEvent e) 00494 { 00495 DBG("Event %d in HTTPClient::onTCPSocketEvent()\n", e); 00496 00497 if(m_closed) 00498 { 00499 DBG("WARN: Discarded\n"); 00500 return; 00501 } 00502 00503 switch(e) 00504 { 00505 case TCPSOCKET_READABLE: //Incoming data 00506 resetTimeout(); 00507 switch(m_state) 00508 { 00509 case HTTP_READ_HEADERS: 00510 if( !readHeaders() ) 00511 { 00512 return; //Connection has been closed or incomplete data 00513 } 00514 if( m_pDataIn ) 00515 { 00516 //Data chunked? 00517 if(m_respHeaders["Transfer-Encoding"].find("chunked")!=string::npos) 00518 { 00519 m_dataChunked = true; 00520 m_dataPos = 0; 00521 m_dataLen = 0; 00522 DBG("Encoding is chunked, Content-Type is %s\n", m_respHeaders["Content-Type"].c_str() ); 00523 } 00524 else 00525 { 00526 m_dataChunked = false; 00527 int len = 0; 00528 //DBG("Preparing read... len = %s\n", m_respHeaders["Content-Length"].c_str()); 00529 sscanf(m_respHeaders["Content-Length"].c_str(), "%d", &len); 00530 m_pDataIn->setDataLen( len ); 00531 m_dataPos = 0; 00532 m_dataLen = len; 00533 DBG("Content-Length is %d, Content-Type is %s\n", len, m_respHeaders["Content-Type"].c_str() ); 00534 } 00535 m_pDataIn->setDataType( m_respHeaders["Content-Type"] ); 00536 } 00537 case HTTP_READ_DATA: 00538 readData(); 00539 break; 00540 case HTTP_READ_DATA_INCOMPLETE: 00541 break; //We need to handle previously received data first 00542 default: 00543 //Should not receive data now, req is not complete 00544 onResult(HTTP_PRTCL); 00545 } 00546 //All data has been read, close w/ success :) 00547 if( m_state == HTTP_DONE ) 00548 { 00549 DBG("Done :)!\n"); 00550 onResult(HTTP_OK); 00551 } 00552 break; 00553 case TCPSOCKET_CONNECTED: 00554 case TCPSOCKET_WRITEABLE: //We can send data 00555 resetTimeout(); 00556 switch(m_state) 00557 { 00558 case HTTP_WRITE_HEADERS: 00559 //Update headers fields according to m_pDataOut 00560 if( m_pDataOut ) 00561 { 00562 //Data is chunked? 00563 if(m_pDataOut->getIsChunked()) 00564 { 00565 m_dataChunked = true; 00566 m_reqHeaders.erase("Content-Length"); 00567 m_reqHeaders["Transfer-Encoding"] = "chunked"; 00568 } 00569 else 00570 { 00571 m_dataChunked = false; 00572 char c_len[16] = "0"; 00573 int len = m_pDataOut->getDataLen(); 00574 sprintf(c_len, "%d", len); 00575 m_dataPos = 0; 00576 m_dataLen = len; 00577 m_reqHeaders.erase("Transfer-Encoding"); 00578 m_reqHeaders["Content-Length"] = string(c_len); 00579 } 00580 string type = m_pDataOut->getDataType(); 00581 if(!type.empty()) 00582 { 00583 m_reqHeaders["Content-Type"] = type; 00584 } 00585 else 00586 { 00587 m_reqHeaders.erase("Content-Type"); 00588 } 00589 } 00590 if( !writeHeaders() ) 00591 { 00592 return; //Connection has been closed 00593 } 00594 break; //Wait for writeable event before sending payload 00595 case HTTP_WRITE_DATA: 00596 writeData(); 00597 break; 00598 } 00599 //Otherwise request has been sent, now wait for resp 00600 break; 00601 case TCPSOCKET_CONTIMEOUT: 00602 case TCPSOCKET_CONRST: 00603 case TCPSOCKET_CONABRT: 00604 case TCPSOCKET_ERROR: 00605 DBG("Connection error.\n"); 00606 onResult(HTTP_CONN); 00607 case TCPSOCKET_DISCONNECTED: 00608 //There might still be some data available for reading 00609 //So if we are in a reading state, do not close the socket yet 00610 if( (m_state != HTTP_READ_DATA_INCOMPLETE) && (m_state != HTTP_DONE) && (m_state != HTTP_CLOSED) ) 00611 { 00612 onResult(HTTP_CONN); 00613 } 00614 DBG("Connection closed by remote host.\n"); 00615 break; 00616 } 00617 } 00618 00619 void HTTPClient::onDNSReply(DNSReply r) 00620 { 00621 if(m_closed) 00622 { 00623 DBG("WARN: Discarded\n"); 00624 return; 00625 } 00626 00627 if( r != DNS_FOUND ) 00628 { 00629 DBG("Could not resolve hostname.\n"); 00630 onResult(HTTP_DNS); 00631 return; 00632 } 00633 00634 DBG("DNS Resolved to %d.%d.%d.%d.\n",m_server.getIp()[0],m_server.getIp()[1],m_server.getIp()[2],m_server.getIp()[3]); 00635 //If no error, m_server has been updated by m_pDnsReq so we're set to go ! 00636 m_pDnsReq->close(); 00637 delete m_pDnsReq; 00638 m_pDnsReq = NULL; 00639 connect(); 00640 } 00641 00642 void HTTPClient::onResult(HTTPResult r) //Called when exchange completed or on failure 00643 { 00644 if(m_pCbItem && m_pCbMeth) 00645 (m_pCbItem->*m_pCbMeth)(r); 00646 else if(m_pCb) 00647 m_pCb(r); 00648 m_blockingResult = r; //Blocking mode 00649 close(); //FIXME:Remove suppl. close() calls 00650 } 00651 00652 void HTTPClient::onTimeout() //Connection has timed out 00653 { 00654 DBG("Timed out.\n"); 00655 onResult(HTTP_TIMEOUT); 00656 close(); 00657 } 00658 00659 //Headers 00660 00661 //TODO: Factorize w/ HTTPRequestHandler in a single HTTPHeader class 00662 00663 HTTPResult HTTPClient::blockingProcess() //Called in blocking mode, calls Net::poll() until return code is available 00664 { 00665 //Disable callbacks 00666 m_pCb = NULL; 00667 m_pCbItem = NULL; 00668 m_pCbMeth = NULL; 00669 m_blockingResult = HTTP_PROCESSING; 00670 do 00671 { 00672 Net::poll(); 00673 } while(m_blockingResult == HTTP_PROCESSING); 00674 Net::poll(); //Necessary for cleanup 00675 return m_blockingResult; 00676 } 00677 00678 bool HTTPClient::readHeaders() 00679 { 00680 static char* line = m_buf; 00681 static char key[128]; 00682 static char value[128]; 00683 if(!m_dataLen) //No incomplete header in buffer, this is the first time we read data 00684 { 00685 if( readLine(line, 128) > 0 ) 00686 { 00687 //Check RC 00688 m_httpResponseCode = 0; 00689 if( sscanf(line, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 ) 00690 { 00691 //Cannot match string, error 00692 DBG("Not a correct HTTP answer : %s\n", line); 00693 onResult(HTTP_PRTCL); 00694 close(); 00695 return false; 00696 } 00697 00698 if(m_httpResponseCode != 200) 00699 { 00700 DBG("Response: error code %d\n", m_httpResponseCode); 00701 HTTPResult res = HTTP_ERROR; 00702 switch(m_httpResponseCode) 00703 { 00704 case 404: 00705 res = HTTP_NOTFOUND; 00706 break; 00707 case 403: 00708 res = HTTP_REFUSED; 00709 break; 00710 default: 00711 res = HTTP_ERROR; 00712 } 00713 onResult(res); 00714 close(); 00715 return false; 00716 } 00717 DBG("Response OK\n"); 00718 } 00719 else 00720 { 00721 //Empty packet, weird! 00722 DBG("Empty packet!\n"); 00723 onResult(HTTP_PRTCL); 00724 close(); 00725 return false; 00726 } 00727 } 00728 bool incomplete = false; 00729 while( true ) 00730 { 00731 int readLen = readLine(line + m_dataLen, 128 - m_dataLen, &incomplete); 00732 m_dataLen = 0; 00733 if( readLen <= 2 ) //if == 1 or 2, it is an empty line = end of headers 00734 { 00735 DBG("All headers read.\n"); 00736 m_state = HTTP_READ_DATA; 00737 break; 00738 } 00739 else if( incomplete == true ) 00740 { 00741 m_dataLen = readLen;//Sets data length available in buffer 00742 return false; 00743 } 00744 //DBG("Header : %s\n", line); 00745 int n = sscanf(line, "%[^:] : %[^\r\n]", key, value); 00746 if ( n == 2 ) 00747 { 00748 DBG("Read header : %s: %s\n", key, value); 00749 m_respHeaders[key] = value; 00750 } 00751 //TODO: Impl n==1 case (part 2 of previous header) 00752 } 00753 00754 return true; 00755 } 00756 00757 bool HTTPClient::writeHeaders() //Called at the first writeData call 00758 { 00759 static char* line = m_buf; 00760 const char* HTTP_METH_STR[] = {"GET", "POST", "HEAD"}; 00761 00762 //Req 00763 sprintf(line, "%s %s HTTP/1.1\r\nHost: %s\r\n", HTTP_METH_STR[m_meth], m_path.c_str(), m_server.getName()); //Write request 00764 m_pTCPSocket->send(line, strlen(line)); 00765 DBG("Request: %s\n", line); 00766 00767 DBG("Writing headers:\n"); 00768 map<string,string>::iterator it; 00769 for( it = m_reqHeaders.begin(); it != m_reqHeaders.end(); it++ ) 00770 { 00771 sprintf(line, "%s: %s\r\n", (*it).first.c_str(), (*it).second.c_str() ); 00772 DBG("\r\n%s", line); 00773 m_pTCPSocket->send(line, strlen(line)); 00774 } 00775 m_pTCPSocket->send("\r\n",2); //End of head 00776 m_state = HTTP_WRITE_DATA; 00777 return true; 00778 } 00779 00780 int HTTPClient::readLine(char* str, int maxLen, bool* pIncomplete /* = NULL*/) 00781 { 00782 int ret; 00783 int len = 0; 00784 if(pIncomplete) 00785 *pIncomplete = false; 00786 for(int i = 0; i < maxLen - 1; i++) 00787 { 00788 ret = m_pTCPSocket->recv(str, 1); 00789 if(ret != 1) 00790 { 00791 if(pIncomplete) 00792 *pIncomplete = true; 00793 break; 00794 } 00795 if( (len > 1) && *(str-1)=='\r' && *str=='\n' ) 00796 { 00797 break; 00798 } 00799 else if( *str=='\n' ) 00800 { 00801 break; 00802 } 00803 str++; 00804 len++; 00805 } 00806 *str = 0; 00807 return len; 00808 } 00809 00810 void HTTPClient::setProxy(const char* proxy_url) // host:port 00811 { 00812 if ( proxy_url == NULL ) 00813 { 00814 m_proxy = false; 00815 return; 00816 } 00817 Url url; 00818 url.fromString(proxy_url); 00819 m_server.setName(url.getHost().c_str()); 00820 00821 if( url.getPort() > 0 ) 00822 m_server.setPort( url.getPort() ); 00823 else 00824 m_server.setPort( 8080 ); 00825 DBG("Setting proxy server\r\nHost: %s\r\nPort: %d\r\n", url.getHost().c_str(), url.getPort()); 00826 IpAddr ip; 00827 if( url.getHostIp(&ip) ) 00828 { 00829 m_server.setIp(ip); 00830 } 00831 else 00832 { 00833 DBG("DNS Query...\n"); 00834 m_pDnsReq = new DNSRequest(); 00835 //m_pDnsReq->setOnReply(this, &HTTPClient::onDNSReply); 00836 m_pDnsReq->resolve(&m_server); 00837 DBG("HTTPClient : DNSRequest %p\n", m_pDnsReq); 00838 } 00839 m_proxy = true; 00840 }
Generated on Tue Jul 12 2022 17:20:06 by
1.7.2