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:
Wed Jul 18 15:40:04 2012 +0000
Revision:
10:e1351de84c16
Parent:
9:ff30cc189191
Child:
11:390362de8c3f
Corrected licence headers

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