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 Jun 29 10:24:38 2012 +0000
Revision:
6:54f79436184f
Parent:
5:791fc3dcb6c4
Child:
7:4e39864f7b15
Forked with right name

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