Used in Live Traffic Update Nokia LCD Display Project

Fork of NetServices by Segundo Equipo

Committer:
rrajan8
Date:
Wed Mar 06 19:07:23 2013 +0000
Revision:
8:92b57208ab99
Parent:
0:ac1725ba162c
This project utilizes mbed's networking features to display live traffic updates on the Nokia LCD using the MapQuest API's Traffic Web Service.

Who changed what in which revision?

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