Mac addr added ICRS

Dependencies:   mbed

Fork of Email2Screen by Oliver Mattos

Committer:
Hello1024
Date:
Mon Nov 21 18:25:34 2011 +0000
Revision:
0:1619a6b826d7

        

Who changed what in which revision?

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