HTTP Client with hardcoded authorization for supertweet proxy server.

Dependents:   twitterCoffeeMakerFinal iCoffee

Fork of HTTPClientAuthAndPathExtension by Joseph Lind

Committer:
tlisowski3
Date:
Wed Apr 23 18:37:32 2014 +0000
Revision:
18:da79dd7e9df2
Parent:
17:951bf897ba01
HTTP Client with authorization hardcoded in

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jlind6 17:951bf897ba01 1 /* HTTPClient.cpp */
jlind6 17:951bf897ba01 2 /* Copyright (C) 2012 mbed.org, MIT License
jlind6 17:951bf897ba01 3 *
jlind6 17:951bf897ba01 4 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
jlind6 17:951bf897ba01 5 * and associated documentation files (the "Software"), to deal in the Software without restriction,
jlind6 17:951bf897ba01 6 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
jlind6 17:951bf897ba01 7 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
jlind6 17:951bf897ba01 8 * furnished to do so, subject to the following conditions:
jlind6 17:951bf897ba01 9 *
jlind6 17:951bf897ba01 10 * The above copyright notice and this permission notice shall be included in all copies or
jlind6 17:951bf897ba01 11 * substantial portions of the Software.
jlind6 17:951bf897ba01 12 *
jlind6 17:951bf897ba01 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
jlind6 17:951bf897ba01 14 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
jlind6 17:951bf897ba01 15 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
jlind6 17:951bf897ba01 16 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
jlind6 17:951bf897ba01 17 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
jlind6 17:951bf897ba01 18 */
jlind6 17:951bf897ba01 19
jlind6 17:951bf897ba01 20 //Debug is disabled by default
jlind6 17:951bf897ba01 21 #if 0
jlind6 17:951bf897ba01 22 //Enable debug
jlind6 17:951bf897ba01 23 #include <cstdio>
jlind6 17:951bf897ba01 24 #define DBG(x, ...) std::printf("[HTTPClient : DBG]"x"\r\n", ##__VA_ARGS__);
jlind6 17:951bf897ba01 25 #define WARN(x, ...) std::printf("[HTTPClient : WARN]"x"\r\n", ##__VA_ARGS__);
jlind6 17:951bf897ba01 26 #define ERR(x, ...) std::printf("[HTTPClient : ERR]"x"\r\n", ##__VA_ARGS__);
jlind6 17:951bf897ba01 27
jlind6 17:951bf897ba01 28 #else
jlind6 17:951bf897ba01 29 //Disable debug
jlind6 17:951bf897ba01 30 #define DBG(x, ...)
jlind6 17:951bf897ba01 31 #define WARN(x, ...)
jlind6 17:951bf897ba01 32 #define ERR(x, ...)
jlind6 17:951bf897ba01 33
jlind6 17:951bf897ba01 34 #endif
jlind6 17:951bf897ba01 35
jlind6 17:951bf897ba01 36 #define HTTP_PORT 80
jlind6 17:951bf897ba01 37
jlind6 17:951bf897ba01 38 #define OK 0
jlind6 17:951bf897ba01 39
jlind6 17:951bf897ba01 40 #define MIN(x,y) (((x)<(y))?(x):(y))
jlind6 17:951bf897ba01 41 #define MAX(x,y) (((x)>(y))?(x):(y))
jlind6 17:951bf897ba01 42
jlind6 17:951bf897ba01 43 #define CHUNK_SIZE 256
jlind6 17:951bf897ba01 44
jlind6 17:951bf897ba01 45 #include <cstring>
jlind6 17:951bf897ba01 46
jlind6 17:951bf897ba01 47 #include "HTTPClient.h"
jlind6 17:951bf897ba01 48
jlind6 17:951bf897ba01 49 HTTPClient::HTTPClient() :
jlind6 17:951bf897ba01 50 m_sock(), m_basicAuthUser(NULL), m_basicAuthPassword(NULL), m_httpResponseCode(0)
jlind6 17:951bf897ba01 51 {
jlind6 17:951bf897ba01 52
jlind6 17:951bf897ba01 53 }
jlind6 17:951bf897ba01 54
jlind6 17:951bf897ba01 55 HTTPClient::~HTTPClient()
jlind6 17:951bf897ba01 56 {
jlind6 17:951bf897ba01 57
jlind6 17:951bf897ba01 58 }
jlind6 17:951bf897ba01 59
jlind6 17:951bf897ba01 60 #if 0
jlind6 17:951bf897ba01 61 void HTTPClient::basicAuth(const char* user, const char* password) //Basic Authentification
jlind6 17:951bf897ba01 62 {
jlind6 17:951bf897ba01 63 m_basicAuthUser = user;
jlind6 17:951bf897ba01 64 m_basicAuthPassword = password;
jlind6 17:951bf897ba01 65 }
jlind6 17:951bf897ba01 66 #endif
jlind6 17:951bf897ba01 67
jlind6 17:951bf897ba01 68 HTTPResult HTTPClient::get(const char* url, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
jlind6 17:951bf897ba01 69 {
jlind6 17:951bf897ba01 70 return connect(url, HTTP_GET, NULL, pDataIn, timeout);
jlind6 17:951bf897ba01 71 }
jlind6 17:951bf897ba01 72
jlind6 17:951bf897ba01 73 HTTPResult HTTPClient::get(const char* url, char* result, size_t maxResultLen, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
jlind6 17:951bf897ba01 74 {
jlind6 17:951bf897ba01 75 HTTPText str(result, maxResultLen);
jlind6 17:951bf897ba01 76 return get(url, &str, timeout);
jlind6 17:951bf897ba01 77 }
jlind6 17:951bf897ba01 78
jlind6 17:951bf897ba01 79 HTTPResult HTTPClient::post(const char* url, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
jlind6 17:951bf897ba01 80 {
jlind6 17:951bf897ba01 81 return connect(url, HTTP_POST, (IHTTPDataOut*)&dataOut, pDataIn, timeout);
jlind6 17:951bf897ba01 82 }
jlind6 17:951bf897ba01 83
jlind6 17:951bf897ba01 84 HTTPResult HTTPClient::put(const char* url, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
jlind6 17:951bf897ba01 85 {
jlind6 17:951bf897ba01 86 return connect(url, HTTP_PUT, (IHTTPDataOut*)&dataOut, pDataIn, timeout);
jlind6 17:951bf897ba01 87 }
jlind6 17:951bf897ba01 88
jlind6 17:951bf897ba01 89 HTTPResult HTTPClient::del(const char* url, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
jlind6 17:951bf897ba01 90 {
jlind6 17:951bf897ba01 91 return connect(url, HTTP_DELETE, NULL, pDataIn, timeout);
jlind6 17:951bf897ba01 92 }
jlind6 17:951bf897ba01 93
jlind6 17:951bf897ba01 94
jlind6 17:951bf897ba01 95 int HTTPClient::getHTTPResponseCode()
jlind6 17:951bf897ba01 96 {
jlind6 17:951bf897ba01 97 return m_httpResponseCode;
jlind6 17:951bf897ba01 98 }
jlind6 17:951bf897ba01 99
jlind6 17:951bf897ba01 100 #define CHECK_CONN_ERR(ret) \
jlind6 17:951bf897ba01 101 do{ \
jlind6 17:951bf897ba01 102 if(ret) { \
jlind6 17:951bf897ba01 103 m_sock.close(); \
jlind6 17:951bf897ba01 104 ERR("Connection error (%d)", ret); \
jlind6 17:951bf897ba01 105 return HTTP_CONN; \
jlind6 17:951bf897ba01 106 } \
jlind6 17:951bf897ba01 107 } while(0)
jlind6 17:951bf897ba01 108
jlind6 17:951bf897ba01 109 #define PRTCL_ERR() \
jlind6 17:951bf897ba01 110 do{ \
jlind6 17:951bf897ba01 111 m_sock.close(); \
jlind6 17:951bf897ba01 112 ERR("Protocol error"); \
jlind6 17:951bf897ba01 113 return HTTP_PRTCL; \
jlind6 17:951bf897ba01 114 } while(0)
jlind6 17:951bf897ba01 115
jlind6 17:951bf897ba01 116 HTTPResult HTTPClient::connect(const char* url, HTTP_METH method, IHTTPDataOut* pDataOut, IHTTPDataIn* pDataIn, int timeout) //Execute request
jlind6 17:951bf897ba01 117 {
jlind6 17:951bf897ba01 118 m_httpResponseCode = 0; //Invalidate code
jlind6 17:951bf897ba01 119 m_timeout = timeout;
jlind6 17:951bf897ba01 120
jlind6 17:951bf897ba01 121 pDataIn->writeReset();
jlind6 17:951bf897ba01 122 if( pDataOut )
jlind6 17:951bf897ba01 123 {
jlind6 17:951bf897ba01 124 pDataOut->readReset();
jlind6 17:951bf897ba01 125 }
jlind6 17:951bf897ba01 126
jlind6 17:951bf897ba01 127 char scheme[8];
jlind6 17:951bf897ba01 128 uint16_t port;
jlind6 17:951bf897ba01 129 char host[32];
jlind6 17:951bf897ba01 130 char path[128];
jlind6 17:951bf897ba01 131 //First we need to parse the url (http[s]://host[:port][/[path]]) -- HTTPS not supported (yet?)
jlind6 17:951bf897ba01 132 HTTPResult res = parseURL(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path));
jlind6 17:951bf897ba01 133 if(res != HTTP_OK)
jlind6 17:951bf897ba01 134 {
jlind6 17:951bf897ba01 135 ERR("parseURL returned %d", res);
jlind6 17:951bf897ba01 136 return res;
jlind6 17:951bf897ba01 137 }
jlind6 17:951bf897ba01 138
jlind6 17:951bf897ba01 139 if(port == 0) //TODO do handle HTTPS->443
jlind6 17:951bf897ba01 140 {
jlind6 17:951bf897ba01 141 port = 80;
jlind6 17:951bf897ba01 142 }
jlind6 17:951bf897ba01 143
jlind6 17:951bf897ba01 144 DBG("Scheme: %s", scheme);
jlind6 17:951bf897ba01 145 DBG("Host: %s", host);
jlind6 17:951bf897ba01 146 DBG("Port: %d", port);
jlind6 17:951bf897ba01 147 DBG("Path: %s", path);
jlind6 17:951bf897ba01 148
jlind6 17:951bf897ba01 149 //Connect
jlind6 17:951bf897ba01 150 DBG("Connecting socket to server");
jlind6 17:951bf897ba01 151 int ret = m_sock.connect(host, port);
jlind6 17:951bf897ba01 152 if (ret < 0)
jlind6 17:951bf897ba01 153 {
jlind6 17:951bf897ba01 154 m_sock.close();
jlind6 17:951bf897ba01 155 ERR("Could not connect");
jlind6 17:951bf897ba01 156 return HTTP_CONN;
jlind6 17:951bf897ba01 157 }
jlind6 17:951bf897ba01 158
jlind6 17:951bf897ba01 159 //Send request
jlind6 17:951bf897ba01 160 DBG("Sending request");
jlind6 17:951bf897ba01 161 char buf[CHUNK_SIZE];
jlind6 17:951bf897ba01 162 const char* meth = (method==HTTP_GET)?"GET":(method==HTTP_POST)?"POST":(method==HTTP_PUT)?"PUT":(method==HTTP_DELETE)?"DELETE":"";
jlind6 17:951bf897ba01 163 snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\n", meth, path, host); //Write request
jlind6 17:951bf897ba01 164 printf("%s\n", buf);
jlind6 17:951bf897ba01 165 ret = send(buf);
jlind6 17:951bf897ba01 166 if(ret)
jlind6 17:951bf897ba01 167 {
jlind6 17:951bf897ba01 168 m_sock.close();
jlind6 17:951bf897ba01 169 ERR("Could not write request");
jlind6 17:951bf897ba01 170 return HTTP_CONN;
jlind6 17:951bf897ba01 171 }
jlind6 17:951bf897ba01 172
jlind6 17:951bf897ba01 173 //Send all headers
jlind6 17:951bf897ba01 174
tlisowski3 18:da79dd7e9df2 175 //Authorization header
tlisowski3 18:da79dd7e9df2 176 snprintf(buf, sizeof(buf), "Authorization: Basic dGxpc293c2tpMzptYXJrZXI=\r\n");
jlind6 17:951bf897ba01 177 ret = send(buf);
jlind6 17:951bf897ba01 178 CHECK_CONN_ERR(ret);
jlind6 17:951bf897ba01 179
jlind6 17:951bf897ba01 180 //Send default headers
jlind6 17:951bf897ba01 181 DBG("Sending headers");
jlind6 17:951bf897ba01 182 if( pDataOut != NULL )
jlind6 17:951bf897ba01 183 {
jlind6 17:951bf897ba01 184 if( pDataOut->getIsChunked() )
jlind6 17:951bf897ba01 185 {
jlind6 17:951bf897ba01 186 ret = send("Transfer-Encoding: chunked\r\n");
jlind6 17:951bf897ba01 187 CHECK_CONN_ERR(ret);
jlind6 17:951bf897ba01 188 }
jlind6 17:951bf897ba01 189 else
jlind6 17:951bf897ba01 190 {
jlind6 17:951bf897ba01 191 snprintf(buf, sizeof(buf), "Content-Length: %d\r\n", pDataOut->getDataLen());
jlind6 17:951bf897ba01 192 ret = send(buf);
jlind6 17:951bf897ba01 193 CHECK_CONN_ERR(ret);
jlind6 17:951bf897ba01 194 }
jlind6 17:951bf897ba01 195 char type[48];
jlind6 17:951bf897ba01 196 if( pDataOut->getDataType(type, 48) == HTTP_OK )
jlind6 17:951bf897ba01 197 {
jlind6 17:951bf897ba01 198 snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", type);
jlind6 17:951bf897ba01 199 ret = send(buf);
jlind6 17:951bf897ba01 200 CHECK_CONN_ERR(ret);
jlind6 17:951bf897ba01 201 }
jlind6 17:951bf897ba01 202 }
jlind6 17:951bf897ba01 203
jlind6 17:951bf897ba01 204
jlind6 17:951bf897ba01 205 //Close headers
jlind6 17:951bf897ba01 206 DBG("Headers sent");
jlind6 17:951bf897ba01 207 ret = send("\r\n");
jlind6 17:951bf897ba01 208 CHECK_CONN_ERR(ret);
jlind6 17:951bf897ba01 209
jlind6 17:951bf897ba01 210 size_t trfLen;
jlind6 17:951bf897ba01 211
jlind6 17:951bf897ba01 212 //Send data (if available)
jlind6 17:951bf897ba01 213 if( pDataOut != NULL )
jlind6 17:951bf897ba01 214 {
jlind6 17:951bf897ba01 215 DBG("Sending data");
jlind6 17:951bf897ba01 216 while(true)
jlind6 17:951bf897ba01 217 {
jlind6 17:951bf897ba01 218 size_t writtenLen = 0;
jlind6 17:951bf897ba01 219 pDataOut->read(buf, CHUNK_SIZE, &trfLen);
jlind6 17:951bf897ba01 220 if( pDataOut->getIsChunked() )
jlind6 17:951bf897ba01 221 {
jlind6 17:951bf897ba01 222 //Write chunk header
jlind6 17:951bf897ba01 223 char chunkHeader[16];
jlind6 17:951bf897ba01 224 snprintf(chunkHeader, sizeof(chunkHeader), "%X\r\n", trfLen); //In hex encoding
jlind6 17:951bf897ba01 225 ret = send(chunkHeader);
jlind6 17:951bf897ba01 226 CHECK_CONN_ERR(ret);
jlind6 17:951bf897ba01 227 }
jlind6 17:951bf897ba01 228 else if( trfLen == 0 )
jlind6 17:951bf897ba01 229 {
jlind6 17:951bf897ba01 230 break;
jlind6 17:951bf897ba01 231 }
jlind6 17:951bf897ba01 232 if( trfLen != 0 )
jlind6 17:951bf897ba01 233 {
jlind6 17:951bf897ba01 234 ret = send(buf, trfLen);
jlind6 17:951bf897ba01 235 CHECK_CONN_ERR(ret);
jlind6 17:951bf897ba01 236 }
jlind6 17:951bf897ba01 237
jlind6 17:951bf897ba01 238 if( pDataOut->getIsChunked() )
jlind6 17:951bf897ba01 239 {
jlind6 17:951bf897ba01 240 ret = send("\r\n"); //Chunk-terminating CRLF
jlind6 17:951bf897ba01 241 CHECK_CONN_ERR(ret);
jlind6 17:951bf897ba01 242 }
jlind6 17:951bf897ba01 243 else
jlind6 17:951bf897ba01 244 {
jlind6 17:951bf897ba01 245 writtenLen += trfLen;
jlind6 17:951bf897ba01 246 if( writtenLen >= pDataOut->getDataLen() )
jlind6 17:951bf897ba01 247 {
jlind6 17:951bf897ba01 248 break;
jlind6 17:951bf897ba01 249 }
jlind6 17:951bf897ba01 250 }
jlind6 17:951bf897ba01 251
jlind6 17:951bf897ba01 252 if( trfLen == 0 )
jlind6 17:951bf897ba01 253 {
jlind6 17:951bf897ba01 254 break;
jlind6 17:951bf897ba01 255 }
jlind6 17:951bf897ba01 256 }
jlind6 17:951bf897ba01 257
jlind6 17:951bf897ba01 258 }
jlind6 17:951bf897ba01 259
jlind6 17:951bf897ba01 260 //Receive response
jlind6 17:951bf897ba01 261 DBG("Receiving response");
jlind6 17:951bf897ba01 262 ret = recv(buf, CHUNK_SIZE - 1, CHUNK_SIZE - 1, &trfLen); //Read n bytes
jlind6 17:951bf897ba01 263 CHECK_CONN_ERR(ret);
jlind6 17:951bf897ba01 264
jlind6 17:951bf897ba01 265 buf[trfLen] = '\0';
jlind6 17:951bf897ba01 266
jlind6 17:951bf897ba01 267 char* crlfPtr = strstr(buf, "\r\n");
jlind6 17:951bf897ba01 268 if(crlfPtr == NULL)
jlind6 17:951bf897ba01 269 {
jlind6 17:951bf897ba01 270 PRTCL_ERR();
jlind6 17:951bf897ba01 271 }
jlind6 17:951bf897ba01 272
jlind6 17:951bf897ba01 273 int crlfPos = crlfPtr - buf;
jlind6 17:951bf897ba01 274 buf[crlfPos] = '\0';
jlind6 17:951bf897ba01 275
jlind6 17:951bf897ba01 276 //Parse HTTP response
jlind6 17:951bf897ba01 277 if( sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 )
jlind6 17:951bf897ba01 278 {
jlind6 17:951bf897ba01 279 //Cannot match string, error
jlind6 17:951bf897ba01 280 ERR("Not a correct HTTP answer : %s\n", buf);
jlind6 17:951bf897ba01 281 PRTCL_ERR();
jlind6 17:951bf897ba01 282 }
jlind6 17:951bf897ba01 283
jlind6 17:951bf897ba01 284 if( (m_httpResponseCode < 200) || (m_httpResponseCode >= 300) )
jlind6 17:951bf897ba01 285 {
jlind6 17:951bf897ba01 286 //Did not return a 2xx code; TODO fetch headers/(&data?) anyway and implement a mean of writing/reading headers
jlind6 17:951bf897ba01 287 WARN("Response code %d", m_httpResponseCode);
jlind6 17:951bf897ba01 288 PRTCL_ERR();
jlind6 17:951bf897ba01 289 }
jlind6 17:951bf897ba01 290
jlind6 17:951bf897ba01 291 DBG("Reading headers");
jlind6 17:951bf897ba01 292
jlind6 17:951bf897ba01 293 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well
jlind6 17:951bf897ba01 294 trfLen -= (crlfPos + 2);
jlind6 17:951bf897ba01 295
jlind6 17:951bf897ba01 296 size_t recvContentLength = 0;
jlind6 17:951bf897ba01 297 bool recvChunked = false;
jlind6 17:951bf897ba01 298 //Now get headers
jlind6 17:951bf897ba01 299 while( true )
jlind6 17:951bf897ba01 300 {
jlind6 17:951bf897ba01 301 crlfPtr = strstr(buf, "\r\n");
jlind6 17:951bf897ba01 302 if(crlfPtr == NULL)
jlind6 17:951bf897ba01 303 {
jlind6 17:951bf897ba01 304 if( trfLen < CHUNK_SIZE - 1 )
jlind6 17:951bf897ba01 305 {
jlind6 17:951bf897ba01 306 size_t newTrfLen;
jlind6 17:951bf897ba01 307 ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen);
jlind6 17:951bf897ba01 308 trfLen += newTrfLen;
jlind6 17:951bf897ba01 309 buf[trfLen] = '\0';
jlind6 17:951bf897ba01 310 DBG("Read %d chars; In buf: [%s]", newTrfLen, buf);
jlind6 17:951bf897ba01 311 CHECK_CONN_ERR(ret);
jlind6 17:951bf897ba01 312 continue;
jlind6 17:951bf897ba01 313 }
jlind6 17:951bf897ba01 314 else
jlind6 17:951bf897ba01 315 {
jlind6 17:951bf897ba01 316 PRTCL_ERR();
jlind6 17:951bf897ba01 317 }
jlind6 17:951bf897ba01 318 }
jlind6 17:951bf897ba01 319
jlind6 17:951bf897ba01 320 crlfPos = crlfPtr - buf;
jlind6 17:951bf897ba01 321
jlind6 17:951bf897ba01 322 if(crlfPos == 0) //End of headers
jlind6 17:951bf897ba01 323 {
jlind6 17:951bf897ba01 324 DBG("Headers read");
jlind6 17:951bf897ba01 325 memmove(buf, &buf[2], trfLen - 2 + 1); //Be sure to move NULL-terminating char as well
jlind6 17:951bf897ba01 326 trfLen -= 2;
jlind6 17:951bf897ba01 327 break;
jlind6 17:951bf897ba01 328 }
jlind6 17:951bf897ba01 329
jlind6 17:951bf897ba01 330 buf[crlfPos] = '\0';
jlind6 17:951bf897ba01 331
jlind6 17:951bf897ba01 332 char key[32];
jlind6 17:951bf897ba01 333 char value[32];
jlind6 17:951bf897ba01 334
jlind6 17:951bf897ba01 335 key[31] = '\0';
jlind6 17:951bf897ba01 336 value[31] = '\0';
jlind6 17:951bf897ba01 337
jlind6 17:951bf897ba01 338 int n = sscanf(buf, "%31[^:]: %31[^\r\n]", key, value);
jlind6 17:951bf897ba01 339 if ( n == 2 )
jlind6 17:951bf897ba01 340 {
jlind6 17:951bf897ba01 341 DBG("Read header : %s: %s\n", key, value);
jlind6 17:951bf897ba01 342 if( !strcmp(key, "Content-Length") )
jlind6 17:951bf897ba01 343 {
jlind6 17:951bf897ba01 344 sscanf(value, "%d", &recvContentLength);
jlind6 17:951bf897ba01 345 pDataIn->setDataLen(recvContentLength);
jlind6 17:951bf897ba01 346 }
jlind6 17:951bf897ba01 347 else if( !strcmp(key, "Transfer-Encoding") )
jlind6 17:951bf897ba01 348 {
jlind6 17:951bf897ba01 349 if( !strcmp(value, "Chunked") || !strcmp(value, "chunked") )
jlind6 17:951bf897ba01 350 {
jlind6 17:951bf897ba01 351 recvChunked = true;
jlind6 17:951bf897ba01 352 pDataIn->setIsChunked(true);
jlind6 17:951bf897ba01 353 }
jlind6 17:951bf897ba01 354 }
jlind6 17:951bf897ba01 355 else if( !strcmp(key, "Content-Type") )
jlind6 17:951bf897ba01 356 {
jlind6 17:951bf897ba01 357 pDataIn->setDataType(value);
jlind6 17:951bf897ba01 358 }
jlind6 17:951bf897ba01 359
jlind6 17:951bf897ba01 360 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well
jlind6 17:951bf897ba01 361 trfLen -= (crlfPos + 2);
jlind6 17:951bf897ba01 362
jlind6 17:951bf897ba01 363 }
jlind6 17:951bf897ba01 364 else
jlind6 17:951bf897ba01 365 {
jlind6 17:951bf897ba01 366 ERR("Could not parse header");
jlind6 17:951bf897ba01 367 PRTCL_ERR();
jlind6 17:951bf897ba01 368 }
jlind6 17:951bf897ba01 369
jlind6 17:951bf897ba01 370 }
jlind6 17:951bf897ba01 371
jlind6 17:951bf897ba01 372 //Receive data
jlind6 17:951bf897ba01 373 DBG("Receiving data");
jlind6 17:951bf897ba01 374 while(true)
jlind6 17:951bf897ba01 375 {
jlind6 17:951bf897ba01 376 size_t readLen = 0;
jlind6 17:951bf897ba01 377
jlind6 17:951bf897ba01 378 if( recvChunked )
jlind6 17:951bf897ba01 379 {
jlind6 17:951bf897ba01 380 //Read chunk header
jlind6 17:951bf897ba01 381 bool foundCrlf;
jlind6 17:951bf897ba01 382 do
jlind6 17:951bf897ba01 383 {
jlind6 17:951bf897ba01 384 foundCrlf = false;
jlind6 17:951bf897ba01 385 crlfPos=0;
jlind6 17:951bf897ba01 386 buf[trfLen]=0;
jlind6 17:951bf897ba01 387 if(trfLen >= 2)
jlind6 17:951bf897ba01 388 {
jlind6 17:951bf897ba01 389 for(; crlfPos < trfLen - 2; crlfPos++)
jlind6 17:951bf897ba01 390 {
jlind6 17:951bf897ba01 391 if( buf[crlfPos] == '\r' && buf[crlfPos + 1] == '\n' )
jlind6 17:951bf897ba01 392 {
jlind6 17:951bf897ba01 393 foundCrlf = true;
jlind6 17:951bf897ba01 394 break;
jlind6 17:951bf897ba01 395 }
jlind6 17:951bf897ba01 396 }
jlind6 17:951bf897ba01 397 }
jlind6 17:951bf897ba01 398 if(!foundCrlf) //Try to read more
jlind6 17:951bf897ba01 399 {
jlind6 17:951bf897ba01 400 if( trfLen < CHUNK_SIZE )
jlind6 17:951bf897ba01 401 {
jlind6 17:951bf897ba01 402 size_t newTrfLen;
jlind6 17:951bf897ba01 403 ret = recv(buf + trfLen, 0, CHUNK_SIZE - trfLen - 1, &newTrfLen);
jlind6 17:951bf897ba01 404 trfLen += newTrfLen;
jlind6 17:951bf897ba01 405 CHECK_CONN_ERR(ret);
jlind6 17:951bf897ba01 406 continue;
jlind6 17:951bf897ba01 407 }
jlind6 17:951bf897ba01 408 else
jlind6 17:951bf897ba01 409 {
jlind6 17:951bf897ba01 410 PRTCL_ERR();
jlind6 17:951bf897ba01 411 }
jlind6 17:951bf897ba01 412 }
jlind6 17:951bf897ba01 413 } while(!foundCrlf);
jlind6 17:951bf897ba01 414 buf[crlfPos] = '\0';
jlind6 17:951bf897ba01 415 int n = sscanf(buf, "%x", &readLen);
jlind6 17:951bf897ba01 416 if(n!=1)
jlind6 17:951bf897ba01 417 {
jlind6 17:951bf897ba01 418 ERR("Could not read chunk length");
jlind6 17:951bf897ba01 419 PRTCL_ERR();
jlind6 17:951bf897ba01 420 }
jlind6 17:951bf897ba01 421
jlind6 17:951bf897ba01 422 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2)); //Not need to move NULL-terminating char any more
jlind6 17:951bf897ba01 423 trfLen -= (crlfPos + 2);
jlind6 17:951bf897ba01 424
jlind6 17:951bf897ba01 425 if( readLen == 0 )
jlind6 17:951bf897ba01 426 {
jlind6 17:951bf897ba01 427 //Last chunk
jlind6 17:951bf897ba01 428 break;
jlind6 17:951bf897ba01 429 }
jlind6 17:951bf897ba01 430 }
jlind6 17:951bf897ba01 431 else
jlind6 17:951bf897ba01 432 {
jlind6 17:951bf897ba01 433 readLen = recvContentLength;
jlind6 17:951bf897ba01 434 }
jlind6 17:951bf897ba01 435
jlind6 17:951bf897ba01 436 DBG("Retrieving %d bytes", readLen);
jlind6 17:951bf897ba01 437
jlind6 17:951bf897ba01 438 do
jlind6 17:951bf897ba01 439 {
jlind6 17:951bf897ba01 440 pDataIn->write(buf, MIN(trfLen, readLen));
jlind6 17:951bf897ba01 441 if( trfLen > readLen )
jlind6 17:951bf897ba01 442 {
jlind6 17:951bf897ba01 443 memmove(buf, &buf[readLen], trfLen - readLen);
jlind6 17:951bf897ba01 444 trfLen -= readLen;
jlind6 17:951bf897ba01 445 readLen = 0;
jlind6 17:951bf897ba01 446 }
jlind6 17:951bf897ba01 447 else
jlind6 17:951bf897ba01 448 {
jlind6 17:951bf897ba01 449 readLen -= trfLen;
jlind6 17:951bf897ba01 450 }
jlind6 17:951bf897ba01 451
jlind6 17:951bf897ba01 452 if(readLen)
jlind6 17:951bf897ba01 453 {
jlind6 17:951bf897ba01 454 ret = recv(buf, 1, CHUNK_SIZE - trfLen - 1, &trfLen);
jlind6 17:951bf897ba01 455 CHECK_CONN_ERR(ret);
jlind6 17:951bf897ba01 456 }
jlind6 17:951bf897ba01 457 } while(readLen);
jlind6 17:951bf897ba01 458
jlind6 17:951bf897ba01 459 if( recvChunked )
jlind6 17:951bf897ba01 460 {
jlind6 17:951bf897ba01 461 if(trfLen < 2)
jlind6 17:951bf897ba01 462 {
jlind6 17:951bf897ba01 463 size_t newTrfLen;
jlind6 17:951bf897ba01 464 //Read missing chars to find end of chunk
jlind6 17:951bf897ba01 465 ret = recv(buf + trfLen, 2 - trfLen, CHUNK_SIZE - trfLen - 1, &newTrfLen);
jlind6 17:951bf897ba01 466 CHECK_CONN_ERR(ret);
jlind6 17:951bf897ba01 467 trfLen += newTrfLen;
jlind6 17:951bf897ba01 468 }
jlind6 17:951bf897ba01 469 if( (buf[0] != '\r') || (buf[1] != '\n') )
jlind6 17:951bf897ba01 470 {
jlind6 17:951bf897ba01 471 ERR("Format error");
jlind6 17:951bf897ba01 472 PRTCL_ERR();
jlind6 17:951bf897ba01 473 }
jlind6 17:951bf897ba01 474 memmove(buf, &buf[2], trfLen - 2);
jlind6 17:951bf897ba01 475 trfLen -= 2;
jlind6 17:951bf897ba01 476 }
jlind6 17:951bf897ba01 477 else
jlind6 17:951bf897ba01 478 {
jlind6 17:951bf897ba01 479 break;
jlind6 17:951bf897ba01 480 }
jlind6 17:951bf897ba01 481
jlind6 17:951bf897ba01 482 }
jlind6 17:951bf897ba01 483
jlind6 17:951bf897ba01 484 m_sock.close();
jlind6 17:951bf897ba01 485 DBG("Completed HTTP transaction");
jlind6 17:951bf897ba01 486
jlind6 17:951bf897ba01 487 return HTTP_OK;
jlind6 17:951bf897ba01 488 }
jlind6 17:951bf897ba01 489
jlind6 17:951bf897ba01 490 HTTPResult HTTPClient::recv(char* buf, size_t minLen, size_t maxLen, size_t* pReadLen) //0 on success, err code on failure
jlind6 17:951bf897ba01 491 {
jlind6 17:951bf897ba01 492 DBG("Trying to read between %d and %d bytes", minLen, maxLen);
jlind6 17:951bf897ba01 493 size_t readLen = 0;
jlind6 17:951bf897ba01 494
jlind6 17:951bf897ba01 495 if(!m_sock.is_connected())
jlind6 17:951bf897ba01 496 {
jlind6 17:951bf897ba01 497 WARN("Connection was closed by server");
jlind6 17:951bf897ba01 498 return HTTP_CLOSED; //Connection was closed by server
jlind6 17:951bf897ba01 499 }
jlind6 17:951bf897ba01 500
jlind6 17:951bf897ba01 501 int ret;
jlind6 17:951bf897ba01 502 while(readLen < maxLen)
jlind6 17:951bf897ba01 503 {
jlind6 17:951bf897ba01 504 if(readLen < minLen)
jlind6 17:951bf897ba01 505 {
jlind6 17:951bf897ba01 506 DBG("Trying to read at most %d bytes [Blocking]", minLen - readLen);
jlind6 17:951bf897ba01 507 m_sock.set_blocking(false, m_timeout);
jlind6 17:951bf897ba01 508 ret = m_sock.receive_all(buf + readLen, minLen - readLen);
jlind6 17:951bf897ba01 509 }
jlind6 17:951bf897ba01 510 else
jlind6 17:951bf897ba01 511 {
jlind6 17:951bf897ba01 512 DBG("Trying to read at most %d bytes [Not blocking]", maxLen - readLen);
jlind6 17:951bf897ba01 513 m_sock.set_blocking(false, 0);
jlind6 17:951bf897ba01 514 ret = m_sock.receive(buf + readLen, maxLen - readLen);
jlind6 17:951bf897ba01 515 }
jlind6 17:951bf897ba01 516
jlind6 17:951bf897ba01 517 if( ret > 0)
jlind6 17:951bf897ba01 518 {
jlind6 17:951bf897ba01 519 readLen += ret;
jlind6 17:951bf897ba01 520 }
jlind6 17:951bf897ba01 521 else if( ret == 0 )
jlind6 17:951bf897ba01 522 {
jlind6 17:951bf897ba01 523 break;
jlind6 17:951bf897ba01 524 }
jlind6 17:951bf897ba01 525 else
jlind6 17:951bf897ba01 526 {
jlind6 17:951bf897ba01 527 if(!m_sock.is_connected())
jlind6 17:951bf897ba01 528 {
jlind6 17:951bf897ba01 529 ERR("Connection error (recv returned %d)", ret);
jlind6 17:951bf897ba01 530 *pReadLen = readLen;
jlind6 17:951bf897ba01 531 return HTTP_CONN;
jlind6 17:951bf897ba01 532 }
jlind6 17:951bf897ba01 533 else
jlind6 17:951bf897ba01 534 {
jlind6 17:951bf897ba01 535 break;
jlind6 17:951bf897ba01 536 }
jlind6 17:951bf897ba01 537 }
jlind6 17:951bf897ba01 538
jlind6 17:951bf897ba01 539 if(!m_sock.is_connected())
jlind6 17:951bf897ba01 540 {
jlind6 17:951bf897ba01 541 break;
jlind6 17:951bf897ba01 542 }
jlind6 17:951bf897ba01 543 }
jlind6 17:951bf897ba01 544 DBG("Read %d bytes", readLen);
jlind6 17:951bf897ba01 545 *pReadLen = readLen;
jlind6 17:951bf897ba01 546 return HTTP_OK;
jlind6 17:951bf897ba01 547 }
jlind6 17:951bf897ba01 548
jlind6 17:951bf897ba01 549 HTTPResult HTTPClient::send(char* buf, size_t len) //0 on success, err code on failure
jlind6 17:951bf897ba01 550 {
jlind6 17:951bf897ba01 551 if(len == 0)
jlind6 17:951bf897ba01 552 {
jlind6 17:951bf897ba01 553 len = strlen(buf);
jlind6 17:951bf897ba01 554 }
jlind6 17:951bf897ba01 555 DBG("Trying to write %d bytes", len);
jlind6 17:951bf897ba01 556 size_t writtenLen = 0;
jlind6 17:951bf897ba01 557
jlind6 17:951bf897ba01 558 if(!m_sock.is_connected())
jlind6 17:951bf897ba01 559 {
jlind6 17:951bf897ba01 560 WARN("Connection was closed by server");
jlind6 17:951bf897ba01 561 return HTTP_CLOSED; //Connection was closed by server
jlind6 17:951bf897ba01 562 }
jlind6 17:951bf897ba01 563
jlind6 17:951bf897ba01 564 m_sock.set_blocking(false, m_timeout);
jlind6 17:951bf897ba01 565 int ret = m_sock.send_all(buf, len);
jlind6 17:951bf897ba01 566 if(ret > 0)
jlind6 17:951bf897ba01 567 {
jlind6 17:951bf897ba01 568 writtenLen += ret;
jlind6 17:951bf897ba01 569 }
jlind6 17:951bf897ba01 570 else if( ret == 0 )
jlind6 17:951bf897ba01 571 {
jlind6 17:951bf897ba01 572 WARN("Connection was closed by server");
jlind6 17:951bf897ba01 573 return HTTP_CLOSED; //Connection was closed by server
jlind6 17:951bf897ba01 574 }
jlind6 17:951bf897ba01 575 else
jlind6 17:951bf897ba01 576 {
jlind6 17:951bf897ba01 577 ERR("Connection error (send returned %d)", ret);
jlind6 17:951bf897ba01 578 return HTTP_CONN;
jlind6 17:951bf897ba01 579 }
jlind6 17:951bf897ba01 580
jlind6 17:951bf897ba01 581 DBG("Written %d bytes", writtenLen);
jlind6 17:951bf897ba01 582 return HTTP_OK;
jlind6 17:951bf897ba01 583 }
jlind6 17:951bf897ba01 584
jlind6 17:951bf897ba01 585 HTTPResult HTTPClient::parseURL(const char* url, char* scheme, size_t maxSchemeLen, char* host, size_t maxHostLen, uint16_t* port, char* path, size_t maxPathLen) //Parse URL
jlind6 17:951bf897ba01 586 {
jlind6 17:951bf897ba01 587 char* schemePtr = (char*) url;
jlind6 17:951bf897ba01 588 char* hostPtr = (char*) strstr(url, "://");
jlind6 17:951bf897ba01 589 if(hostPtr == NULL)
jlind6 17:951bf897ba01 590 {
jlind6 17:951bf897ba01 591 WARN("Could not find host");
jlind6 17:951bf897ba01 592 return HTTP_PARSE; //URL is invalid
jlind6 17:951bf897ba01 593 }
jlind6 17:951bf897ba01 594
jlind6 17:951bf897ba01 595 if( maxSchemeLen < hostPtr - schemePtr + 1 ) //including NULL-terminating char
jlind6 17:951bf897ba01 596 {
jlind6 17:951bf897ba01 597 WARN("Scheme str is too small (%d >= %d)", maxSchemeLen, hostPtr - schemePtr + 1);
jlind6 17:951bf897ba01 598 return HTTP_PARSE;
jlind6 17:951bf897ba01 599 }
jlind6 17:951bf897ba01 600 memcpy(scheme, schemePtr, hostPtr - schemePtr);
jlind6 17:951bf897ba01 601 scheme[hostPtr - schemePtr] = '\0';
jlind6 17:951bf897ba01 602
jlind6 17:951bf897ba01 603 hostPtr+=3;
jlind6 17:951bf897ba01 604
jlind6 17:951bf897ba01 605 size_t hostLen = 0;
jlind6 17:951bf897ba01 606
jlind6 17:951bf897ba01 607 char* portPtr = strchr(hostPtr, ':');
jlind6 17:951bf897ba01 608 if( portPtr != NULL )
jlind6 17:951bf897ba01 609 {
jlind6 17:951bf897ba01 610 hostLen = portPtr - hostPtr;
jlind6 17:951bf897ba01 611 portPtr++;
jlind6 17:951bf897ba01 612 if( sscanf(portPtr, "%hu", port) != 1)
jlind6 17:951bf897ba01 613 {
jlind6 17:951bf897ba01 614 WARN("Could not find port");
jlind6 17:951bf897ba01 615 return HTTP_PARSE;
jlind6 17:951bf897ba01 616 }
jlind6 17:951bf897ba01 617 }
jlind6 17:951bf897ba01 618 else
jlind6 17:951bf897ba01 619 {
jlind6 17:951bf897ba01 620 *port=0;
jlind6 17:951bf897ba01 621 }
jlind6 17:951bf897ba01 622 char* pathPtr = strchr(hostPtr, '/');
jlind6 17:951bf897ba01 623 if( hostLen == 0 )
jlind6 17:951bf897ba01 624 {
jlind6 17:951bf897ba01 625 hostLen = pathPtr - hostPtr;
jlind6 17:951bf897ba01 626 }
jlind6 17:951bf897ba01 627
jlind6 17:951bf897ba01 628 if( maxHostLen < hostLen + 1 ) //including NULL-terminating char
jlind6 17:951bf897ba01 629 {
jlind6 17:951bf897ba01 630 WARN("Host str is too small (%d >= %d)", maxHostLen, hostLen + 1);
jlind6 17:951bf897ba01 631 return HTTP_PARSE;
jlind6 17:951bf897ba01 632 }
jlind6 17:951bf897ba01 633 memcpy(host, hostPtr, hostLen);
jlind6 17:951bf897ba01 634 host[hostLen] = '\0';
jlind6 17:951bf897ba01 635
jlind6 17:951bf897ba01 636 size_t pathLen;
jlind6 17:951bf897ba01 637 char* fragmentPtr = strchr(hostPtr, '#');
jlind6 17:951bf897ba01 638 if(fragmentPtr != NULL)
jlind6 17:951bf897ba01 639 {
jlind6 17:951bf897ba01 640 pathLen = fragmentPtr - pathPtr;
jlind6 17:951bf897ba01 641 }
jlind6 17:951bf897ba01 642 else
jlind6 17:951bf897ba01 643 {
jlind6 17:951bf897ba01 644 pathLen = strlen(pathPtr);
jlind6 17:951bf897ba01 645 }
jlind6 17:951bf897ba01 646
jlind6 17:951bf897ba01 647 if( maxPathLen < pathLen + 1 ) //including NULL-terminating char
jlind6 17:951bf897ba01 648 {
jlind6 17:951bf897ba01 649 WARN("Path str is too small (%d >= %d)", maxPathLen, pathLen + 1);
jlind6 17:951bf897ba01 650 return HTTP_PARSE;
jlind6 17:951bf897ba01 651 }
jlind6 17:951bf897ba01 652 memcpy(path, pathPtr, pathLen);
jlind6 17:951bf897ba01 653 path[pathLen] = '\0';
jlind6 17:951bf897ba01 654
jlind6 17:951bf897ba01 655 return HTTP_OK;
jlind6 17:951bf897ba01 656 }