HTTPClient test for IoT Workshop

Dependencies:   UbloxUSBModem mbed

Fork of UbloxModemHTTPClientTest by mbed official

Committer:
sam_grove
Date:
Mon Feb 03 14:35:03 2014 +0000
Revision:
6:8cf840145f92
Parent:
1:0112fc45285a
update to make CDMA default

Who changed what in which revision?

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