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:
donatien
Date:
Tue Aug 28 15:55:32 2012 +0000
Revision:
14:2744e0c0e527
Parent:
13:be61104f4e91
Child:
15:5ad07f90e895
Fixed short chunk buffer issue

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