Netservices modded to read fragmented HTTP respsonse/payload from special purpose server - 180 bytes only

Committer:
RodColeman
Date:
Thu Sep 08 10:41:36 2011 +0000
Revision:
0:8f5825f330b0
setDataLen hacked to 180bytes

Who changed what in which revision?

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