Got modem to work with MedSentry website. Includes minor change to a library file.

Dependencies:   CyaSSL

Dependents:   MTS-Socket

Fork of HTTPClient-SSL by MultiTech

Committer:
kruenhec
Date:
Fri Sep 11 21:51:39 2015 +0000
Revision:
50:6b0d6121914f
Parent:
46:369da903fca9
Child:
51:68aeee0a25f3
Child:
52:d49ba1ed624c
Made modem work with MedSentry site by increasing chunk size to 512 and changing encoding from text to url

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 */
ansond 29:2d96cc752d19 19
ansond 29:2d96cc752d19 20 // DMA: Added tunable to adapt size of larger input URLs
ansond 29:2d96cc752d19 21 #define MAX_URL_HOSTNAME_LENGTH 128
ansond 29:2d96cc752d19 22 #define MAX_URL_PATH_LENGTH 128
donatien 0:2ccb9960a044 23
donatien 7:4e39864f7b15 24 //Debug is disabled by default
Vanger 40:6d9725c3eb6f 25 #if 0
donatien 12:89d09a6db00a 26 //Enable debug
donatien 11:390362de8c3f 27 #include <cstdio>
wolfSSL 18:d89df40b4cf3 28 #define DBG(x, ...) std::printf("[HTTPClient : DBG]"x"\r\n", ##__VA_ARGS__);
wolfSSL 18:d89df40b4cf3 29 #define WARN(x, ...) std::printf("[HTTPClient : WARN]"x"\r\n", ##__VA_ARGS__);
wolfSSL 18:d89df40b4cf3 30 #define ERR(x, ...) std::printf("[HTTPClient : ERR]"x"\r\n", ##__VA_ARGS__);
donatien 12:89d09a6db00a 31
donatien 12:89d09a6db00a 32 #else
donatien 12:89d09a6db00a 33 //Disable debug
wolfSSL 18:d89df40b4cf3 34 #define DBG(x, ...)
donatien 12:89d09a6db00a 35 #define WARN(x, ...)
wolfSSL 18:d89df40b4cf3 36 #define ERR(x, ...)
donatien 12:89d09a6db00a 37
donatien 7:4e39864f7b15 38 #endif
donatien 0:2ccb9960a044 39
donatien 0:2ccb9960a044 40 #define HTTP_PORT 80
wolfSSL 17:c73d8e61d391 41 #define HTTPS_PORT 443
donatien 0:2ccb9960a044 42
donatien 11:390362de8c3f 43 #define OK 0
donatien 11:390362de8c3f 44
donatien 11:390362de8c3f 45 #define MIN(x,y) (((x)<(y))?(x):(y))
donatien 11:390362de8c3f 46 #define MAX(x,y) (((x)>(y))?(x):(y))
donatien 11:390362de8c3f 47
wolfSSL 17:c73d8e61d391 48 #include <cstring>
donatien 0:2ccb9960a044 49
mfiore 41:236fa1143e5a 50 #include <settings.h>
mfiore 41:236fa1143e5a 51 #include <types.h>
mfiore 41:236fa1143e5a 52 #include <internal.h>
mfiore 41:236fa1143e5a 53 #include <ssl.h>
donatien 0:2ccb9960a044 54
donatien 11:390362de8c3f 55 #include "HTTPClient.h"
wolfSSL 17:c73d8e61d391 56
Vanger 33:3b2809748a9e 57 static TCPSocketConnection* m_sock;
kruenhec 50:6b0d6121914f 58 #define CHUNK_SIZE 512 // changed from 256 to work with MedSentry site
ansond 32:d9db238bb8a3 59 #define SEND_BUF_SIZE 1024
wolfSSL 17:c73d8e61d391 60 static char send_buf[SEND_BUF_SIZE] ;
ansond 32:d9db238bb8a3 61 static char *send_buf_p = NULL;
wolfSSL 17:c73d8e61d391 62
wolfSSL 17:c73d8e61d391 63 static int SocketReceive(CYASSL* ssl, char *buf, int sz, void *ctx)
wolfSSL 17:c73d8e61d391 64 {
wolfSSL 17:c73d8e61d391 65 int n ;
wolfSSL 17:c73d8e61d391 66 int i ;
wolfSSL 18:d89df40b4cf3 67 #define RECV_RETRY 3
wolfSSL 22:4b9a4151cc73 68
wolfSSL 17:c73d8e61d391 69 for(i=0; i<RECV_RETRY; i++) {
Vanger 33:3b2809748a9e 70 n = m_sock->receive(buf, sz) ;
wolfSSL 17:c73d8e61d391 71 if(n >= 0)return n ;
wolfSSL 22:4b9a4151cc73 72 wait(0.2) ;
wolfSSL 17:c73d8e61d391 73 }
wolfSSL 17:c73d8e61d391 74 ERR("SocketReceive:%d/%d\n", n, sz) ;
wolfSSL 17:c73d8e61d391 75 return n ;
wolfSSL 17:c73d8e61d391 76 }
wolfSSL 17:c73d8e61d391 77
wolfSSL 17:c73d8e61d391 78 static int SocketSend(CYASSL* ssl, char *buf, int sz, void *ctx)
wolfSSL 17:c73d8e61d391 79 {
wolfSSL 17:c73d8e61d391 80 int n ;
Vanger 34:13920d48893d 81
Vanger 34:13920d48893d 82 wait(0.1);
Vanger 33:3b2809748a9e 83 n = m_sock->send(buf, sz);
wolfSSL 17:c73d8e61d391 84 if(n > 0) {
Vanger 34:13920d48893d 85 wait(0.3);
Vanger 34:13920d48893d 86 return n;
Vanger 34:13920d48893d 87 } else {
Vanger 34:13920d48893d 88 ERR("SocketSend:%d/%d\n", n, sz);
Vanger 34:13920d48893d 89 }
Vanger 34:13920d48893d 90 return n;
wolfSSL 17:c73d8e61d391 91 }
donatien 11:390362de8c3f 92
wolfSSL 22:4b9a4151cc73 93 static void base64enc(char *out, const char *in) {
wolfSSL 22:4b9a4151cc73 94 const char code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" ;
wolfSSL 22:4b9a4151cc73 95 int i = 0, x = 0, l = 0;
wolfSSL 22:4b9a4151cc73 96
wolfSSL 22:4b9a4151cc73 97 for (; *in; in++) {
wolfSSL 22:4b9a4151cc73 98 x = x << 8 | *in;
wolfSSL 22:4b9a4151cc73 99 for (l += 8; l >= 6; l -= 6) {
wolfSSL 22:4b9a4151cc73 100 out[i++] = code[(x >> (l - 6)) & 0x3f];
wolfSSL 22:4b9a4151cc73 101 }
wolfSSL 22:4b9a4151cc73 102 }
wolfSSL 22:4b9a4151cc73 103 if (l > 0) {
wolfSSL 22:4b9a4151cc73 104 x <<= 6 - l;
wolfSSL 22:4b9a4151cc73 105 out[i++] = code[x & 0x3f];
wolfSSL 22:4b9a4151cc73 106 }
wolfSSL 22:4b9a4151cc73 107 for (; i % 4;) {
wolfSSL 22:4b9a4151cc73 108 out[i++] = '=';
wolfSSL 22:4b9a4151cc73 109 }
wolfSSL 22:4b9a4151cc73 110 out[i] = '\0' ;
wolfSSL 22:4b9a4151cc73 111 }
wolfSSL 22:4b9a4151cc73 112
donatien 0:2ccb9960a044 113 HTTPClient::HTTPClient() :
wolfSSL 18:d89df40b4cf3 114 m_basicAuthUser(NULL), m_basicAuthPassword(NULL), m_httpResponseCode(0)
donatien 0:2ccb9960a044 115 {
Vanger 42:2f464f96c204 116 m_sock = &_m_sock;
Vanger 46:369da903fca9 117 //CyaSSL_Debugging_ON() ; //Turn on if the CyaSSL library isn't working, turns on debug printf's
Vanger 38:a4ccad70be9d 118
Vanger 42:2f464f96c204 119 peerMethod = VERIFY_NONE;
wolfSSL 18:d89df40b4cf3 120 ctx = 0 ;
wolfSSL 18:d89df40b4cf3 121 ssl = 0 ;
wolfSSL 22:4b9a4151cc73 122 SSLver = 3 ;
Vanger 38:a4ccad70be9d 123 certificates = NULL;
wolfSSL 27:5d4739eae63e 124 redirect_url = NULL ;
wolfSSL 27:5d4739eae63e 125 redirect = 0 ;
wolfSSL 27:5d4739eae63e 126 header = NULL ;
donatien 0:2ccb9960a044 127 }
donatien 0:2ccb9960a044 128
donatien 0:2ccb9960a044 129 HTTPClient::~HTTPClient()
donatien 0:2ccb9960a044 130 {
Vanger 42:2f464f96c204 131 if(m_basicAuthPassword) {
Vanger 42:2f464f96c204 132 free((void *)m_basicAuthPassword);
Vanger 42:2f464f96c204 133 m_basicAuthPassword = NULL;
Vanger 42:2f464f96c204 134 }
Vanger 42:2f464f96c204 135 if(m_basicAuthUser) {
Vanger 42:2f464f96c204 136 free((void *)m_basicAuthUser);
Vanger 42:2f464f96c204 137 m_basicAuthUser = NULL;
Vanger 42:2f464f96c204 138 }
Vanger 42:2f464f96c204 139 if(certificates) {
Vanger 42:2f464f96c204 140 free((void *)certificates);
Vanger 42:2f464f96c204 141 certificates = NULL;
Vanger 42:2f464f96c204 142 }
donatien 0:2ccb9960a044 143 }
donatien 0:2ccb9960a044 144
wolfSSL 22:4b9a4151cc73 145 HTTPResult HTTPClient::basicAuth(const char* user, const char* password) //Basic Authentification
donatien 0:2ccb9960a044 146 {
wolfSSL 22:4b9a4151cc73 147 #define AUTHB_SIZE 128
wolfSSL 22:4b9a4151cc73 148 if((strlen(user) + strlen(password)) >= AUTHB_SIZE)
wolfSSL 22:4b9a4151cc73 149 return HTTP_ERROR ;
ansond 30:6fef375c94e6 150
ansond 30:6fef375c94e6 151 if (m_basicAuthUser) free((void *)m_basicAuthUser);
ansond 30:6fef375c94e6 152 if (user != NULL) {
ansond 30:6fef375c94e6 153 m_basicAuthUser = (char *)malloc(strlen(user)+1);
ansond 30:6fef375c94e6 154 strcpy((char *)m_basicAuthUser, user);
Vanger 38:a4ccad70be9d 155 } else {
Vanger 38:a4ccad70be9d 156 m_basicAuthUser = NULL;
ansond 30:6fef375c94e6 157 }
ansond 30:6fef375c94e6 158
ansond 30:6fef375c94e6 159 if (m_basicAuthPassword) free((void *)m_basicAuthPassword);
ansond 30:6fef375c94e6 160 if (password != NULL) {
ansond 30:6fef375c94e6 161 m_basicAuthPassword = (char *)malloc(strlen(password)+1);
ansond 30:6fef375c94e6 162 strcpy((char *)m_basicAuthPassword, password);
Vanger 38:a4ccad70be9d 163 } else {
Vanger 38:a4ccad70be9d 164 m_basicAuthPassword = NULL;
Vanger 38:a4ccad70be9d 165 }
ansond 30:6fef375c94e6 166
wolfSSL 22:4b9a4151cc73 167 return HTTP_OK ;
donatien 0:2ccb9960a044 168 }
donatien 0:2ccb9960a044 169
donatien 12:89d09a6db00a 170 HTTPResult HTTPClient::get(const char* url, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
donatien 0:2ccb9960a044 171 {
wolfSSL 18:d89df40b4cf3 172 return connect(url, HTTP_GET, NULL, pDataIn, timeout);
donatien 0:2ccb9960a044 173 }
donatien 0:2ccb9960a044 174
donatien 12:89d09a6db00a 175 HTTPResult HTTPClient::get(const char* url, char* result, size_t maxResultLen, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
donatien 0:2ccb9960a044 176 {
wolfSSL 18:d89df40b4cf3 177 HTTPText str(result, maxResultLen);
wolfSSL 18:d89df40b4cf3 178 return get(url, &str, timeout);
donatien 0:2ccb9960a044 179 }
donatien 0:2ccb9960a044 180
donatien 12:89d09a6db00a 181 HTTPResult HTTPClient::post(const char* url, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
donatien 0:2ccb9960a044 182 {
wolfSSL 18:d89df40b4cf3 183 return connect(url, HTTP_POST, (IHTTPDataOut*)&dataOut, pDataIn, timeout);
donatien 0:2ccb9960a044 184 }
donatien 0:2ccb9960a044 185
donatien 16:1f743885e7de 186 HTTPResult HTTPClient::put(const char* url, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
donatien 16:1f743885e7de 187 {
wolfSSL 18:d89df40b4cf3 188 return connect(url, HTTP_PUT, (IHTTPDataOut*)&dataOut, pDataIn, timeout);
donatien 16:1f743885e7de 189 }
donatien 16:1f743885e7de 190
donatien 16:1f743885e7de 191 HTTPResult HTTPClient::del(const char* url, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
donatien 16:1f743885e7de 192 {
wolfSSL 18:d89df40b4cf3 193 return connect(url, HTTP_DELETE, NULL, pDataIn, timeout);
donatien 16:1f743885e7de 194 }
donatien 16:1f743885e7de 195
donatien 16:1f743885e7de 196
donatien 0:2ccb9960a044 197 int HTTPClient::getHTTPResponseCode()
donatien 0:2ccb9960a044 198 {
wolfSSL 18:d89df40b4cf3 199 return m_httpResponseCode;
donatien 0:2ccb9960a044 200 }
donatien 0:2ccb9960a044 201
wolfSSL 27:5d4739eae63e 202 void HTTPClient::setHeader(const char * h)
wolfSSL 17:c73d8e61d391 203 {
wolfSSL 17:c73d8e61d391 204 header = h ;
wolfSSL 17:c73d8e61d391 205 }
wolfSSL 17:c73d8e61d391 206
wolfSSL 27:5d4739eae63e 207 void HTTPClient::setLocationBuf(char * url, int size)
wolfSSL 27:5d4739eae63e 208 {
wolfSSL 27:5d4739eae63e 209 redirect_url = url ;
wolfSSL 27:5d4739eae63e 210 redirect_url_size = size ;
wolfSSL 27:5d4739eae63e 211 }
wolfSSL 27:5d4739eae63e 212
wolfSSL 22:4b9a4151cc73 213 HTTPResult HTTPClient::setSSLversion(int minorV)
wolfSSL 22:4b9a4151cc73 214 {
wolfSSL 22:4b9a4151cc73 215 if((minorV>=0) && (minorV<=3))
wolfSSL 22:4b9a4151cc73 216 SSLver = minorV ;
wolfSSL 22:4b9a4151cc73 217 else return HTTP_ERROR ;
wolfSSL 22:4b9a4151cc73 218 return HTTP_OK ;
wolfSSL 22:4b9a4151cc73 219 }
wolfSSL 22:4b9a4151cc73 220
Vanger 38:a4ccad70be9d 221 HTTPResult HTTPClient::addRootCACertificate(const char* cert)
Vanger 38:a4ccad70be9d 222 {
Vanger 38:a4ccad70be9d 223 if(cert == NULL) {
Vanger 38:a4ccad70be9d 224 if(certificates != NULL) {
Vanger 38:a4ccad70be9d 225 free((void *)certificates);
Vanger 38:a4ccad70be9d 226 }
Vanger 38:a4ccad70be9d 227 } else {
Vanger 38:a4ccad70be9d 228 //Append certificate, else allocate new certificate
Vanger 38:a4ccad70be9d 229 if(certificates != NULL) {
Vanger 38:a4ccad70be9d 230 certificates = (char *)realloc((void *)certificates, strlen(cert) + 1 + strlen(certificates)); //+1 is for '\0' char
Vanger 38:a4ccad70be9d 231 if(certificates == NULL) {
Vanger 38:a4ccad70be9d 232 return HTTP_ERROR;
Vanger 38:a4ccad70be9d 233 } else {
Vanger 38:a4ccad70be9d 234 strcat((char *)certificates, cert);
Vanger 38:a4ccad70be9d 235 }
Vanger 38:a4ccad70be9d 236 } else {
Vanger 38:a4ccad70be9d 237 certificates = (char *)malloc(strlen(cert) + 1);
Vanger 38:a4ccad70be9d 238 if(certificates == NULL) {
Vanger 38:a4ccad70be9d 239 return HTTP_ERROR;
Vanger 38:a4ccad70be9d 240 } else {
Vanger 38:a4ccad70be9d 241 strcpy((char *)certificates, cert);
Vanger 38:a4ccad70be9d 242 }
Vanger 38:a4ccad70be9d 243 }
Vanger 38:a4ccad70be9d 244 }
Vanger 38:a4ccad70be9d 245 return HTTP_OK;
Vanger 38:a4ccad70be9d 246 }
Vanger 38:a4ccad70be9d 247
Vanger 38:a4ccad70be9d 248 void HTTPClient::setPeerVerification(SSLMethod method) {
Vanger 42:2f464f96c204 249 peerMethod = method;
Vanger 38:a4ccad70be9d 250 }
Vanger 38:a4ccad70be9d 251
wolfSSL 17:c73d8e61d391 252
donatien 5:791fc3dcb6c4 253 #define CHECK_CONN_ERR(ret) \
donatien 5:791fc3dcb6c4 254 do{ \
donatien 7:4e39864f7b15 255 if(ret) { \
wolfSSL 17:c73d8e61d391 256 cyassl_free() ;\
Vanger 33:3b2809748a9e 257 m_sock->close(); \
donatien 5:791fc3dcb6c4 258 ERR("Connection error (%d)", ret); \
donatien 11:390362de8c3f 259 return HTTP_CONN; \
donatien 5:791fc3dcb6c4 260 } \
donatien 5:791fc3dcb6c4 261 } while(0)
donatien 5:791fc3dcb6c4 262
donatien 5:791fc3dcb6c4 263 #define PRTCL_ERR() \
donatien 5:791fc3dcb6c4 264 do{ \
wolfSSL 17:c73d8e61d391 265 cyassl_free() ;\
Vanger 33:3b2809748a9e 266 m_sock->close(); \
donatien 5:791fc3dcb6c4 267 ERR("Protocol error"); \
donatien 11:390362de8c3f 268 return HTTP_PRTCL; \
donatien 5:791fc3dcb6c4 269 } while(0)
donatien 0:2ccb9960a044 270
wolfSSL 17:c73d8e61d391 271 void HTTPClient::cyassl_free(void)
wolfSSL 17:c73d8e61d391 272 {
wolfSSL 19:1e2f05809eb1 273 if(ssl) {
wolfSSL 17:c73d8e61d391 274 CyaSSL_free(ssl) ;
wolfSSL 19:1e2f05809eb1 275 ssl = NULL ;
wolfSSL 19:1e2f05809eb1 276 }
wolfSSL 19:1e2f05809eb1 277 if(ctx) {
wolfSSL 17:c73d8e61d391 278 CyaSSL_CTX_free(ctx) ;
wolfSSL 19:1e2f05809eb1 279 ctx = NULL ;
wolfSSL 19:1e2f05809eb1 280 }
wolfSSL 22:4b9a4151cc73 281 CyaSSL_Cleanup() ;
wolfSSL 22:4b9a4151cc73 282 }
wolfSSL 17:c73d8e61d391 283
donatien 12:89d09a6db00a 284 HTTPResult HTTPClient::connect(const char* url, HTTP_METH method, IHTTPDataOut* pDataOut, IHTTPDataIn* pDataIn, int timeout) //Execute request
wolfSSL 18:d89df40b4cf3 285 {
Vanger 33:3b2809748a9e 286 CYASSL_METHOD * SSLmethod = 0;
wolfSSL 18:d89df40b4cf3 287 m_httpResponseCode = 0; //Invalidate code
wolfSSL 18:d89df40b4cf3 288 m_timeout = timeout;
wolfSSL 27:5d4739eae63e 289 redirect = 0 ;
wolfSSL 27:5d4739eae63e 290
wolfSSL 18:d89df40b4cf3 291 pDataIn->writeReset();
wolfSSL 18:d89df40b4cf3 292 if( pDataOut ) {
wolfSSL 18:d89df40b4cf3 293 pDataOut->readReset();
wolfSSL 18:d89df40b4cf3 294 }
wolfSSL 17:c73d8e61d391 295
wolfSSL 18:d89df40b4cf3 296 char scheme[8];
ansond 29:2d96cc752d19 297 char host[MAX_URL_HOSTNAME_LENGTH];
ansond 29:2d96cc752d19 298 char path[MAX_URL_PATH_LENGTH];
wolfSSL 18:d89df40b4cf3 299
wolfSSL 18:d89df40b4cf3 300 int ret ;
donatien 0:2ccb9960a044 301
wolfSSL 18:d89df40b4cf3 302 //First we need to parse the url (http[s]://host[:port][/[path]])
wolfSSL 18:d89df40b4cf3 303 HTTPResult res = parseURL(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path));
wolfSSL 18:d89df40b4cf3 304 if(res != HTTP_OK) {
wolfSSL 18:d89df40b4cf3 305 ERR("parseURL returned %d", res);
wolfSSL 18:d89df40b4cf3 306 return res;
wolfSSL 18:d89df40b4cf3 307 }
donatien 0:2ccb9960a044 308
wolfSSL 22:4b9a4151cc73 309 if(port == 0) {
wolfSSL 18:d89df40b4cf3 310 if(strcmp(scheme, "http") == 0)
wolfSSL 18:d89df40b4cf3 311 port = HTTP_PORT ;
wolfSSL 18:d89df40b4cf3 312 else if(strcmp(scheme, "https") == 0)
wolfSSL 18:d89df40b4cf3 313 port = HTTPS_PORT ;
wolfSSL 18:d89df40b4cf3 314 }
donatien 0:2ccb9960a044 315
wolfSSL 18:d89df40b4cf3 316 DBG("Scheme: %s", scheme);
wolfSSL 18:d89df40b4cf3 317 DBG("Host: %s", host);
wolfSSL 18:d89df40b4cf3 318 DBG("Port: %d", port);
wolfSSL 18:d89df40b4cf3 319 DBG("Path: %s", path);
wolfSSL 17:c73d8e61d391 320
wolfSSL 18:d89df40b4cf3 321 //Connect
wolfSSL 18:d89df40b4cf3 322 DBG("Connecting socket to server");
wolfSSL 18:d89df40b4cf3 323
wolfSSL 18:d89df40b4cf3 324 #define MAX_RETRY 5
wolfSSL 18:d89df40b4cf3 325 int retry ;
donatien 0:2ccb9960a044 326
wolfSSL 18:d89df40b4cf3 327 for(retry=0; retry<MAX_RETRY; retry++) {
Vanger 33:3b2809748a9e 328 int ret = m_sock->connect(host, port);
wolfSSL 18:d89df40b4cf3 329 if(ret == 0)break ;
Vanger 34:13920d48893d 330 if(m_sock->is_connected()) {
Vanger 34:13920d48893d 331 m_sock->close(true);
Vanger 34:13920d48893d 332 }
wolfSSL 17:c73d8e61d391 333 }
wolfSSL 18:d89df40b4cf3 334 if(retry == MAX_RETRY) {
Vanger 33:3b2809748a9e 335 m_sock->close();
wolfSSL 18:d89df40b4cf3 336 ERR("Could not connect");
wolfSSL 18:d89df40b4cf3 337 return HTTP_CONN;
wolfSSL 17:c73d8e61d391 338 }
wolfSSL 17:c73d8e61d391 339
wolfSSL 18:d89df40b4cf3 340 if(port == HTTPS_PORT) {
wolfSSL 22:4b9a4151cc73 341
wolfSSL 18:d89df40b4cf3 342 /* Start SSL connect */
wolfSSL 27:5d4739eae63e 343 DBG("SSLver=%d", SSLver) ;
wolfSSL 19:1e2f05809eb1 344 if(ctx == NULL) {
wolfSSL 22:4b9a4151cc73 345 switch(SSLver) {
wolfSSL 22:4b9a4151cc73 346 case 0 : SSLmethod = CyaSSLv3_client_method() ; break ;
wolfSSL 22:4b9a4151cc73 347 case 1 : SSLmethod = CyaTLSv1_client_method() ; break ;
wolfSSL 22:4b9a4151cc73 348 case 2 : SSLmethod = CyaTLSv1_1_client_method() ; break ;
Vanger 38:a4ccad70be9d 349 case 3 : SSLmethod = CyaTLSv1_2_client_method() ; break ;
wolfSSL 22:4b9a4151cc73 350 }
wolfSSL 22:4b9a4151cc73 351 ctx = CyaSSL_CTX_new((CYASSL_METHOD *)SSLmethod);
wolfSSL 19:1e2f05809eb1 352 if (ctx == NULL) {
wolfSSL 19:1e2f05809eb1 353 ERR("unable to get ctx");
wolfSSL 19:1e2f05809eb1 354 return HTTP_CONN;
wolfSSL 19:1e2f05809eb1 355 }
Vanger 38:a4ccad70be9d 356
Vanger 38:a4ccad70be9d 357 if(certificates == NULL && peerMethod != VERIFY_NONE) {
Vanger 38:a4ccad70be9d 358 ERR("No certificates passed for peer verification");
Vanger 38:a4ccad70be9d 359 return HTTP_PROCESSING;
Vanger 38:a4ccad70be9d 360 }
Vanger 38:a4ccad70be9d 361
Vanger 39:d7c5541a9124 362 //SSL setup if being used
Vanger 38:a4ccad70be9d 363 { //Localize pMethod array for less overall memory time-use
Vanger 38:a4ccad70be9d 364 std::string pMethod;
Vanger 38:a4ccad70be9d 365 if(peerMethod == VERIFY_NONE) {
Vanger 38:a4ccad70be9d 366 pMethod = "not verify peer";
Vanger 38:a4ccad70be9d 367 } else if (peerMethod == VERIFY_PEER) {
Vanger 38:a4ccad70be9d 368 pMethod = "verify peer if certificates available";
Vanger 39:d7c5541a9124 369 //Load the CA certificate(s) (If using multiple, concatenate them in the buffer being passed)
Vanger 39:d7c5541a9124 370 if(certificates != NULL) {
Vanger 39:d7c5541a9124 371 if (SSL_SUCCESS != CyaSSL_CTX_load_verify_buffer(ctx, (const unsigned char*)certificates, strlen(certificates), SSL_FILETYPE_PEM)) {
Vanger 39:d7c5541a9124 372 ERR("unable to load root certificates");
Vanger 39:d7c5541a9124 373 return HTTP_CONN;
Vanger 39:d7c5541a9124 374 }
Vanger 39:d7c5541a9124 375 }
Vanger 38:a4ccad70be9d 376 }
Vanger 38:a4ccad70be9d 377 DBG("SSL connection set to %s", pMethod.c_str());
Vanger 38:a4ccad70be9d 378 }
Vanger 38:a4ccad70be9d 379
Vanger 38:a4ccad70be9d 380 CyaSSL_CTX_set_verify(ctx, peerMethod, 0); //SSL_VERIFY_FAIL_IF_NO_PEER_CERT, VERIFY_NONE, SSL_VERIFY_PEER
Vanger 38:a4ccad70be9d 381
wolfSSL 19:1e2f05809eb1 382 CyaSSL_SetIORecv(ctx, SocketReceive) ;
wolfSSL 19:1e2f05809eb1 383 CyaSSL_SetIOSend(ctx, SocketSend) ;
wolfSSL 18:d89df40b4cf3 384 }
wolfSSL 18:d89df40b4cf3 385 if (ssl == NULL) {
wolfSSL 19:1e2f05809eb1 386 ssl = CyaSSL_new(ctx);
wolfSSL 19:1e2f05809eb1 387 if (ssl == NULL) {
wolfSSL 19:1e2f05809eb1 388 ERR("unable to get SSL object");
wolfSSL 19:1e2f05809eb1 389 cyassl_free() ;
wolfSSL 19:1e2f05809eb1 390 return HTTP_CONN;
wolfSSL 19:1e2f05809eb1 391 }
wolfSSL 18:d89df40b4cf3 392 }
donatien 0:2ccb9960a044 393
Vanger 34:13920d48893d 394 DBG("ctx=%x, ssl=%x, ssl->ctx->CBIORecv, CBIOSend=%x, %x\r\n",
wolfSSL 18:d89df40b4cf3 395 ctx, ssl, SocketReceive, SocketSend ) ;
Vanger 38:a4ccad70be9d 396 int ret = CyaSSL_connect(ssl);
Vanger 38:a4ccad70be9d 397 if (ret != SSL_SUCCESS) {
wolfSSL 18:d89df40b4cf3 398 ERR("SSL_connect failed");
Vanger 38:a4ccad70be9d 399 int err = CyaSSL_get_error(ssl, ret);
Vanger 38:a4ccad70be9d 400 char data[32];
Vanger 38:a4ccad70be9d 401 char data_new[32];
Vanger 38:a4ccad70be9d 402 strcpy(data_new, CyaSSL_ERR_error_string(err, data));
Vanger 38:a4ccad70be9d 403 if(!strcmp(data,data_new)) {
Vanger 38:a4ccad70be9d 404 printf("Error code [%d] is [%s]\r\n", err, data);
Vanger 38:a4ccad70be9d 405 } else {
Vanger 38:a4ccad70be9d 406 printf("Failed to get error code [%d], Reason: [%s]\r\n", err, data_new);
Vanger 38:a4ccad70be9d 407 }
wolfSSL 18:d89df40b4cf3 408 cyassl_free() ;
wolfSSL 18:d89df40b4cf3 409 return HTTP_CONN;
wolfSSL 18:d89df40b4cf3 410 }
wolfSSL 18:d89df40b4cf3 411 } /* SSL connect complete */
donatien 0:2ccb9960a044 412
wolfSSL 18:d89df40b4cf3 413 //Send request
wolfSSL 18:d89df40b4cf3 414 DBG("Sending request");
wolfSSL 18:d89df40b4cf3 415 char buf[CHUNK_SIZE];
ansond 30:6fef375c94e6 416 memset(buf,0,CHUNK_SIZE);
wolfSSL 18:d89df40b4cf3 417 send_buf_p = send_buf ; // Reset send buffer ;
wolfSSL 18:d89df40b4cf3 418
wolfSSL 18:d89df40b4cf3 419 const char* meth = (method==HTTP_GET)?"GET":(method==HTTP_POST)?"POST":(method==HTTP_PUT)?"PUT":(method==HTTP_DELETE)?"DELETE":"";
ansond 31:0675a342e45c 420 snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n", meth, path, host); //Write request
wolfSSL 18:d89df40b4cf3 421 ret = send(buf);
wolfSSL 18:d89df40b4cf3 422 if(ret) {
Vanger 33:3b2809748a9e 423 m_sock->close();
wolfSSL 18:d89df40b4cf3 424 ERR("Could not write request");
wolfSSL 18:d89df40b4cf3 425 return HTTP_CONN;
donatien 0:2ccb9960a044 426 }
wolfSSL 17:c73d8e61d391 427
wolfSSL 18:d89df40b4cf3 428 //Send all headers
donatien 0:2ccb9960a044 429
wolfSSL 18:d89df40b4cf3 430 //Send default headers
wolfSSL 18:d89df40b4cf3 431 DBG("Sending headers");
ansond 31:0675a342e45c 432 if(m_basicAuthUser && m_basicAuthPassword) {
ansond 31:0675a342e45c 433 bAuth() ; /* send out Basic Auth header */
wolfSSL 27:5d4739eae63e 434 }
wolfSSL 18:d89df40b4cf3 435 if( pDataOut != NULL ) {
wolfSSL 18:d89df40b4cf3 436 if( pDataOut->getIsChunked() ) {
wolfSSL 18:d89df40b4cf3 437 ret = send("Transfer-Encoding: chunked\r\n");
wolfSSL 18:d89df40b4cf3 438 CHECK_CONN_ERR(ret);
wolfSSL 18:d89df40b4cf3 439 } else {
wolfSSL 18:d89df40b4cf3 440 snprintf(buf, sizeof(buf), "Content-Length: %d\r\n", pDataOut->getDataLen());
wolfSSL 22:4b9a4151cc73 441 DBG("Content buf:%s", buf) ;
wolfSSL 18:d89df40b4cf3 442 ret = send(buf);
wolfSSL 18:d89df40b4cf3 443 CHECK_CONN_ERR(ret);
wolfSSL 18:d89df40b4cf3 444 }
wolfSSL 18:d89df40b4cf3 445 char type[48];
wolfSSL 18:d89df40b4cf3 446 if( pDataOut->getDataType(type, 48) == HTTP_OK ) {
wolfSSL 18:d89df40b4cf3 447 snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", type);
wolfSSL 18:d89df40b4cf3 448 ret = send(buf);
wolfSSL 18:d89df40b4cf3 449 CHECK_CONN_ERR(ret);
wolfSSL 18:d89df40b4cf3 450 }
wolfSSL 18:d89df40b4cf3 451 }
wolfSSL 18:d89df40b4cf3 452
wolfSSL 18:d89df40b4cf3 453 //Add user headers
wolfSSL 18:d89df40b4cf3 454 if(header) {
wolfSSL 27:5d4739eae63e 455 ret = send((char *)header);
donatien 5:791fc3dcb6c4 456 CHECK_CONN_ERR(ret);
donatien 0:2ccb9960a044 457 }
donatien 0:2ccb9960a044 458
wolfSSL 18:d89df40b4cf3 459 //Close headers
wolfSSL 18:d89df40b4cf3 460 DBG("Headers sent");
wolfSSL 18:d89df40b4cf3 461 ret = send("\r\n");
wolfSSL 18:d89df40b4cf3 462 CHECK_CONN_ERR(ret);
wolfSSL 17:c73d8e61d391 463
wolfSSL 18:d89df40b4cf3 464 size_t trfLen;
donatien 0:2ccb9960a044 465
wolfSSL 18:d89df40b4cf3 466 //Send data (if available)
wolfSSL 18:d89df40b4cf3 467 if( pDataOut != NULL ) {
wolfSSL 18:d89df40b4cf3 468 DBG("Sending data");
wolfSSL 18:d89df40b4cf3 469 while(true) {
wolfSSL 18:d89df40b4cf3 470 size_t writtenLen = 0;
wolfSSL 18:d89df40b4cf3 471 pDataOut->read(buf, CHUNK_SIZE, &trfLen);
wolfSSL 18:d89df40b4cf3 472 buf[trfLen] = 0x0 ;
wolfSSL 18:d89df40b4cf3 473 DBG("buf:%s", buf) ;
wolfSSL 18:d89df40b4cf3 474 if( pDataOut->getIsChunked() ) {
wolfSSL 18:d89df40b4cf3 475 //Write chunk header
wolfSSL 22:4b9a4151cc73 476 char chunkHeader[64];
wolfSSL 18:d89df40b4cf3 477 snprintf(chunkHeader, sizeof(chunkHeader), "%X\r\n", trfLen); //In hex encoding
wolfSSL 18:d89df40b4cf3 478 ret = send(chunkHeader);
wolfSSL 18:d89df40b4cf3 479 CHECK_CONN_ERR(ret);
wolfSSL 18:d89df40b4cf3 480 } else if( trfLen == 0 ) {
wolfSSL 22:4b9a4151cc73 481 DBG("trfLen==0") ;
wolfSSL 18:d89df40b4cf3 482 break;
wolfSSL 18:d89df40b4cf3 483 }
wolfSSL 22:4b9a4151cc73 484 DBG("trfLen 1=%d", trfLen) ;
wolfSSL 18:d89df40b4cf3 485 if( trfLen != 0 ) {
wolfSSL 22:4b9a4151cc73 486 DBG("Sending 1") ;
wolfSSL 18:d89df40b4cf3 487 ret = send(buf, trfLen);
wolfSSL 22:4b9a4151cc73 488 DBG("Sent 1") ;
wolfSSL 18:d89df40b4cf3 489 CHECK_CONN_ERR(ret);
wolfSSL 18:d89df40b4cf3 490 }
donatien 0:2ccb9960a044 491
wolfSSL 18:d89df40b4cf3 492 if( pDataOut->getIsChunked() ) {
wolfSSL 18:d89df40b4cf3 493 ret = send("\r\n"); //Chunk-terminating CRLF
wolfSSL 18:d89df40b4cf3 494 CHECK_CONN_ERR(ret);
wolfSSL 18:d89df40b4cf3 495 } else {
wolfSSL 18:d89df40b4cf3 496 writtenLen += trfLen;
wolfSSL 18:d89df40b4cf3 497 if( writtenLen >= pDataOut->getDataLen() ) {
wolfSSL 22:4b9a4151cc73 498 DBG("writtenLen=%d", writtenLen) ;
wolfSSL 18:d89df40b4cf3 499 break;
wolfSSL 18:d89df40b4cf3 500 }
wolfSSL 22:4b9a4151cc73 501 DBG("writtenLen+=trfLen = %d", writtenLen) ;
wolfSSL 18:d89df40b4cf3 502 }
wolfSSL 22:4b9a4151cc73 503 DBG("trfLen 2=%d", trfLen) ;
wolfSSL 18:d89df40b4cf3 504 if( trfLen == 0 ) {
wolfSSL 22:4b9a4151cc73 505 DBG("trfLen == 0") ;
wolfSSL 18:d89df40b4cf3 506 break;
wolfSSL 18:d89df40b4cf3 507 }
wolfSSL 18:d89df40b4cf3 508 }
donatien 0:2ccb9960a044 509
wolfSSL 18:d89df40b4cf3 510 }
wolfSSL 18:d89df40b4cf3 511 ret = flush() ; // flush the send buffer ;
wolfSSL 18:d89df40b4cf3 512 CHECK_CONN_ERR(ret);
wolfSSL 18:d89df40b4cf3 513
wolfSSL 18:d89df40b4cf3 514 //Receive response
wolfSSL 18:d89df40b4cf3 515 DBG("Receiving response");
wolfSSL 18:d89df40b4cf3 516
wolfSSL 18:d89df40b4cf3 517 ret = recv(buf, CHUNK_SIZE - 1, CHUNK_SIZE - 1, &trfLen); //Read n bytes
wolfSSL 18:d89df40b4cf3 518 CHECK_CONN_ERR(ret);
wolfSSL 18:d89df40b4cf3 519
wolfSSL 18:d89df40b4cf3 520 buf[trfLen] = '\0';
wolfSSL 18:d89df40b4cf3 521
wolfSSL 18:d89df40b4cf3 522 char* crlfPtr = strstr(buf, "\r\n");
wolfSSL 18:d89df40b4cf3 523 if(crlfPtr == NULL) {
donatien 5:791fc3dcb6c4 524 PRTCL_ERR();
donatien 0:2ccb9960a044 525 }
donatien 0:2ccb9960a044 526
wolfSSL 18:d89df40b4cf3 527 int crlfPos = crlfPtr - buf;
donatien 0:2ccb9960a044 528 buf[crlfPos] = '\0';
donatien 0:2ccb9960a044 529
wolfSSL 18:d89df40b4cf3 530 //Parse HTTP response
wolfSSL 18:d89df40b4cf3 531 if( sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 ) {
wolfSSL 18:d89df40b4cf3 532 //Cannot match string, error
wolfSSL 18:d89df40b4cf3 533 ERR("Not a correct HTTP answer : %s\n", buf);
wolfSSL 18:d89df40b4cf3 534 PRTCL_ERR();
wolfSSL 18:d89df40b4cf3 535 }
donatien 4:c071b05ac026 536
wolfSSL 27:5d4739eae63e 537 if( (m_httpResponseCode < 200) || (m_httpResponseCode >= 400) ) {
wolfSSL 18:d89df40b4cf3 538 //Did not return a 2xx code; TODO fetch headers/(&data?) anyway and implement a mean of writing/reading headers
wolfSSL 18:d89df40b4cf3 539 WARN("Response code %d", m_httpResponseCode);
wolfSSL 18:d89df40b4cf3 540 PRTCL_ERR();
donatien 0:2ccb9960a044 541 }
donatien 0:2ccb9960a044 542
wolfSSL 18:d89df40b4cf3 543 DBG("Reading headers");
donatien 0:2ccb9960a044 544
wolfSSL 18:d89df40b4cf3 545 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well
wolfSSL 18:d89df40b4cf3 546 trfLen -= (crlfPos + 2);
donatien 0:2ccb9960a044 547
wolfSSL 18:d89df40b4cf3 548 size_t recvContentLength = 0;
wolfSSL 18:d89df40b4cf3 549 bool recvChunked = false;
wolfSSL 18:d89df40b4cf3 550 //Now get headers
wolfSSL 18:d89df40b4cf3 551 while( true ) {
wolfSSL 18:d89df40b4cf3 552 crlfPtr = strstr(buf, "\r\n");
wolfSSL 18:d89df40b4cf3 553 if(crlfPtr == NULL) {
wolfSSL 18:d89df40b4cf3 554 if( trfLen < CHUNK_SIZE - 1 ) {
ansond 30:6fef375c94e6 555 size_t newTrfLen = 0;
wolfSSL 18:d89df40b4cf3 556 ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen);
wolfSSL 18:d89df40b4cf3 557 trfLen += newTrfLen;
wolfSSL 18:d89df40b4cf3 558 buf[trfLen] = '\0';
wolfSSL 18:d89df40b4cf3 559 DBG("Read %d chars; In buf: [%s]", newTrfLen, buf);
wolfSSL 18:d89df40b4cf3 560 CHECK_CONN_ERR(ret);
wolfSSL 18:d89df40b4cf3 561 continue;
wolfSSL 18:d89df40b4cf3 562 } else {
wolfSSL 18:d89df40b4cf3 563 PRTCL_ERR();
donatien 14:2744e0c0e527 564 }
wolfSSL 18:d89df40b4cf3 565 }
wolfSSL 18:d89df40b4cf3 566
wolfSSL 18:d89df40b4cf3 567 crlfPos = crlfPtr - buf;
wolfSSL 18:d89df40b4cf3 568
wolfSSL 18:d89df40b4cf3 569 if(crlfPos == 0) { //End of headers
wolfSSL 18:d89df40b4cf3 570 DBG("Headers read");
wolfSSL 18:d89df40b4cf3 571 memmove(buf, &buf[2], trfLen - 2 + 1); //Be sure to move NULL-terminating char as well
wolfSSL 18:d89df40b4cf3 572 trfLen -= 2;
wolfSSL 18:d89df40b4cf3 573 break;
donatien 0:2ccb9960a044 574 }
wolfSSL 18:d89df40b4cf3 575
wolfSSL 18:d89df40b4cf3 576 buf[crlfPos] = '\0';
wolfSSL 18:d89df40b4cf3 577
ansond 30:6fef375c94e6 578 char key[41];
ansond 30:6fef375c94e6 579 char value[41];
wolfSSL 18:d89df40b4cf3 580
ansond 30:6fef375c94e6 581 memset(key,0,41);
ansond 30:6fef375c94e6 582 memset(value,0,41);
wolfSSL 18:d89df40b4cf3 583
ansond 30:6fef375c94e6 584 int n = sscanf(buf, "%40[^:]: %40[^\r\n]", key, value);
wolfSSL 18:d89df40b4cf3 585 if ( n == 2 ) {
wolfSSL 18:d89df40b4cf3 586 DBG("Read header : %s: %s\n", key, value);
wolfSSL 18:d89df40b4cf3 587 if( !strcmp(key, "Content-Length") ) {
wolfSSL 18:d89df40b4cf3 588 sscanf(value, "%d", &recvContentLength);
wolfSSL 18:d89df40b4cf3 589 pDataIn->setDataLen(recvContentLength);
wolfSSL 18:d89df40b4cf3 590 } else if( !strcmp(key, "Transfer-Encoding") ) {
wolfSSL 18:d89df40b4cf3 591 if( !strcmp(value, "Chunked") || !strcmp(value, "chunked") ) {
wolfSSL 18:d89df40b4cf3 592 recvChunked = true;
wolfSSL 18:d89df40b4cf3 593 pDataIn->setIsChunked(true);
wolfSSL 18:d89df40b4cf3 594 }
wolfSSL 18:d89df40b4cf3 595 } else if( !strcmp(key, "Content-Type") ) {
wolfSSL 18:d89df40b4cf3 596 pDataIn->setDataType(value);
wolfSSL 27:5d4739eae63e 597 } else if( !strcmp(key, "location") && redirect_url) {
ansond 31:0675a342e45c 598 sscanf(buf, "%40[^:]: %128[^\r\n]", key, redirect_url);
wolfSSL 27:5d4739eae63e 599 DBG("Redirect %s: %s", key, redirect_url) ;
wolfSSL 27:5d4739eae63e 600 redirect = 1 ;
wolfSSL 18:d89df40b4cf3 601 }
wolfSSL 18:d89df40b4cf3 602 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well
wolfSSL 18:d89df40b4cf3 603 trfLen -= (crlfPos + 2);
wolfSSL 18:d89df40b4cf3 604
wolfSSL 18:d89df40b4cf3 605 } else {
wolfSSL 18:d89df40b4cf3 606 ERR("Could not parse header");
donatien 14:2744e0c0e527 607 PRTCL_ERR();
donatien 0:2ccb9960a044 608 }
donatien 0:2ccb9960a044 609
donatien 0:2ccb9960a044 610 }
donatien 0:2ccb9960a044 611
wolfSSL 18:d89df40b4cf3 612 //Receive data
wolfSSL 18:d89df40b4cf3 613 DBG("Receiving data");
wolfSSL 18:d89df40b4cf3 614
wolfSSL 18:d89df40b4cf3 615 while(true) {
wolfSSL 18:d89df40b4cf3 616 size_t readLen = 0;
donatien 0:2ccb9960a044 617
wolfSSL 18:d89df40b4cf3 618 if( recvChunked ) {
wolfSSL 18:d89df40b4cf3 619 //Read chunk header
wolfSSL 18:d89df40b4cf3 620 bool foundCrlf;
wolfSSL 18:d89df40b4cf3 621 do {
wolfSSL 18:d89df40b4cf3 622 foundCrlf = false;
wolfSSL 18:d89df40b4cf3 623 crlfPos=0;
wolfSSL 18:d89df40b4cf3 624 buf[trfLen]=0;
wolfSSL 18:d89df40b4cf3 625 if(trfLen >= 2) {
wolfSSL 18:d89df40b4cf3 626 for(; crlfPos < trfLen - 2; crlfPos++) {
wolfSSL 18:d89df40b4cf3 627 if( buf[crlfPos] == '\r' && buf[crlfPos + 1] == '\n' ) {
wolfSSL 18:d89df40b4cf3 628 foundCrlf = true;
wolfSSL 18:d89df40b4cf3 629 break;
wolfSSL 18:d89df40b4cf3 630 }
wolfSSL 18:d89df40b4cf3 631 }
wolfSSL 18:d89df40b4cf3 632 }
wolfSSL 18:d89df40b4cf3 633 if(!foundCrlf) { //Try to read more
wolfSSL 18:d89df40b4cf3 634 if( trfLen < CHUNK_SIZE ) {
ansond 30:6fef375c94e6 635 size_t newTrfLen = 0;
wolfSSL 18:d89df40b4cf3 636 ret = recv(buf + trfLen, 0, CHUNK_SIZE - trfLen - 1, &newTrfLen);
wolfSSL 18:d89df40b4cf3 637 trfLen += newTrfLen;
wolfSSL 18:d89df40b4cf3 638 CHECK_CONN_ERR(ret);
wolfSSL 18:d89df40b4cf3 639 continue;
wolfSSL 18:d89df40b4cf3 640 } else {
wolfSSL 18:d89df40b4cf3 641 PRTCL_ERR();
wolfSSL 18:d89df40b4cf3 642 }
wolfSSL 18:d89df40b4cf3 643 }
wolfSSL 18:d89df40b4cf3 644 } while(!foundCrlf);
wolfSSL 18:d89df40b4cf3 645 buf[crlfPos] = '\0';
wolfSSL 18:d89df40b4cf3 646 int n = sscanf(buf, "%x", &readLen);
wolfSSL 18:d89df40b4cf3 647 if(n!=1) {
wolfSSL 18:d89df40b4cf3 648 ERR("Could not read chunk length");
wolfSSL 18:d89df40b4cf3 649 PRTCL_ERR();
wolfSSL 18:d89df40b4cf3 650 }
wolfSSL 18:d89df40b4cf3 651
wolfSSL 18:d89df40b4cf3 652 memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2)); //Not need to move NULL-terminating char any more
wolfSSL 18:d89df40b4cf3 653 trfLen -= (crlfPos + 2);
donatien 0:2ccb9960a044 654
wolfSSL 18:d89df40b4cf3 655 if( readLen == 0 ) {
wolfSSL 18:d89df40b4cf3 656 //Last chunk
wolfSSL 18:d89df40b4cf3 657 break;
wolfSSL 18:d89df40b4cf3 658 }
wolfSSL 18:d89df40b4cf3 659 } else {
wolfSSL 18:d89df40b4cf3 660 readLen = recvContentLength;
wolfSSL 18:d89df40b4cf3 661 }
wolfSSL 18:d89df40b4cf3 662
wolfSSL 18:d89df40b4cf3 663 DBG("Retrieving %d bytes", readLen);
wolfSSL 18:d89df40b4cf3 664
wolfSSL 18:d89df40b4cf3 665 do {
wolfSSL 18:d89df40b4cf3 666 pDataIn->write(buf, MIN(trfLen, readLen));
wolfSSL 18:d89df40b4cf3 667 if( trfLen > readLen ) {
wolfSSL 18:d89df40b4cf3 668 memmove(buf, &buf[readLen], trfLen - readLen);
wolfSSL 18:d89df40b4cf3 669 trfLen -= readLen;
wolfSSL 18:d89df40b4cf3 670 readLen = 0;
wolfSSL 18:d89df40b4cf3 671 } else {
wolfSSL 18:d89df40b4cf3 672 readLen -= trfLen;
wolfSSL 18:d89df40b4cf3 673 }
donatien 0:2ccb9960a044 674
wolfSSL 18:d89df40b4cf3 675 if(readLen) {
wolfSSL 18:d89df40b4cf3 676 ret = recv(buf, 1, CHUNK_SIZE - trfLen - 1, &trfLen);
wolfSSL 18:d89df40b4cf3 677 CHECK_CONN_ERR(ret);
wolfSSL 18:d89df40b4cf3 678 }
wolfSSL 18:d89df40b4cf3 679 } while(readLen);
wolfSSL 18:d89df40b4cf3 680
wolfSSL 18:d89df40b4cf3 681 if( recvChunked ) {
wolfSSL 18:d89df40b4cf3 682 if(trfLen < 2) {
ansond 30:6fef375c94e6 683 size_t newTrfLen = 0;
wolfSSL 18:d89df40b4cf3 684 //Read missing chars to find end of chunk
wolfSSL 18:d89df40b4cf3 685 ret = recv(buf + trfLen, 2 - trfLen, CHUNK_SIZE - trfLen - 1, &newTrfLen);
wolfSSL 18:d89df40b4cf3 686 CHECK_CONN_ERR(ret);
wolfSSL 18:d89df40b4cf3 687 trfLen += newTrfLen;
wolfSSL 18:d89df40b4cf3 688 }
wolfSSL 18:d89df40b4cf3 689 if( (buf[0] != '\r') || (buf[1] != '\n') ) {
wolfSSL 18:d89df40b4cf3 690 ERR("Format error");
wolfSSL 18:d89df40b4cf3 691 PRTCL_ERR();
wolfSSL 18:d89df40b4cf3 692 }
wolfSSL 18:d89df40b4cf3 693 memmove(buf, &buf[2], trfLen - 2);
wolfSSL 18:d89df40b4cf3 694 trfLen -= 2;
wolfSSL 18:d89df40b4cf3 695 } else {
wolfSSL 18:d89df40b4cf3 696 break;
wolfSSL 18:d89df40b4cf3 697 }
wolfSSL 18:d89df40b4cf3 698
donatien 0:2ccb9960a044 699 }
Vanger 39:d7c5541a9124 700
Vanger 39:d7c5541a9124 701 m_sock->close(true);
wolfSSL 20:bec882d85856 702 cyassl_free() ;
wolfSSL 18:d89df40b4cf3 703 DBG("Completed HTTP transaction");
wolfSSL 27:5d4739eae63e 704 if(redirect)return HTTP_REDIRECT ;
wolfSSL 27:5d4739eae63e 705 else return HTTP_OK;
donatien 0:2ccb9960a044 706 }
donatien 0:2ccb9960a044 707
wolfSSL 19:1e2f05809eb1 708 HTTPResult HTTPClient::recv(char* buf, size_t minLen, size_t maxLen, size_t* pReadLen) //0 on success, err code on failure
donatien 0:2ccb9960a044 709 {
wolfSSL 18:d89df40b4cf3 710 DBG("Trying to read between %d and %d bytes", minLen, maxLen);
wolfSSL 18:d89df40b4cf3 711 size_t readLen = 0;
wolfSSL 18:d89df40b4cf3 712
Vanger 33:3b2809748a9e 713 if(!m_sock->is_connected()) {
wolfSSL 18:d89df40b4cf3 714 WARN("Connection was closed by server");
wolfSSL 18:d89df40b4cf3 715 return HTTP_CLOSED; //Connection was closed by server
wolfSSL 18:d89df40b4cf3 716 }
wolfSSL 18:d89df40b4cf3 717
wolfSSL 18:d89df40b4cf3 718 int ret;
wolfSSL 18:d89df40b4cf3 719
wolfSSL 18:d89df40b4cf3 720 if(port == HTTPS_PORT) {
wolfSSL 18:d89df40b4cf3 721 DBG("Enter CyaSSL_read") ;
wolfSSL 18:d89df40b4cf3 722
Vanger 33:3b2809748a9e 723 m_sock->set_blocking(false, m_timeout);
wolfSSL 18:d89df40b4cf3 724 readLen = CyaSSL_read(ssl, buf, maxLen);
wolfSSL 18:d89df40b4cf3 725 if (readLen > 0) {
wolfSSL 18:d89df40b4cf3 726 buf[readLen] = 0;
wolfSSL 18:d89df40b4cf3 727 DBG("CyaSSL_read:%s\n", buf);
wolfSSL 18:d89df40b4cf3 728 } else {
wolfSSL 18:d89df40b4cf3 729 ERR("CyaSSL_read, ret = %d", readLen) ;
wolfSSL 18:d89df40b4cf3 730 return HTTP_ERROR ;
wolfSSL 18:d89df40b4cf3 731 }
wolfSSL 18:d89df40b4cf3 732 DBG("Read %d bytes", readLen);
wolfSSL 18:d89df40b4cf3 733 *pReadLen = readLen;
wolfSSL 18:d89df40b4cf3 734 return HTTP_OK;
wolfSSL 18:d89df40b4cf3 735 }
wolfSSL 18:d89df40b4cf3 736
wolfSSL 18:d89df40b4cf3 737 while(readLen < maxLen) {
wolfSSL 18:d89df40b4cf3 738 if(readLen < minLen) {
wolfSSL 18:d89df40b4cf3 739 DBG("Trying to read at most %d bytes [Blocking]", minLen - readLen);
Vanger 33:3b2809748a9e 740 m_sock->set_blocking(false, m_timeout);
Vanger 33:3b2809748a9e 741 ret = m_sock->receive_all(buf + readLen, minLen - readLen);
wolfSSL 18:d89df40b4cf3 742 } else {
wolfSSL 18:d89df40b4cf3 743 DBG("Trying to read at most %d bytes [Not blocking]", maxLen - readLen);
Vanger 33:3b2809748a9e 744 m_sock->set_blocking(false, 0);
Vanger 33:3b2809748a9e 745 ret = m_sock->receive(buf + readLen, maxLen - readLen);
wolfSSL 18:d89df40b4cf3 746 }
wolfSSL 18:d89df40b4cf3 747
wolfSSL 18:d89df40b4cf3 748 if( ret > 0) {
wolfSSL 18:d89df40b4cf3 749 readLen += ret;
wolfSSL 18:d89df40b4cf3 750 } else if( ret == 0 ) {
wolfSSL 18:d89df40b4cf3 751 break;
wolfSSL 18:d89df40b4cf3 752 } else {
Vanger 33:3b2809748a9e 753 if(!m_sock->is_connected()) {
wolfSSL 18:d89df40b4cf3 754 ERR("Connection error (recv returned %d)", ret);
wolfSSL 18:d89df40b4cf3 755 *pReadLen = readLen;
wolfSSL 18:d89df40b4cf3 756 return HTTP_CONN;
wolfSSL 18:d89df40b4cf3 757 } else {
wolfSSL 18:d89df40b4cf3 758 break;
wolfSSL 18:d89df40b4cf3 759 }
wolfSSL 18:d89df40b4cf3 760 }
wolfSSL 18:d89df40b4cf3 761
Vanger 33:3b2809748a9e 762 if(!m_sock->is_connected()) {
wolfSSL 18:d89df40b4cf3 763 break;
wolfSSL 18:d89df40b4cf3 764 }
wolfSSL 17:c73d8e61d391 765 }
wolfSSL 17:c73d8e61d391 766 DBG("Read %d bytes", readLen);
wolfSSL 17:c73d8e61d391 767 *pReadLen = readLen;
Vanger 34:13920d48893d 768 m_sock->set_blocking(false, m_timeout);
wolfSSL 17:c73d8e61d391 769 return HTTP_OK;
donatien 7:4e39864f7b15 770 }
donatien 7:4e39864f7b15 771
wolfSSL 19:1e2f05809eb1 772 HTTPResult HTTPClient::send(char* buf, size_t len) //0 on success, err code on failure
donatien 7:4e39864f7b15 773 {
wolfSSL 18:d89df40b4cf3 774 HTTPResult ret ;
wolfSSL 18:d89df40b4cf3 775 int cp_len ;
wolfSSL 18:d89df40b4cf3 776
wolfSSL 18:d89df40b4cf3 777 if(len == 0) {
wolfSSL 18:d89df40b4cf3 778 len = strlen(buf);
wolfSSL 17:c73d8e61d391 779 }
wolfSSL 17:c73d8e61d391 780
wolfSSL 18:d89df40b4cf3 781 do {
wolfSSL 22:4b9a4151cc73 782
wolfSSL 18:d89df40b4cf3 783 if((SEND_BUF_SIZE - (send_buf_p - send_buf)) >= len) {
wolfSSL 18:d89df40b4cf3 784 cp_len = len ;
wolfSSL 18:d89df40b4cf3 785 } else {
wolfSSL 22:4b9a4151cc73 786 cp_len = SEND_BUF_SIZE - (send_buf_p - send_buf) ;
wolfSSL 18:d89df40b4cf3 787 }
wolfSSL 22:4b9a4151cc73 788 DBG("send_buf_p:%x. send_buf+SIZE:%x, len=%d, cp_len=%d", send_buf_p, send_buf+SEND_BUF_SIZE, len, cp_len) ;
wolfSSL 18:d89df40b4cf3 789 memcpy(send_buf_p, buf, cp_len) ;
wolfSSL 18:d89df40b4cf3 790 send_buf_p += cp_len ;
wolfSSL 18:d89df40b4cf3 791 len -= cp_len ;
wolfSSL 18:d89df40b4cf3 792
wolfSSL 18:d89df40b4cf3 793 if(send_buf_p == send_buf + SEND_BUF_SIZE) {
wolfSSL 22:4b9a4151cc73 794 if(port == HTTPS_PORT){
wolfSSL 22:4b9a4151cc73 795 ERR("HTTPClient::send buffer overflow");
wolfSSL 22:4b9a4151cc73 796 return HTTP_ERROR ;
wolfSSL 22:4b9a4151cc73 797 }
wolfSSL 18:d89df40b4cf3 798 ret = flush() ;
wolfSSL 18:d89df40b4cf3 799 if(ret)return(ret) ;
wolfSSL 18:d89df40b4cf3 800 }
wolfSSL 18:d89df40b4cf3 801 } while(len) ;
wolfSSL 18:d89df40b4cf3 802 return HTTP_OK ;
wolfSSL 17:c73d8e61d391 803 }
wolfSSL 17:c73d8e61d391 804
wolfSSL 19:1e2f05809eb1 805 HTTPResult HTTPClient::flush() //0 on success, err code on failure
wolfSSL 17:c73d8e61d391 806 {
wolfSSL 18:d89df40b4cf3 807 int len ;
wolfSSL 18:d89df40b4cf3 808 char * buf ;
wolfSSL 18:d89df40b4cf3 809
wolfSSL 18:d89df40b4cf3 810 buf = send_buf ;
wolfSSL 18:d89df40b4cf3 811 len = send_buf_p - send_buf ;
wolfSSL 18:d89df40b4cf3 812 send_buf_p = send_buf ; // reset send buffer
wolfSSL 18:d89df40b4cf3 813
wolfSSL 18:d89df40b4cf3 814 DBG("Trying to write %d bytes:%s\n", len, buf);
wolfSSL 18:d89df40b4cf3 815 size_t writtenLen = 0;
wolfSSL 18:d89df40b4cf3 816
Vanger 33:3b2809748a9e 817 if(!m_sock->is_connected()) {
wolfSSL 18:d89df40b4cf3 818 WARN("Connection was closed by server");
wolfSSL 18:d89df40b4cf3 819 return HTTP_CLOSED; //Connection was closed by server
wolfSSL 17:c73d8e61d391 820 }
wolfSSL 18:d89df40b4cf3 821
wolfSSL 18:d89df40b4cf3 822 if(port == HTTPS_PORT) {
wolfSSL 18:d89df40b4cf3 823 DBG("Enter CyaSSL_write") ;
wolfSSL 18:d89df40b4cf3 824 if (CyaSSL_write(ssl, buf, len) != len) {
wolfSSL 18:d89df40b4cf3 825 ERR("SSL_write failed");
wolfSSL 18:d89df40b4cf3 826 return HTTP_ERROR ;
wolfSSL 18:d89df40b4cf3 827 }
wolfSSL 18:d89df40b4cf3 828 DBG("Written %d bytes", writtenLen);
wolfSSL 18:d89df40b4cf3 829 return HTTP_OK;
wolfSSL 18:d89df40b4cf3 830 }
Vanger 33:3b2809748a9e 831 m_sock->set_blocking(false, m_timeout);
Vanger 33:3b2809748a9e 832 int ret = m_sock->send_all(buf, len);
wolfSSL 18:d89df40b4cf3 833 if(ret > 0) {
wolfSSL 18:d89df40b4cf3 834 writtenLen += ret;
wolfSSL 18:d89df40b4cf3 835 } else if( ret == 0 ) {
wolfSSL 18:d89df40b4cf3 836 WARN("Connection was closed by server");
wolfSSL 18:d89df40b4cf3 837 return HTTP_CLOSED; //Connection was closed by server
wolfSSL 18:d89df40b4cf3 838 } else {
wolfSSL 18:d89df40b4cf3 839 ERR("Connection error (send returned %d)", ret);
wolfSSL 18:d89df40b4cf3 840 return HTTP_CONN;
wolfSSL 18:d89df40b4cf3 841 }
wolfSSL 18:d89df40b4cf3 842
wolfSSL 17:c73d8e61d391 843 DBG("Written %d bytes", writtenLen);
wolfSSL 17:c73d8e61d391 844 return HTTP_OK;
donatien 0:2ccb9960a044 845 }
donatien 0:2ccb9960a044 846
wolfSSL 19:1e2f05809eb1 847 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 848 {
wolfSSL 18:d89df40b4cf3 849 char* schemePtr = (char*) url;
wolfSSL 18:d89df40b4cf3 850 char* hostPtr = (char*) strstr(url, "://");
wolfSSL 18:d89df40b4cf3 851 if(hostPtr == NULL) {
wolfSSL 18:d89df40b4cf3 852 WARN("Could not find host");
wolfSSL 18:d89df40b4cf3 853 return HTTP_PARSE; //URL is invalid
wolfSSL 18:d89df40b4cf3 854 }
wolfSSL 18:d89df40b4cf3 855
wolfSSL 18:d89df40b4cf3 856 if( maxSchemeLen < hostPtr - schemePtr + 1 ) { //including NULL-terminating char
wolfSSL 18:d89df40b4cf3 857 WARN("Scheme str is too small (%d >= %d)", maxSchemeLen, hostPtr - schemePtr + 1);
wolfSSL 18:d89df40b4cf3 858 return HTTP_PARSE;
wolfSSL 18:d89df40b4cf3 859 }
wolfSSL 18:d89df40b4cf3 860 memcpy(scheme, schemePtr, hostPtr - schemePtr);
wolfSSL 18:d89df40b4cf3 861 scheme[hostPtr - schemePtr] = '\0';
donatien 0:2ccb9960a044 862
wolfSSL 18:d89df40b4cf3 863 hostPtr+=3;
donatien 0:2ccb9960a044 864
wolfSSL 18:d89df40b4cf3 865 size_t hostLen = 0;
donatien 0:2ccb9960a044 866
wolfSSL 18:d89df40b4cf3 867 char* portPtr = strchr(hostPtr, ':');
wolfSSL 18:d89df40b4cf3 868 if( portPtr != NULL ) {
wolfSSL 18:d89df40b4cf3 869 hostLen = portPtr - hostPtr;
wolfSSL 18:d89df40b4cf3 870 portPtr++;
wolfSSL 18:d89df40b4cf3 871 if( sscanf(portPtr, "%hu", port) != 1) {
wolfSSL 18:d89df40b4cf3 872 WARN("Could not find port");
wolfSSL 18:d89df40b4cf3 873 return HTTP_PARSE;
wolfSSL 18:d89df40b4cf3 874 }
wolfSSL 18:d89df40b4cf3 875 } else {
wolfSSL 18:d89df40b4cf3 876 *port=0;
donatien 0:2ccb9960a044 877 }
wolfSSL 18:d89df40b4cf3 878 char* pathPtr = strchr(hostPtr, '/');
Vanger 38:a4ccad70be9d 879
wolfSSL 18:d89df40b4cf3 880 if( hostLen == 0 ) {
wolfSSL 18:d89df40b4cf3 881 hostLen = pathPtr - hostPtr;
wolfSSL 18:d89df40b4cf3 882 }
donatien 0:2ccb9960a044 883
wolfSSL 18:d89df40b4cf3 884 if( maxHostLen < hostLen + 1 ) { //including NULL-terminating char
wolfSSL 18:d89df40b4cf3 885 WARN("Host str is too small (%d >= %d)", maxHostLen, hostLen + 1);
wolfSSL 18:d89df40b4cf3 886 return HTTP_PARSE;
wolfSSL 18:d89df40b4cf3 887 }
donatien 0:2ccb9960a044 888
wolfSSL 18:d89df40b4cf3 889 size_t pathLen;
wolfSSL 18:d89df40b4cf3 890 char* fragmentPtr = strchr(hostPtr, '#');
wolfSSL 18:d89df40b4cf3 891 if(fragmentPtr != NULL) {
wolfSSL 18:d89df40b4cf3 892 pathLen = fragmentPtr - pathPtr;
wolfSSL 18:d89df40b4cf3 893 } else {
wolfSSL 18:d89df40b4cf3 894 pathLen = strlen(pathPtr);
wolfSSL 18:d89df40b4cf3 895 }
donatien 0:2ccb9960a044 896
wolfSSL 18:d89df40b4cf3 897 if( maxPathLen < pathLen + 1 ) { //including NULL-terminating char
wolfSSL 18:d89df40b4cf3 898 WARN("Path str is too small (%d >= %d)", maxPathLen, pathLen + 1);
wolfSSL 18:d89df40b4cf3 899 return HTTP_PARSE;
wolfSSL 18:d89df40b4cf3 900 }
Vanger 42:2f464f96c204 901 memcpy(host, hostPtr, hostLen);
Vanger 42:2f464f96c204 902 host[hostLen] = '\0';
wolfSSL 18:d89df40b4cf3 903 memcpy(path, pathPtr, pathLen);
wolfSSL 18:d89df40b4cf3 904 path[pathLen] = '\0';
donatien 0:2ccb9960a044 905
wolfSSL 18:d89df40b4cf3 906 return HTTP_OK;
donatien 0:2ccb9960a044 907 }
wolfSSL 22:4b9a4151cc73 908
wolfSSL 22:4b9a4151cc73 909 HTTPResult HTTPClient::bAuth(void)
wolfSSL 22:4b9a4151cc73 910 {
wolfSSL 22:4b9a4151cc73 911 HTTPResult ret ;
wolfSSL 22:4b9a4151cc73 912 char b_auth[(int)((AUTHB_SIZE+3)*4/3+1)] ;
wolfSSL 22:4b9a4151cc73 913 char base64buff[AUTHB_SIZE+3] ;
Vanger 34:13920d48893d 914
wolfSSL 22:4b9a4151cc73 915 ret = send("Authorization: Basic ") ;
wolfSSL 22:4b9a4151cc73 916 CHECK_CONN_ERR(ret);
wolfSSL 22:4b9a4151cc73 917 sprintf(base64buff, "%s:%s", m_basicAuthUser, m_basicAuthPassword) ;
wolfSSL 27:5d4739eae63e 918 DBG("bAuth: %s", base64buff) ;
wolfSSL 22:4b9a4151cc73 919 base64enc(b_auth, base64buff) ;
Vanger 37:293e8eae4230 920
Vanger 34:13920d48893d 921 int b_auth_len = strlen(b_auth);
Vanger 34:13920d48893d 922 if(b_auth_len + 3 >= sizeof(b_auth)) { //\r\n\0 characters make up the +3
Vanger 34:13920d48893d 923 ERR("The encoded line is larger than the buffer that holds it");
Vanger 34:13920d48893d 924 }
Vanger 34:13920d48893d 925 b_auth[b_auth_len + 2] = '\0' ;
Vanger 34:13920d48893d 926 b_auth[b_auth_len + 1] = '\n' ;
Vanger 34:13920d48893d 927 b_auth[b_auth_len] = '\r' ;
wolfSSL 22:4b9a4151cc73 928 DBG("b_auth:%s", b_auth) ;
wolfSSL 22:4b9a4151cc73 929 ret = send(b_auth) ;
wolfSSL 22:4b9a4151cc73 930 CHECK_CONN_ERR(ret);
wolfSSL 22:4b9a4151cc73 931 return HTTP_OK ;
wolfSSL 22:4b9a4151cc73 932 }