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:
Mon Jul 30 15:16:51 2012 +0000
Revision:
11:390362de8c3f
Parent:
10:e1351de84c16
Child:
12:89d09a6db00a
Update for compat with newest Socket API

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