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:
Thu Apr 26 14:23:15 2012 +0000
Revision:
3:5aef7584de4b
Parent:
2:75f5b83238af
Child:
4:c071b05ac026

        

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 0:2ccb9960a044 80
donatien 0:2ccb9960a044 81 int HTTPClient::connect(const char* url, HTTP_METH method, IHTTPDataOut* pDataOut, IHTTPDataIn* pDataIn, uint32_t timeout) //Execute request
donatien 0:2ccb9960a044 82 {
donatien 0:2ccb9960a044 83 m_httpResponseCode = 0; //Invalidate code
donatien 0:2ccb9960a044 84 m_timeout = timeout;
donatien 0:2ccb9960a044 85
donatien 0:2ccb9960a044 86 char scheme[8];
donatien 0:2ccb9960a044 87 uint16_t port;
donatien 0:2ccb9960a044 88 char host[32];
donatien 0:2ccb9960a044 89 char path[64];
donatien 0:2ccb9960a044 90 //First we need to parse the url (http[s]://host[:port][/[path]]) -- HTTPS not supported (yet?)
donatien 0:2ccb9960a044 91 int ret = parseURL(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path));
donatien 0:2ccb9960a044 92 if(ret != OK)
donatien 0:2ccb9960a044 93 {
donatien 0:2ccb9960a044 94 ERR("parseURL returned %d", ret);
donatien 0:2ccb9960a044 95 return ret;
donatien 0:2ccb9960a044 96 }
donatien 0:2ccb9960a044 97
donatien 0:2ccb9960a044 98 if(port == 0) //TODO do handle HTTPS->443
donatien 0:2ccb9960a044 99 {
donatien 0:2ccb9960a044 100 port = 80;
donatien 0:2ccb9960a044 101 }
donatien 0:2ccb9960a044 102
donatien 0:2ccb9960a044 103 DBG("Scheme: %s", scheme);
donatien 0:2ccb9960a044 104 DBG("Host: %s", host);
donatien 0:2ccb9960a044 105 DBG("Port: %d", port);
donatien 0:2ccb9960a044 106 DBG("Path: %s", path);
donatien 0:2ccb9960a044 107
donatien 0:2ccb9960a044 108 //Now populate structure
donatien 0:2ccb9960a044 109 std::memset(&m_serverAddr, 0, sizeof(struct sockaddr_in));
donatien 0:2ccb9960a044 110
donatien 0:2ccb9960a044 111 //Resolve DNS if needed
donatien 0:2ccb9960a044 112
donatien 0:2ccb9960a044 113 DBG("Resolving DNS address or populate hard-coded IP address");
donatien 0:2ccb9960a044 114 struct hostent *server = socket::gethostbyname(host);
donatien 0:2ccb9960a044 115 if(server == NULL)
donatien 0:2ccb9960a044 116 {
donatien 0:2ccb9960a044 117 return NET_NOTFOUND; //Fail
donatien 0:2ccb9960a044 118 }
donatien 0:2ccb9960a044 119 memcpy((char*)&m_serverAddr.sin_addr.s_addr, (char*)server->h_addr_list[0], server->h_length);
donatien 0:2ccb9960a044 120
donatien 0:2ccb9960a044 121 m_serverAddr.sin_family = AF_INET;
donatien 0:2ccb9960a044 122 m_serverAddr.sin_port = htons(port);
donatien 0:2ccb9960a044 123
donatien 0:2ccb9960a044 124 //Create socket
donatien 0:2ccb9960a044 125 DBG("Creating socket");
donatien 0:2ccb9960a044 126 m_sock = socket::socket(AF_INET, SOCK_STREAM, 0); //UDP socket
donatien 0:2ccb9960a044 127 if (m_sock < 0)
donatien 0:2ccb9960a044 128 {
donatien 0:2ccb9960a044 129 ERR("Could not create socket");
donatien 0:2ccb9960a044 130 return NET_OOM;
donatien 0:2ccb9960a044 131 }
donatien 0:2ccb9960a044 132 DBG("Handle is %d", m_sock);
donatien 0:2ccb9960a044 133
donatien 0:2ccb9960a044 134 //Connect it
donatien 0:2ccb9960a044 135 DBG("Connecting socket to %s:%d", inet_ntoa(m_serverAddr.sin_addr), ntohs(m_serverAddr.sin_port));
donatien 0:2ccb9960a044 136 ret = socket::connect(m_sock, (const struct sockaddr *)&m_serverAddr, sizeof(m_serverAddr));
donatien 0:2ccb9960a044 137 if (ret < 0)
donatien 0:2ccb9960a044 138 {
donatien 0:2ccb9960a044 139 socket::close(m_sock);
donatien 0:2ccb9960a044 140 ERR("Could not connect");
donatien 0:2ccb9960a044 141 return NET_CONN;
donatien 0:2ccb9960a044 142 }
donatien 0:2ccb9960a044 143
donatien 0:2ccb9960a044 144 //Send request
donatien 0:2ccb9960a044 145 DBG("Sending request");
donatien 0:2ccb9960a044 146 char line[128];
donatien 0:2ccb9960a044 147 const char* meth = (method==HTTP_GET)?"GET":(method==HTTP_POST)?"POST":"";
donatien 0:2ccb9960a044 148 snprintf(line, sizeof(line), "%s %s HTTP/1.1\r\nHost: %s\r\n", meth, path, host); //Write request
donatien 0:2ccb9960a044 149 ret = send(line);
donatien 0:2ccb9960a044 150 if(ret)
donatien 0:2ccb9960a044 151 {
donatien 0:2ccb9960a044 152 socket::close(m_sock);
donatien 0:2ccb9960a044 153 ERR("Could not write request");
donatien 0:2ccb9960a044 154 return NET_CONN;
donatien 0:2ccb9960a044 155 }
donatien 0:2ccb9960a044 156
donatien 1:b70c37cf73ca 157 size_t recvContentLength = 0;
donatien 1:b70c37cf73ca 158 bool recvChunked = false;
donatien 2:75f5b83238af 159 char buf[CHUNK_SIZE];
donatien 2:75f5b83238af 160 size_t trfLen;
donatien 2:75f5b83238af 161 int crlfPos;
donatien 1:b70c37cf73ca 162
donatien 0:2ccb9960a044 163 //Send all headers
donatien 0:2ccb9960a044 164
donatien 0:2ccb9960a044 165 //Send default headers
donatien 0:2ccb9960a044 166 DBG("Sending headers");
donatien 0:2ccb9960a044 167 if( (method == HTTP_POST) && (pDataOut != NULL) )
donatien 0:2ccb9960a044 168 {
donatien 0:2ccb9960a044 169 if( pDataOut->getIsChunked() )
donatien 0:2ccb9960a044 170 {
donatien 0:2ccb9960a044 171 ret = send("Transfer-Encoding: chunked\r\n");
donatien 0:2ccb9960a044 172 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 173 }
donatien 0:2ccb9960a044 174 else
donatien 0:2ccb9960a044 175 {
donatien 0:2ccb9960a044 176 snprintf(line, sizeof(line), "Content-Length: %d\r\n", pDataOut->getDataLen());
donatien 0:2ccb9960a044 177 ret = send(line);
donatien 0:2ccb9960a044 178 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 179 }
donatien 0:2ccb9960a044 180 char type[48];
donatien 0:2ccb9960a044 181 if( pDataOut->getDataType(type, 48) == OK )
donatien 0:2ccb9960a044 182 {
donatien 0:2ccb9960a044 183 snprintf(line, sizeof(line), "Content-Type: %s\r\n", type);
donatien 0:2ccb9960a044 184 ret = send(line);
donatien 0:2ccb9960a044 185 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 186 }
donatien 0:2ccb9960a044 187 }
donatien 0:2ccb9960a044 188
donatien 0:2ccb9960a044 189 //Close headers
donatien 0:2ccb9960a044 190 DBG("Headers sent");
donatien 0:2ccb9960a044 191 ret = send("\r\n");
donatien 0:2ccb9960a044 192 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 193
donatien 0:2ccb9960a044 194 //Send data (if POST)
donatien 0:2ccb9960a044 195 if( (method == HTTP_POST) && (pDataOut != NULL) )
donatien 0:2ccb9960a044 196 {
donatien 0:2ccb9960a044 197 DBG("Sending data");
donatien 0:2ccb9960a044 198 while(true)
donatien 0:2ccb9960a044 199 {
donatien 0:2ccb9960a044 200 size_t writtenLen = 0;
donatien 0:2ccb9960a044 201 pDataOut->read(buf, CHUNK_SIZE, &trfLen);
donatien 0:2ccb9960a044 202 if( pDataOut->getIsChunked() )
donatien 0:2ccb9960a044 203 {
donatien 0:2ccb9960a044 204 //Write chunk header
donatien 0:2ccb9960a044 205 snprintf(line, sizeof(line), "%X\r\n", trfLen); //In hex encoding
donatien 0:2ccb9960a044 206 ret = send(line);
donatien 0:2ccb9960a044 207 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 208 }
donatien 0:2ccb9960a044 209 else if( trfLen == 0 )
donatien 0:2ccb9960a044 210 {
donatien 0:2ccb9960a044 211 break;
donatien 0:2ccb9960a044 212 }
donatien 0:2ccb9960a044 213 if( trfLen != 0 )
donatien 0:2ccb9960a044 214 {
donatien 0:2ccb9960a044 215 ret = send(buf, trfLen);
donatien 0:2ccb9960a044 216 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 217 }
donatien 0:2ccb9960a044 218
donatien 0:2ccb9960a044 219 if( pDataOut->getIsChunked() )
donatien 0:2ccb9960a044 220 {
donatien 0:2ccb9960a044 221 ret = send("\r\n"); //Chunk-terminating CRLF
donatien 0:2ccb9960a044 222 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 223 }
donatien 0:2ccb9960a044 224 else
donatien 0:2ccb9960a044 225 {
donatien 0:2ccb9960a044 226 writtenLen += trfLen;
donatien 0:2ccb9960a044 227 if( writtenLen >= pDataOut->getDataLen() )
donatien 0:2ccb9960a044 228 {
donatien 0:2ccb9960a044 229 break;
donatien 0:2ccb9960a044 230 }
donatien 0:2ccb9960a044 231 }
donatien 0:2ccb9960a044 232
donatien 0:2ccb9960a044 233 if( trfLen == 0 )
donatien 0:2ccb9960a044 234 {
donatien 0:2ccb9960a044 235 break;
donatien 0:2ccb9960a044 236 }
donatien 0:2ccb9960a044 237 }
donatien 0:2ccb9960a044 238
donatien 0:2ccb9960a044 239 }
donatien 0:2ccb9960a044 240
donatien 0:2ccb9960a044 241 //Receive response
donatien 0:2ccb9960a044 242 DBG("Receiving response");
donatien 0:2ccb9960a044 243 ret = recv(buf, CHUNK_SIZE, CHUNK_SIZE, &trfLen); //Read n bytes
donatien 0:2ccb9960a044 244 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 245
donatien 0:2ccb9960a044 246 buf[trfLen] = '\0';
donatien 0:2ccb9960a044 247
donatien 0:2ccb9960a044 248 char* crlfPtr = strstr(buf, "\r\n");
donatien 0:2ccb9960a044 249 if(crlfPtr == NULL)
donatien 0:2ccb9960a044 250 {
donatien 0:2ccb9960a044 251 goto prtclerr;
donatien 0:2ccb9960a044 252 }
donatien 0:2ccb9960a044 253
donatien 2:75f5b83238af 254 crlfPos = crlfPtr - buf;
donatien 0:2ccb9960a044 255 buf[crlfPos] = '\0';
donatien 0:2ccb9960a044 256
donatien 0:2ccb9960a044 257 //Parse HTTP response
donatien 0:2ccb9960a044 258 if( sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 )
donatien 0:2ccb9960a044 259 {
donatien 0:2ccb9960a044 260 //Cannot match string, error
donatien 0:2ccb9960a044 261 ERR("Not a correct HTTP answer : %s\n", buf);
donatien 0:2ccb9960a044 262 goto prtclerr;
donatien 0:2ccb9960a044 263 }
donatien 0:2ccb9960a044 264
donatien 0:2ccb9960a044 265 if(m_httpResponseCode != 200)
donatien 0:2ccb9960a044 266 {
donatien 0:2ccb9960a044 267 //Cannot match string, error
donatien 0:2ccb9960a044 268 WARN("Response code %d", m_httpResponseCode);
donatien 0:2ccb9960a044 269 goto prtclerr;
donatien 0:2ccb9960a044 270 }
donatien 0:2ccb9960a044 271
donatien 0:2ccb9960a044 272 DBG("Reading headers");
donatien 0:2ccb9960a044 273
donatien 0:2ccb9960a044 274 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2));
donatien 0:2ccb9960a044 275 trfLen -= (crlfPos + 2);
donatien 0:2ccb9960a044 276
donatien 0:2ccb9960a044 277 //Now get headers
donatien 0:2ccb9960a044 278 while( true )
donatien 0:2ccb9960a044 279 {
donatien 0:2ccb9960a044 280 crlfPtr = strstr(buf, "\r\n");
donatien 0:2ccb9960a044 281 if(crlfPtr == NULL)
donatien 0:2ccb9960a044 282 {
donatien 0:2ccb9960a044 283 if( trfLen < CHUNK_SIZE )
donatien 0:2ccb9960a044 284 {
donatien 0:2ccb9960a044 285 size_t newTrfLen;
donatien 0:2ccb9960a044 286 ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen);
donatien 0:2ccb9960a044 287 trfLen += newTrfLen;
donatien 0:2ccb9960a044 288 buf[trfLen] = '\0';
donatien 0:2ccb9960a044 289 DBG("In buf: [%s]", buf);
donatien 0:2ccb9960a044 290 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 291 continue;
donatien 0:2ccb9960a044 292 }
donatien 0:2ccb9960a044 293 else
donatien 0:2ccb9960a044 294 {
donatien 0:2ccb9960a044 295 goto prtclerr;
donatien 0:2ccb9960a044 296 }
donatien 0:2ccb9960a044 297 }
donatien 0:2ccb9960a044 298
donatien 0:2ccb9960a044 299 crlfPos = crlfPtr - buf;
donatien 0:2ccb9960a044 300
donatien 0:2ccb9960a044 301 if(crlfPos == 0) //End of headers
donatien 0:2ccb9960a044 302 {
donatien 0:2ccb9960a044 303 DBG("Headers read");
donatien 0:2ccb9960a044 304 memmove(buf, &buf[2], trfLen - 2);
donatien 0:2ccb9960a044 305 trfLen -= 2;
donatien 0:2ccb9960a044 306 break;
donatien 0:2ccb9960a044 307 }
donatien 0:2ccb9960a044 308
donatien 0:2ccb9960a044 309 buf[crlfPos] = '\0';
donatien 0:2ccb9960a044 310
donatien 0:2ccb9960a044 311 char key[16];
donatien 0:2ccb9960a044 312 char value[16];
donatien 0:2ccb9960a044 313
donatien 0:2ccb9960a044 314 int n = sscanf(buf, "%16[^:]: %16[^\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 0:2ccb9960a044 336 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2));
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 0:2ccb9960a044 343 goto prtclerr;
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 0:2ccb9960a044 372 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 373 continue;
donatien 0:2ccb9960a044 374 }
donatien 0:2ccb9960a044 375 else
donatien 0:2ccb9960a044 376 {
donatien 0:2ccb9960a044 377 goto prtclerr;
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 0:2ccb9960a044 385 goto prtclerr;
donatien 0:2ccb9960a044 386 }
donatien 0:2ccb9960a044 387
donatien 0:2ccb9960a044 388 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2));
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 0:2ccb9960a044 421 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 422
donatien 0:2ccb9960a044 423 }
donatien 0:2ccb9960a044 424 } while(readLen);
donatien 0:2ccb9960a044 425
donatien 0:2ccb9960a044 426 if( recvChunked )
donatien 0:2ccb9960a044 427 {
donatien 0:2ccb9960a044 428 if(trfLen < 2)
donatien 0:2ccb9960a044 429 {
donatien 0:2ccb9960a044 430 size_t newTrfLen;
donatien 0:2ccb9960a044 431 //Read missing chars to find end of chunk
donatien 0:2ccb9960a044 432 ret = recv(buf, 2 - trfLen, CHUNK_SIZE, &newTrfLen);
donatien 0:2ccb9960a044 433 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 434 trfLen += newTrfLen;
donatien 0:2ccb9960a044 435 }
donatien 0:2ccb9960a044 436 if( (buf[0] != '\r') || (buf[1] != '\n') )
donatien 0:2ccb9960a044 437 {
donatien 0:2ccb9960a044 438 ERR("Format error");
donatien 0:2ccb9960a044 439 goto prtclerr;
donatien 0:2ccb9960a044 440 }
donatien 0:2ccb9960a044 441 memmove(buf, &buf[2], trfLen - 2);
donatien 0:2ccb9960a044 442 trfLen -= 2;
donatien 0:2ccb9960a044 443 }
donatien 0:2ccb9960a044 444 else
donatien 0:2ccb9960a044 445 {
donatien 0:2ccb9960a044 446 break;
donatien 0:2ccb9960a044 447 }
donatien 0:2ccb9960a044 448
donatien 0:2ccb9960a044 449 }
donatien 0:2ccb9960a044 450
donatien 0:2ccb9960a044 451 socket::close(m_sock);
donatien 0:2ccb9960a044 452 DBG("Completed HTTP transaction");
donatien 0:2ccb9960a044 453
donatien 0:2ccb9960a044 454 return OK;
donatien 0:2ccb9960a044 455
donatien 0:2ccb9960a044 456 connerr:
donatien 3:5aef7584de4b 457 {
donatien 0:2ccb9960a044 458 socket::close(m_sock);
donatien 0:2ccb9960a044 459 ERR("Connection error (%d)", ret);
donatien 3:5aef7584de4b 460 return NET_CONN;
donatien 3:5aef7584de4b 461 }
donatien 3:5aef7584de4b 462
donatien 0:2ccb9960a044 463 prtclerr:
donatien 3:5aef7584de4b 464 {
donatien 0:2ccb9960a044 465 socket::close(m_sock);
donatien 0:2ccb9960a044 466 ERR("Protocol error");
donatien 3:5aef7584de4b 467 return NET_PROTOCOL;
donatien 3:5aef7584de4b 468 }
donatien 0:2ccb9960a044 469 }
donatien 0:2ccb9960a044 470
donatien 0:2ccb9960a044 471 int HTTPClient::recv(char* buf, size_t minLen, size_t maxLen, size_t* pReadLen) //0 on success, err code on failure
donatien 0:2ccb9960a044 472 {
donatien 0:2ccb9960a044 473 DBG("Trying to read between %d and %d bytes", minLen, maxLen);
donatien 0:2ccb9960a044 474 size_t readLen = 0;
donatien 0:2ccb9960a044 475 while(readLen < minLen)
donatien 0:2ccb9960a044 476 {
donatien 0:2ccb9960a044 477 //Wait for socket to be readable
donatien 0:2ccb9960a044 478 //Creating FS set
donatien 0:2ccb9960a044 479 fd_set socksSet;
donatien 0:2ccb9960a044 480 FD_ZERO(&socksSet);
donatien 0:2ccb9960a044 481 FD_SET(m_sock, &socksSet);
donatien 0:2ccb9960a044 482 struct timeval t_val;
donatien 0:2ccb9960a044 483 t_val.tv_sec = m_timeout / 1000;
donatien 0:2ccb9960a044 484 t_val.tv_usec = (m_timeout - (t_val.tv_sec * 1000)) * 1000;
donatien 0:2ccb9960a044 485 int ret = socket::select(FD_SETSIZE, &socksSet, NULL, NULL, &t_val);
donatien 0:2ccb9960a044 486 if(ret <= 0 || !FD_ISSET(m_sock, &socksSet))
donatien 0:2ccb9960a044 487 {
donatien 0:2ccb9960a044 488 WARN("Timeout");
donatien 0:2ccb9960a044 489 return NET_TIMEOUT; //Timeout
donatien 0:2ccb9960a044 490 }
donatien 0:2ccb9960a044 491
donatien 0:2ccb9960a044 492 ret = socket::recv(m_sock, buf + readLen, maxLen - readLen, 0);
donatien 0:2ccb9960a044 493 if( ret > 0)
donatien 0:2ccb9960a044 494 {
donatien 0:2ccb9960a044 495 readLen += ret;
donatien 0:2ccb9960a044 496 continue;
donatien 0:2ccb9960a044 497 }
donatien 0:2ccb9960a044 498 else if( ret == 0 )
donatien 0:2ccb9960a044 499 {
donatien 0:2ccb9960a044 500 WARN("Connection was closed by server");
donatien 0:2ccb9960a044 501 return NET_CLOSED; //Connection was closed by server
donatien 0:2ccb9960a044 502 }
donatien 0:2ccb9960a044 503 else
donatien 0:2ccb9960a044 504 {
donatien 0:2ccb9960a044 505 ERR("Connection error (recv returned %d)", ret);
donatien 0:2ccb9960a044 506 return NET_CONN;
donatien 0:2ccb9960a044 507 }
donatien 0:2ccb9960a044 508 }
donatien 0:2ccb9960a044 509 *pReadLen = readLen;
donatien 0:2ccb9960a044 510 DBG("Read %d bytes", readLen);
donatien 0:2ccb9960a044 511 return OK;
donatien 0:2ccb9960a044 512 }
donatien 0:2ccb9960a044 513
donatien 0:2ccb9960a044 514 int HTTPClient::send(char* buf, size_t len) //0 on success, err code on failure
donatien 0:2ccb9960a044 515 {
donatien 0:2ccb9960a044 516 if(len == 0)
donatien 0:2ccb9960a044 517 {
donatien 0:2ccb9960a044 518 len = strlen(buf);
donatien 0:2ccb9960a044 519 }
donatien 0:2ccb9960a044 520 DBG("Trying to write %d bytes", len);
donatien 0:2ccb9960a044 521 size_t writtenLen = 0;
donatien 0:2ccb9960a044 522 while(writtenLen < len)
donatien 0:2ccb9960a044 523 {
donatien 0:2ccb9960a044 524 //Wait for socket to be writeable
donatien 0:2ccb9960a044 525 //Creating FS set
donatien 0:2ccb9960a044 526 fd_set socksSet;
donatien 0:2ccb9960a044 527 FD_ZERO(&socksSet);
donatien 0:2ccb9960a044 528 FD_SET(m_sock, &socksSet);
donatien 0:2ccb9960a044 529 struct timeval t_val;
donatien 0:2ccb9960a044 530 t_val.tv_sec = m_timeout / 1000;
donatien 0:2ccb9960a044 531 t_val.tv_usec = (m_timeout - (t_val.tv_sec * 1000)) * 1000;
donatien 0:2ccb9960a044 532 int ret = socket::select(FD_SETSIZE, NULL, &socksSet, NULL, &t_val);
donatien 0:2ccb9960a044 533 if(ret <= 0 || !FD_ISSET(m_sock, &socksSet))
donatien 0:2ccb9960a044 534 {
donatien 0:2ccb9960a044 535 WARN("Timeout");
donatien 0:2ccb9960a044 536 return NET_TIMEOUT; //Timeout
donatien 0:2ccb9960a044 537 }
donatien 0:2ccb9960a044 538
donatien 0:2ccb9960a044 539 ret = socket::send(m_sock, buf + writtenLen, len - writtenLen, 0);
donatien 0:2ccb9960a044 540 if( ret > 0)
donatien 0:2ccb9960a044 541 {
donatien 0:2ccb9960a044 542 writtenLen += ret;
donatien 0:2ccb9960a044 543 continue;
donatien 0:2ccb9960a044 544 }
donatien 0:2ccb9960a044 545 else if( ret == 0 )
donatien 0:2ccb9960a044 546 {
donatien 0:2ccb9960a044 547 WARN("Connection was closed by server");
donatien 0:2ccb9960a044 548 return NET_CLOSED; //Connection was closed by server
donatien 0:2ccb9960a044 549 }
donatien 0:2ccb9960a044 550 else
donatien 0:2ccb9960a044 551 {
donatien 0:2ccb9960a044 552 ERR("Connection error (recv returned %d)", ret);
donatien 0:2ccb9960a044 553 return NET_CONN;
donatien 0:2ccb9960a044 554 }
donatien 0:2ccb9960a044 555 }
donatien 0:2ccb9960a044 556 DBG("Written %d bytes", writtenLen);
donatien 0:2ccb9960a044 557 return OK;
donatien 0:2ccb9960a044 558 }
donatien 0:2ccb9960a044 559
donatien 0:2ccb9960a044 560 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 561 {
donatien 0:2ccb9960a044 562 char* schemePtr = (char*) url;
donatien 0:2ccb9960a044 563 char* hostPtr = (char*) strstr(url, "://");
donatien 0:2ccb9960a044 564 if(hostPtr == NULL)
donatien 0:2ccb9960a044 565 {
donatien 0:2ccb9960a044 566 WARN("Could not find host");
donatien 0:2ccb9960a044 567 return NET_INVALID; //URL is invalid
donatien 0:2ccb9960a044 568 }
donatien 0:2ccb9960a044 569
donatien 0:2ccb9960a044 570 if( maxSchemeLen < hostPtr - schemePtr + 1 ) //including NULL-terminating char
donatien 0:2ccb9960a044 571 {
donatien 0:2ccb9960a044 572 WARN("Scheme str is too small (%d >= %d)", maxSchemeLen, hostPtr - schemePtr + 1);
donatien 0:2ccb9960a044 573 return NET_TOOSMALL;
donatien 0:2ccb9960a044 574 }
donatien 0:2ccb9960a044 575 memcpy(scheme, schemePtr, hostPtr - schemePtr);
donatien 0:2ccb9960a044 576 scheme[hostPtr - schemePtr] = '\0';
donatien 0:2ccb9960a044 577
donatien 0:2ccb9960a044 578 hostPtr+=3;
donatien 0:2ccb9960a044 579
donatien 0:2ccb9960a044 580 size_t hostLen = 0;
donatien 0:2ccb9960a044 581
donatien 0:2ccb9960a044 582 char* portPtr = strchr(hostPtr, ':');
donatien 0:2ccb9960a044 583 if( portPtr != NULL )
donatien 0:2ccb9960a044 584 {
donatien 0:2ccb9960a044 585 hostLen = portPtr - hostPtr;
donatien 0:2ccb9960a044 586 portPtr++;
donatien 0:2ccb9960a044 587 if( sscanf(portPtr, "%d", &port) != 1)
donatien 0:2ccb9960a044 588 {
donatien 0:2ccb9960a044 589 WARN("Could not find port");
donatien 0:2ccb9960a044 590 return NET_INVALID;
donatien 0:2ccb9960a044 591 }
donatien 0:2ccb9960a044 592 }
donatien 0:2ccb9960a044 593 else
donatien 0:2ccb9960a044 594 {
donatien 0:2ccb9960a044 595 *port=0;
donatien 0:2ccb9960a044 596 }
donatien 0:2ccb9960a044 597 char* pathPtr = strchr(hostPtr, '/');
donatien 0:2ccb9960a044 598 if( hostLen == 0 )
donatien 0:2ccb9960a044 599 {
donatien 0:2ccb9960a044 600 hostLen = pathPtr - hostPtr;
donatien 0:2ccb9960a044 601 }
donatien 0:2ccb9960a044 602
donatien 0:2ccb9960a044 603 if( maxHostLen < hostLen + 1 ) //including NULL-terminating char
donatien 0:2ccb9960a044 604 {
donatien 0:2ccb9960a044 605 WARN("Host str is too small (%d >= %d)", maxHostLen, hostLen + 1);
donatien 0:2ccb9960a044 606 return NET_TOOSMALL;
donatien 0:2ccb9960a044 607 }
donatien 0:2ccb9960a044 608 memcpy(host, hostPtr, hostLen);
donatien 0:2ccb9960a044 609 host[hostLen] = '\0';
donatien 0:2ccb9960a044 610
donatien 0:2ccb9960a044 611 size_t pathLen;
donatien 0:2ccb9960a044 612 char* fragmentPtr = strchr(hostPtr, '#');
donatien 0:2ccb9960a044 613 if(fragmentPtr != NULL)
donatien 0:2ccb9960a044 614 {
donatien 0:2ccb9960a044 615 pathLen = fragmentPtr - pathPtr;
donatien 0:2ccb9960a044 616 }
donatien 0:2ccb9960a044 617 else
donatien 0:2ccb9960a044 618 {
donatien 0:2ccb9960a044 619 pathLen = strlen(pathPtr);
donatien 0:2ccb9960a044 620 }
donatien 0:2ccb9960a044 621
donatien 0:2ccb9960a044 622 if( maxPathLen < pathLen + 1 ) //including NULL-terminating char
donatien 0:2ccb9960a044 623 {
donatien 0:2ccb9960a044 624 WARN("Path str is too small (%d >= %d)", maxPathLen, pathLen + 1);
donatien 0:2ccb9960a044 625 return NET_TOOSMALL;
donatien 0:2ccb9960a044 626 }
donatien 0:2ccb9960a044 627 memcpy(path, pathPtr, pathLen);
donatien 0:2ccb9960a044 628 path[pathLen] = '\0';
donatien 0:2ccb9960a044 629
donatien 0:2ccb9960a044 630 return OK;
donatien 0:2ccb9960a044 631 }