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