A HTTP Client for the mbed networking libraries with HTTPFile for use with latest networking stack

Fork of HTTPClient by Donatien Garnier

An extension of the HTTPClient that adds HTTPFile. Currently on get is support and only works when getting binary files.

HTTPFile data("/local/firm.bin");
HTTPResult r = client.get("https://217.140.101.20/media/uploads/ollie8/firm.bin", &data);
if (r == HTTP_OK) {
                            
}
Committer:
ollie8
Date:
Sun Jul 26 09:02:21 2015 +0000
Revision:
19:bc765a7fd8f2
Parent:
16:1f743885e7de
Fixed bug in file write method

Who changed what in which revision?

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