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 13:04:56 2012 +0000
Revision:
0:2ccb9960a044
Child:
1:b70c37cf73ca

        

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 0:2ccb9960a044 157 //Send all headers
donatien 0:2ccb9960a044 158
donatien 0:2ccb9960a044 159 //Send default headers
donatien 0:2ccb9960a044 160 DBG("Sending headers");
donatien 0:2ccb9960a044 161 if( (method == HTTP_POST) && (pDataOut != NULL) )
donatien 0:2ccb9960a044 162 {
donatien 0:2ccb9960a044 163 if( pDataOut->getIsChunked() )
donatien 0:2ccb9960a044 164 {
donatien 0:2ccb9960a044 165 ret = send("Transfer-Encoding: chunked\r\n");
donatien 0:2ccb9960a044 166 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 167 }
donatien 0:2ccb9960a044 168 else
donatien 0:2ccb9960a044 169 {
donatien 0:2ccb9960a044 170 snprintf(line, sizeof(line), "Content-Length: %d\r\n", pDataOut->getDataLen());
donatien 0:2ccb9960a044 171 ret = send(line);
donatien 0:2ccb9960a044 172 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 173 }
donatien 0:2ccb9960a044 174 char type[48];
donatien 0:2ccb9960a044 175 if( pDataOut->getDataType(type, 48) == OK )
donatien 0:2ccb9960a044 176 {
donatien 0:2ccb9960a044 177 snprintf(line, sizeof(line), "Content-Type: %s\r\n", type);
donatien 0:2ccb9960a044 178 ret = send(line);
donatien 0:2ccb9960a044 179 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 180 }
donatien 0:2ccb9960a044 181 }
donatien 0:2ccb9960a044 182
donatien 0:2ccb9960a044 183 //Close headers
donatien 0:2ccb9960a044 184 DBG("Headers sent");
donatien 0:2ccb9960a044 185 ret = send("\r\n");
donatien 0:2ccb9960a044 186 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 187
donatien 0:2ccb9960a044 188 char buf[CHUNK_SIZE];
donatien 0:2ccb9960a044 189 size_t trfLen;
donatien 0:2ccb9960a044 190
donatien 0:2ccb9960a044 191 //Send data (if POST)
donatien 0:2ccb9960a044 192 if( (method == HTTP_POST) && (pDataOut != NULL) )
donatien 0:2ccb9960a044 193 {
donatien 0:2ccb9960a044 194 DBG("Sending data");
donatien 0:2ccb9960a044 195 while(true)
donatien 0:2ccb9960a044 196 {
donatien 0:2ccb9960a044 197 size_t writtenLen = 0;
donatien 0:2ccb9960a044 198 pDataOut->read(buf, CHUNK_SIZE, &trfLen);
donatien 0:2ccb9960a044 199 if( pDataOut->getIsChunked() )
donatien 0:2ccb9960a044 200 {
donatien 0:2ccb9960a044 201 //Write chunk header
donatien 0:2ccb9960a044 202 snprintf(line, sizeof(line), "%X\r\n", trfLen); //In hex encoding
donatien 0:2ccb9960a044 203 ret = send(line);
donatien 0:2ccb9960a044 204 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 205 }
donatien 0:2ccb9960a044 206 else if( trfLen == 0 )
donatien 0:2ccb9960a044 207 {
donatien 0:2ccb9960a044 208 break;
donatien 0:2ccb9960a044 209 }
donatien 0:2ccb9960a044 210 if( trfLen != 0 )
donatien 0:2ccb9960a044 211 {
donatien 0:2ccb9960a044 212 ret = send(buf, trfLen);
donatien 0:2ccb9960a044 213 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 214 }
donatien 0:2ccb9960a044 215
donatien 0:2ccb9960a044 216 if( pDataOut->getIsChunked() )
donatien 0:2ccb9960a044 217 {
donatien 0:2ccb9960a044 218 ret = send("\r\n"); //Chunk-terminating CRLF
donatien 0:2ccb9960a044 219 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 220 }
donatien 0:2ccb9960a044 221 else
donatien 0:2ccb9960a044 222 {
donatien 0:2ccb9960a044 223 writtenLen += trfLen;
donatien 0:2ccb9960a044 224 if( writtenLen >= pDataOut->getDataLen() )
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 if( trfLen == 0 )
donatien 0:2ccb9960a044 231 {
donatien 0:2ccb9960a044 232 break;
donatien 0:2ccb9960a044 233 }
donatien 0:2ccb9960a044 234 }
donatien 0:2ccb9960a044 235
donatien 0:2ccb9960a044 236 }
donatien 0:2ccb9960a044 237
donatien 0:2ccb9960a044 238 //Receive response
donatien 0:2ccb9960a044 239 DBG("Receiving response");
donatien 0:2ccb9960a044 240 ret = recv(buf, CHUNK_SIZE, CHUNK_SIZE, &trfLen); //Read n bytes
donatien 0:2ccb9960a044 241 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 242
donatien 0:2ccb9960a044 243 buf[trfLen] = '\0';
donatien 0:2ccb9960a044 244
donatien 0:2ccb9960a044 245 char* crlfPtr = strstr(buf, "\r\n");
donatien 0:2ccb9960a044 246 if(crlfPtr == NULL)
donatien 0:2ccb9960a044 247 {
donatien 0:2ccb9960a044 248 goto prtclerr;
donatien 0:2ccb9960a044 249 }
donatien 0:2ccb9960a044 250
donatien 0:2ccb9960a044 251 int crlfPos = crlfPtr - buf;
donatien 0:2ccb9960a044 252 buf[crlfPos] = '\0';
donatien 0:2ccb9960a044 253
donatien 0:2ccb9960a044 254 //Parse HTTP response
donatien 0:2ccb9960a044 255 if( sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 )
donatien 0:2ccb9960a044 256 {
donatien 0:2ccb9960a044 257 //Cannot match string, error
donatien 0:2ccb9960a044 258 ERR("Not a correct HTTP answer : %s\n", buf);
donatien 0:2ccb9960a044 259 goto prtclerr;
donatien 0:2ccb9960a044 260 }
donatien 0:2ccb9960a044 261
donatien 0:2ccb9960a044 262 if(m_httpResponseCode != 200)
donatien 0:2ccb9960a044 263 {
donatien 0:2ccb9960a044 264 //Cannot match string, error
donatien 0:2ccb9960a044 265 WARN("Response code %d", m_httpResponseCode);
donatien 0:2ccb9960a044 266 goto prtclerr;
donatien 0:2ccb9960a044 267 }
donatien 0:2ccb9960a044 268
donatien 0:2ccb9960a044 269 DBG("Reading headers");
donatien 0:2ccb9960a044 270
donatien 0:2ccb9960a044 271 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2));
donatien 0:2ccb9960a044 272 trfLen -= (crlfPos + 2);
donatien 0:2ccb9960a044 273
donatien 0:2ccb9960a044 274 size_t recvContentLength = 0;
donatien 0:2ccb9960a044 275 bool recvChunked = false;
donatien 0:2ccb9960a044 276 //Now get headers
donatien 0:2ccb9960a044 277 while( true )
donatien 0:2ccb9960a044 278 {
donatien 0:2ccb9960a044 279 crlfPtr = strstr(buf, "\r\n");
donatien 0:2ccb9960a044 280 if(crlfPtr == NULL)
donatien 0:2ccb9960a044 281 {
donatien 0:2ccb9960a044 282 if( trfLen < CHUNK_SIZE )
donatien 0:2ccb9960a044 283 {
donatien 0:2ccb9960a044 284 size_t newTrfLen;
donatien 0:2ccb9960a044 285 ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen);
donatien 0:2ccb9960a044 286 trfLen += newTrfLen;
donatien 0:2ccb9960a044 287 buf[trfLen] = '\0';
donatien 0:2ccb9960a044 288 DBG("In buf: [%s]", buf);
donatien 0:2ccb9960a044 289 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 290 continue;
donatien 0:2ccb9960a044 291 }
donatien 0:2ccb9960a044 292 else
donatien 0:2ccb9960a044 293 {
donatien 0:2ccb9960a044 294 goto prtclerr;
donatien 0:2ccb9960a044 295 }
donatien 0:2ccb9960a044 296 }
donatien 0:2ccb9960a044 297
donatien 0:2ccb9960a044 298 crlfPos = crlfPtr - buf;
donatien 0:2ccb9960a044 299
donatien 0:2ccb9960a044 300 if(crlfPos == 0) //End of headers
donatien 0:2ccb9960a044 301 {
donatien 0:2ccb9960a044 302 DBG("Headers read");
donatien 0:2ccb9960a044 303 memmove(buf, &buf[2], trfLen - 2);
donatien 0:2ccb9960a044 304 trfLen -= 2;
donatien 0:2ccb9960a044 305 break;
donatien 0:2ccb9960a044 306 }
donatien 0:2ccb9960a044 307
donatien 0:2ccb9960a044 308 buf[crlfPos] = '\0';
donatien 0:2ccb9960a044 309
donatien 0:2ccb9960a044 310 char key[16];
donatien 0:2ccb9960a044 311 char value[16];
donatien 0:2ccb9960a044 312
donatien 0:2ccb9960a044 313 int n = sscanf(buf, "%16[^:]: %16[^\r\n]", key, value);
donatien 0:2ccb9960a044 314 if ( n == 2 )
donatien 0:2ccb9960a044 315 {
donatien 0:2ccb9960a044 316 DBG("Read header : %s: %s\n", key, value);
donatien 0:2ccb9960a044 317 if( !strcmp(key, "Content-Length") )
donatien 0:2ccb9960a044 318 {
donatien 0:2ccb9960a044 319 sscanf(value, "%d", &recvContentLength);
donatien 0:2ccb9960a044 320 pDataIn->setDataLen(recvContentLength);
donatien 0:2ccb9960a044 321 }
donatien 0:2ccb9960a044 322 else if( !strcmp(key, "Transfer-Encoding") )
donatien 0:2ccb9960a044 323 {
donatien 0:2ccb9960a044 324 if( !strcmp(value, "Chunked") || !strcmp(value, "chunked") )
donatien 0:2ccb9960a044 325 {
donatien 0:2ccb9960a044 326 recvChunked = true;
donatien 0:2ccb9960a044 327 pDataIn->setIsChunked(true);
donatien 0:2ccb9960a044 328 }
donatien 0:2ccb9960a044 329 }
donatien 0:2ccb9960a044 330 else if( !strcmp(key, "Content-Type") )
donatien 0:2ccb9960a044 331 {
donatien 0:2ccb9960a044 332 pDataIn->setDataType(value);
donatien 0:2ccb9960a044 333 }
donatien 0:2ccb9960a044 334
donatien 0:2ccb9960a044 335 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2));
donatien 0:2ccb9960a044 336 trfLen -= (crlfPos + 2);
donatien 0:2ccb9960a044 337
donatien 0:2ccb9960a044 338 }
donatien 0:2ccb9960a044 339 else
donatien 0:2ccb9960a044 340 {
donatien 0:2ccb9960a044 341 ERR("Could not parse header");
donatien 0:2ccb9960a044 342 goto prtclerr;
donatien 0:2ccb9960a044 343 }
donatien 0:2ccb9960a044 344
donatien 0:2ccb9960a044 345 }
donatien 0:2ccb9960a044 346
donatien 0:2ccb9960a044 347 //Receive data
donatien 0:2ccb9960a044 348 DBG("Receiving data");
donatien 0:2ccb9960a044 349 while(true)
donatien 0:2ccb9960a044 350 {
donatien 0:2ccb9960a044 351 size_t readLen = 0;
donatien 0:2ccb9960a044 352
donatien 0:2ccb9960a044 353 if( recvChunked )
donatien 0:2ccb9960a044 354 {
donatien 0:2ccb9960a044 355 //Read chunk header
donatien 0:2ccb9960a044 356 crlfPos=0;
donatien 0:2ccb9960a044 357 for(crlfPos++; crlfPos < trfLen - 2; crlfPos++)
donatien 0:2ccb9960a044 358 {
donatien 0:2ccb9960a044 359 if( buf[crlfPos] == '\r' && buf[crlfPos + 1] == '\n' )
donatien 0:2ccb9960a044 360 {
donatien 0:2ccb9960a044 361 break;
donatien 0:2ccb9960a044 362 }
donatien 0:2ccb9960a044 363 }
donatien 0:2ccb9960a044 364 if(crlfPos >= trfLen - 2) //Try to read more
donatien 0:2ccb9960a044 365 {
donatien 0:2ccb9960a044 366 if( trfLen < CHUNK_SIZE )
donatien 0:2ccb9960a044 367 {
donatien 0:2ccb9960a044 368 size_t newTrfLen;
donatien 0:2ccb9960a044 369 ret = recv(buf + trfLen, 0, CHUNK_SIZE - trfLen - 1, &newTrfLen);
donatien 0:2ccb9960a044 370 trfLen += newTrfLen;
donatien 0:2ccb9960a044 371 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 372 continue;
donatien 0:2ccb9960a044 373 }
donatien 0:2ccb9960a044 374 else
donatien 0:2ccb9960a044 375 {
donatien 0:2ccb9960a044 376 goto prtclerr;
donatien 0:2ccb9960a044 377 }
donatien 0:2ccb9960a044 378 }
donatien 0:2ccb9960a044 379 buf[crlfPos] = '\0';
donatien 0:2ccb9960a044 380 int n = sscanf(buf, "%x", &readLen);
donatien 0:2ccb9960a044 381 if(n!=1)
donatien 0:2ccb9960a044 382 {
donatien 0:2ccb9960a044 383 ERR("Could not read chunk length");
donatien 0:2ccb9960a044 384 goto prtclerr;
donatien 0:2ccb9960a044 385 }
donatien 0:2ccb9960a044 386
donatien 0:2ccb9960a044 387 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2));
donatien 0:2ccb9960a044 388 trfLen -= (crlfPos + 2);
donatien 0:2ccb9960a044 389
donatien 0:2ccb9960a044 390 if( readLen == 0 )
donatien 0:2ccb9960a044 391 {
donatien 0:2ccb9960a044 392 //Last chunk
donatien 0:2ccb9960a044 393 break;
donatien 0:2ccb9960a044 394 }
donatien 0:2ccb9960a044 395 }
donatien 0:2ccb9960a044 396 else
donatien 0:2ccb9960a044 397 {
donatien 0:2ccb9960a044 398 readLen = recvContentLength;
donatien 0:2ccb9960a044 399 }
donatien 0:2ccb9960a044 400
donatien 0:2ccb9960a044 401 DBG("Retrieving %d bytes", readLen);
donatien 0:2ccb9960a044 402
donatien 0:2ccb9960a044 403 do
donatien 0:2ccb9960a044 404 {
donatien 0:2ccb9960a044 405 pDataIn->write(buf, MIN(trfLen, readLen));
donatien 0:2ccb9960a044 406 if( trfLen > readLen )
donatien 0:2ccb9960a044 407 {
donatien 0:2ccb9960a044 408 memmove(buf, &buf[readLen], trfLen - readLen);
donatien 0:2ccb9960a044 409 trfLen -= readLen;
donatien 0:2ccb9960a044 410 readLen = 0;
donatien 0:2ccb9960a044 411 }
donatien 0:2ccb9960a044 412 else
donatien 0:2ccb9960a044 413 {
donatien 0:2ccb9960a044 414 readLen -= trfLen;
donatien 0:2ccb9960a044 415 }
donatien 0:2ccb9960a044 416
donatien 0:2ccb9960a044 417 if(readLen)
donatien 0:2ccb9960a044 418 {
donatien 0:2ccb9960a044 419 ret = recv(buf, 1, CHUNK_SIZE - trfLen - 1, &trfLen);
donatien 0:2ccb9960a044 420 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 421
donatien 0:2ccb9960a044 422 }
donatien 0:2ccb9960a044 423 } while(readLen);
donatien 0:2ccb9960a044 424
donatien 0:2ccb9960a044 425 if( recvChunked )
donatien 0:2ccb9960a044 426 {
donatien 0:2ccb9960a044 427 if(trfLen < 2)
donatien 0:2ccb9960a044 428 {
donatien 0:2ccb9960a044 429 size_t newTrfLen;
donatien 0:2ccb9960a044 430 //Read missing chars to find end of chunk
donatien 0:2ccb9960a044 431 ret = recv(buf, 2 - trfLen, CHUNK_SIZE, &newTrfLen);
donatien 0:2ccb9960a044 432 if(ret != OK) goto connerr;
donatien 0:2ccb9960a044 433 trfLen += newTrfLen;
donatien 0:2ccb9960a044 434 }
donatien 0:2ccb9960a044 435 if( (buf[0] != '\r') || (buf[1] != '\n') )
donatien 0:2ccb9960a044 436 {
donatien 0:2ccb9960a044 437 ERR("Format error");
donatien 0:2ccb9960a044 438 goto prtclerr;
donatien 0:2ccb9960a044 439 }
donatien 0:2ccb9960a044 440 memmove(buf, &buf[2], trfLen - 2);
donatien 0:2ccb9960a044 441 trfLen -= 2;
donatien 0:2ccb9960a044 442 }
donatien 0:2ccb9960a044 443 else
donatien 0:2ccb9960a044 444 {
donatien 0:2ccb9960a044 445 break;
donatien 0:2ccb9960a044 446 }
donatien 0:2ccb9960a044 447
donatien 0:2ccb9960a044 448 }
donatien 0:2ccb9960a044 449
donatien 0:2ccb9960a044 450 socket::close(m_sock);
donatien 0:2ccb9960a044 451 DBG("Completed HTTP transaction");
donatien 0:2ccb9960a044 452
donatien 0:2ccb9960a044 453 return OK;
donatien 0:2ccb9960a044 454
donatien 0:2ccb9960a044 455 connerr:
donatien 0:2ccb9960a044 456 socket::close(m_sock);
donatien 0:2ccb9960a044 457 ERR("Connection error (%d)", ret);
donatien 0:2ccb9960a044 458 return NET_CONN;
donatien 0:2ccb9960a044 459
donatien 0:2ccb9960a044 460 prtclerr:
donatien 0:2ccb9960a044 461 socket::close(m_sock);
donatien 0:2ccb9960a044 462 ERR("Protocol error");
donatien 0:2ccb9960a044 463 return NET_PROTOCOL;
donatien 0:2ccb9960a044 464
donatien 0:2ccb9960a044 465 }
donatien 0:2ccb9960a044 466
donatien 0:2ccb9960a044 467 int HTTPClient::recv(char* buf, size_t minLen, size_t maxLen, size_t* pReadLen) //0 on success, err code on failure
donatien 0:2ccb9960a044 468 {
donatien 0:2ccb9960a044 469 DBG("Trying to read between %d and %d bytes", minLen, maxLen);
donatien 0:2ccb9960a044 470 size_t readLen = 0;
donatien 0:2ccb9960a044 471 while(readLen < minLen)
donatien 0:2ccb9960a044 472 {
donatien 0:2ccb9960a044 473 //Wait for socket to be readable
donatien 0:2ccb9960a044 474 //Creating FS set
donatien 0:2ccb9960a044 475 fd_set socksSet;
donatien 0:2ccb9960a044 476 FD_ZERO(&socksSet);
donatien 0:2ccb9960a044 477 FD_SET(m_sock, &socksSet);
donatien 0:2ccb9960a044 478 struct timeval t_val;
donatien 0:2ccb9960a044 479 t_val.tv_sec = m_timeout / 1000;
donatien 0:2ccb9960a044 480 t_val.tv_usec = (m_timeout - (t_val.tv_sec * 1000)) * 1000;
donatien 0:2ccb9960a044 481 int ret = socket::select(FD_SETSIZE, &socksSet, NULL, NULL, &t_val);
donatien 0:2ccb9960a044 482 if(ret <= 0 || !FD_ISSET(m_sock, &socksSet))
donatien 0:2ccb9960a044 483 {
donatien 0:2ccb9960a044 484 WARN("Timeout");
donatien 0:2ccb9960a044 485 return NET_TIMEOUT; //Timeout
donatien 0:2ccb9960a044 486 }
donatien 0:2ccb9960a044 487
donatien 0:2ccb9960a044 488 ret = socket::recv(m_sock, buf + readLen, maxLen - readLen, 0);
donatien 0:2ccb9960a044 489 if( ret > 0)
donatien 0:2ccb9960a044 490 {
donatien 0:2ccb9960a044 491 readLen += ret;
donatien 0:2ccb9960a044 492 continue;
donatien 0:2ccb9960a044 493 }
donatien 0:2ccb9960a044 494 else if( ret == 0 )
donatien 0:2ccb9960a044 495 {
donatien 0:2ccb9960a044 496 WARN("Connection was closed by server");
donatien 0:2ccb9960a044 497 return NET_CLOSED; //Connection was closed by server
donatien 0:2ccb9960a044 498 }
donatien 0:2ccb9960a044 499 else
donatien 0:2ccb9960a044 500 {
donatien 0:2ccb9960a044 501 ERR("Connection error (recv returned %d)", ret);
donatien 0:2ccb9960a044 502 return NET_CONN;
donatien 0:2ccb9960a044 503 }
donatien 0:2ccb9960a044 504 }
donatien 0:2ccb9960a044 505 *pReadLen = readLen;
donatien 0:2ccb9960a044 506 DBG("Read %d bytes", readLen);
donatien 0:2ccb9960a044 507 return OK;
donatien 0:2ccb9960a044 508 }
donatien 0:2ccb9960a044 509
donatien 0:2ccb9960a044 510 int HTTPClient::send(char* buf, size_t len) //0 on success, err code on failure
donatien 0:2ccb9960a044 511 {
donatien 0:2ccb9960a044 512 if(len == 0)
donatien 0:2ccb9960a044 513 {
donatien 0:2ccb9960a044 514 len = strlen(buf);
donatien 0:2ccb9960a044 515 }
donatien 0:2ccb9960a044 516 DBG("Trying to write %d bytes", len);
donatien 0:2ccb9960a044 517 size_t writtenLen = 0;
donatien 0:2ccb9960a044 518 while(writtenLen < len)
donatien 0:2ccb9960a044 519 {
donatien 0:2ccb9960a044 520 //Wait for socket to be writeable
donatien 0:2ccb9960a044 521 //Creating FS set
donatien 0:2ccb9960a044 522 fd_set socksSet;
donatien 0:2ccb9960a044 523 FD_ZERO(&socksSet);
donatien 0:2ccb9960a044 524 FD_SET(m_sock, &socksSet);
donatien 0:2ccb9960a044 525 struct timeval t_val;
donatien 0:2ccb9960a044 526 t_val.tv_sec = m_timeout / 1000;
donatien 0:2ccb9960a044 527 t_val.tv_usec = (m_timeout - (t_val.tv_sec * 1000)) * 1000;
donatien 0:2ccb9960a044 528 int ret = socket::select(FD_SETSIZE, NULL, &socksSet, NULL, &t_val);
donatien 0:2ccb9960a044 529 if(ret <= 0 || !FD_ISSET(m_sock, &socksSet))
donatien 0:2ccb9960a044 530 {
donatien 0:2ccb9960a044 531 WARN("Timeout");
donatien 0:2ccb9960a044 532 return NET_TIMEOUT; //Timeout
donatien 0:2ccb9960a044 533 }
donatien 0:2ccb9960a044 534
donatien 0:2ccb9960a044 535 ret = socket::send(m_sock, buf + writtenLen, len - writtenLen, 0);
donatien 0:2ccb9960a044 536 if( ret > 0)
donatien 0:2ccb9960a044 537 {
donatien 0:2ccb9960a044 538 writtenLen += ret;
donatien 0:2ccb9960a044 539 continue;
donatien 0:2ccb9960a044 540 }
donatien 0:2ccb9960a044 541 else if( ret == 0 )
donatien 0:2ccb9960a044 542 {
donatien 0:2ccb9960a044 543 WARN("Connection was closed by server");
donatien 0:2ccb9960a044 544 return NET_CLOSED; //Connection was closed by server
donatien 0:2ccb9960a044 545 }
donatien 0:2ccb9960a044 546 else
donatien 0:2ccb9960a044 547 {
donatien 0:2ccb9960a044 548 ERR("Connection error (recv returned %d)", ret);
donatien 0:2ccb9960a044 549 return NET_CONN;
donatien 0:2ccb9960a044 550 }
donatien 0:2ccb9960a044 551 }
donatien 0:2ccb9960a044 552 DBG("Written %d bytes", writtenLen);
donatien 0:2ccb9960a044 553 return OK;
donatien 0:2ccb9960a044 554 }
donatien 0:2ccb9960a044 555
donatien 0:2ccb9960a044 556 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 557 {
donatien 0:2ccb9960a044 558 char* schemePtr = (char*) url;
donatien 0:2ccb9960a044 559 char* hostPtr = (char*) strstr(url, "://");
donatien 0:2ccb9960a044 560 if(hostPtr == NULL)
donatien 0:2ccb9960a044 561 {
donatien 0:2ccb9960a044 562 WARN("Could not find host");
donatien 0:2ccb9960a044 563 return NET_INVALID; //URL is invalid
donatien 0:2ccb9960a044 564 }
donatien 0:2ccb9960a044 565
donatien 0:2ccb9960a044 566 if( maxSchemeLen < hostPtr - schemePtr + 1 ) //including NULL-terminating char
donatien 0:2ccb9960a044 567 {
donatien 0:2ccb9960a044 568 WARN("Scheme str is too small (%d >= %d)", maxSchemeLen, hostPtr - schemePtr + 1);
donatien 0:2ccb9960a044 569 return NET_TOOSMALL;
donatien 0:2ccb9960a044 570 }
donatien 0:2ccb9960a044 571 memcpy(scheme, schemePtr, hostPtr - schemePtr);
donatien 0:2ccb9960a044 572 scheme[hostPtr - schemePtr] = '\0';
donatien 0:2ccb9960a044 573
donatien 0:2ccb9960a044 574 hostPtr+=3;
donatien 0:2ccb9960a044 575
donatien 0:2ccb9960a044 576 size_t hostLen = 0;
donatien 0:2ccb9960a044 577
donatien 0:2ccb9960a044 578 char* portPtr = strchr(hostPtr, ':');
donatien 0:2ccb9960a044 579 if( portPtr != NULL )
donatien 0:2ccb9960a044 580 {
donatien 0:2ccb9960a044 581 hostLen = portPtr - hostPtr;
donatien 0:2ccb9960a044 582 portPtr++;
donatien 0:2ccb9960a044 583 if( sscanf(portPtr, "%d", &port) != 1)
donatien 0:2ccb9960a044 584 {
donatien 0:2ccb9960a044 585 WARN("Could not find port");
donatien 0:2ccb9960a044 586 return NET_INVALID;
donatien 0:2ccb9960a044 587 }
donatien 0:2ccb9960a044 588 }
donatien 0:2ccb9960a044 589 else
donatien 0:2ccb9960a044 590 {
donatien 0:2ccb9960a044 591 *port=0;
donatien 0:2ccb9960a044 592 }
donatien 0:2ccb9960a044 593 char* pathPtr = strchr(hostPtr, '/');
donatien 0:2ccb9960a044 594 if( hostLen == 0 )
donatien 0:2ccb9960a044 595 {
donatien 0:2ccb9960a044 596 hostLen = pathPtr - hostPtr;
donatien 0:2ccb9960a044 597 }
donatien 0:2ccb9960a044 598
donatien 0:2ccb9960a044 599 if( maxHostLen < hostLen + 1 ) //including NULL-terminating char
donatien 0:2ccb9960a044 600 {
donatien 0:2ccb9960a044 601 WARN("Host str is too small (%d >= %d)", maxHostLen, hostLen + 1);
donatien 0:2ccb9960a044 602 return NET_TOOSMALL;
donatien 0:2ccb9960a044 603 }
donatien 0:2ccb9960a044 604 memcpy(host, hostPtr, hostLen);
donatien 0:2ccb9960a044 605 host[hostLen] = '\0';
donatien 0:2ccb9960a044 606
donatien 0:2ccb9960a044 607 size_t pathLen;
donatien 0:2ccb9960a044 608 char* fragmentPtr = strchr(hostPtr, '#');
donatien 0:2ccb9960a044 609 if(fragmentPtr != NULL)
donatien 0:2ccb9960a044 610 {
donatien 0:2ccb9960a044 611 pathLen = fragmentPtr - pathPtr;
donatien 0:2ccb9960a044 612 }
donatien 0:2ccb9960a044 613 else
donatien 0:2ccb9960a044 614 {
donatien 0:2ccb9960a044 615 pathLen = strlen(pathPtr);
donatien 0:2ccb9960a044 616 }
donatien 0:2ccb9960a044 617
donatien 0:2ccb9960a044 618 if( maxPathLen < pathLen + 1 ) //including NULL-terminating char
donatien 0:2ccb9960a044 619 {
donatien 0:2ccb9960a044 620 WARN("Path str is too small (%d >= %d)", maxPathLen, pathLen + 1);
donatien 0:2ccb9960a044 621 return NET_TOOSMALL;
donatien 0:2ccb9960a044 622 }
donatien 0:2ccb9960a044 623 memcpy(path, pathPtr, pathLen);
donatien 0:2ccb9960a044 624 path[pathLen] = '\0';
donatien 0:2ccb9960a044 625
donatien 0:2ccb9960a044 626 return OK;
donatien 0:2ccb9960a044 627 }
donatien 0:2ccb9960a044 628