HTTP and HTTPS example application for Mbed OS 5

Dependencies:   mbed-http

This application demonstrates how to make HTTP and HTTPS requests and parse the response from Mbed OS 5.

It consists of six example applications, which you can select in source/select-demo.h:

Response parsing is done through nodejs/http-parser.

Note: HTTPS requests do not work on targets with less than 128K of RAM due to the size of the TLS handshake. For more background see mbed-http.

To build

  1. If you're using WiFi, specify the credentials in mbed_app.json.
  2. Build the project in the online compiler or using Mbed CLI.
  3. Flash the project to your development board.
  4. Attach a serial monitor to your board to see the debug messages.

Defining the network interface

This application uses the on-board network interface for your board. If you use an external network interface (f.e. a WiFi module) you need to add the driver to this project. Then, open network-helper.h and specify which network driver to use.

More information is in the Mbed OS documentation under IP Networking.

Entropy (or lack thereof)

On all platforms that do not have the TRNG feature, the application is compiled without TLS entropy sources. This means that your code is inherently unsafe and should not be deployed to any production systems. To enable entropy, remove the MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES and MBEDTLS_TEST_NULL_ENTROPY macros from mbed_app.json.

Flash size

Default flash size for HTTPS is very large, as the application is loading the default Mbed TLS configuration. To use a more optimized version, you can disable unused cypher suites and other Mbed TLS features with a custom configuration file. Create a new configuration file, then add in mbed_app.json:

"MBEDTLS_CONFIG_FILE=\"mbedtls_config.h\""

to the macros array.

Running tests

You can run the integration tests from this project via Mbed CLI.

  1. In select-demo.h set the DEMO macro to DEMO_TESTS.
  2. Set your WiFi credentials in mbed_app.json.
  3. Then run the tests via:

$ mbed test -v -n mbed-http-tests-tests-*

Tested on

  • K64F with Ethernet.
  • NUCLEO_F411RE with ESP8266 (not working on Mbed OS 5.12+)
  • ODIN-W2 with WiFi.
  • K64F with Atmel 6LoWPAN shield.
  • DISCO-L475VG-IOT01A with WiFi (requires the wifi-ism43362 driver).
Committer:
Jan Jongboom
Date:
Thu Feb 16 11:13:40 2017 +0100
Revision:
1:3bff14db67c7
Add mbed-http

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Jan Jongboom 1:3bff14db67c7 1 #ifndef _MBED_HTTPS_REQUEST_H_
Jan Jongboom 1:3bff14db67c7 2 #define _MBED_HTTPS_REQUEST_H_
Jan Jongboom 1:3bff14db67c7 3
Jan Jongboom 1:3bff14db67c7 4 /* Change to a number between 1 and 4 to debug the TLS connection */
Jan Jongboom 1:3bff14db67c7 5 #define DEBUG_LEVEL 0
Jan Jongboom 1:3bff14db67c7 6
Jan Jongboom 1:3bff14db67c7 7 #include <string>
Jan Jongboom 1:3bff14db67c7 8 #include <vector>
Jan Jongboom 1:3bff14db67c7 9 #include <map>
Jan Jongboom 1:3bff14db67c7 10 #include "http_parser.h"
Jan Jongboom 1:3bff14db67c7 11 #include "http_response.h"
Jan Jongboom 1:3bff14db67c7 12 #include "http_request_builder.h"
Jan Jongboom 1:3bff14db67c7 13 #include "http_response_parser.h"
Jan Jongboom 1:3bff14db67c7 14 #include "http_parsed_url.h"
Jan Jongboom 1:3bff14db67c7 15
Jan Jongboom 1:3bff14db67c7 16 #include "mbedtls/platform.h"
Jan Jongboom 1:3bff14db67c7 17 #include "mbedtls/ssl.h"
Jan Jongboom 1:3bff14db67c7 18 #include "mbedtls/entropy.h"
Jan Jongboom 1:3bff14db67c7 19 #include "mbedtls/ctr_drbg.h"
Jan Jongboom 1:3bff14db67c7 20 #include "mbedtls/error.h"
Jan Jongboom 1:3bff14db67c7 21
Jan Jongboom 1:3bff14db67c7 22 #if DEBUG_LEVEL > 0
Jan Jongboom 1:3bff14db67c7 23 #include "mbedtls/debug.h"
Jan Jongboom 1:3bff14db67c7 24 #endif
Jan Jongboom 1:3bff14db67c7 25
Jan Jongboom 1:3bff14db67c7 26 /**
Jan Jongboom 1:3bff14db67c7 27 * \brief HttpsRequest implements the logic for interacting with HTTPS servers.
Jan Jongboom 1:3bff14db67c7 28 */
Jan Jongboom 1:3bff14db67c7 29 class HttpsRequest {
Jan Jongboom 1:3bff14db67c7 30 public:
Jan Jongboom 1:3bff14db67c7 31 /**
Jan Jongboom 1:3bff14db67c7 32 * HttpsRequest Constructor
Jan Jongboom 1:3bff14db67c7 33 * Initializes the TCP socket, sets up event handlers and flags.
Jan Jongboom 1:3bff14db67c7 34 *
Jan Jongboom 1:3bff14db67c7 35 * @param[in] net_iface The network interface
Jan Jongboom 1:3bff14db67c7 36 * @param[in] ssl_ca_pem String containing the trusted CAs
Jan Jongboom 1:3bff14db67c7 37 * @param[in] method HTTP method to use
Jan Jongboom 1:3bff14db67c7 38 * @param[in] url URL to the resource
Jan Jongboom 1:3bff14db67c7 39 * @param[in] body_callback Callback on which to retrieve chunks of the response body.
Jan Jongboom 1:3bff14db67c7 40 If not set, the complete body will be allocated on the HttpResponse object,
Jan Jongboom 1:3bff14db67c7 41 which might use lots of memory.
Jan Jongboom 1:3bff14db67c7 42 */
Jan Jongboom 1:3bff14db67c7 43 HttpsRequest(NetworkInterface* net_iface,
Jan Jongboom 1:3bff14db67c7 44 const char* ssl_ca_pem,
Jan Jongboom 1:3bff14db67c7 45 http_method method,
Jan Jongboom 1:3bff14db67c7 46 const char* url,
Jan Jongboom 1:3bff14db67c7 47 Callback<void(const char *at, size_t length)> body_callback = 0)
Jan Jongboom 1:3bff14db67c7 48 {
Jan Jongboom 1:3bff14db67c7 49 _parsed_url = new ParsedUrl(url);
Jan Jongboom 1:3bff14db67c7 50 _body_callback = body_callback;
Jan Jongboom 1:3bff14db67c7 51 _tcpsocket = new TCPSocket(net_iface);
Jan Jongboom 1:3bff14db67c7 52 _request_builder = new HttpRequestBuilder(method, _parsed_url);
Jan Jongboom 1:3bff14db67c7 53 _response = NULL;
Jan Jongboom 1:3bff14db67c7 54 _debug = false;
Jan Jongboom 1:3bff14db67c7 55 _ssl_ca_pem = ssl_ca_pem;
Jan Jongboom 1:3bff14db67c7 56
Jan Jongboom 1:3bff14db67c7 57 DRBG_PERS = "mbed TLS helloword client";
Jan Jongboom 1:3bff14db67c7 58
Jan Jongboom 1:3bff14db67c7 59 mbedtls_entropy_init(&_entropy);
Jan Jongboom 1:3bff14db67c7 60 mbedtls_ctr_drbg_init(&_ctr_drbg);
Jan Jongboom 1:3bff14db67c7 61 mbedtls_x509_crt_init(&_cacert);
Jan Jongboom 1:3bff14db67c7 62 mbedtls_ssl_init(&_ssl);
Jan Jongboom 1:3bff14db67c7 63 mbedtls_ssl_config_init(&_ssl_conf);
Jan Jongboom 1:3bff14db67c7 64 }
Jan Jongboom 1:3bff14db67c7 65
Jan Jongboom 1:3bff14db67c7 66 /**
Jan Jongboom 1:3bff14db67c7 67 * HttpsRequest Destructor
Jan Jongboom 1:3bff14db67c7 68 */
Jan Jongboom 1:3bff14db67c7 69 ~HttpsRequest() {
Jan Jongboom 1:3bff14db67c7 70 mbedtls_entropy_free(&_entropy);
Jan Jongboom 1:3bff14db67c7 71 mbedtls_ctr_drbg_free(&_ctr_drbg);
Jan Jongboom 1:3bff14db67c7 72 mbedtls_x509_crt_free(&_cacert);
Jan Jongboom 1:3bff14db67c7 73 mbedtls_ssl_free(&_ssl);
Jan Jongboom 1:3bff14db67c7 74 mbedtls_ssl_config_free(&_ssl_conf);
Jan Jongboom 1:3bff14db67c7 75
Jan Jongboom 1:3bff14db67c7 76 if (_request_builder) {
Jan Jongboom 1:3bff14db67c7 77 delete _request_builder;
Jan Jongboom 1:3bff14db67c7 78 }
Jan Jongboom 1:3bff14db67c7 79
Jan Jongboom 1:3bff14db67c7 80 if (_tcpsocket) {
Jan Jongboom 1:3bff14db67c7 81 delete _tcpsocket;
Jan Jongboom 1:3bff14db67c7 82 }
Jan Jongboom 1:3bff14db67c7 83
Jan Jongboom 1:3bff14db67c7 84 if (_parsed_url) {
Jan Jongboom 1:3bff14db67c7 85 delete _parsed_url;
Jan Jongboom 1:3bff14db67c7 86 }
Jan Jongboom 1:3bff14db67c7 87
Jan Jongboom 1:3bff14db67c7 88 if (_response) {
Jan Jongboom 1:3bff14db67c7 89 delete _response;
Jan Jongboom 1:3bff14db67c7 90 }
Jan Jongboom 1:3bff14db67c7 91
Jan Jongboom 1:3bff14db67c7 92 // @todo: free DRBG_PERS ?
Jan Jongboom 1:3bff14db67c7 93 }
Jan Jongboom 1:3bff14db67c7 94
Jan Jongboom 1:3bff14db67c7 95 /**
Jan Jongboom 1:3bff14db67c7 96 * Execute the HTTPS request.
Jan Jongboom 1:3bff14db67c7 97 *
Jan Jongboom 1:3bff14db67c7 98 * @param[in] body Pointer to the request body
Jan Jongboom 1:3bff14db67c7 99 * @param[in] body_size Size of the request body
Jan Jongboom 1:3bff14db67c7 100 * @return An HttpResponse pointer on success, or NULL on failure.
Jan Jongboom 1:3bff14db67c7 101 * See get_error() for the error code.
Jan Jongboom 1:3bff14db67c7 102 */
Jan Jongboom 1:3bff14db67c7 103 HttpResponse* send(const void* body = NULL, nsapi_size_t body_size = 0) {
Jan Jongboom 1:3bff14db67c7 104 /* Initialize the flags */
Jan Jongboom 1:3bff14db67c7 105 /*
Jan Jongboom 1:3bff14db67c7 106 * Initialize TLS-related stuf.
Jan Jongboom 1:3bff14db67c7 107 */
Jan Jongboom 1:3bff14db67c7 108 int ret;
Jan Jongboom 1:3bff14db67c7 109 if ((ret = mbedtls_ctr_drbg_seed(&_ctr_drbg, mbedtls_entropy_func, &_entropy,
Jan Jongboom 1:3bff14db67c7 110 (const unsigned char *) DRBG_PERS,
Jan Jongboom 1:3bff14db67c7 111 sizeof (DRBG_PERS))) != 0) {
Jan Jongboom 1:3bff14db67c7 112 print_mbedtls_error("mbedtls_crt_drbg_init", ret);
Jan Jongboom 1:3bff14db67c7 113 _error = ret;
Jan Jongboom 1:3bff14db67c7 114 return NULL;
Jan Jongboom 1:3bff14db67c7 115 }
Jan Jongboom 1:3bff14db67c7 116
Jan Jongboom 1:3bff14db67c7 117 if ((ret = mbedtls_x509_crt_parse(&_cacert, (const unsigned char *)_ssl_ca_pem,
Jan Jongboom 1:3bff14db67c7 118 strlen(_ssl_ca_pem) + 1)) != 0) {
Jan Jongboom 1:3bff14db67c7 119 print_mbedtls_error("mbedtls_x509_crt_parse", ret);
Jan Jongboom 1:3bff14db67c7 120 _error = ret;
Jan Jongboom 1:3bff14db67c7 121 return NULL;
Jan Jongboom 1:3bff14db67c7 122 }
Jan Jongboom 1:3bff14db67c7 123
Jan Jongboom 1:3bff14db67c7 124 if ((ret = mbedtls_ssl_config_defaults(&_ssl_conf,
Jan Jongboom 1:3bff14db67c7 125 MBEDTLS_SSL_IS_CLIENT,
Jan Jongboom 1:3bff14db67c7 126 MBEDTLS_SSL_TRANSPORT_STREAM,
Jan Jongboom 1:3bff14db67c7 127 MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
Jan Jongboom 1:3bff14db67c7 128 print_mbedtls_error("mbedtls_ssl_config_defaults", ret);
Jan Jongboom 1:3bff14db67c7 129 _error = ret;
Jan Jongboom 1:3bff14db67c7 130 return NULL;
Jan Jongboom 1:3bff14db67c7 131 }
Jan Jongboom 1:3bff14db67c7 132
Jan Jongboom 1:3bff14db67c7 133 mbedtls_ssl_conf_ca_chain(&_ssl_conf, &_cacert, NULL);
Jan Jongboom 1:3bff14db67c7 134 mbedtls_ssl_conf_rng(&_ssl_conf, mbedtls_ctr_drbg_random, &_ctr_drbg);
Jan Jongboom 1:3bff14db67c7 135
Jan Jongboom 1:3bff14db67c7 136 /* It is possible to disable authentication by passing
Jan Jongboom 1:3bff14db67c7 137 * MBEDTLS_SSL_VERIFY_NONE in the call to mbedtls_ssl_conf_authmode()
Jan Jongboom 1:3bff14db67c7 138 */
Jan Jongboom 1:3bff14db67c7 139 mbedtls_ssl_conf_authmode(&_ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
Jan Jongboom 1:3bff14db67c7 140
Jan Jongboom 1:3bff14db67c7 141 #if DEBUG_LEVEL > 0
Jan Jongboom 1:3bff14db67c7 142 mbedtls_ssl_conf_verify(&_ssl_conf, my_verify, NULL);
Jan Jongboom 1:3bff14db67c7 143 mbedtls_ssl_conf_dbg(&_ssl_conf, my_debug, NULL);
Jan Jongboom 1:3bff14db67c7 144 mbedtls_debug_set_threshold(DEBUG_LEVEL);
Jan Jongboom 1:3bff14db67c7 145 #endif
Jan Jongboom 1:3bff14db67c7 146
Jan Jongboom 1:3bff14db67c7 147 if ((ret = mbedtls_ssl_setup(&_ssl, &_ssl_conf)) != 0) {
Jan Jongboom 1:3bff14db67c7 148 print_mbedtls_error("mbedtls_ssl_setup", ret);
Jan Jongboom 1:3bff14db67c7 149 _error = ret;
Jan Jongboom 1:3bff14db67c7 150 return NULL;
Jan Jongboom 1:3bff14db67c7 151 }
Jan Jongboom 1:3bff14db67c7 152
Jan Jongboom 1:3bff14db67c7 153 mbedtls_ssl_set_hostname(&_ssl, _parsed_url->host());
Jan Jongboom 1:3bff14db67c7 154
Jan Jongboom 1:3bff14db67c7 155 mbedtls_ssl_set_bio(&_ssl, static_cast<void *>(_tcpsocket),
Jan Jongboom 1:3bff14db67c7 156 ssl_send, ssl_recv, NULL );
Jan Jongboom 1:3bff14db67c7 157
Jan Jongboom 1:3bff14db67c7 158 /* Connect to the server */
Jan Jongboom 1:3bff14db67c7 159 if (_debug) mbedtls_printf("Connecting to %s:%d\r\n", _parsed_url->host(), _parsed_url->port());
Jan Jongboom 1:3bff14db67c7 160 ret = _tcpsocket->connect(_parsed_url->host(), _parsed_url->port());
Jan Jongboom 1:3bff14db67c7 161 if (ret != NSAPI_ERROR_OK) {
Jan Jongboom 1:3bff14db67c7 162 if (_debug) mbedtls_printf("Failed to connect\r\n");
Jan Jongboom 1:3bff14db67c7 163 onError(_tcpsocket, -1);
Jan Jongboom 1:3bff14db67c7 164 return NULL;
Jan Jongboom 1:3bff14db67c7 165 }
Jan Jongboom 1:3bff14db67c7 166
Jan Jongboom 1:3bff14db67c7 167 /* Start the handshake, the rest will be done in onReceive() */
Jan Jongboom 1:3bff14db67c7 168 if (_debug) mbedtls_printf("Starting the TLS handshake...\r\n");
Jan Jongboom 1:3bff14db67c7 169 ret = mbedtls_ssl_handshake(&_ssl);
Jan Jongboom 1:3bff14db67c7 170 if (ret < 0) {
Jan Jongboom 1:3bff14db67c7 171 if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
Jan Jongboom 1:3bff14db67c7 172 ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
Jan Jongboom 1:3bff14db67c7 173 print_mbedtls_error("mbedtls_ssl_handshake", ret);
Jan Jongboom 1:3bff14db67c7 174 onError(_tcpsocket, -1);
Jan Jongboom 1:3bff14db67c7 175 }
Jan Jongboom 1:3bff14db67c7 176 else {
Jan Jongboom 1:3bff14db67c7 177 _error = ret;
Jan Jongboom 1:3bff14db67c7 178 }
Jan Jongboom 1:3bff14db67c7 179 return NULL;
Jan Jongboom 1:3bff14db67c7 180 }
Jan Jongboom 1:3bff14db67c7 181
Jan Jongboom 1:3bff14db67c7 182 char* request = _request_builder->build(body, body_size);
Jan Jongboom 1:3bff14db67c7 183 size_t request_size = strlen(request);
Jan Jongboom 1:3bff14db67c7 184
Jan Jongboom 1:3bff14db67c7 185 ret = mbedtls_ssl_write(&_ssl, (const unsigned char *) request, request_size);
Jan Jongboom 1:3bff14db67c7 186
Jan Jongboom 1:3bff14db67c7 187 free(request);
Jan Jongboom 1:3bff14db67c7 188
Jan Jongboom 1:3bff14db67c7 189 if (ret < 0) {
Jan Jongboom 1:3bff14db67c7 190 if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
Jan Jongboom 1:3bff14db67c7 191 ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
Jan Jongboom 1:3bff14db67c7 192 print_mbedtls_error("mbedtls_ssl_write", ret);
Jan Jongboom 1:3bff14db67c7 193 onError(_tcpsocket, -1 );
Jan Jongboom 1:3bff14db67c7 194 }
Jan Jongboom 1:3bff14db67c7 195 else {
Jan Jongboom 1:3bff14db67c7 196 _error = ret;
Jan Jongboom 1:3bff14db67c7 197 }
Jan Jongboom 1:3bff14db67c7 198 return NULL;
Jan Jongboom 1:3bff14db67c7 199 }
Jan Jongboom 1:3bff14db67c7 200
Jan Jongboom 1:3bff14db67c7 201 /* It also means the handshake is done, time to print info */
Jan Jongboom 1:3bff14db67c7 202 if (_debug) mbedtls_printf("TLS connection to %s:%d established\r\n", _parsed_url->host(), _parsed_url->port());
Jan Jongboom 1:3bff14db67c7 203
Jan Jongboom 1:3bff14db67c7 204 const uint32_t buf_size = 1024;
Jan Jongboom 1:3bff14db67c7 205 char *buf = new char[buf_size];
Jan Jongboom 1:3bff14db67c7 206 mbedtls_x509_crt_info(buf, buf_size, "\r ",
Jan Jongboom 1:3bff14db67c7 207 mbedtls_ssl_get_peer_cert(&_ssl));
Jan Jongboom 1:3bff14db67c7 208 if (_debug) mbedtls_printf("Server certificate:\r\n%s\r", buf);
Jan Jongboom 1:3bff14db67c7 209
Jan Jongboom 1:3bff14db67c7 210 uint32_t flags = mbedtls_ssl_get_verify_result(&_ssl);
Jan Jongboom 1:3bff14db67c7 211 if( flags != 0 )
Jan Jongboom 1:3bff14db67c7 212 {
Jan Jongboom 1:3bff14db67c7 213 mbedtls_x509_crt_verify_info(buf, buf_size, "\r ! ", flags);
Jan Jongboom 1:3bff14db67c7 214 if (_debug) mbedtls_printf("Certificate verification failed:\r\n%s\r\r\n", buf);
Jan Jongboom 1:3bff14db67c7 215 }
Jan Jongboom 1:3bff14db67c7 216 else {
Jan Jongboom 1:3bff14db67c7 217 if (_debug) mbedtls_printf("Certificate verification passed\r\n\r\n");
Jan Jongboom 1:3bff14db67c7 218 }
Jan Jongboom 1:3bff14db67c7 219
Jan Jongboom 1:3bff14db67c7 220 // Create a response object
Jan Jongboom 1:3bff14db67c7 221 _response = new HttpResponse();
Jan Jongboom 1:3bff14db67c7 222 // And a response parser
Jan Jongboom 1:3bff14db67c7 223 HttpResponseParser parser(_response, _body_callback);
Jan Jongboom 1:3bff14db67c7 224
Jan Jongboom 1:3bff14db67c7 225 // Set up a receive buffer (on the heap)
Jan Jongboom 1:3bff14db67c7 226 uint8_t* recv_buffer = (uint8_t*)malloc(HTTP_RECEIVE_BUFFER_SIZE);
Jan Jongboom 1:3bff14db67c7 227
Jan Jongboom 1:3bff14db67c7 228 /* Read data out of the socket */
Jan Jongboom 1:3bff14db67c7 229 while ((ret = mbedtls_ssl_read(&_ssl, (unsigned char *) recv_buffer, HTTP_RECEIVE_BUFFER_SIZE)) > 0) {
Jan Jongboom 1:3bff14db67c7 230 // Don't know if this is actually needed, but OK
Jan Jongboom 1:3bff14db67c7 231 size_t _bpos = static_cast<size_t>(ret);
Jan Jongboom 1:3bff14db67c7 232 recv_buffer[_bpos] = 0;
Jan Jongboom 1:3bff14db67c7 233
Jan Jongboom 1:3bff14db67c7 234 size_t nparsed = parser.execute((const char*)recv_buffer, _bpos);
Jan Jongboom 1:3bff14db67c7 235 if (nparsed != _bpos) {
Jan Jongboom 1:3bff14db67c7 236 print_mbedtls_error("parser_error", nparsed);
Jan Jongboom 1:3bff14db67c7 237 // parser error...
Jan Jongboom 1:3bff14db67c7 238 _error = -2101;
Jan Jongboom 1:3bff14db67c7 239 free(recv_buffer);
Jan Jongboom 1:3bff14db67c7 240 return NULL;
Jan Jongboom 1:3bff14db67c7 241 }
Jan Jongboom 1:3bff14db67c7 242 // No more chunks? break out of this loop
Jan Jongboom 1:3bff14db67c7 243 if (_bpos < HTTP_RECEIVE_BUFFER_SIZE) {
Jan Jongboom 1:3bff14db67c7 244 break;
Jan Jongboom 1:3bff14db67c7 245 }
Jan Jongboom 1:3bff14db67c7 246 }
Jan Jongboom 1:3bff14db67c7 247 if (ret < 0) {
Jan Jongboom 1:3bff14db67c7 248 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
Jan Jongboom 1:3bff14db67c7 249 print_mbedtls_error("mbedtls_ssl_read", ret);
Jan Jongboom 1:3bff14db67c7 250 onError(_tcpsocket, -1 );
Jan Jongboom 1:3bff14db67c7 251 }
Jan Jongboom 1:3bff14db67c7 252 else {
Jan Jongboom 1:3bff14db67c7 253 _error = ret;
Jan Jongboom 1:3bff14db67c7 254 }
Jan Jongboom 1:3bff14db67c7 255 free(recv_buffer);
Jan Jongboom 1:3bff14db67c7 256 return NULL;
Jan Jongboom 1:3bff14db67c7 257 }
Jan Jongboom 1:3bff14db67c7 258
Jan Jongboom 1:3bff14db67c7 259 parser.finish();
Jan Jongboom 1:3bff14db67c7 260
Jan Jongboom 1:3bff14db67c7 261 _tcpsocket->close();
Jan Jongboom 1:3bff14db67c7 262 free(recv_buffer);
Jan Jongboom 1:3bff14db67c7 263
Jan Jongboom 1:3bff14db67c7 264 return _response;
Jan Jongboom 1:3bff14db67c7 265 }
Jan Jongboom 1:3bff14db67c7 266
Jan Jongboom 1:3bff14db67c7 267 /**
Jan Jongboom 1:3bff14db67c7 268 * Closes the TCP socket
Jan Jongboom 1:3bff14db67c7 269 */
Jan Jongboom 1:3bff14db67c7 270 void close() {
Jan Jongboom 1:3bff14db67c7 271 _tcpsocket->close();
Jan Jongboom 1:3bff14db67c7 272 }
Jan Jongboom 1:3bff14db67c7 273
Jan Jongboom 1:3bff14db67c7 274 /**
Jan Jongboom 1:3bff14db67c7 275 * Set a header for the request.
Jan Jongboom 1:3bff14db67c7 276 *
Jan Jongboom 1:3bff14db67c7 277 * The 'Host' and 'Content-Length' headers are set automatically.
Jan Jongboom 1:3bff14db67c7 278 * Setting the same header twice will overwrite the previous entry.
Jan Jongboom 1:3bff14db67c7 279 *
Jan Jongboom 1:3bff14db67c7 280 * @param[in] key Header key
Jan Jongboom 1:3bff14db67c7 281 * @param[in] value Header value
Jan Jongboom 1:3bff14db67c7 282 */
Jan Jongboom 1:3bff14db67c7 283 void set_header(string key, string value) {
Jan Jongboom 1:3bff14db67c7 284 _request_builder->set_header(key, value);
Jan Jongboom 1:3bff14db67c7 285 }
Jan Jongboom 1:3bff14db67c7 286
Jan Jongboom 1:3bff14db67c7 287 /**
Jan Jongboom 1:3bff14db67c7 288 * Get the error code.
Jan Jongboom 1:3bff14db67c7 289 *
Jan Jongboom 1:3bff14db67c7 290 * When send() fails, this error is set.
Jan Jongboom 1:3bff14db67c7 291 */
Jan Jongboom 1:3bff14db67c7 292 nsapi_error_t get_error() {
Jan Jongboom 1:3bff14db67c7 293 return _error;
Jan Jongboom 1:3bff14db67c7 294 }
Jan Jongboom 1:3bff14db67c7 295
Jan Jongboom 1:3bff14db67c7 296 /**
Jan Jongboom 1:3bff14db67c7 297 * Set the debug flag.
Jan Jongboom 1:3bff14db67c7 298 *
Jan Jongboom 1:3bff14db67c7 299 * If this flag is set, debug information from mbed TLS will be logged to stdout.
Jan Jongboom 1:3bff14db67c7 300 */
Jan Jongboom 1:3bff14db67c7 301 void set_debug(bool debug) {
Jan Jongboom 1:3bff14db67c7 302 _debug = debug;
Jan Jongboom 1:3bff14db67c7 303 }
Jan Jongboom 1:3bff14db67c7 304
Jan Jongboom 1:3bff14db67c7 305 protected:
Jan Jongboom 1:3bff14db67c7 306 /**
Jan Jongboom 1:3bff14db67c7 307 * Helper for pretty-printing mbed TLS error codes
Jan Jongboom 1:3bff14db67c7 308 */
Jan Jongboom 1:3bff14db67c7 309 static void print_mbedtls_error(const char *name, int err) {
Jan Jongboom 1:3bff14db67c7 310 char buf[128];
Jan Jongboom 1:3bff14db67c7 311 mbedtls_strerror(err, buf, sizeof (buf));
Jan Jongboom 1:3bff14db67c7 312 mbedtls_printf("%s() failed: -0x%04x (%d): %s\r\n", name, -err, err, buf);
Jan Jongboom 1:3bff14db67c7 313 }
Jan Jongboom 1:3bff14db67c7 314
Jan Jongboom 1:3bff14db67c7 315 #if DEBUG_LEVEL > 0
Jan Jongboom 1:3bff14db67c7 316 /**
Jan Jongboom 1:3bff14db67c7 317 * Debug callback for mbed TLS
Jan Jongboom 1:3bff14db67c7 318 * Just prints on the USB serial port
Jan Jongboom 1:3bff14db67c7 319 */
Jan Jongboom 1:3bff14db67c7 320 static void my_debug(void *ctx, int level, const char *file, int line,
Jan Jongboom 1:3bff14db67c7 321 const char *str)
Jan Jongboom 1:3bff14db67c7 322 {
Jan Jongboom 1:3bff14db67c7 323 const char *p, *basename;
Jan Jongboom 1:3bff14db67c7 324 (void) ctx;
Jan Jongboom 1:3bff14db67c7 325
Jan Jongboom 1:3bff14db67c7 326 /* Extract basename from file */
Jan Jongboom 1:3bff14db67c7 327 for(p = basename = file; *p != '\0'; p++) {
Jan Jongboom 1:3bff14db67c7 328 if(*p == '/' || *p == '\\') {
Jan Jongboom 1:3bff14db67c7 329 basename = p + 1;
Jan Jongboom 1:3bff14db67c7 330 }
Jan Jongboom 1:3bff14db67c7 331 }
Jan Jongboom 1:3bff14db67c7 332
Jan Jongboom 1:3bff14db67c7 333 if (_debug) {
Jan Jongboom 1:3bff14db67c7 334 mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str);
Jan Jongboom 1:3bff14db67c7 335 }
Jan Jongboom 1:3bff14db67c7 336 }
Jan Jongboom 1:3bff14db67c7 337
Jan Jongboom 1:3bff14db67c7 338 /**
Jan Jongboom 1:3bff14db67c7 339 * Certificate verification callback for mbed TLS
Jan Jongboom 1:3bff14db67c7 340 * Here we only use it to display information on each cert in the chain
Jan Jongboom 1:3bff14db67c7 341 */
Jan Jongboom 1:3bff14db67c7 342 static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
Jan Jongboom 1:3bff14db67c7 343 {
Jan Jongboom 1:3bff14db67c7 344 const uint32_t buf_size = 1024;
Jan Jongboom 1:3bff14db67c7 345 char *buf = new char[buf_size];
Jan Jongboom 1:3bff14db67c7 346 (void) data;
Jan Jongboom 1:3bff14db67c7 347
Jan Jongboom 1:3bff14db67c7 348 if (_debug) mbedtls_printf("\nVerifying certificate at depth %d:\n", depth);
Jan Jongboom 1:3bff14db67c7 349 mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt);
Jan Jongboom 1:3bff14db67c7 350 if (_debug) mbedtls_printf("%s", buf);
Jan Jongboom 1:3bff14db67c7 351
Jan Jongboom 1:3bff14db67c7 352 if (*flags == 0)
Jan Jongboom 1:3bff14db67c7 353 if (_debug) mbedtls_printf("No verification issue for this certificate\n");
Jan Jongboom 1:3bff14db67c7 354 else
Jan Jongboom 1:3bff14db67c7 355 {
Jan Jongboom 1:3bff14db67c7 356 mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags);
Jan Jongboom 1:3bff14db67c7 357 if (_debug) mbedtls_printf("%s\n", buf);
Jan Jongboom 1:3bff14db67c7 358 }
Jan Jongboom 1:3bff14db67c7 359
Jan Jongboom 1:3bff14db67c7 360 delete[] buf;
Jan Jongboom 1:3bff14db67c7 361 return 0;
Jan Jongboom 1:3bff14db67c7 362 }
Jan Jongboom 1:3bff14db67c7 363 #endif
Jan Jongboom 1:3bff14db67c7 364
Jan Jongboom 1:3bff14db67c7 365 /**
Jan Jongboom 1:3bff14db67c7 366 * Receive callback for mbed TLS
Jan Jongboom 1:3bff14db67c7 367 */
Jan Jongboom 1:3bff14db67c7 368 static int ssl_recv(void *ctx, unsigned char *buf, size_t len) {
Jan Jongboom 1:3bff14db67c7 369 int recv = -1;
Jan Jongboom 1:3bff14db67c7 370 TCPSocket *socket = static_cast<TCPSocket *>(ctx);
Jan Jongboom 1:3bff14db67c7 371 recv = socket->recv(buf, len);
Jan Jongboom 1:3bff14db67c7 372
Jan Jongboom 1:3bff14db67c7 373 if (NSAPI_ERROR_WOULD_BLOCK == recv) {
Jan Jongboom 1:3bff14db67c7 374 return MBEDTLS_ERR_SSL_WANT_READ;
Jan Jongboom 1:3bff14db67c7 375 }
Jan Jongboom 1:3bff14db67c7 376 else if (recv < 0) {
Jan Jongboom 1:3bff14db67c7 377 return -1;
Jan Jongboom 1:3bff14db67c7 378 }
Jan Jongboom 1:3bff14db67c7 379 else {
Jan Jongboom 1:3bff14db67c7 380 return recv;
Jan Jongboom 1:3bff14db67c7 381 }
Jan Jongboom 1:3bff14db67c7 382 }
Jan Jongboom 1:3bff14db67c7 383
Jan Jongboom 1:3bff14db67c7 384 /**
Jan Jongboom 1:3bff14db67c7 385 * Send callback for mbed TLS
Jan Jongboom 1:3bff14db67c7 386 */
Jan Jongboom 1:3bff14db67c7 387 static int ssl_send(void *ctx, const unsigned char *buf, size_t len) {
Jan Jongboom 1:3bff14db67c7 388 int size = -1;
Jan Jongboom 1:3bff14db67c7 389 TCPSocket *socket = static_cast<TCPSocket *>(ctx);
Jan Jongboom 1:3bff14db67c7 390 size = socket->send(buf, len);
Jan Jongboom 1:3bff14db67c7 391
Jan Jongboom 1:3bff14db67c7 392 if(NSAPI_ERROR_WOULD_BLOCK == size) {
Jan Jongboom 1:3bff14db67c7 393 return len;
Jan Jongboom 1:3bff14db67c7 394 }
Jan Jongboom 1:3bff14db67c7 395 else if (size < 0){
Jan Jongboom 1:3bff14db67c7 396 return -1;
Jan Jongboom 1:3bff14db67c7 397 }
Jan Jongboom 1:3bff14db67c7 398 else {
Jan Jongboom 1:3bff14db67c7 399 return size;
Jan Jongboom 1:3bff14db67c7 400 }
Jan Jongboom 1:3bff14db67c7 401 }
Jan Jongboom 1:3bff14db67c7 402
Jan Jongboom 1:3bff14db67c7 403 void onError(TCPSocket *s, int error) {
Jan Jongboom 1:3bff14db67c7 404 s->close();
Jan Jongboom 1:3bff14db67c7 405 _error = error;
Jan Jongboom 1:3bff14db67c7 406 }
Jan Jongboom 1:3bff14db67c7 407
Jan Jongboom 1:3bff14db67c7 408 protected:
Jan Jongboom 1:3bff14db67c7 409 TCPSocket* _tcpsocket;
Jan Jongboom 1:3bff14db67c7 410
Jan Jongboom 1:3bff14db67c7 411 Callback<void(const char *at, size_t length)> _body_callback;
Jan Jongboom 1:3bff14db67c7 412 ParsedUrl* _parsed_url;
Jan Jongboom 1:3bff14db67c7 413 HttpRequestBuilder* _request_builder;
Jan Jongboom 1:3bff14db67c7 414 HttpResponse* _response;
Jan Jongboom 1:3bff14db67c7 415 const char *DRBG_PERS;
Jan Jongboom 1:3bff14db67c7 416 const char *_ssl_ca_pem;
Jan Jongboom 1:3bff14db67c7 417
Jan Jongboom 1:3bff14db67c7 418 nsapi_error_t _error;
Jan Jongboom 1:3bff14db67c7 419 bool _debug;
Jan Jongboom 1:3bff14db67c7 420
Jan Jongboom 1:3bff14db67c7 421 mbedtls_entropy_context _entropy;
Jan Jongboom 1:3bff14db67c7 422 mbedtls_ctr_drbg_context _ctr_drbg;
Jan Jongboom 1:3bff14db67c7 423 mbedtls_x509_crt _cacert;
Jan Jongboom 1:3bff14db67c7 424 mbedtls_ssl_context _ssl;
Jan Jongboom 1:3bff14db67c7 425 mbedtls_ssl_config _ssl_conf;
Jan Jongboom 1:3bff14db67c7 426 };
Jan Jongboom 1:3bff14db67c7 427
Jan Jongboom 1:3bff14db67c7 428 #endif // _MBED_HTTPS_REQUEST_H_