iSDIO Library for TOSHIBA FlashAir. include HTTP or HTTPS Client.

Dependencies:   SDFileSystem

Dependents:   FlashAir_Twitter Neon_F303K8_04

Fork of HTTPClient by Donatien Garnier

Committer:
ban4jp
Date:
Sun Dec 14 19:05:31 2014 +0000
Revision:
19:3b1625dbd7e9
Parent:
18:277279a1891e
Child:
20:51abf34bcc06
Format code.

Who changed what in which revision?

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