Simple IoT Board用のライブラリです。 ESP8266ライブラリの軽量化 送信のみのソフトシリアルライブラリを含んでいます。

Dependents:   SITB_HttpGetSample SITB_IFTTTSample SITB_INA226PRC AmbientExampleSITB ... more

Committer:
jksoft
Date:
Sun Nov 15 13:36:44 2015 +0000
Revision:
0:890c12951e96
??

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jksoft 0:890c12951e96 1 /* HTTPClient.cpp */
jksoft 0:890c12951e96 2 /* Copyright (C) 2012 mbed.org, MIT License
jksoft 0:890c12951e96 3 *
jksoft 0:890c12951e96 4 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
jksoft 0:890c12951e96 5 * and associated documentation files (the "Software"), to deal in the Software without restriction,
jksoft 0:890c12951e96 6 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
jksoft 0:890c12951e96 7 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
jksoft 0:890c12951e96 8 * furnished to do so, subject to the following conditions:
jksoft 0:890c12951e96 9 *
jksoft 0:890c12951e96 10 * The above copyright notice and this permission notice shall be included in all copies or
jksoft 0:890c12951e96 11 * substantial portions of the Software.
jksoft 0:890c12951e96 12 *
jksoft 0:890c12951e96 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
jksoft 0:890c12951e96 14 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
jksoft 0:890c12951e96 15 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
jksoft 0:890c12951e96 16 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
jksoft 0:890c12951e96 17 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
jksoft 0:890c12951e96 18 */
jksoft 0:890c12951e96 19
jksoft 0:890c12951e96 20 //Debug is disabled by default
jksoft 0:890c12951e96 21 #if 0
jksoft 0:890c12951e96 22 //Enable debug
jksoft 0:890c12951e96 23 #include <cstdio>
jksoft 0:890c12951e96 24 #define DBG(x, ...) std::printf("[HTTPClient : DBG]"x"\r\n", ##__VA_ARGS__);
jksoft 0:890c12951e96 25 #define WARN(x, ...) std::printf("[HTTPClient : WARN]"x"\r\n", ##__VA_ARGS__);
jksoft 0:890c12951e96 26 #define ERR(x, ...) std::printf("[HTTPClient : ERR]"x"\r\n", ##__VA_ARGS__);
jksoft 0:890c12951e96 27
jksoft 0:890c12951e96 28 #else
jksoft 0:890c12951e96 29 //Disable debug
jksoft 0:890c12951e96 30 #define DBG(x, ...)
jksoft 0:890c12951e96 31 #define WARN(x, ...)
jksoft 0:890c12951e96 32 #define ERR(x, ...)
jksoft 0:890c12951e96 33
jksoft 0:890c12951e96 34 #endif
jksoft 0:890c12951e96 35
jksoft 0:890c12951e96 36 #define HTTP_PORT 80
jksoft 0:890c12951e96 37
jksoft 0:890c12951e96 38 #define OK 0
jksoft 0:890c12951e96 39
jksoft 0:890c12951e96 40 #define MIN(x,y) (((x)<(y))?(x):(y))
jksoft 0:890c12951e96 41 #define MAX(x,y) (((x)>(y))?(x):(y))
jksoft 0:890c12951e96 42
jksoft 0:890c12951e96 43 #define CHUNK_SIZE 256
jksoft 0:890c12951e96 44
jksoft 0:890c12951e96 45 #include <cstring>
jksoft 0:890c12951e96 46
jksoft 0:890c12951e96 47 #include "HTTPClient.h"
jksoft 0:890c12951e96 48
jksoft 0:890c12951e96 49
jksoft 0:890c12951e96 50 HTTPClient::HTTPClient() :
jksoft 0:890c12951e96 51 m_sock(), m_basicAuthUser(NULL), m_basicAuthPassword(NULL), m_httpResponseCode(0)
jksoft 0:890c12951e96 52 {
jksoft 0:890c12951e96 53
jksoft 0:890c12951e96 54 }
jksoft 0:890c12951e96 55
jksoft 0:890c12951e96 56 HTTPClient::~HTTPClient()
jksoft 0:890c12951e96 57 {
jksoft 0:890c12951e96 58
jksoft 0:890c12951e96 59 }
jksoft 0:890c12951e96 60
jksoft 0:890c12951e96 61 #if 0
jksoft 0:890c12951e96 62 void HTTPClient::basicAuth(const char* user, const char* password) //Basic Authentification
jksoft 0:890c12951e96 63 {
jksoft 0:890c12951e96 64 m_basicAuthUser = user;
jksoft 0:890c12951e96 65 m_basicAuthPassword = password;
jksoft 0:890c12951e96 66 }
jksoft 0:890c12951e96 67 #endif
jksoft 0:890c12951e96 68
jksoft 0:890c12951e96 69 HTTPResult HTTPClient::get(const char* url, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
jksoft 0:890c12951e96 70 {
jksoft 0:890c12951e96 71 return connect(url, HTTP_GET, NULL, pDataIn, timeout);
jksoft 0:890c12951e96 72 }
jksoft 0:890c12951e96 73
jksoft 0:890c12951e96 74 HTTPResult HTTPClient::get(const char* url, char* result, size_t maxResultLen, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
jksoft 0:890c12951e96 75 {
jksoft 0:890c12951e96 76 HTTPText str(result, maxResultLen);
jksoft 0:890c12951e96 77 return get(url, &str, timeout);
jksoft 0:890c12951e96 78 }
jksoft 0:890c12951e96 79
jksoft 0:890c12951e96 80 HTTPResult HTTPClient::post(const char* url, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
jksoft 0:890c12951e96 81 {
jksoft 0:890c12951e96 82 return connect(url, HTTP_POST, (IHTTPDataOut*)&dataOut, pDataIn, timeout);
jksoft 0:890c12951e96 83 }
jksoft 0:890c12951e96 84
jksoft 0:890c12951e96 85 HTTPResult HTTPClient::put(const char* url, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
jksoft 0:890c12951e96 86 {
jksoft 0:890c12951e96 87 return connect(url, HTTP_PUT, (IHTTPDataOut*)&dataOut, pDataIn, timeout);
jksoft 0:890c12951e96 88 }
jksoft 0:890c12951e96 89
jksoft 0:890c12951e96 90 HTTPResult HTTPClient::del(const char* url, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
jksoft 0:890c12951e96 91 {
jksoft 0:890c12951e96 92 return connect(url, HTTP_DELETE, NULL, pDataIn, timeout);
jksoft 0:890c12951e96 93 }
jksoft 0:890c12951e96 94
jksoft 0:890c12951e96 95
jksoft 0:890c12951e96 96 int HTTPClient::getHTTPResponseCode()
jksoft 0:890c12951e96 97 {
jksoft 0:890c12951e96 98 return m_httpResponseCode;
jksoft 0:890c12951e96 99 }
jksoft 0:890c12951e96 100
jksoft 0:890c12951e96 101 #define CHECK_CONN_ERR(ret) \
jksoft 0:890c12951e96 102 do{ \
jksoft 0:890c12951e96 103 if(ret) { \
jksoft 0:890c12951e96 104 m_sock.close(); \
jksoft 0:890c12951e96 105 ERR("Connection error (%d)", ret); \
jksoft 0:890c12951e96 106 return HTTP_CONN; \
jksoft 0:890c12951e96 107 } \
jksoft 0:890c12951e96 108 } while(0)
jksoft 0:890c12951e96 109
jksoft 0:890c12951e96 110 #define PRTCL_ERR() \
jksoft 0:890c12951e96 111 do{ \
jksoft 0:890c12951e96 112 m_sock.close(); \
jksoft 0:890c12951e96 113 ERR("Protocol error"); \
jksoft 0:890c12951e96 114 return HTTP_PRTCL; \
jksoft 0:890c12951e96 115 } while(0)
jksoft 0:890c12951e96 116
jksoft 0:890c12951e96 117 HTTPResult HTTPClient::connect(const char* url, HTTP_METH method, IHTTPDataOut* pDataOut, IHTTPDataIn* pDataIn, int timeout) //Execute request
jksoft 0:890c12951e96 118 {
jksoft 0:890c12951e96 119 m_httpResponseCode = 0; //Invalidate code
jksoft 0:890c12951e96 120 m_timeout = timeout;
jksoft 0:890c12951e96 121
jksoft 0:890c12951e96 122 pDataIn->writeReset();
jksoft 0:890c12951e96 123 if( pDataOut )
jksoft 0:890c12951e96 124 {
jksoft 0:890c12951e96 125 pDataOut->readReset();
jksoft 0:890c12951e96 126 }
jksoft 0:890c12951e96 127
jksoft 0:890c12951e96 128 char scheme[8];
jksoft 0:890c12951e96 129 uint16_t port;
jksoft 0:890c12951e96 130 char host[32];
jksoft 0:890c12951e96 131 char path[64];
jksoft 0:890c12951e96 132 //First we need to parse the url (http[s]://host[:port][/[path]]) -- HTTPS not supported (yet?)
jksoft 0:890c12951e96 133 HTTPResult res = parseURL(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path));
jksoft 0:890c12951e96 134 if(res != HTTP_OK)
jksoft 0:890c12951e96 135 {
jksoft 0:890c12951e96 136 ERR("parseURL returned %d", res);
jksoft 0:890c12951e96 137 return res;
jksoft 0:890c12951e96 138 }
jksoft 0:890c12951e96 139
jksoft 0:890c12951e96 140 if(port == 0) //TODO do handle HTTPS->443
jksoft 0:890c12951e96 141 {
jksoft 0:890c12951e96 142 port = 80;
jksoft 0:890c12951e96 143 }
jksoft 0:890c12951e96 144
jksoft 0:890c12951e96 145 DBG("Scheme: %s", scheme);
jksoft 0:890c12951e96 146 DBG("Host: %s", host);
jksoft 0:890c12951e96 147 DBG("Port: %d", port);
jksoft 0:890c12951e96 148 DBG("Path: %s", path);
jksoft 0:890c12951e96 149
jksoft 0:890c12951e96 150 //Connect
jksoft 0:890c12951e96 151 DBG("Connecting socket to server");
jksoft 0:890c12951e96 152 int ret = m_sock.connect(host, port);
jksoft 0:890c12951e96 153 if (ret < 0)
jksoft 0:890c12951e96 154 {
jksoft 0:890c12951e96 155 m_sock.close();
jksoft 0:890c12951e96 156 ERR("Could not connect");
jksoft 0:890c12951e96 157 return HTTP_CONN;
jksoft 0:890c12951e96 158 }
jksoft 0:890c12951e96 159 //Send request
jksoft 0:890c12951e96 160 DBG("Sending request");
jksoft 0:890c12951e96 161 char buf[CHUNK_SIZE];
jksoft 0:890c12951e96 162 const char* meth = (method==HTTP_GET)?"GET":(method==HTTP_POST)?"POST":(method==HTTP_PUT)?"PUT":(method==HTTP_DELETE)?"DELETE":"";
jksoft 0:890c12951e96 163 snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\n", meth, path, host); //Write request
jksoft 0:890c12951e96 164 ret = send(buf);
jksoft 0:890c12951e96 165 if(ret)
jksoft 0:890c12951e96 166 {
jksoft 0:890c12951e96 167 m_sock.close();
jksoft 0:890c12951e96 168 ERR("Could not write request");
jksoft 0:890c12951e96 169 return HTTP_CONN;
jksoft 0:890c12951e96 170 }
jksoft 0:890c12951e96 171
jksoft 0:890c12951e96 172 //Send all headers
jksoft 0:890c12951e96 173
jksoft 0:890c12951e96 174 //Send default headers
jksoft 0:890c12951e96 175 DBG("Sending headers");
jksoft 0:890c12951e96 176 if( pDataOut != NULL )
jksoft 0:890c12951e96 177 {
jksoft 0:890c12951e96 178 if( pDataOut->getIsChunked() )
jksoft 0:890c12951e96 179 {
jksoft 0:890c12951e96 180 ret = send("Transfer-Encoding: chunked\r\n");
jksoft 0:890c12951e96 181 CHECK_CONN_ERR(ret);
jksoft 0:890c12951e96 182 }
jksoft 0:890c12951e96 183 else
jksoft 0:890c12951e96 184 {
jksoft 0:890c12951e96 185 snprintf(buf, sizeof(buf), "Content-Length: %d\r\n", pDataOut->getDataLen());
jksoft 0:890c12951e96 186 ret = send(buf);
jksoft 0:890c12951e96 187 CHECK_CONN_ERR(ret);
jksoft 0:890c12951e96 188 }
jksoft 0:890c12951e96 189 char type[48];
jksoft 0:890c12951e96 190 if( pDataOut->getDataType(type, 48) == HTTP_OK )
jksoft 0:890c12951e96 191 {
jksoft 0:890c12951e96 192 snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", type);
jksoft 0:890c12951e96 193 ret = send(buf);
jksoft 0:890c12951e96 194 CHECK_CONN_ERR(ret);
jksoft 0:890c12951e96 195 }
jksoft 0:890c12951e96 196
jksoft 0:890c12951e96 197 //Send specific headers
jksoft 0:890c12951e96 198 while( pDataOut->getHeader(buf, sizeof(buf) - 3) ) //must have space left for CRLF + 0 terminating char
jksoft 0:890c12951e96 199 {
jksoft 0:890c12951e96 200 size_t headerlen = strlen(buf);
jksoft 0:890c12951e96 201 snprintf(buf + headerlen, sizeof(buf) - headerlen, "\r\n");
jksoft 0:890c12951e96 202 ret = send(buf);
jksoft 0:890c12951e96 203 CHECK_CONN_ERR(ret);
jksoft 0:890c12951e96 204 }
jksoft 0:890c12951e96 205 }
jksoft 0:890c12951e96 206
jksoft 0:890c12951e96 207 //Send specific headers
jksoft 0:890c12951e96 208 while( pDataIn->getHeader(buf, sizeof(buf) - 3) )
jksoft 0:890c12951e96 209 {
jksoft 0:890c12951e96 210 size_t headerlen = strlen(buf);
jksoft 0:890c12951e96 211 snprintf(buf + headerlen, sizeof(buf) - headerlen, "\r\n");
jksoft 0:890c12951e96 212 ret = send(buf);
jksoft 0:890c12951e96 213 CHECK_CONN_ERR(ret);
jksoft 0:890c12951e96 214 }
jksoft 0:890c12951e96 215
jksoft 0:890c12951e96 216 //Close headers
jksoft 0:890c12951e96 217 DBG("Headers sent");
jksoft 0:890c12951e96 218 ret = send("\r\n");
jksoft 0:890c12951e96 219 CHECK_CONN_ERR(ret);
jksoft 0:890c12951e96 220
jksoft 0:890c12951e96 221 size_t trfLen;
jksoft 0:890c12951e96 222
jksoft 0:890c12951e96 223 //Send data (if available)
jksoft 0:890c12951e96 224 if( pDataOut != NULL )
jksoft 0:890c12951e96 225 {
jksoft 0:890c12951e96 226 DBG("Sending data");
jksoft 0:890c12951e96 227 while(true)
jksoft 0:890c12951e96 228 {
jksoft 0:890c12951e96 229 size_t writtenLen = 0;
jksoft 0:890c12951e96 230 pDataOut->read(buf, CHUNK_SIZE, &trfLen);
jksoft 0:890c12951e96 231 if( pDataOut->getIsChunked() )
jksoft 0:890c12951e96 232 {
jksoft 0:890c12951e96 233 //Write chunk header
jksoft 0:890c12951e96 234 char chunkHeader[16];
jksoft 0:890c12951e96 235 snprintf(chunkHeader, sizeof(chunkHeader), "%X\r\n", trfLen); //In hex encoding
jksoft 0:890c12951e96 236 ret = send(chunkHeader);
jksoft 0:890c12951e96 237 CHECK_CONN_ERR(ret);
jksoft 0:890c12951e96 238 }
jksoft 0:890c12951e96 239 else if( trfLen == 0 )
jksoft 0:890c12951e96 240 {
jksoft 0:890c12951e96 241 break;
jksoft 0:890c12951e96 242 }
jksoft 0:890c12951e96 243 if( trfLen != 0 )
jksoft 0:890c12951e96 244 {
jksoft 0:890c12951e96 245 ret = send(buf, trfLen);
jksoft 0:890c12951e96 246 CHECK_CONN_ERR(ret);
jksoft 0:890c12951e96 247 }
jksoft 0:890c12951e96 248
jksoft 0:890c12951e96 249 if( pDataOut->getIsChunked() )
jksoft 0:890c12951e96 250 {
jksoft 0:890c12951e96 251 ret = send("\r\n"); //Chunk-terminating CRLF
jksoft 0:890c12951e96 252 CHECK_CONN_ERR(ret);
jksoft 0:890c12951e96 253 }
jksoft 0:890c12951e96 254 else
jksoft 0:890c12951e96 255 {
jksoft 0:890c12951e96 256 writtenLen += trfLen;
jksoft 0:890c12951e96 257 if( writtenLen >= pDataOut->getDataLen() )
jksoft 0:890c12951e96 258 {
jksoft 0:890c12951e96 259 break;
jksoft 0:890c12951e96 260 }
jksoft 0:890c12951e96 261 }
jksoft 0:890c12951e96 262
jksoft 0:890c12951e96 263 if( trfLen == 0 )
jksoft 0:890c12951e96 264 {
jksoft 0:890c12951e96 265 break;
jksoft 0:890c12951e96 266 }
jksoft 0:890c12951e96 267 }
jksoft 0:890c12951e96 268 }
jksoft 0:890c12951e96 269
jksoft 0:890c12951e96 270 //Receive response
jksoft 0:890c12951e96 271 DBG("Receiving response");
jksoft 0:890c12951e96 272 ret = recv(buf, 1, CHUNK_SIZE - 1, &trfLen); //Read n bytes
jksoft 0:890c12951e96 273 CHECK_CONN_ERR(ret);
jksoft 0:890c12951e96 274
jksoft 0:890c12951e96 275 buf[trfLen] = '\0';
jksoft 0:890c12951e96 276
jksoft 0:890c12951e96 277 //Make sure we got the first response line
jksoft 0:890c12951e96 278 char* crlfPtr = NULL;
jksoft 0:890c12951e96 279 while( true )
jksoft 0:890c12951e96 280 {
jksoft 0:890c12951e96 281 crlfPtr = strstr(buf, "\r\n");
jksoft 0:890c12951e96 282 if(crlfPtr == NULL)
jksoft 0:890c12951e96 283 {
jksoft 0:890c12951e96 284 if( trfLen < CHUNK_SIZE - 1 )
jksoft 0:890c12951e96 285 {
jksoft 0:890c12951e96 286 size_t newTrfLen;
jksoft 0:890c12951e96 287 ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen);
jksoft 0:890c12951e96 288 trfLen += newTrfLen;
jksoft 0:890c12951e96 289 buf[trfLen] = '\0';
jksoft 0:890c12951e96 290 DBG("Read %d chars; In buf: [%s]", newTrfLen, buf);
jksoft 0:890c12951e96 291 CHECK_CONN_ERR(ret);
jksoft 0:890c12951e96 292 continue;
jksoft 0:890c12951e96 293 }
jksoft 0:890c12951e96 294 else
jksoft 0:890c12951e96 295 {
jksoft 0:890c12951e96 296 PRTCL_ERR();
jksoft 0:890c12951e96 297 }
jksoft 0:890c12951e96 298 }
jksoft 0:890c12951e96 299 break;
jksoft 0:890c12951e96 300 }
jksoft 0:890c12951e96 301
jksoft 0:890c12951e96 302 int crlfPos = crlfPtr - buf;
jksoft 0:890c12951e96 303 buf[crlfPos] = '\0';
jksoft 0:890c12951e96 304
jksoft 0:890c12951e96 305 //Parse HTTP response
jksoft 0:890c12951e96 306 //if( sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 )
jksoft 0:890c12951e96 307 if(crlfPos > 13)
jksoft 0:890c12951e96 308 {
jksoft 0:890c12951e96 309 buf[13] = '\0';
jksoft 0:890c12951e96 310 }
jksoft 0:890c12951e96 311 if( sscanf(buf, "HTTP/%*d.%*d %d", &m_httpResponseCode) != 1 ) //Kludge for newlib nano
jksoft 0:890c12951e96 312 {
jksoft 0:890c12951e96 313 //Cannot match string, error
jksoft 0:890c12951e96 314 ERR("Not a correct HTTP answer : %s\n", buf);
jksoft 0:890c12951e96 315 PRTCL_ERR();
jksoft 0:890c12951e96 316 }
jksoft 0:890c12951e96 317
jksoft 0:890c12951e96 318 if( (m_httpResponseCode < 200) || (m_httpResponseCode >= 300) )
jksoft 0:890c12951e96 319 {
jksoft 0:890c12951e96 320 //Did not return a 2xx code; TODO fetch headers/(&data?) anyway and implement a mean of writing/reading headers
jksoft 0:890c12951e96 321 WARN("Response code %d", m_httpResponseCode);
jksoft 0:890c12951e96 322 PRTCL_ERR();
jksoft 0:890c12951e96 323 }
jksoft 0:890c12951e96 324
jksoft 0:890c12951e96 325 DBG("Reading headers");
jksoft 0:890c12951e96 326
jksoft 0:890c12951e96 327 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well
jksoft 0:890c12951e96 328 trfLen -= (crlfPos + 2);
jksoft 0:890c12951e96 329
jksoft 0:890c12951e96 330 size_t recvContentLength = 0;
jksoft 0:890c12951e96 331 bool recvChunked = false;
jksoft 0:890c12951e96 332 bool recvLengthUnknown = true;
jksoft 0:890c12951e96 333 //Now get headers
jksoft 0:890c12951e96 334 while( true )
jksoft 0:890c12951e96 335 {
jksoft 0:890c12951e96 336 crlfPtr = strstr(buf, "\r\n");
jksoft 0:890c12951e96 337 if(crlfPtr == NULL)
jksoft 0:890c12951e96 338 {
jksoft 0:890c12951e96 339 if( trfLen < CHUNK_SIZE - 1 )
jksoft 0:890c12951e96 340 {
jksoft 0:890c12951e96 341 size_t newTrfLen;
jksoft 0:890c12951e96 342 ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen);
jksoft 0:890c12951e96 343 trfLen += newTrfLen;
jksoft 0:890c12951e96 344 buf[trfLen] = '\0';
jksoft 0:890c12951e96 345 DBG("Read %d chars; In buf: [%s]", newTrfLen, buf);
jksoft 0:890c12951e96 346 CHECK_CONN_ERR(ret);
jksoft 0:890c12951e96 347 continue;
jksoft 0:890c12951e96 348 }
jksoft 0:890c12951e96 349 else
jksoft 0:890c12951e96 350 {
jksoft 0:890c12951e96 351 PRTCL_ERR();
jksoft 0:890c12951e96 352 }
jksoft 0:890c12951e96 353 }
jksoft 0:890c12951e96 354
jksoft 0:890c12951e96 355 crlfPos = crlfPtr - buf;
jksoft 0:890c12951e96 356
jksoft 0:890c12951e96 357 if(crlfPos == 0) //End of headers
jksoft 0:890c12951e96 358 {
jksoft 0:890c12951e96 359 DBG("Headers read");
jksoft 0:890c12951e96 360 memmove(buf, &buf[2], trfLen - 2 + 1); //Be sure to move NULL-terminating char as well
jksoft 0:890c12951e96 361 trfLen -= 2;
jksoft 0:890c12951e96 362 break;
jksoft 0:890c12951e96 363 }
jksoft 0:890c12951e96 364
jksoft 0:890c12951e96 365 buf[crlfPos] = '\0';
jksoft 0:890c12951e96 366
jksoft 0:890c12951e96 367 char key[32];
jksoft 0:890c12951e96 368 char value[32];
jksoft 0:890c12951e96 369
jksoft 0:890c12951e96 370 //key[31] = '\0';
jksoft 0:890c12951e96 371 //value[31] = '\0';
jksoft 0:890c12951e96 372
jksoft 0:890c12951e96 373 memset(key, 0, 32);
jksoft 0:890c12951e96 374 memset(value, 0, 32);
jksoft 0:890c12951e96 375
jksoft 0:890c12951e96 376 //int n = sscanf(buf, "%31[^:]: %31[^\r\n]", key, value);
jksoft 0:890c12951e96 377
jksoft 0:890c12951e96 378 int n = 0;
jksoft 0:890c12951e96 379
jksoft 0:890c12951e96 380 char* keyEnd = strchr(buf, ':');
jksoft 0:890c12951e96 381 if(keyEnd != NULL)
jksoft 0:890c12951e96 382 {
jksoft 0:890c12951e96 383 *keyEnd = '\0';
jksoft 0:890c12951e96 384 if(strlen(buf) < 32)
jksoft 0:890c12951e96 385 {
jksoft 0:890c12951e96 386 strcpy(key, buf);
jksoft 0:890c12951e96 387 n++;
jksoft 0:890c12951e96 388 char* valueStart = keyEnd + 2;
jksoft 0:890c12951e96 389 if( (valueStart - buf) < crlfPos )
jksoft 0:890c12951e96 390 {
jksoft 0:890c12951e96 391 if(strlen(valueStart) < 32)
jksoft 0:890c12951e96 392 {
jksoft 0:890c12951e96 393 strcpy(value, valueStart);
jksoft 0:890c12951e96 394 n++;
jksoft 0:890c12951e96 395 }
jksoft 0:890c12951e96 396 }
jksoft 0:890c12951e96 397 }
jksoft 0:890c12951e96 398 }
jksoft 0:890c12951e96 399 if ( n == 2 )
jksoft 0:890c12951e96 400 {
jksoft 0:890c12951e96 401 DBG("Read header : %s: %s\n", key, value);
jksoft 0:890c12951e96 402 if( !strcmp(key, "Content-Length") )
jksoft 0:890c12951e96 403 {
jksoft 0:890c12951e96 404 sscanf(value, "%d", &recvContentLength);
jksoft 0:890c12951e96 405 recvLengthUnknown = false;
jksoft 0:890c12951e96 406 pDataIn->setDataLen(recvContentLength);
jksoft 0:890c12951e96 407 }
jksoft 0:890c12951e96 408 else if( !strcmp(key, "Transfer-Encoding") )
jksoft 0:890c12951e96 409 {
jksoft 0:890c12951e96 410 if( !strcmp(value, "Chunked") || !strcmp(value, "chunked") )
jksoft 0:890c12951e96 411 {
jksoft 0:890c12951e96 412 recvChunked = true;
jksoft 0:890c12951e96 413 recvLengthUnknown = false;
jksoft 0:890c12951e96 414 pDataIn->setIsChunked(true);
jksoft 0:890c12951e96 415 }
jksoft 0:890c12951e96 416 }
jksoft 0:890c12951e96 417 else if( !strcmp(key, "Content-Type") )
jksoft 0:890c12951e96 418 {
jksoft 0:890c12951e96 419 pDataIn->setDataType(value);
jksoft 0:890c12951e96 420 }
jksoft 0:890c12951e96 421
jksoft 0:890c12951e96 422 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well
jksoft 0:890c12951e96 423 trfLen -= (crlfPos + 2);
jksoft 0:890c12951e96 424
jksoft 0:890c12951e96 425 }
jksoft 0:890c12951e96 426 else
jksoft 0:890c12951e96 427 {
jksoft 0:890c12951e96 428 ERR("Could not parse header");
jksoft 0:890c12951e96 429 PRTCL_ERR();
jksoft 0:890c12951e96 430 }
jksoft 0:890c12951e96 431
jksoft 0:890c12951e96 432 }
jksoft 0:890c12951e96 433
jksoft 0:890c12951e96 434 //Receive data
jksoft 0:890c12951e96 435 DBG("Receiving data");
jksoft 0:890c12951e96 436 while(true)
jksoft 0:890c12951e96 437 {
jksoft 0:890c12951e96 438 size_t readLen = 0;
jksoft 0:890c12951e96 439
jksoft 0:890c12951e96 440 if( recvChunked )
jksoft 0:890c12951e96 441 {
jksoft 0:890c12951e96 442 //Read chunk header
jksoft 0:890c12951e96 443 bool foundCrlf;
jksoft 0:890c12951e96 444 do
jksoft 0:890c12951e96 445 {
jksoft 0:890c12951e96 446 foundCrlf = false;
jksoft 0:890c12951e96 447 crlfPos=0;
jksoft 0:890c12951e96 448 buf[trfLen]=0;
jksoft 0:890c12951e96 449 if(trfLen >= 2)
jksoft 0:890c12951e96 450 {
jksoft 0:890c12951e96 451 for(; crlfPos < trfLen - 2; crlfPos++)
jksoft 0:890c12951e96 452 {
jksoft 0:890c12951e96 453 if( buf[crlfPos] == '\r' && buf[crlfPos + 1] == '\n' )
jksoft 0:890c12951e96 454 {
jksoft 0:890c12951e96 455 foundCrlf = true;
jksoft 0:890c12951e96 456 break;
jksoft 0:890c12951e96 457 }
jksoft 0:890c12951e96 458 }
jksoft 0:890c12951e96 459 }
jksoft 0:890c12951e96 460 if(!foundCrlf) //Try to read more
jksoft 0:890c12951e96 461 {
jksoft 0:890c12951e96 462 if( trfLen < CHUNK_SIZE )
jksoft 0:890c12951e96 463 {
jksoft 0:890c12951e96 464 size_t newTrfLen;
jksoft 0:890c12951e96 465 ret = recv(buf + trfLen, 0, CHUNK_SIZE - trfLen - 1, &newTrfLen);
jksoft 0:890c12951e96 466 trfLen += newTrfLen;
jksoft 0:890c12951e96 467 CHECK_CONN_ERR(ret);
jksoft 0:890c12951e96 468 continue;
jksoft 0:890c12951e96 469 }
jksoft 0:890c12951e96 470 else
jksoft 0:890c12951e96 471 {
jksoft 0:890c12951e96 472 PRTCL_ERR();
jksoft 0:890c12951e96 473 }
jksoft 0:890c12951e96 474 }
jksoft 0:890c12951e96 475 } while(!foundCrlf);
jksoft 0:890c12951e96 476 buf[crlfPos] = '\0';
jksoft 0:890c12951e96 477 int n = sscanf(buf, "%x", &readLen);
jksoft 0:890c12951e96 478 if(n!=1)
jksoft 0:890c12951e96 479 {
jksoft 0:890c12951e96 480 ERR("Could not read chunk length");
jksoft 0:890c12951e96 481 PRTCL_ERR();
jksoft 0:890c12951e96 482 }
jksoft 0:890c12951e96 483
jksoft 0:890c12951e96 484 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2)); //Not need to move NULL-terminating char any more
jksoft 0:890c12951e96 485 trfLen -= (crlfPos + 2);
jksoft 0:890c12951e96 486
jksoft 0:890c12951e96 487 if( readLen == 0 )
jksoft 0:890c12951e96 488 {
jksoft 0:890c12951e96 489 //Last chunk
jksoft 0:890c12951e96 490 break;
jksoft 0:890c12951e96 491 }
jksoft 0:890c12951e96 492 }
jksoft 0:890c12951e96 493 else
jksoft 0:890c12951e96 494 {
jksoft 0:890c12951e96 495 readLen = recvContentLength;
jksoft 0:890c12951e96 496 }
jksoft 0:890c12951e96 497
jksoft 0:890c12951e96 498 DBG("Retrieving %d bytes (%d bytes in buffer)", readLen, trfLen);
jksoft 0:890c12951e96 499
jksoft 0:890c12951e96 500 do
jksoft 0:890c12951e96 501 {
jksoft 0:890c12951e96 502 if(recvLengthUnknown )
jksoft 0:890c12951e96 503 {
jksoft 0:890c12951e96 504 readLen = trfLen;
jksoft 0:890c12951e96 505 }
jksoft 0:890c12951e96 506 pDataIn->write(buf, MIN(trfLen, readLen));
jksoft 0:890c12951e96 507 if(!recvLengthUnknown)
jksoft 0:890c12951e96 508 {
jksoft 0:890c12951e96 509 if( trfLen > readLen )
jksoft 0:890c12951e96 510 {
jksoft 0:890c12951e96 511 memmove(buf, &buf[readLen], trfLen - readLen);
jksoft 0:890c12951e96 512 trfLen -= readLen;
jksoft 0:890c12951e96 513 readLen = 0;
jksoft 0:890c12951e96 514 }
jksoft 0:890c12951e96 515 else
jksoft 0:890c12951e96 516 {
jksoft 0:890c12951e96 517 readLen -= trfLen;
jksoft 0:890c12951e96 518 }
jksoft 0:890c12951e96 519 }
jksoft 0:890c12951e96 520 else
jksoft 0:890c12951e96 521 {
jksoft 0:890c12951e96 522 trfLen = 0;
jksoft 0:890c12951e96 523 }
jksoft 0:890c12951e96 524
jksoft 0:890c12951e96 525 if(readLen || recvLengthUnknown)
jksoft 0:890c12951e96 526 {
jksoft 0:890c12951e96 527 ret = recv(buf, 1, CHUNK_SIZE - trfLen - 1, &trfLen);
jksoft 0:890c12951e96 528 if(recvLengthUnknown && (ret == HTTP_CLOSED))
jksoft 0:890c12951e96 529 {
jksoft 0:890c12951e96 530 //Write and exit
jksoft 0:890c12951e96 531 pDataIn->write(buf, trfLen);
jksoft 0:890c12951e96 532 break;
jksoft 0:890c12951e96 533 }
jksoft 0:890c12951e96 534 CHECK_CONN_ERR(ret);
jksoft 0:890c12951e96 535 if(recvLengthUnknown && (trfLen == 0))
jksoft 0:890c12951e96 536 {
jksoft 0:890c12951e96 537 break;
jksoft 0:890c12951e96 538 }
jksoft 0:890c12951e96 539 }
jksoft 0:890c12951e96 540 } while(readLen || recvLengthUnknown);
jksoft 0:890c12951e96 541
jksoft 0:890c12951e96 542 if( recvChunked )
jksoft 0:890c12951e96 543 {
jksoft 0:890c12951e96 544 if(trfLen < 2)
jksoft 0:890c12951e96 545 {
jksoft 0:890c12951e96 546 size_t newTrfLen;
jksoft 0:890c12951e96 547 //Read missing chars to find end of chunk
jksoft 0:890c12951e96 548 ret = recv(buf + trfLen, 2 - trfLen, CHUNK_SIZE - trfLen - 1, &newTrfLen);
jksoft 0:890c12951e96 549 CHECK_CONN_ERR(ret);
jksoft 0:890c12951e96 550 trfLen += newTrfLen;
jksoft 0:890c12951e96 551 }
jksoft 0:890c12951e96 552 if( (buf[0] != '\r') || (buf[1] != '\n') )
jksoft 0:890c12951e96 553 {
jksoft 0:890c12951e96 554 ERR("Format error");
jksoft 0:890c12951e96 555 PRTCL_ERR();
jksoft 0:890c12951e96 556 }
jksoft 0:890c12951e96 557 memmove(buf, &buf[2], trfLen - 2);
jksoft 0:890c12951e96 558 trfLen -= 2;
jksoft 0:890c12951e96 559 }
jksoft 0:890c12951e96 560 else
jksoft 0:890c12951e96 561 {
jksoft 0:890c12951e96 562 break;
jksoft 0:890c12951e96 563 }
jksoft 0:890c12951e96 564
jksoft 0:890c12951e96 565 }
jksoft 0:890c12951e96 566
jksoft 0:890c12951e96 567 m_sock.close();
jksoft 0:890c12951e96 568 DBG("Completed HTTP transaction");
jksoft 0:890c12951e96 569
jksoft 0:890c12951e96 570 return HTTP_OK;
jksoft 0:890c12951e96 571 }
jksoft 0:890c12951e96 572
jksoft 0:890c12951e96 573 HTTPResult HTTPClient::recv(char* buf, size_t minLen, size_t maxLen, size_t* pReadLen) //0 on success, err code on failure
jksoft 0:890c12951e96 574 {
jksoft 0:890c12951e96 575 DBG("Trying to read between %d and %d bytes", minLen, maxLen);
jksoft 0:890c12951e96 576 size_t readLen = 0;
jksoft 0:890c12951e96 577
jksoft 0:890c12951e96 578 if(!m_sock.is_connected())
jksoft 0:890c12951e96 579 {
jksoft 0:890c12951e96 580 WARN("Connection was closed by server");
jksoft 0:890c12951e96 581 return HTTP_CLOSED; //Connection was closed by server
jksoft 0:890c12951e96 582 }
jksoft 0:890c12951e96 583
jksoft 0:890c12951e96 584 int ret;
jksoft 0:890c12951e96 585 while(readLen < maxLen)
jksoft 0:890c12951e96 586 {
jksoft 0:890c12951e96 587 if(readLen < minLen)
jksoft 0:890c12951e96 588 {
jksoft 0:890c12951e96 589 DBG("Trying to read at most %d bytes [Blocking]", minLen - readLen);
jksoft 0:890c12951e96 590 m_sock.set_blocking(false, m_timeout);
jksoft 0:890c12951e96 591 ret = m_sock.receive_all(buf + readLen, minLen - readLen);
jksoft 0:890c12951e96 592 }
jksoft 0:890c12951e96 593 else
jksoft 0:890c12951e96 594 {
jksoft 0:890c12951e96 595 DBG("Trying to read at most %d bytes [Not blocking]", maxLen - readLen);
jksoft 0:890c12951e96 596 m_sock.set_blocking(false, 0);
jksoft 0:890c12951e96 597 ret = m_sock.receive(buf + readLen, maxLen - readLen);
jksoft 0:890c12951e96 598 }
jksoft 0:890c12951e96 599
jksoft 0:890c12951e96 600 if( ret > 0)
jksoft 0:890c12951e96 601 {
jksoft 0:890c12951e96 602 readLen += ret;
jksoft 0:890c12951e96 603 }
jksoft 0:890c12951e96 604 else if( ret == 0 )
jksoft 0:890c12951e96 605 {
jksoft 0:890c12951e96 606 break;
jksoft 0:890c12951e96 607 }
jksoft 0:890c12951e96 608 else
jksoft 0:890c12951e96 609 {
jksoft 0:890c12951e96 610 if(!m_sock.is_connected())
jksoft 0:890c12951e96 611 {
jksoft 0:890c12951e96 612 ERR("Connection error (recv returned %d)", ret);
jksoft 0:890c12951e96 613 *pReadLen = readLen;
jksoft 0:890c12951e96 614 return HTTP_CONN;
jksoft 0:890c12951e96 615 }
jksoft 0:890c12951e96 616 else
jksoft 0:890c12951e96 617 {
jksoft 0:890c12951e96 618 break;
jksoft 0:890c12951e96 619 }
jksoft 0:890c12951e96 620 }
jksoft 0:890c12951e96 621
jksoft 0:890c12951e96 622 if(!m_sock.is_connected())
jksoft 0:890c12951e96 623 {
jksoft 0:890c12951e96 624 break;
jksoft 0:890c12951e96 625 }
jksoft 0:890c12951e96 626 }
jksoft 0:890c12951e96 627 DBG("Read %d bytes", readLen);
jksoft 0:890c12951e96 628 *pReadLen = readLen;
jksoft 0:890c12951e96 629 return HTTP_OK;
jksoft 0:890c12951e96 630 }
jksoft 0:890c12951e96 631
jksoft 0:890c12951e96 632 HTTPResult HTTPClient::send(char* buf, size_t len) //0 on success, err code on failure
jksoft 0:890c12951e96 633 {
jksoft 0:890c12951e96 634 if(len == 0)
jksoft 0:890c12951e96 635 {
jksoft 0:890c12951e96 636 len = strlen(buf);
jksoft 0:890c12951e96 637 }
jksoft 0:890c12951e96 638 DBG("Trying to write %d bytes", len);
jksoft 0:890c12951e96 639 size_t writtenLen = 0;
jksoft 0:890c12951e96 640
jksoft 0:890c12951e96 641 if(!m_sock.is_connected())
jksoft 0:890c12951e96 642 {
jksoft 0:890c12951e96 643 WARN("Connection was closed by server");
jksoft 0:890c12951e96 644 return HTTP_CLOSED; //Connection was closed by server
jksoft 0:890c12951e96 645 }
jksoft 0:890c12951e96 646
jksoft 0:890c12951e96 647 m_sock.set_blocking(false, m_timeout);
jksoft 0:890c12951e96 648 int ret = m_sock.send_all(buf, len);
jksoft 0:890c12951e96 649 if(ret > 0)
jksoft 0:890c12951e96 650 {
jksoft 0:890c12951e96 651 writtenLen += ret;
jksoft 0:890c12951e96 652 }
jksoft 0:890c12951e96 653 else if( ret == 0 )
jksoft 0:890c12951e96 654 {
jksoft 0:890c12951e96 655 WARN("Connection was closed by server");
jksoft 0:890c12951e96 656 return HTTP_CLOSED; //Connection was closed by server
jksoft 0:890c12951e96 657 }
jksoft 0:890c12951e96 658 else
jksoft 0:890c12951e96 659 {
jksoft 0:890c12951e96 660 ERR("Connection error (send returned %d)", ret);
jksoft 0:890c12951e96 661 return HTTP_CONN;
jksoft 0:890c12951e96 662 }
jksoft 0:890c12951e96 663
jksoft 0:890c12951e96 664 DBG("Written %d bytes", writtenLen);
jksoft 0:890c12951e96 665 return HTTP_OK;
jksoft 0:890c12951e96 666 }
jksoft 0:890c12951e96 667
jksoft 0:890c12951e96 668 HTTPResult 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
jksoft 0:890c12951e96 669 {
jksoft 0:890c12951e96 670 char* schemePtr = (char*) url;
jksoft 0:890c12951e96 671 char* hostPtr = (char*) strstr(url, "://");
jksoft 0:890c12951e96 672 if(hostPtr == NULL)
jksoft 0:890c12951e96 673 {
jksoft 0:890c12951e96 674 WARN("Could not find host");
jksoft 0:890c12951e96 675 return HTTP_PARSE; //URL is invalid
jksoft 0:890c12951e96 676 }
jksoft 0:890c12951e96 677
jksoft 0:890c12951e96 678 if( maxSchemeLen < hostPtr - schemePtr + 1 ) //including NULL-terminating char
jksoft 0:890c12951e96 679 {
jksoft 0:890c12951e96 680 WARN("Scheme str is too small (%d >= %d)", maxSchemeLen, hostPtr - schemePtr + 1);
jksoft 0:890c12951e96 681 return HTTP_PARSE;
jksoft 0:890c12951e96 682 }
jksoft 0:890c12951e96 683 memcpy(scheme, schemePtr, hostPtr - schemePtr);
jksoft 0:890c12951e96 684 scheme[hostPtr - schemePtr] = '\0';
jksoft 0:890c12951e96 685
jksoft 0:890c12951e96 686 hostPtr+=3;
jksoft 0:890c12951e96 687
jksoft 0:890c12951e96 688 size_t hostLen = 0;
jksoft 0:890c12951e96 689
jksoft 0:890c12951e96 690 char* portPtr = strchr(hostPtr, ':');
jksoft 0:890c12951e96 691 if( portPtr != NULL )
jksoft 0:890c12951e96 692 {
jksoft 0:890c12951e96 693 hostLen = portPtr - hostPtr;
jksoft 0:890c12951e96 694 portPtr++;
jksoft 0:890c12951e96 695 if( sscanf(portPtr, "%hu", port) != 1)
jksoft 0:890c12951e96 696 {
jksoft 0:890c12951e96 697 WARN("Could not find port");
jksoft 0:890c12951e96 698 return HTTP_PARSE;
jksoft 0:890c12951e96 699 }
jksoft 0:890c12951e96 700 }
jksoft 0:890c12951e96 701 else
jksoft 0:890c12951e96 702 {
jksoft 0:890c12951e96 703 *port=0;
jksoft 0:890c12951e96 704 }
jksoft 0:890c12951e96 705 char* pathPtr = strchr(hostPtr, '/');
jksoft 0:890c12951e96 706 if( hostLen == 0 )
jksoft 0:890c12951e96 707 {
jksoft 0:890c12951e96 708 hostLen = pathPtr - hostPtr;
jksoft 0:890c12951e96 709 }
jksoft 0:890c12951e96 710
jksoft 0:890c12951e96 711 if( maxHostLen < hostLen + 1 ) //including NULL-terminating char
jksoft 0:890c12951e96 712 {
jksoft 0:890c12951e96 713 WARN("Host str is too small (%d >= %d)", maxHostLen, hostLen + 1);
jksoft 0:890c12951e96 714 return HTTP_PARSE;
jksoft 0:890c12951e96 715 }
jksoft 0:890c12951e96 716 memcpy(host, hostPtr, hostLen);
jksoft 0:890c12951e96 717 host[hostLen] = '\0';
jksoft 0:890c12951e96 718
jksoft 0:890c12951e96 719 size_t pathLen;
jksoft 0:890c12951e96 720 char* fragmentPtr = strchr(hostPtr, '#');
jksoft 0:890c12951e96 721 if(fragmentPtr != NULL)
jksoft 0:890c12951e96 722 {
jksoft 0:890c12951e96 723 pathLen = fragmentPtr - pathPtr;
jksoft 0:890c12951e96 724 }
jksoft 0:890c12951e96 725 else
jksoft 0:890c12951e96 726 {
jksoft 0:890c12951e96 727 pathLen = strlen(pathPtr);
jksoft 0:890c12951e96 728 }
jksoft 0:890c12951e96 729
jksoft 0:890c12951e96 730 if( maxPathLen < pathLen + 1 ) //including NULL-terminating char
jksoft 0:890c12951e96 731 {
jksoft 0:890c12951e96 732 WARN("Path str is too small (%d >= %d)", maxPathLen, pathLen + 1);
jksoft 0:890c12951e96 733 return HTTP_PARSE;
jksoft 0:890c12951e96 734 }
jksoft 0:890c12951e96 735 memcpy(path, pathPtr, pathLen);
jksoft 0:890c12951e96 736 path[pathLen] = '\0';
jksoft 0:890c12951e96 737
jksoft 0:890c12951e96 738 return HTTP_OK;
jksoft 0:890c12951e96 739 }