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:
Fri Jul 06 10:26:17 2012 +0000
Revision:
8:45c8da29a1cf
Parent:
7:4e39864f7b15
Child:
9:ff30cc189191
Fixed bug in URL parsing method

Who changed what in which revision?

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