Experimental HTTPClient with proxy support

Committer:
igorsk
Date:
Wed Jun 29 16:01:58 2011 +0000
Revision:
0:b56b6a05cad4

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
igorsk 0:b56b6a05cad4 1
igorsk 0:b56b6a05cad4 2 /*
igorsk 0:b56b6a05cad4 3 Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
igorsk 0:b56b6a05cad4 4
igorsk 0:b56b6a05cad4 5 Permission is hereby granted, free of charge, to any person obtaining a copy
igorsk 0:b56b6a05cad4 6 of this software and associated documentation files (the "Software"), to deal
igorsk 0:b56b6a05cad4 7 in the Software without restriction, including without limitation the rights
igorsk 0:b56b6a05cad4 8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
igorsk 0:b56b6a05cad4 9 copies of the Software, and to permit persons to whom the Software is
igorsk 0:b56b6a05cad4 10 furnished to do so, subject to the following conditions:
igorsk 0:b56b6a05cad4 11
igorsk 0:b56b6a05cad4 12 The above copyright notice and this permission notice shall be included in
igorsk 0:b56b6a05cad4 13 all copies or substantial portions of the Software.
igorsk 0:b56b6a05cad4 14
igorsk 0:b56b6a05cad4 15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
igorsk 0:b56b6a05cad4 16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
igorsk 0:b56b6a05cad4 17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
igorsk 0:b56b6a05cad4 18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
igorsk 0:b56b6a05cad4 19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
igorsk 0:b56b6a05cad4 20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
igorsk 0:b56b6a05cad4 21 THE SOFTWARE.
igorsk 0:b56b6a05cad4 22 */
igorsk 0:b56b6a05cad4 23
igorsk 0:b56b6a05cad4 24 #include "core/netservice.h"
igorsk 0:b56b6a05cad4 25 #include "HTTPClient.h"
igorsk 0:b56b6a05cad4 26 #include "../util/base64.h"
igorsk 0:b56b6a05cad4 27 #include "../util/url.h"
igorsk 0:b56b6a05cad4 28
igorsk 0:b56b6a05cad4 29 //#define __DEBUG
igorsk 0:b56b6a05cad4 30 #include "dbg/dbg.h"
igorsk 0:b56b6a05cad4 31
igorsk 0:b56b6a05cad4 32 #define HTTP_REQUEST_TIMEOUT 30000//15000
igorsk 0:b56b6a05cad4 33 #define HTTP_PORT 80
igorsk 0:b56b6a05cad4 34
igorsk 0:b56b6a05cad4 35 #define CHUNK_SIZE 256
igorsk 0:b56b6a05cad4 36
igorsk 0:b56b6a05cad4 37 HTTPClient::HTTPClient() : NetService(false) /*Not owned by the pool*/, m_meth(HTTP_GET), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL),
igorsk 0:b56b6a05cad4 38 m_watchdog(), m_timeout(0), m_pDnsReq(NULL), m_server(), m_path(),
igorsk 0:b56b6a05cad4 39 m_closed(true), m_proxy(false), m_state(HTTP_CLOSED),
igorsk 0:b56b6a05cad4 40 m_pDataOut(NULL), m_pDataIn(NULL), m_dataChunked(false), m_dataPos(0), m_dataLen(0), m_httpResponseCode(0), m_blockingResult(HTTP_PROCESSING)
igorsk 0:b56b6a05cad4 41
igorsk 0:b56b6a05cad4 42 {
igorsk 0:b56b6a05cad4 43 setTimeout(HTTP_REQUEST_TIMEOUT);
igorsk 0:b56b6a05cad4 44 m_buf = new char[CHUNK_SIZE];
igorsk 0:b56b6a05cad4 45 DBG("New HTTPClient %p\n",this);
igorsk 0:b56b6a05cad4 46 }
igorsk 0:b56b6a05cad4 47
igorsk 0:b56b6a05cad4 48 HTTPClient::~HTTPClient()
igorsk 0:b56b6a05cad4 49 {
igorsk 0:b56b6a05cad4 50 close();
igorsk 0:b56b6a05cad4 51 delete[] m_buf;
igorsk 0:b56b6a05cad4 52 }
igorsk 0:b56b6a05cad4 53
igorsk 0:b56b6a05cad4 54 void HTTPClient::basicAuth(const char* user, const char* password) //Basic Authentification
igorsk 0:b56b6a05cad4 55 {
igorsk 0:b56b6a05cad4 56 if(user==NULL)
igorsk 0:b56b6a05cad4 57 {
igorsk 0:b56b6a05cad4 58 m_reqHeaders.erase("Authorization"); //Remove auth str
igorsk 0:b56b6a05cad4 59 return;
igorsk 0:b56b6a05cad4 60 }
igorsk 0:b56b6a05cad4 61 string auth = "Basic ";
igorsk 0:b56b6a05cad4 62 string decStr = user;
igorsk 0:b56b6a05cad4 63 decStr += ":";
igorsk 0:b56b6a05cad4 64 decStr += password;
igorsk 0:b56b6a05cad4 65 auth.append( Base64::encode(decStr) );
igorsk 0:b56b6a05cad4 66 DBG("Auth str is %s\n", auth.c_str());
igorsk 0:b56b6a05cad4 67 m_reqHeaders["Authorization"] = auth;
igorsk 0:b56b6a05cad4 68 }
igorsk 0:b56b6a05cad4 69
igorsk 0:b56b6a05cad4 70 //High Level setup functions
igorsk 0:b56b6a05cad4 71 HTTPResult HTTPClient::get(const char* uri, HTTPData* pDataIn) //Blocking
igorsk 0:b56b6a05cad4 72 {
igorsk 0:b56b6a05cad4 73 doGet(uri, pDataIn);
igorsk 0:b56b6a05cad4 74 return blockingProcess();
igorsk 0:b56b6a05cad4 75 }
igorsk 0:b56b6a05cad4 76
igorsk 0:b56b6a05cad4 77 HTTPResult HTTPClient::get(const char* uri, HTTPData* pDataIn, void (*pMethod)(HTTPResult)) //Non blocking
igorsk 0:b56b6a05cad4 78 {
igorsk 0:b56b6a05cad4 79 setOnResult(pMethod);
igorsk 0:b56b6a05cad4 80 doGet(uri, pDataIn);
igorsk 0:b56b6a05cad4 81 return HTTP_PROCESSING;
igorsk 0:b56b6a05cad4 82 }
igorsk 0:b56b6a05cad4 83
igorsk 0:b56b6a05cad4 84 #if 0 //For info only
igorsk 0:b56b6a05cad4 85 template<class T>
igorsk 0:b56b6a05cad4 86 HTTPResult HTTPClient::get(const char* uri, HTTPData* pDataIn, T* pItem, void (T::*pMethod)(HTTPResult)) //Non blocking
igorsk 0:b56b6a05cad4 87 {
igorsk 0:b56b6a05cad4 88 setOnResult(pItem, pMethod);
igorsk 0:b56b6a05cad4 89 doGet(uri, pDataIn);
igorsk 0:b56b6a05cad4 90 return HTTP_PROCESSING;
igorsk 0:b56b6a05cad4 91 }
igorsk 0:b56b6a05cad4 92 #endif
igorsk 0:b56b6a05cad4 93
igorsk 0:b56b6a05cad4 94 HTTPResult HTTPClient::post(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn) //Blocking
igorsk 0:b56b6a05cad4 95 {
igorsk 0:b56b6a05cad4 96 doPost(uri, dataOut, pDataIn);
igorsk 0:b56b6a05cad4 97 return blockingProcess();
igorsk 0:b56b6a05cad4 98 }
igorsk 0:b56b6a05cad4 99
igorsk 0:b56b6a05cad4 100 HTTPResult HTTPClient::post(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn, void (*pMethod)(HTTPResult)) //Non blocking
igorsk 0:b56b6a05cad4 101 {
igorsk 0:b56b6a05cad4 102 setOnResult(pMethod);
igorsk 0:b56b6a05cad4 103 doPost(uri, dataOut, pDataIn);
igorsk 0:b56b6a05cad4 104 return HTTP_PROCESSING;
igorsk 0:b56b6a05cad4 105 }
igorsk 0:b56b6a05cad4 106
igorsk 0:b56b6a05cad4 107 #if 0 //For info only
igorsk 0:b56b6a05cad4 108 template<class T>
igorsk 0:b56b6a05cad4 109 HTTPResult HTTPClient::post(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn, T* pItem, void (T::*pMethod)(HTTPResult)) //Non blocking
igorsk 0:b56b6a05cad4 110 {
igorsk 0:b56b6a05cad4 111 setOnResult(pItem, pMethod);
igorsk 0:b56b6a05cad4 112 doPost(uri, dataOut, pDataIn);
igorsk 0:b56b6a05cad4 113 return HTTP_PROCESSING;
igorsk 0:b56b6a05cad4 114 }
igorsk 0:b56b6a05cad4 115 #endif
igorsk 0:b56b6a05cad4 116
igorsk 0:b56b6a05cad4 117 void HTTPClient::doGet(const char* uri, HTTPData* pDataIn)
igorsk 0:b56b6a05cad4 118 {
igorsk 0:b56b6a05cad4 119 m_meth = HTTP_GET;
igorsk 0:b56b6a05cad4 120 setup(uri, NULL, pDataIn);
igorsk 0:b56b6a05cad4 121 }
igorsk 0:b56b6a05cad4 122
igorsk 0:b56b6a05cad4 123 void HTTPClient::doPost(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn)
igorsk 0:b56b6a05cad4 124 {
igorsk 0:b56b6a05cad4 125 m_meth = HTTP_POST;
igorsk 0:b56b6a05cad4 126 setup(uri, (HTTPData*) &dataOut, pDataIn);
igorsk 0:b56b6a05cad4 127 }
igorsk 0:b56b6a05cad4 128
igorsk 0:b56b6a05cad4 129 void HTTPClient::setOnResult( void (*pMethod)(HTTPResult) )
igorsk 0:b56b6a05cad4 130 {
igorsk 0:b56b6a05cad4 131 m_pCb = pMethod;
igorsk 0:b56b6a05cad4 132 m_pCbItem = NULL;
igorsk 0:b56b6a05cad4 133 m_pCbMeth = NULL;
igorsk 0:b56b6a05cad4 134 }
igorsk 0:b56b6a05cad4 135
igorsk 0:b56b6a05cad4 136 #if 0 //For info only
igorsk 0:b56b6a05cad4 137 template<class T>
igorsk 0:b56b6a05cad4 138 void HTTPClient::setOnResult( T* pItem, void (T::*pMethod)(NtpResult) )
igorsk 0:b56b6a05cad4 139 {
igorsk 0:b56b6a05cad4 140 m_pCb = NULL;
igorsk 0:b56b6a05cad4 141 m_pCbItem = (CDummy*) pItem;
igorsk 0:b56b6a05cad4 142 m_pCbMeth = (void (CDummy::*)(NtpResult)) pMethod;
igorsk 0:b56b6a05cad4 143 }
igorsk 0:b56b6a05cad4 144 #endif
igorsk 0:b56b6a05cad4 145
igorsk 0:b56b6a05cad4 146 void HTTPClient::setTimeout(int ms)
igorsk 0:b56b6a05cad4 147 {
igorsk 0:b56b6a05cad4 148 m_timeout = ms;
igorsk 0:b56b6a05cad4 149 //resetTimeout();
igorsk 0:b56b6a05cad4 150 }
igorsk 0:b56b6a05cad4 151
igorsk 0:b56b6a05cad4 152 void HTTPClient::poll() //Called by NetServices
igorsk 0:b56b6a05cad4 153 {
igorsk 0:b56b6a05cad4 154 if(m_closed)
igorsk 0:b56b6a05cad4 155 {
igorsk 0:b56b6a05cad4 156 return;
igorsk 0:b56b6a05cad4 157 }
igorsk 0:b56b6a05cad4 158 if(m_watchdog.read_ms()>m_timeout)
igorsk 0:b56b6a05cad4 159 {
igorsk 0:b56b6a05cad4 160 onTimeout();
igorsk 0:b56b6a05cad4 161 }
igorsk 0:b56b6a05cad4 162 else if(m_state == HTTP_READ_DATA_INCOMPLETE)
igorsk 0:b56b6a05cad4 163 {
igorsk 0:b56b6a05cad4 164 readData(); //Try to read more data
igorsk 0:b56b6a05cad4 165 if( m_state == HTTP_DONE )
igorsk 0:b56b6a05cad4 166 {
igorsk 0:b56b6a05cad4 167 //All data has been read, close w/ success :)
igorsk 0:b56b6a05cad4 168 DBG("Done :)!\n");
igorsk 0:b56b6a05cad4 169 onResult(HTTP_OK);
igorsk 0:b56b6a05cad4 170 close();
igorsk 0:b56b6a05cad4 171 }
igorsk 0:b56b6a05cad4 172 }
igorsk 0:b56b6a05cad4 173
igorsk 0:b56b6a05cad4 174 }
igorsk 0:b56b6a05cad4 175
igorsk 0:b56b6a05cad4 176 int HTTPClient::getHTTPResponseCode()
igorsk 0:b56b6a05cad4 177 {
igorsk 0:b56b6a05cad4 178 return m_httpResponseCode;
igorsk 0:b56b6a05cad4 179 }
igorsk 0:b56b6a05cad4 180
igorsk 0:b56b6a05cad4 181 void HTTPClient::setRequestHeader(const string& header, const string& value)
igorsk 0:b56b6a05cad4 182 {
igorsk 0:b56b6a05cad4 183 m_reqHeaders[header] = value;
igorsk 0:b56b6a05cad4 184 }
igorsk 0:b56b6a05cad4 185
igorsk 0:b56b6a05cad4 186 string& HTTPClient::getResponseHeader(const string& header)
igorsk 0:b56b6a05cad4 187 {
igorsk 0:b56b6a05cad4 188 return m_respHeaders[header];
igorsk 0:b56b6a05cad4 189 }
igorsk 0:b56b6a05cad4 190
igorsk 0:b56b6a05cad4 191 void HTTPClient::resetRequestHeaders()
igorsk 0:b56b6a05cad4 192 {
igorsk 0:b56b6a05cad4 193 m_reqHeaders.clear();
igorsk 0:b56b6a05cad4 194 }
igorsk 0:b56b6a05cad4 195
igorsk 0:b56b6a05cad4 196 void HTTPClient::resetTimeout()
igorsk 0:b56b6a05cad4 197 {
igorsk 0:b56b6a05cad4 198 m_watchdog.reset();
igorsk 0:b56b6a05cad4 199 m_watchdog.start();
igorsk 0:b56b6a05cad4 200 }
igorsk 0:b56b6a05cad4 201
igorsk 0:b56b6a05cad4 202 void HTTPClient::init() //Create and setup socket if needed
igorsk 0:b56b6a05cad4 203 {
igorsk 0:b56b6a05cad4 204 close(); //Remove previous elements
igorsk 0:b56b6a05cad4 205 if(!m_closed) //Already opened
igorsk 0:b56b6a05cad4 206 return;
igorsk 0:b56b6a05cad4 207 m_state = HTTP_WRITE_HEADERS;
igorsk 0:b56b6a05cad4 208 m_pTCPSocket = new TCPSocket;
igorsk 0:b56b6a05cad4 209 m_pTCPSocket->setOnEvent(this, &HTTPClient::onTCPSocketEvent);
igorsk 0:b56b6a05cad4 210 m_closed = false;
igorsk 0:b56b6a05cad4 211 m_httpResponseCode = 0;
igorsk 0:b56b6a05cad4 212 }
igorsk 0:b56b6a05cad4 213
igorsk 0:b56b6a05cad4 214 void HTTPClient::close()
igorsk 0:b56b6a05cad4 215 {
igorsk 0:b56b6a05cad4 216 if(m_closed)
igorsk 0:b56b6a05cad4 217 return;
igorsk 0:b56b6a05cad4 218 m_state = HTTP_CLOSED;
igorsk 0:b56b6a05cad4 219 //Now Request headers are kept btw requests unless resetRequestHeaders() is called
igorsk 0:b56b6a05cad4 220 //m_reqHeaders.clear(); //Clear headers for next requests
igorsk 0:b56b6a05cad4 221 m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else
igorsk 0:b56b6a05cad4 222 m_watchdog.stop(); //Stop timeout
igorsk 0:b56b6a05cad4 223 m_watchdog.reset();
igorsk 0:b56b6a05cad4 224 m_pTCPSocket->resetOnEvent();
igorsk 0:b56b6a05cad4 225 m_pTCPSocket->close();
igorsk 0:b56b6a05cad4 226 delete m_pTCPSocket;
igorsk 0:b56b6a05cad4 227 m_pTCPSocket = NULL;
igorsk 0:b56b6a05cad4 228 if( m_pDnsReq )
igorsk 0:b56b6a05cad4 229 {
igorsk 0:b56b6a05cad4 230 m_pDnsReq->close();
igorsk 0:b56b6a05cad4 231 delete m_pDnsReq;
igorsk 0:b56b6a05cad4 232 m_pDnsReq = NULL;
igorsk 0:b56b6a05cad4 233 }
igorsk 0:b56b6a05cad4 234 }
igorsk 0:b56b6a05cad4 235
igorsk 0:b56b6a05cad4 236 void HTTPClient::setup(const char* uri, HTTPData* pDataOut, HTTPData* pDataIn) //Setup request, make DNS Req if necessary
igorsk 0:b56b6a05cad4 237 {
igorsk 0:b56b6a05cad4 238 init(); //Initialize client in known state, create socket
igorsk 0:b56b6a05cad4 239 m_pDataOut = pDataOut;
igorsk 0:b56b6a05cad4 240 m_pDataIn = pDataIn;
igorsk 0:b56b6a05cad4 241 resetTimeout();
igorsk 0:b56b6a05cad4 242
igorsk 0:b56b6a05cad4 243 //Erase previous headers
igorsk 0:b56b6a05cad4 244 //Do NOT clear m_reqHeaders as they might have already set before connecting
igorsk 0:b56b6a05cad4 245 m_respHeaders.clear();
igorsk 0:b56b6a05cad4 246
igorsk 0:b56b6a05cad4 247 //Erase response buffer
igorsk 0:b56b6a05cad4 248 if(m_pDataIn)
igorsk 0:b56b6a05cad4 249 m_pDataIn->clear();
igorsk 0:b56b6a05cad4 250
igorsk 0:b56b6a05cad4 251 //Assert that buffers are initialized properly
igorsk 0:b56b6a05cad4 252 m_dataLen = 0;
igorsk 0:b56b6a05cad4 253 m_bufRemainingLen = 0;
igorsk 0:b56b6a05cad4 254
igorsk 0:b56b6a05cad4 255 if ( m_proxy )
igorsk 0:b56b6a05cad4 256 {
igorsk 0:b56b6a05cad4 257 // m_server is the proxy server, no need to parse the URL
igorsk 0:b56b6a05cad4 258 DBG("Using proxy\r\nHost: %s\r\nPort: %d\r\nURL: %s\n", m_server.getName().c_str(), m_server.getPort(), uri);
igorsk 0:b56b6a05cad4 259 // use the full URL as the request path
igorsk 0:b56b6a05cad4 260 m_path = uri;
igorsk 0:b56b6a05cad4 261 connect();
igorsk 0:b56b6a05cad4 262 }
igorsk 0:b56b6a05cad4 263 else
igorsk 0:b56b6a05cad4 264 {
igorsk 0:b56b6a05cad4 265 // parse the server to connect to from the URL
igorsk 0:b56b6a05cad4 266 Url url;
igorsk 0:b56b6a05cad4 267 url.fromString(uri);
igorsk 0:b56b6a05cad4 268
igorsk 0:b56b6a05cad4 269 m_path = url.getPath();
igorsk 0:b56b6a05cad4 270
igorsk 0:b56b6a05cad4 271 m_server.setName(url.getHost().c_str());
igorsk 0:b56b6a05cad4 272
igorsk 0:b56b6a05cad4 273 if( url.getPort() > 0 )
igorsk 0:b56b6a05cad4 274 {
igorsk 0:b56b6a05cad4 275 m_server.setPort( url.getPort() );
igorsk 0:b56b6a05cad4 276 }
igorsk 0:b56b6a05cad4 277 else
igorsk 0:b56b6a05cad4 278 {
igorsk 0:b56b6a05cad4 279 m_server.setPort( HTTP_PORT );
igorsk 0:b56b6a05cad4 280 }
igorsk 0:b56b6a05cad4 281 DBG("URL parsed,\r\nHost: %s\r\nPort: %d\r\nPath: %s\n", url.getHost().c_str(), url.getPort(), url.getPath().c_str());
igorsk 0:b56b6a05cad4 282 IpAddr ip;
igorsk 0:b56b6a05cad4 283 if( url.getHostIp(&ip) )
igorsk 0:b56b6a05cad4 284 {
igorsk 0:b56b6a05cad4 285 m_server.setIp(ip);
igorsk 0:b56b6a05cad4 286 connect();
igorsk 0:b56b6a05cad4 287 }
igorsk 0:b56b6a05cad4 288 else
igorsk 0:b56b6a05cad4 289 {
igorsk 0:b56b6a05cad4 290 DBG("DNS Query...\n");
igorsk 0:b56b6a05cad4 291 m_pDnsReq = new DNSRequest();
igorsk 0:b56b6a05cad4 292 m_pDnsReq->setOnReply(this, &HTTPClient::onDNSReply);
igorsk 0:b56b6a05cad4 293 m_pDnsReq->resolve(&m_server);
igorsk 0:b56b6a05cad4 294 DBG("HTTPClient : DNSRequest %p\n", m_pDnsReq);
igorsk 0:b56b6a05cad4 295 // onDNSReply will call connect()
igorsk 0:b56b6a05cad4 296 }
igorsk 0:b56b6a05cad4 297 }
igorsk 0:b56b6a05cad4 298 }
igorsk 0:b56b6a05cad4 299
igorsk 0:b56b6a05cad4 300 void HTTPClient::connect() //Start Connection
igorsk 0:b56b6a05cad4 301 {
igorsk 0:b56b6a05cad4 302 resetTimeout();
igorsk 0:b56b6a05cad4 303 DBG("Connecting...\n");
igorsk 0:b56b6a05cad4 304 m_pTCPSocket->connect(m_server);
igorsk 0:b56b6a05cad4 305 }
igorsk 0:b56b6a05cad4 306
igorsk 0:b56b6a05cad4 307 #define MIN(a,b) ((a)<(b)?(a):(b))
igorsk 0:b56b6a05cad4 308 #define ABS(a) (((a)>0)?(a):0)
igorsk 0:b56b6a05cad4 309 int HTTPClient::tryRead() //Try to read data from tcp packet and put in the HTTPData object
igorsk 0:b56b6a05cad4 310 {
igorsk 0:b56b6a05cad4 311 int len = 0;
igorsk 0:b56b6a05cad4 312 int readLen;
igorsk 0:b56b6a05cad4 313 do
igorsk 0:b56b6a05cad4 314 {
igorsk 0:b56b6a05cad4 315 if(m_state == HTTP_READ_DATA_INCOMPLETE) //First try to complete buffer copy
igorsk 0:b56b6a05cad4 316 {
igorsk 0:b56b6a05cad4 317 readLen = m_bufRemainingLen;
igorsk 0:b56b6a05cad4 318 /* if (readLen == 0)
igorsk 0:b56b6a05cad4 319 {
igorsk 0:b56b6a05cad4 320 m_state = HTTP_READ_DATA;
igorsk 0:b56b6a05cad4 321 continue;
igorsk 0:b56b6a05cad4 322 }*/
igorsk 0:b56b6a05cad4 323 }
igorsk 0:b56b6a05cad4 324 else
igorsk 0:b56b6a05cad4 325 {
igorsk 0:b56b6a05cad4 326 readLen = m_pTCPSocket->recv(m_buf, MIN(ABS(m_dataLen-m_dataPos),CHUNK_SIZE));
igorsk 0:b56b6a05cad4 327 if(readLen < 0) //Error
igorsk 0:b56b6a05cad4 328 {
igorsk 0:b56b6a05cad4 329 return readLen;
igorsk 0:b56b6a05cad4 330 }
igorsk 0:b56b6a05cad4 331
igorsk 0:b56b6a05cad4 332 DBG("%d bytes read\n", readLen);
igorsk 0:b56b6a05cad4 333
igorsk 0:b56b6a05cad4 334 m_pBufRemaining = m_buf;
igorsk 0:b56b6a05cad4 335 }
igorsk 0:b56b6a05cad4 336 if (readLen == 0)
igorsk 0:b56b6a05cad4 337 {
igorsk 0:b56b6a05cad4 338 m_state = HTTP_READ_DATA;
igorsk 0:b56b6a05cad4 339 return len;
igorsk 0:b56b6a05cad4 340 }
igorsk 0:b56b6a05cad4 341
igorsk 0:b56b6a05cad4 342 DBG("Trying to write %d bytes\n", readLen);
igorsk 0:b56b6a05cad4 343
igorsk 0:b56b6a05cad4 344 int writtenLen = m_pDataIn->write(m_pBufRemaining, readLen);
igorsk 0:b56b6a05cad4 345 m_dataPos += writtenLen;
igorsk 0:b56b6a05cad4 346
igorsk 0:b56b6a05cad4 347 DBG("%d bytes written\n", writtenLen);
igorsk 0:b56b6a05cad4 348
igorsk 0:b56b6a05cad4 349 if(writtenLen<readLen) //Data was not completely written
igorsk 0:b56b6a05cad4 350 {
igorsk 0:b56b6a05cad4 351 m_pBufRemaining += writtenLen;
igorsk 0:b56b6a05cad4 352 m_bufRemainingLen = readLen - writtenLen;
igorsk 0:b56b6a05cad4 353 m_state = HTTP_READ_DATA_INCOMPLETE;
igorsk 0:b56b6a05cad4 354 return len + writtenLen;
igorsk 0:b56b6a05cad4 355 }
igorsk 0:b56b6a05cad4 356 else
igorsk 0:b56b6a05cad4 357 {
igorsk 0:b56b6a05cad4 358 m_state = HTTP_READ_DATA;
igorsk 0:b56b6a05cad4 359 }
igorsk 0:b56b6a05cad4 360 len += readLen;
igorsk 0:b56b6a05cad4 361 } while(readLen>0);
igorsk 0:b56b6a05cad4 362
igorsk 0:b56b6a05cad4 363 return len;
igorsk 0:b56b6a05cad4 364 }
igorsk 0:b56b6a05cad4 365
igorsk 0:b56b6a05cad4 366 void HTTPClient::readData() //Data has been read
igorsk 0:b56b6a05cad4 367 {
igorsk 0:b56b6a05cad4 368 if(m_pDataIn == NULL) //Nothing to read (in HEAD for instance, not supported now)
igorsk 0:b56b6a05cad4 369 {
igorsk 0:b56b6a05cad4 370 m_state = HTTP_DONE;
igorsk 0:b56b6a05cad4 371 return;
igorsk 0:b56b6a05cad4 372 }
igorsk 0:b56b6a05cad4 373 DBG("Reading response...\n");
igorsk 0:b56b6a05cad4 374 int len = 0;
igorsk 0:b56b6a05cad4 375 do
igorsk 0:b56b6a05cad4 376 {
igorsk 0:b56b6a05cad4 377 if(m_dataChunked && (m_state != HTTP_READ_DATA_INCOMPLETE))
igorsk 0:b56b6a05cad4 378 {
igorsk 0:b56b6a05cad4 379 if(m_dataLen==0)
igorsk 0:b56b6a05cad4 380 {
igorsk 0:b56b6a05cad4 381 DBG("Reading chunk length...\n");
igorsk 0:b56b6a05cad4 382 //New block
igorsk 0:b56b6a05cad4 383 static char chunkHeader[16];
igorsk 0:b56b6a05cad4 384 //We use m_dataPos to retain the read position in chunkHeader, it has been set to 0 before the first call of readData()
igorsk 0:b56b6a05cad4 385 m_dataPos += readLine(chunkHeader + m_dataPos, ABS(16 - m_dataPos));
igorsk 0:b56b6a05cad4 386 if( m_dataPos > 0 )
igorsk 0:b56b6a05cad4 387 {
igorsk 0:b56b6a05cad4 388 if( chunkHeader[strlen(chunkHeader)-1] == 0x0d )
igorsk 0:b56b6a05cad4 389 {
igorsk 0:b56b6a05cad4 390 sscanf(chunkHeader, "%x%*[^\r\n]", &m_dataLen);
igorsk 0:b56b6a05cad4 391 DBG("Chunk length is %d\n", m_dataLen);
igorsk 0:b56b6a05cad4 392 m_dataPos = 0;
igorsk 0:b56b6a05cad4 393 }
igorsk 0:b56b6a05cad4 394 else
igorsk 0:b56b6a05cad4 395 {
igorsk 0:b56b6a05cad4 396 //Wait for end of line
igorsk 0:b56b6a05cad4 397 DBG("Wait for CRLF\n");
igorsk 0:b56b6a05cad4 398 return;
igorsk 0:b56b6a05cad4 399 }
igorsk 0:b56b6a05cad4 400 }
igorsk 0:b56b6a05cad4 401 else
igorsk 0:b56b6a05cad4 402 {
igorsk 0:b56b6a05cad4 403 DBG("Wait for data\n");
igorsk 0:b56b6a05cad4 404 //Wait for data
igorsk 0:b56b6a05cad4 405 return;
igorsk 0:b56b6a05cad4 406 }
igorsk 0:b56b6a05cad4 407 }
igorsk 0:b56b6a05cad4 408 }
igorsk 0:b56b6a05cad4 409
igorsk 0:b56b6a05cad4 410 //Proper data recovery
igorsk 0:b56b6a05cad4 411 len = tryRead();
igorsk 0:b56b6a05cad4 412 if(len<0) //Error
igorsk 0:b56b6a05cad4 413 {
igorsk 0:b56b6a05cad4 414 onResult(HTTP_CONN);
igorsk 0:b56b6a05cad4 415 return;
igorsk 0:b56b6a05cad4 416 }
igorsk 0:b56b6a05cad4 417
igorsk 0:b56b6a05cad4 418 if(len>0)
igorsk 0:b56b6a05cad4 419 resetTimeout();
igorsk 0:b56b6a05cad4 420
igorsk 0:b56b6a05cad4 421 if(m_state == HTTP_READ_DATA_INCOMPLETE)
igorsk 0:b56b6a05cad4 422 return;
igorsk 0:b56b6a05cad4 423
igorsk 0:b56b6a05cad4 424 //Chunk Tail
igorsk 0:b56b6a05cad4 425 if(m_dataChunked)
igorsk 0:b56b6a05cad4 426 {
igorsk 0:b56b6a05cad4 427 if(m_dataPos >= m_dataLen)
igorsk 0:b56b6a05cad4 428 {
igorsk 0:b56b6a05cad4 429 DBG("Chunk read, wait for CRLF\n");
igorsk 0:b56b6a05cad4 430 char chunkTail[3];
igorsk 0:b56b6a05cad4 431 m_dataPos += readLine(chunkTail, 3);
igorsk 0:b56b6a05cad4 432 }
igorsk 0:b56b6a05cad4 433
igorsk 0:b56b6a05cad4 434 if(m_dataPos >= m_dataLen + 1) //1 == strlen("\n"),
igorsk 0:b56b6a05cad4 435 {
igorsk 0:b56b6a05cad4 436 DBG("End of chunk\n");
igorsk 0:b56b6a05cad4 437 if(m_dataLen==0)
igorsk 0:b56b6a05cad4 438 {
igorsk 0:b56b6a05cad4 439 DBG("End of file\n");
igorsk 0:b56b6a05cad4 440 //End of file
igorsk 0:b56b6a05cad4 441 m_state = HTTP_DONE; //Done
igorsk 0:b56b6a05cad4 442 }
igorsk 0:b56b6a05cad4 443 m_dataLen = 0;
igorsk 0:b56b6a05cad4 444 m_dataPos = 0;
igorsk 0:b56b6a05cad4 445 }
igorsk 0:b56b6a05cad4 446 }
igorsk 0:b56b6a05cad4 447
igorsk 0:b56b6a05cad4 448 } while(len>0);
igorsk 0:b56b6a05cad4 449
igorsk 0:b56b6a05cad4 450
igorsk 0:b56b6a05cad4 451 if(!m_dataChunked && (m_dataPos >= m_dataLen)) //All Data has been received
igorsk 0:b56b6a05cad4 452 {
igorsk 0:b56b6a05cad4 453 DBG("End of file\n");
igorsk 0:b56b6a05cad4 454 m_state = HTTP_DONE; //Done
igorsk 0:b56b6a05cad4 455 }
igorsk 0:b56b6a05cad4 456 }
igorsk 0:b56b6a05cad4 457
igorsk 0:b56b6a05cad4 458 void HTTPClient::writeData() //Data has been written & buf is free
igorsk 0:b56b6a05cad4 459 {
igorsk 0:b56b6a05cad4 460 if(m_pDataOut == NULL) //Nothing to write (in POST for instance)
igorsk 0:b56b6a05cad4 461 {
igorsk 0:b56b6a05cad4 462 m_dataLen = 0; //Reset Data Length
igorsk 0:b56b6a05cad4 463 m_state = HTTP_READ_HEADERS;
igorsk 0:b56b6a05cad4 464 return;
igorsk 0:b56b6a05cad4 465 }
igorsk 0:b56b6a05cad4 466 int len = m_pDataOut->read(m_buf, CHUNK_SIZE);
igorsk 0:b56b6a05cad4 467 if( m_dataChunked )
igorsk 0:b56b6a05cad4 468 {
igorsk 0:b56b6a05cad4 469 //Write chunk header
igorsk 0:b56b6a05cad4 470 char chunkHeader[16];
igorsk 0:b56b6a05cad4 471 sprintf(chunkHeader, "%d\r\n", len);
igorsk 0:b56b6a05cad4 472 int ret = m_pTCPSocket->send(chunkHeader, strlen(chunkHeader));
igorsk 0:b56b6a05cad4 473 if(ret < 0)//Error
igorsk 0:b56b6a05cad4 474 {
igorsk 0:b56b6a05cad4 475 onResult(HTTP_CONN);
igorsk 0:b56b6a05cad4 476 return;
igorsk 0:b56b6a05cad4 477 }
igorsk 0:b56b6a05cad4 478 }
igorsk 0:b56b6a05cad4 479 m_pTCPSocket->send(m_buf, len);
igorsk 0:b56b6a05cad4 480 m_dataPos+=len;
igorsk 0:b56b6a05cad4 481 if( m_dataChunked )
igorsk 0:b56b6a05cad4 482 {
igorsk 0:b56b6a05cad4 483 m_pTCPSocket->send("\r\n", 2); //Chunk-terminating CRLF
igorsk 0:b56b6a05cad4 484 }
igorsk 0:b56b6a05cad4 485 if( ( !m_dataChunked && (m_dataPos >= m_dataLen) )
igorsk 0:b56b6a05cad4 486 || ( m_dataChunked && !len ) ) //All Data has been sent
igorsk 0:b56b6a05cad4 487 {
igorsk 0:b56b6a05cad4 488 m_dataLen = 0; //Reset Data Length
igorsk 0:b56b6a05cad4 489 m_state = HTTP_READ_HEADERS; //Wait for resp
igorsk 0:b56b6a05cad4 490 }
igorsk 0:b56b6a05cad4 491 }
igorsk 0:b56b6a05cad4 492
igorsk 0:b56b6a05cad4 493 void HTTPClient::onTCPSocketEvent(TCPSocketEvent e)
igorsk 0:b56b6a05cad4 494 {
igorsk 0:b56b6a05cad4 495 DBG("Event %d in HTTPClient::onTCPSocketEvent()\n", e);
igorsk 0:b56b6a05cad4 496
igorsk 0:b56b6a05cad4 497 if(m_closed)
igorsk 0:b56b6a05cad4 498 {
igorsk 0:b56b6a05cad4 499 DBG("WARN: Discarded\n");
igorsk 0:b56b6a05cad4 500 return;
igorsk 0:b56b6a05cad4 501 }
igorsk 0:b56b6a05cad4 502
igorsk 0:b56b6a05cad4 503 switch(e)
igorsk 0:b56b6a05cad4 504 {
igorsk 0:b56b6a05cad4 505 case TCPSOCKET_READABLE: //Incoming data
igorsk 0:b56b6a05cad4 506 resetTimeout();
igorsk 0:b56b6a05cad4 507 switch(m_state)
igorsk 0:b56b6a05cad4 508 {
igorsk 0:b56b6a05cad4 509 case HTTP_READ_HEADERS:
igorsk 0:b56b6a05cad4 510 if( !readHeaders() )
igorsk 0:b56b6a05cad4 511 {
igorsk 0:b56b6a05cad4 512 return; //Connection has been closed or incomplete data
igorsk 0:b56b6a05cad4 513 }
igorsk 0:b56b6a05cad4 514 if( m_pDataIn )
igorsk 0:b56b6a05cad4 515 {
igorsk 0:b56b6a05cad4 516 //Data chunked?
igorsk 0:b56b6a05cad4 517 if(m_respHeaders["Transfer-Encoding"].find("chunked")!=string::npos)
igorsk 0:b56b6a05cad4 518 {
igorsk 0:b56b6a05cad4 519 m_dataChunked = true;
igorsk 0:b56b6a05cad4 520 m_dataPos = 0;
igorsk 0:b56b6a05cad4 521 m_dataLen = 0;
igorsk 0:b56b6a05cad4 522 DBG("Encoding is chunked, Content-Type is %s\n", m_respHeaders["Content-Type"].c_str() );
igorsk 0:b56b6a05cad4 523 }
igorsk 0:b56b6a05cad4 524 else
igorsk 0:b56b6a05cad4 525 {
igorsk 0:b56b6a05cad4 526 m_dataChunked = false;
igorsk 0:b56b6a05cad4 527 int len = 0;
igorsk 0:b56b6a05cad4 528 //DBG("Preparing read... len = %s\n", m_respHeaders["Content-Length"].c_str());
igorsk 0:b56b6a05cad4 529 sscanf(m_respHeaders["Content-Length"].c_str(), "%d", &len);
igorsk 0:b56b6a05cad4 530 m_pDataIn->setDataLen( len );
igorsk 0:b56b6a05cad4 531 m_dataPos = 0;
igorsk 0:b56b6a05cad4 532 m_dataLen = len;
igorsk 0:b56b6a05cad4 533 DBG("Content-Length is %d, Content-Type is %s\n", len, m_respHeaders["Content-Type"].c_str() );
igorsk 0:b56b6a05cad4 534 }
igorsk 0:b56b6a05cad4 535 m_pDataIn->setDataType( m_respHeaders["Content-Type"] );
igorsk 0:b56b6a05cad4 536 }
igorsk 0:b56b6a05cad4 537 case HTTP_READ_DATA:
igorsk 0:b56b6a05cad4 538 readData();
igorsk 0:b56b6a05cad4 539 break;
igorsk 0:b56b6a05cad4 540 case HTTP_READ_DATA_INCOMPLETE:
igorsk 0:b56b6a05cad4 541 break; //We need to handle previously received data first
igorsk 0:b56b6a05cad4 542 default:
igorsk 0:b56b6a05cad4 543 //Should not receive data now, req is not complete
igorsk 0:b56b6a05cad4 544 onResult(HTTP_PRTCL);
igorsk 0:b56b6a05cad4 545 }
igorsk 0:b56b6a05cad4 546 //All data has been read, close w/ success :)
igorsk 0:b56b6a05cad4 547 if( m_state == HTTP_DONE )
igorsk 0:b56b6a05cad4 548 {
igorsk 0:b56b6a05cad4 549 DBG("Done :)!\n");
igorsk 0:b56b6a05cad4 550 onResult(HTTP_OK);
igorsk 0:b56b6a05cad4 551 }
igorsk 0:b56b6a05cad4 552 break;
igorsk 0:b56b6a05cad4 553 case TCPSOCKET_CONNECTED:
igorsk 0:b56b6a05cad4 554 case TCPSOCKET_WRITEABLE: //We can send data
igorsk 0:b56b6a05cad4 555 resetTimeout();
igorsk 0:b56b6a05cad4 556 switch(m_state)
igorsk 0:b56b6a05cad4 557 {
igorsk 0:b56b6a05cad4 558 case HTTP_WRITE_HEADERS:
igorsk 0:b56b6a05cad4 559 //Update headers fields according to m_pDataOut
igorsk 0:b56b6a05cad4 560 if( m_pDataOut )
igorsk 0:b56b6a05cad4 561 {
igorsk 0:b56b6a05cad4 562 //Data is chunked?
igorsk 0:b56b6a05cad4 563 if(m_pDataOut->getIsChunked())
igorsk 0:b56b6a05cad4 564 {
igorsk 0:b56b6a05cad4 565 m_dataChunked = true;
igorsk 0:b56b6a05cad4 566 m_reqHeaders.erase("Content-Length");
igorsk 0:b56b6a05cad4 567 m_reqHeaders["Transfer-Encoding"] = "chunked";
igorsk 0:b56b6a05cad4 568 }
igorsk 0:b56b6a05cad4 569 else
igorsk 0:b56b6a05cad4 570 {
igorsk 0:b56b6a05cad4 571 m_dataChunked = false;
igorsk 0:b56b6a05cad4 572 char c_len[16] = "0";
igorsk 0:b56b6a05cad4 573 int len = m_pDataOut->getDataLen();
igorsk 0:b56b6a05cad4 574 sprintf(c_len, "%d", len);
igorsk 0:b56b6a05cad4 575 m_dataPos = 0;
igorsk 0:b56b6a05cad4 576 m_dataLen = len;
igorsk 0:b56b6a05cad4 577 m_reqHeaders.erase("Transfer-Encoding");
igorsk 0:b56b6a05cad4 578 m_reqHeaders["Content-Length"] = string(c_len);
igorsk 0:b56b6a05cad4 579 }
igorsk 0:b56b6a05cad4 580 string type = m_pDataOut->getDataType();
igorsk 0:b56b6a05cad4 581 if(!type.empty())
igorsk 0:b56b6a05cad4 582 {
igorsk 0:b56b6a05cad4 583 m_reqHeaders["Content-Type"] = type;
igorsk 0:b56b6a05cad4 584 }
igorsk 0:b56b6a05cad4 585 else
igorsk 0:b56b6a05cad4 586 {
igorsk 0:b56b6a05cad4 587 m_reqHeaders.erase("Content-Type");
igorsk 0:b56b6a05cad4 588 }
igorsk 0:b56b6a05cad4 589 }
igorsk 0:b56b6a05cad4 590 if( !writeHeaders() )
igorsk 0:b56b6a05cad4 591 {
igorsk 0:b56b6a05cad4 592 return; //Connection has been closed
igorsk 0:b56b6a05cad4 593 }
igorsk 0:b56b6a05cad4 594 break; //Wait for writeable event before sending payload
igorsk 0:b56b6a05cad4 595 case HTTP_WRITE_DATA:
igorsk 0:b56b6a05cad4 596 writeData();
igorsk 0:b56b6a05cad4 597 break;
igorsk 0:b56b6a05cad4 598 }
igorsk 0:b56b6a05cad4 599 //Otherwise request has been sent, now wait for resp
igorsk 0:b56b6a05cad4 600 break;
igorsk 0:b56b6a05cad4 601 case TCPSOCKET_CONTIMEOUT:
igorsk 0:b56b6a05cad4 602 case TCPSOCKET_CONRST:
igorsk 0:b56b6a05cad4 603 case TCPSOCKET_CONABRT:
igorsk 0:b56b6a05cad4 604 case TCPSOCKET_ERROR:
igorsk 0:b56b6a05cad4 605 DBG("Connection error.\n");
igorsk 0:b56b6a05cad4 606 onResult(HTTP_CONN);
igorsk 0:b56b6a05cad4 607 case TCPSOCKET_DISCONNECTED:
igorsk 0:b56b6a05cad4 608 //There might still be some data available for reading
igorsk 0:b56b6a05cad4 609 //So if we are in a reading state, do not close the socket yet
igorsk 0:b56b6a05cad4 610 if( (m_state != HTTP_READ_DATA_INCOMPLETE) && (m_state != HTTP_DONE) && (m_state != HTTP_CLOSED) )
igorsk 0:b56b6a05cad4 611 {
igorsk 0:b56b6a05cad4 612 onResult(HTTP_CONN);
igorsk 0:b56b6a05cad4 613 }
igorsk 0:b56b6a05cad4 614 DBG("Connection closed by remote host.\n");
igorsk 0:b56b6a05cad4 615 break;
igorsk 0:b56b6a05cad4 616 }
igorsk 0:b56b6a05cad4 617 }
igorsk 0:b56b6a05cad4 618
igorsk 0:b56b6a05cad4 619 void HTTPClient::onDNSReply(DNSReply r)
igorsk 0:b56b6a05cad4 620 {
igorsk 0:b56b6a05cad4 621 if(m_closed)
igorsk 0:b56b6a05cad4 622 {
igorsk 0:b56b6a05cad4 623 DBG("WARN: Discarded\n");
igorsk 0:b56b6a05cad4 624 return;
igorsk 0:b56b6a05cad4 625 }
igorsk 0:b56b6a05cad4 626
igorsk 0:b56b6a05cad4 627 if( r != DNS_FOUND )
igorsk 0:b56b6a05cad4 628 {
igorsk 0:b56b6a05cad4 629 DBG("Could not resolve hostname.\n");
igorsk 0:b56b6a05cad4 630 onResult(HTTP_DNS);
igorsk 0:b56b6a05cad4 631 return;
igorsk 0:b56b6a05cad4 632 }
igorsk 0:b56b6a05cad4 633
igorsk 0:b56b6a05cad4 634 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]);
igorsk 0:b56b6a05cad4 635 //If no error, m_server has been updated by m_pDnsReq so we're set to go !
igorsk 0:b56b6a05cad4 636 m_pDnsReq->close();
igorsk 0:b56b6a05cad4 637 delete m_pDnsReq;
igorsk 0:b56b6a05cad4 638 m_pDnsReq = NULL;
igorsk 0:b56b6a05cad4 639 connect();
igorsk 0:b56b6a05cad4 640 }
igorsk 0:b56b6a05cad4 641
igorsk 0:b56b6a05cad4 642 void HTTPClient::onResult(HTTPResult r) //Called when exchange completed or on failure
igorsk 0:b56b6a05cad4 643 {
igorsk 0:b56b6a05cad4 644 if(m_pCbItem && m_pCbMeth)
igorsk 0:b56b6a05cad4 645 (m_pCbItem->*m_pCbMeth)(r);
igorsk 0:b56b6a05cad4 646 else if(m_pCb)
igorsk 0:b56b6a05cad4 647 m_pCb(r);
igorsk 0:b56b6a05cad4 648 m_blockingResult = r; //Blocking mode
igorsk 0:b56b6a05cad4 649 close(); //FIXME:Remove suppl. close() calls
igorsk 0:b56b6a05cad4 650 }
igorsk 0:b56b6a05cad4 651
igorsk 0:b56b6a05cad4 652 void HTTPClient::onTimeout() //Connection has timed out
igorsk 0:b56b6a05cad4 653 {
igorsk 0:b56b6a05cad4 654 DBG("Timed out.\n");
igorsk 0:b56b6a05cad4 655 onResult(HTTP_TIMEOUT);
igorsk 0:b56b6a05cad4 656 close();
igorsk 0:b56b6a05cad4 657 }
igorsk 0:b56b6a05cad4 658
igorsk 0:b56b6a05cad4 659 //Headers
igorsk 0:b56b6a05cad4 660
igorsk 0:b56b6a05cad4 661 //TODO: Factorize w/ HTTPRequestHandler in a single HTTPHeader class
igorsk 0:b56b6a05cad4 662
igorsk 0:b56b6a05cad4 663 HTTPResult HTTPClient::blockingProcess() //Called in blocking mode, calls Net::poll() until return code is available
igorsk 0:b56b6a05cad4 664 {
igorsk 0:b56b6a05cad4 665 //Disable callbacks
igorsk 0:b56b6a05cad4 666 m_pCb = NULL;
igorsk 0:b56b6a05cad4 667 m_pCbItem = NULL;
igorsk 0:b56b6a05cad4 668 m_pCbMeth = NULL;
igorsk 0:b56b6a05cad4 669 m_blockingResult = HTTP_PROCESSING;
igorsk 0:b56b6a05cad4 670 do
igorsk 0:b56b6a05cad4 671 {
igorsk 0:b56b6a05cad4 672 Net::poll();
igorsk 0:b56b6a05cad4 673 } while(m_blockingResult == HTTP_PROCESSING);
igorsk 0:b56b6a05cad4 674 Net::poll(); //Necessary for cleanup
igorsk 0:b56b6a05cad4 675 return m_blockingResult;
igorsk 0:b56b6a05cad4 676 }
igorsk 0:b56b6a05cad4 677
igorsk 0:b56b6a05cad4 678 bool HTTPClient::readHeaders()
igorsk 0:b56b6a05cad4 679 {
igorsk 0:b56b6a05cad4 680 static char* line = m_buf;
igorsk 0:b56b6a05cad4 681 static char key[128];
igorsk 0:b56b6a05cad4 682 static char value[128];
igorsk 0:b56b6a05cad4 683 if(!m_dataLen) //No incomplete header in buffer, this is the first time we read data
igorsk 0:b56b6a05cad4 684 {
igorsk 0:b56b6a05cad4 685 if( readLine(line, 128) > 0 )
igorsk 0:b56b6a05cad4 686 {
igorsk 0:b56b6a05cad4 687 //Check RC
igorsk 0:b56b6a05cad4 688 m_httpResponseCode = 0;
igorsk 0:b56b6a05cad4 689 if( sscanf(line, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 )
igorsk 0:b56b6a05cad4 690 {
igorsk 0:b56b6a05cad4 691 //Cannot match string, error
igorsk 0:b56b6a05cad4 692 DBG("Not a correct HTTP answer : %s\n", line);
igorsk 0:b56b6a05cad4 693 onResult(HTTP_PRTCL);
igorsk 0:b56b6a05cad4 694 close();
igorsk 0:b56b6a05cad4 695 return false;
igorsk 0:b56b6a05cad4 696 }
igorsk 0:b56b6a05cad4 697
igorsk 0:b56b6a05cad4 698 if(m_httpResponseCode != 200)
igorsk 0:b56b6a05cad4 699 {
igorsk 0:b56b6a05cad4 700 DBG("Response: error code %d\n", m_httpResponseCode);
igorsk 0:b56b6a05cad4 701 HTTPResult res = HTTP_ERROR;
igorsk 0:b56b6a05cad4 702 switch(m_httpResponseCode)
igorsk 0:b56b6a05cad4 703 {
igorsk 0:b56b6a05cad4 704 case 404:
igorsk 0:b56b6a05cad4 705 res = HTTP_NOTFOUND;
igorsk 0:b56b6a05cad4 706 break;
igorsk 0:b56b6a05cad4 707 case 403:
igorsk 0:b56b6a05cad4 708 res = HTTP_REFUSED;
igorsk 0:b56b6a05cad4 709 break;
igorsk 0:b56b6a05cad4 710 default:
igorsk 0:b56b6a05cad4 711 res = HTTP_ERROR;
igorsk 0:b56b6a05cad4 712 }
igorsk 0:b56b6a05cad4 713 onResult(res);
igorsk 0:b56b6a05cad4 714 close();
igorsk 0:b56b6a05cad4 715 return false;
igorsk 0:b56b6a05cad4 716 }
igorsk 0:b56b6a05cad4 717 DBG("Response OK\n");
igorsk 0:b56b6a05cad4 718 }
igorsk 0:b56b6a05cad4 719 else
igorsk 0:b56b6a05cad4 720 {
igorsk 0:b56b6a05cad4 721 //Empty packet, weird!
igorsk 0:b56b6a05cad4 722 DBG("Empty packet!\n");
igorsk 0:b56b6a05cad4 723 onResult(HTTP_PRTCL);
igorsk 0:b56b6a05cad4 724 close();
igorsk 0:b56b6a05cad4 725 return false;
igorsk 0:b56b6a05cad4 726 }
igorsk 0:b56b6a05cad4 727 }
igorsk 0:b56b6a05cad4 728 bool incomplete = false;
igorsk 0:b56b6a05cad4 729 while( true )
igorsk 0:b56b6a05cad4 730 {
igorsk 0:b56b6a05cad4 731 int readLen = readLine(line + m_dataLen, 128 - m_dataLen, &incomplete);
igorsk 0:b56b6a05cad4 732 m_dataLen = 0;
igorsk 0:b56b6a05cad4 733 if( readLen <= 2 ) //if == 1 or 2, it is an empty line = end of headers
igorsk 0:b56b6a05cad4 734 {
igorsk 0:b56b6a05cad4 735 DBG("All headers read.\n");
igorsk 0:b56b6a05cad4 736 m_state = HTTP_READ_DATA;
igorsk 0:b56b6a05cad4 737 break;
igorsk 0:b56b6a05cad4 738 }
igorsk 0:b56b6a05cad4 739 else if( incomplete == true )
igorsk 0:b56b6a05cad4 740 {
igorsk 0:b56b6a05cad4 741 m_dataLen = readLen;//Sets data length available in buffer
igorsk 0:b56b6a05cad4 742 return false;
igorsk 0:b56b6a05cad4 743 }
igorsk 0:b56b6a05cad4 744 //DBG("Header : %s\n", line);
igorsk 0:b56b6a05cad4 745 int n = sscanf(line, "%[^:] : %[^\r\n]", key, value);
igorsk 0:b56b6a05cad4 746 if ( n == 2 )
igorsk 0:b56b6a05cad4 747 {
igorsk 0:b56b6a05cad4 748 DBG("Read header : %s: %s\n", key, value);
igorsk 0:b56b6a05cad4 749 m_respHeaders[key] = value;
igorsk 0:b56b6a05cad4 750 }
igorsk 0:b56b6a05cad4 751 //TODO: Impl n==1 case (part 2 of previous header)
igorsk 0:b56b6a05cad4 752 }
igorsk 0:b56b6a05cad4 753
igorsk 0:b56b6a05cad4 754 return true;
igorsk 0:b56b6a05cad4 755 }
igorsk 0:b56b6a05cad4 756
igorsk 0:b56b6a05cad4 757 bool HTTPClient::writeHeaders() //Called at the first writeData call
igorsk 0:b56b6a05cad4 758 {
igorsk 0:b56b6a05cad4 759 static char* line = m_buf;
igorsk 0:b56b6a05cad4 760 const char* HTTP_METH_STR[] = {"GET", "POST", "HEAD"};
igorsk 0:b56b6a05cad4 761
igorsk 0:b56b6a05cad4 762 //Req
igorsk 0:b56b6a05cad4 763 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
igorsk 0:b56b6a05cad4 764 m_pTCPSocket->send(line, strlen(line));
igorsk 0:b56b6a05cad4 765 DBG("Request: %s\n", line);
igorsk 0:b56b6a05cad4 766
igorsk 0:b56b6a05cad4 767 DBG("Writing headers:\n");
igorsk 0:b56b6a05cad4 768 map<string,string>::iterator it;
igorsk 0:b56b6a05cad4 769 for( it = m_reqHeaders.begin(); it != m_reqHeaders.end(); it++ )
igorsk 0:b56b6a05cad4 770 {
igorsk 0:b56b6a05cad4 771 sprintf(line, "%s: %s\r\n", (*it).first.c_str(), (*it).second.c_str() );
igorsk 0:b56b6a05cad4 772 DBG("\r\n%s", line);
igorsk 0:b56b6a05cad4 773 m_pTCPSocket->send(line, strlen(line));
igorsk 0:b56b6a05cad4 774 }
igorsk 0:b56b6a05cad4 775 m_pTCPSocket->send("\r\n",2); //End of head
igorsk 0:b56b6a05cad4 776 m_state = HTTP_WRITE_DATA;
igorsk 0:b56b6a05cad4 777 return true;
igorsk 0:b56b6a05cad4 778 }
igorsk 0:b56b6a05cad4 779
igorsk 0:b56b6a05cad4 780 int HTTPClient::readLine(char* str, int maxLen, bool* pIncomplete /* = NULL*/)
igorsk 0:b56b6a05cad4 781 {
igorsk 0:b56b6a05cad4 782 int ret;
igorsk 0:b56b6a05cad4 783 int len = 0;
igorsk 0:b56b6a05cad4 784 if(pIncomplete)
igorsk 0:b56b6a05cad4 785 *pIncomplete = false;
igorsk 0:b56b6a05cad4 786 for(int i = 0; i < maxLen - 1; i++)
igorsk 0:b56b6a05cad4 787 {
igorsk 0:b56b6a05cad4 788 ret = m_pTCPSocket->recv(str, 1);
igorsk 0:b56b6a05cad4 789 if(ret != 1)
igorsk 0:b56b6a05cad4 790 {
igorsk 0:b56b6a05cad4 791 if(pIncomplete)
igorsk 0:b56b6a05cad4 792 *pIncomplete = true;
igorsk 0:b56b6a05cad4 793 break;
igorsk 0:b56b6a05cad4 794 }
igorsk 0:b56b6a05cad4 795 if( (len > 1) && *(str-1)=='\r' && *str=='\n' )
igorsk 0:b56b6a05cad4 796 {
igorsk 0:b56b6a05cad4 797 break;
igorsk 0:b56b6a05cad4 798 }
igorsk 0:b56b6a05cad4 799 else if( *str=='\n' )
igorsk 0:b56b6a05cad4 800 {
igorsk 0:b56b6a05cad4 801 break;
igorsk 0:b56b6a05cad4 802 }
igorsk 0:b56b6a05cad4 803 str++;
igorsk 0:b56b6a05cad4 804 len++;
igorsk 0:b56b6a05cad4 805 }
igorsk 0:b56b6a05cad4 806 *str = 0;
igorsk 0:b56b6a05cad4 807 return len;
igorsk 0:b56b6a05cad4 808 }
igorsk 0:b56b6a05cad4 809
igorsk 0:b56b6a05cad4 810 void HTTPClient::setProxy(const char* proxy_url) // host:port
igorsk 0:b56b6a05cad4 811 {
igorsk 0:b56b6a05cad4 812 if ( proxy_url == NULL )
igorsk 0:b56b6a05cad4 813 {
igorsk 0:b56b6a05cad4 814 m_proxy = false;
igorsk 0:b56b6a05cad4 815 return;
igorsk 0:b56b6a05cad4 816 }
igorsk 0:b56b6a05cad4 817 Url url;
igorsk 0:b56b6a05cad4 818 url.fromString(proxy_url);
igorsk 0:b56b6a05cad4 819 m_server.setName(url.getHost().c_str());
igorsk 0:b56b6a05cad4 820
igorsk 0:b56b6a05cad4 821 if( url.getPort() > 0 )
igorsk 0:b56b6a05cad4 822 m_server.setPort( url.getPort() );
igorsk 0:b56b6a05cad4 823 else
igorsk 0:b56b6a05cad4 824 m_server.setPort( 8080 );
igorsk 0:b56b6a05cad4 825 DBG("Setting proxy server\r\nHost: %s\r\nPort: %d\r\n", url.getHost().c_str(), url.getPort());
igorsk 0:b56b6a05cad4 826 IpAddr ip;
igorsk 0:b56b6a05cad4 827 if( url.getHostIp(&ip) )
igorsk 0:b56b6a05cad4 828 {
igorsk 0:b56b6a05cad4 829 m_server.setIp(ip);
igorsk 0:b56b6a05cad4 830 }
igorsk 0:b56b6a05cad4 831 else
igorsk 0:b56b6a05cad4 832 {
igorsk 0:b56b6a05cad4 833 DBG("DNS Query...\n");
igorsk 0:b56b6a05cad4 834 m_pDnsReq = new DNSRequest();
igorsk 0:b56b6a05cad4 835 //m_pDnsReq->setOnReply(this, &HTTPClient::onDNSReply);
igorsk 0:b56b6a05cad4 836 m_pDnsReq->resolve(&m_server);
igorsk 0:b56b6a05cad4 837 DBG("HTTPClient : DNSRequest %p\n", m_pDnsReq);
igorsk 0:b56b6a05cad4 838 }
igorsk 0:b56b6a05cad4 839 m_proxy = true;
igorsk 0:b56b6a05cad4 840 }