Committer:
donatien
Date:
Fri Jul 06 10:22:15 2012 +0000
Revision:
0:7aca7353eebf
Fixed parseURL issue for port parsing

Who changed what in which revision?

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