fix the problem http request with '\0' and fixx query string in url
Fork of mbed-http by
https_request.h
00001 /* 00002 * PackageLicenseDeclared: Apache-2.0 00003 * Copyright (c) 2017 ARM Limited 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #ifndef _MBED_HTTPS_REQUEST_H_ 00019 #define _MBED_HTTPS_REQUEST_H_ 00020 00021 /* Change to a number between 1 and 4 to debug the TLS connection */ 00022 #define DEBUG_LEVEL 0 00023 00024 #include <string> 00025 #include <vector> 00026 #include <map> 00027 #include "http_parser.h" 00028 #include "http_response.h" 00029 #include "http_request_builder.h" 00030 #include "http_response_parser.h" 00031 #include "http_parsed_url.h" 00032 00033 #include "mbedtls/platform.h" 00034 #include "mbedtls/ssl.h" 00035 #include "mbedtls/entropy.h" 00036 #include "mbedtls/ctr_drbg.h" 00037 #include "mbedtls/error.h" 00038 00039 #if DEBUG_LEVEL > 0 00040 #include "mbedtls/debug.h" 00041 #endif 00042 00043 /** 00044 * \brief HttpsRequest implements the logic for interacting with HTTPS servers. 00045 */ 00046 class HttpsRequest { 00047 public: 00048 /** 00049 * HttpsRequest Constructor 00050 * Initializes the TCP socket, sets up event handlers and flags. 00051 * 00052 * @param[in] net_iface The network interface 00053 * @param[in] ssl_ca_pem String containing the trusted CAs 00054 * @param[in] method HTTP method to use 00055 * @param[in] url URL to the resource 00056 * @param[in] body_callback Callback on which to retrieve chunks of the response body. 00057 If not set, the complete body will be allocated on the HttpResponse object, 00058 which might use lots of memory. 00059 */ 00060 HttpsRequest(NetworkInterface* net_iface, 00061 const char* ssl_ca_pem, 00062 http_method method, 00063 const char* url, 00064 Callback<void(const char *at, size_t length)> body_callback = 0) 00065 { 00066 _parsed_url = new ParsedUrl(url); 00067 _body_callback = body_callback; 00068 _tcpsocket = new TCPSocket(net_iface); 00069 _request_builder = new HttpRequestBuilder(method, _parsed_url); 00070 _response = NULL; 00071 _debug = false; 00072 _ssl_ca_pem = ssl_ca_pem; 00073 00074 DRBG_PERS = "mbed TLS helloword client"; 00075 00076 mbedtls_entropy_init(&_entropy); 00077 mbedtls_ctr_drbg_init(&_ctr_drbg); 00078 mbedtls_x509_crt_init(&_cacert); 00079 mbedtls_ssl_init(&_ssl); 00080 mbedtls_ssl_config_init(&_ssl_conf); 00081 } 00082 00083 /** 00084 * HttpsRequest Destructor 00085 */ 00086 ~HttpsRequest() { 00087 mbedtls_entropy_free(&_entropy); 00088 mbedtls_ctr_drbg_free(&_ctr_drbg); 00089 mbedtls_x509_crt_free(&_cacert); 00090 mbedtls_ssl_free(&_ssl); 00091 mbedtls_ssl_config_free(&_ssl_conf); 00092 00093 if (_request_builder) { 00094 delete _request_builder; 00095 } 00096 00097 if (_tcpsocket) { 00098 delete _tcpsocket; 00099 } 00100 00101 if (_parsed_url) { 00102 delete _parsed_url; 00103 } 00104 00105 if (_response) { 00106 delete _response; 00107 } 00108 00109 // @todo: free DRBG_PERS ? 00110 } 00111 00112 /** 00113 * Execute the HTTPS request. 00114 * 00115 * @param[in] body Pointer to the request body 00116 * @param[in] body_size Size of the request body 00117 * @return An HttpResponse pointer on success, or NULL on failure. 00118 * See get_error() for the error code. 00119 */ 00120 HttpResponse* send(const void* body = NULL, nsapi_size_t body_size = 0) { 00121 /* Initialize the flags */ 00122 /* 00123 * Initialize TLS-related stuf. 00124 */ 00125 int ret; 00126 if ((ret = mbedtls_ctr_drbg_seed(&_ctr_drbg, mbedtls_entropy_func, &_entropy, 00127 (const unsigned char *) DRBG_PERS, 00128 sizeof (DRBG_PERS))) != 0) { 00129 print_mbedtls_error("mbedtls_crt_drbg_init", ret); 00130 _error = ret; 00131 return NULL; 00132 } 00133 00134 if ((ret = mbedtls_x509_crt_parse(&_cacert, (const unsigned char *)_ssl_ca_pem, 00135 strlen(_ssl_ca_pem) + 1)) != 0) { 00136 print_mbedtls_error("mbedtls_x509_crt_parse", ret); 00137 _error = ret; 00138 return NULL; 00139 } 00140 00141 if ((ret = mbedtls_ssl_config_defaults(&_ssl_conf, 00142 MBEDTLS_SSL_IS_CLIENT, 00143 MBEDTLS_SSL_TRANSPORT_STREAM, 00144 MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { 00145 print_mbedtls_error("mbedtls_ssl_config_defaults", ret); 00146 _error = ret; 00147 return NULL; 00148 } 00149 00150 mbedtls_ssl_conf_ca_chain(&_ssl_conf, &_cacert, NULL); 00151 mbedtls_ssl_conf_rng(&_ssl_conf, mbedtls_ctr_drbg_random, &_ctr_drbg); 00152 00153 /* It is possible to disable authentication by passing 00154 * MBEDTLS_SSL_VERIFY_NONE in the call to mbedtls_ssl_conf_authmode() 00155 */ 00156 mbedtls_ssl_conf_authmode(&_ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED); 00157 00158 #if DEBUG_LEVEL > 0 00159 mbedtls_ssl_conf_verify(&_ssl_conf, my_verify, NULL); 00160 mbedtls_ssl_conf_dbg(&_ssl_conf, my_debug, NULL); 00161 mbedtls_debug_set_threshold(DEBUG_LEVEL); 00162 #endif 00163 00164 if ((ret = mbedtls_ssl_setup(&_ssl, &_ssl_conf)) != 0) { 00165 print_mbedtls_error("mbedtls_ssl_setup", ret); 00166 _error = ret; 00167 return NULL; 00168 } 00169 00170 mbedtls_ssl_set_hostname(&_ssl, _parsed_url->host()); 00171 00172 mbedtls_ssl_set_bio(&_ssl, static_cast<void *>(_tcpsocket), 00173 ssl_send, ssl_recv, NULL ); 00174 00175 /* Connect to the server */ 00176 if (_debug) mbedtls_printf("Connecting to %s:%d\r\n", _parsed_url->host(), _parsed_url->port()); 00177 ret = _tcpsocket->connect(_parsed_url->host(), _parsed_url->port()); 00178 if (ret != NSAPI_ERROR_OK) { 00179 if (_debug) mbedtls_printf("Failed to connect\r\n"); 00180 onError(_tcpsocket, -1); 00181 return NULL; 00182 } 00183 00184 /* Start the handshake, the rest will be done in onReceive() */ 00185 if (_debug) mbedtls_printf("Starting the TLS handshake...\r\n"); 00186 ret = mbedtls_ssl_handshake(&_ssl); 00187 if (ret < 0) { 00188 if (ret != MBEDTLS_ERR_SSL_WANT_READ && 00189 ret != MBEDTLS_ERR_SSL_WANT_WRITE) { 00190 print_mbedtls_error("mbedtls_ssl_handshake", ret); 00191 onError(_tcpsocket, -1); 00192 } 00193 else { 00194 _error = ret; 00195 } 00196 return NULL; 00197 } 00198 00199 size_t request_size = 0; 00200 char* request = _request_builder->build(body, body_size, request_size); 00201 00202 ret = mbedtls_ssl_write(&_ssl, (const unsigned char *) request, request_size); 00203 00204 free(request); 00205 00206 if (ret < 0) { 00207 if (ret != MBEDTLS_ERR_SSL_WANT_READ && 00208 ret != MBEDTLS_ERR_SSL_WANT_WRITE) { 00209 print_mbedtls_error("mbedtls_ssl_write", ret); 00210 onError(_tcpsocket, -1 ); 00211 } 00212 else { 00213 _error = ret; 00214 } 00215 return NULL; 00216 } 00217 00218 /* It also means the handshake is done, time to print info */ 00219 if (_debug) mbedtls_printf("TLS connection to %s:%d established\r\n", _parsed_url->host(), _parsed_url->port()); 00220 00221 const uint32_t buf_size = 1024; 00222 char *buf = new char[buf_size]; 00223 mbedtls_x509_crt_info(buf, buf_size, "\r ", 00224 mbedtls_ssl_get_peer_cert(&_ssl)); 00225 if (_debug) mbedtls_printf("Server certificate:\r\n%s\r", buf); 00226 00227 uint32_t flags = mbedtls_ssl_get_verify_result(&_ssl); 00228 if( flags != 0 ) 00229 { 00230 mbedtls_x509_crt_verify_info(buf, buf_size, "\r ! ", flags); 00231 if (_debug) mbedtls_printf("Certificate verification failed:\r\n%s\r\r\n", buf); 00232 } 00233 else { 00234 if (_debug) mbedtls_printf("Certificate verification passed\r\n\r\n"); 00235 } 00236 00237 // Create a response object 00238 _response = new HttpResponse(); 00239 // And a response parser 00240 HttpResponseParser parser(_response, _body_callback); 00241 00242 // Set up a receive buffer (on the heap) 00243 uint8_t* recv_buffer = (uint8_t*)malloc(HTTP_RECEIVE_BUFFER_SIZE); 00244 00245 /* Read data out of the socket */ 00246 while ((ret = mbedtls_ssl_read(&_ssl, (unsigned char *) recv_buffer, HTTP_RECEIVE_BUFFER_SIZE)) > 0) { 00247 // Don't know if this is actually needed, but OK 00248 size_t _bpos = static_cast<size_t>(ret); 00249 recv_buffer[_bpos] = 0; 00250 00251 size_t nparsed = parser.execute((const char*)recv_buffer, _bpos); 00252 if (nparsed != _bpos) { 00253 print_mbedtls_error("parser_error", nparsed); 00254 // parser error... 00255 _error = -2101; 00256 free(recv_buffer); 00257 return NULL; 00258 } 00259 00260 if (_response->is_message_complete()) { 00261 break; 00262 } 00263 } 00264 if (ret < 0) { 00265 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { 00266 print_mbedtls_error("mbedtls_ssl_read", ret); 00267 onError(_tcpsocket, -1 ); 00268 } 00269 else { 00270 _error = ret; 00271 } 00272 free(recv_buffer); 00273 return NULL; 00274 } 00275 00276 parser.finish(); 00277 00278 _tcpsocket->close(); 00279 free(recv_buffer); 00280 00281 return _response; 00282 } 00283 00284 /** 00285 * Closes the TCP socket 00286 */ 00287 void close() { 00288 _tcpsocket->close(); 00289 } 00290 00291 /** 00292 * Set a header for the request. 00293 * 00294 * The 'Host' and 'Content-Length' headers are set automatically. 00295 * Setting the same header twice will overwrite the previous entry. 00296 * 00297 * @param[in] key Header key 00298 * @param[in] value Header value 00299 */ 00300 void set_header(string key, string value) { 00301 _request_builder->set_header(key, value); 00302 } 00303 00304 /** 00305 * Get the error code. 00306 * 00307 * When send() fails, this error is set. 00308 */ 00309 nsapi_error_t get_error() { 00310 return _error; 00311 } 00312 00313 /** 00314 * Set the debug flag. 00315 * 00316 * If this flag is set, debug information from mbed TLS will be logged to stdout. 00317 */ 00318 void set_debug(bool debug) { 00319 _debug = debug; 00320 } 00321 00322 protected: 00323 /** 00324 * Helper for pretty-printing mbed TLS error codes 00325 */ 00326 static void print_mbedtls_error(const char *name, int err) { 00327 char buf[128]; 00328 mbedtls_strerror(err, buf, sizeof (buf)); 00329 mbedtls_printf("%s() failed: -0x%04x (%d): %s\r\n", name, -err, err, buf); 00330 } 00331 00332 #if DEBUG_LEVEL > 0 00333 /** 00334 * Debug callback for mbed TLS 00335 * Just prints on the USB serial port 00336 */ 00337 static void my_debug(void *ctx, int level, const char *file, int line, 00338 const char *str) 00339 { 00340 const char *p, *basename; 00341 (void) ctx; 00342 00343 /* Extract basename from file */ 00344 for(p = basename = file; *p != '\0'; p++) { 00345 if(*p == '/' || *p == '\\') { 00346 basename = p + 1; 00347 } 00348 } 00349 00350 if (_debug) { 00351 mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str); 00352 } 00353 } 00354 00355 /** 00356 * Certificate verification callback for mbed TLS 00357 * Here we only use it to display information on each cert in the chain 00358 */ 00359 static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) 00360 { 00361 const uint32_t buf_size = 1024; 00362 char *buf = new char[buf_size]; 00363 (void) data; 00364 00365 if (_debug) mbedtls_printf("\nVerifying certificate at depth %d:\n", depth); 00366 mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt); 00367 if (_debug) mbedtls_printf("%s", buf); 00368 00369 if (*flags == 0) 00370 if (_debug) mbedtls_printf("No verification issue for this certificate\n"); 00371 else 00372 { 00373 mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags); 00374 if (_debug) mbedtls_printf("%s\n", buf); 00375 } 00376 00377 delete[] buf; 00378 return 0; 00379 } 00380 #endif 00381 00382 /** 00383 * Receive callback for mbed TLS 00384 */ 00385 static int ssl_recv(void *ctx, unsigned char *buf, size_t len) { 00386 int recv = -1; 00387 TCPSocket *socket = static_cast<TCPSocket *>(ctx); 00388 recv = socket->recv(buf, len); 00389 00390 if (NSAPI_ERROR_WOULD_BLOCK == recv) { 00391 return MBEDTLS_ERR_SSL_WANT_READ; 00392 } 00393 else if (recv < 0) { 00394 return -1; 00395 } 00396 else { 00397 return recv; 00398 } 00399 } 00400 00401 /** 00402 * Send callback for mbed TLS 00403 */ 00404 static int ssl_send(void *ctx, const unsigned char *buf, size_t len) { 00405 int size = -1; 00406 TCPSocket *socket = static_cast<TCPSocket *>(ctx); 00407 size = socket->send(buf, len); 00408 00409 if(NSAPI_ERROR_WOULD_BLOCK == size) { 00410 return len; 00411 } 00412 else if (size < 0){ 00413 return -1; 00414 } 00415 else { 00416 return size; 00417 } 00418 } 00419 00420 void onError(TCPSocket *s, int error) { 00421 s->close(); 00422 _error = error; 00423 } 00424 00425 protected: 00426 TCPSocket* _tcpsocket; 00427 00428 Callback<void(const char *at, size_t length)> _body_callback; 00429 ParsedUrl* _parsed_url; 00430 HttpRequestBuilder* _request_builder; 00431 HttpResponse* _response; 00432 const char *DRBG_PERS; 00433 const char *_ssl_ca_pem; 00434 00435 nsapi_error_t _error; 00436 bool _debug; 00437 00438 mbedtls_entropy_context _entropy; 00439 mbedtls_ctr_drbg_context _ctr_drbg; 00440 mbedtls_x509_crt _cacert; 00441 mbedtls_ssl_context _ssl; 00442 mbedtls_ssl_config _ssl_conf; 00443 }; 00444 00445 #endif // _MBED_HTTPS_REQUEST_H_
Generated on Fri Jul 22 2022 08:07:18 by
1.7.2
