Hiroaki Okoshi / Mbed OS http-webserver-example-mbed-os-5-odin-w2
Committer:
Hiroaki_Okoshi
Date:
Sat Oct 09 14:23:23 2021 +0000
Revision:
0:a21b8a29df03
Sample web server via WiFi program. for mbed os 5.15

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Hiroaki_Okoshi 0:a21b8a29df03 1 /*
Hiroaki_Okoshi 0:a21b8a29df03 2 * PackageLicenseDeclared: Apache-2.0
Hiroaki_Okoshi 0:a21b8a29df03 3 * Copyright (c) 2017 ARM Limited
Hiroaki_Okoshi 0:a21b8a29df03 4 *
Hiroaki_Okoshi 0:a21b8a29df03 5 * Licensed under the Apache License, Version 2.0 (the "License");
Hiroaki_Okoshi 0:a21b8a29df03 6 * you may not use this file except in compliance with the License.
Hiroaki_Okoshi 0:a21b8a29df03 7 * You may obtain a copy of the License at
Hiroaki_Okoshi 0:a21b8a29df03 8 *
Hiroaki_Okoshi 0:a21b8a29df03 9 * http://www.apache.org/licenses/LICENSE-2.0
Hiroaki_Okoshi 0:a21b8a29df03 10 *
Hiroaki_Okoshi 0:a21b8a29df03 11 * Unless required by applicable law or agreed to in writing, software
Hiroaki_Okoshi 0:a21b8a29df03 12 * distributed under the License is distributed on an "AS IS" BASIS,
Hiroaki_Okoshi 0:a21b8a29df03 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Hiroaki_Okoshi 0:a21b8a29df03 14 * See the License for the specific language governing permissions and
Hiroaki_Okoshi 0:a21b8a29df03 15 * limitations under the License.
Hiroaki_Okoshi 0:a21b8a29df03 16 */
Hiroaki_Okoshi 0:a21b8a29df03 17
Hiroaki_Okoshi 0:a21b8a29df03 18 #ifndef _MBED_HTTPS_REQUEST_H_
Hiroaki_Okoshi 0:a21b8a29df03 19 #define _MBED_HTTPS_REQUEST_H_
Hiroaki_Okoshi 0:a21b8a29df03 20
Hiroaki_Okoshi 0:a21b8a29df03 21 #include <string>
Hiroaki_Okoshi 0:a21b8a29df03 22 #include <vector>
Hiroaki_Okoshi 0:a21b8a29df03 23 #include <map>
Hiroaki_Okoshi 0:a21b8a29df03 24 #include "http_parser.h"
Hiroaki_Okoshi 0:a21b8a29df03 25 #include "http_response.h"
Hiroaki_Okoshi 0:a21b8a29df03 26 #include "http_request_builder.h"
Hiroaki_Okoshi 0:a21b8a29df03 27 #include "http_request_parser.h"
Hiroaki_Okoshi 0:a21b8a29df03 28 #include "http_parsed_url.h"
Hiroaki_Okoshi 0:a21b8a29df03 29 #include "tls_socket.h"
Hiroaki_Okoshi 0:a21b8a29df03 30
Hiroaki_Okoshi 0:a21b8a29df03 31 /**
Hiroaki_Okoshi 0:a21b8a29df03 32 * \brief HttpsRequest implements the logic for interacting with HTTPS servers.
Hiroaki_Okoshi 0:a21b8a29df03 33 */
Hiroaki_Okoshi 0:a21b8a29df03 34 class HttpsRequest {
Hiroaki_Okoshi 0:a21b8a29df03 35 public:
Hiroaki_Okoshi 0:a21b8a29df03 36 /**
Hiroaki_Okoshi 0:a21b8a29df03 37 * HttpsRequest Constructor
Hiroaki_Okoshi 0:a21b8a29df03 38 * Initializes the TCP socket, sets up event handlers and flags.
Hiroaki_Okoshi 0:a21b8a29df03 39 *
Hiroaki_Okoshi 0:a21b8a29df03 40 * @param[in] net_iface The network interface
Hiroaki_Okoshi 0:a21b8a29df03 41 * @param[in] ssl_ca_pem String containing the trusted CAs
Hiroaki_Okoshi 0:a21b8a29df03 42 * @param[in] method HTTP method to use
Hiroaki_Okoshi 0:a21b8a29df03 43 * @param[in] url URL to the resource
Hiroaki_Okoshi 0:a21b8a29df03 44 * @param[in] body_callback Callback on which to retrieve chunks of the response body.
Hiroaki_Okoshi 0:a21b8a29df03 45 If not set, the complete body will be allocated on the HttpResponse object,
Hiroaki_Okoshi 0:a21b8a29df03 46 which might use lots of memory.
Hiroaki_Okoshi 0:a21b8a29df03 47 */
Hiroaki_Okoshi 0:a21b8a29df03 48 HttpsRequest(NetworkInterface* net_iface,
Hiroaki_Okoshi 0:a21b8a29df03 49 const char* ssl_ca_pem,
Hiroaki_Okoshi 0:a21b8a29df03 50 http_method method,
Hiroaki_Okoshi 0:a21b8a29df03 51 const char* url,
Hiroaki_Okoshi 0:a21b8a29df03 52 Callback<void(const char *at, size_t length)> body_callback = 0)
Hiroaki_Okoshi 0:a21b8a29df03 53 {
Hiroaki_Okoshi 0:a21b8a29df03 54 _parsed_url = new ParsedUrl(url);
Hiroaki_Okoshi 0:a21b8a29df03 55 _body_callback = body_callback;
Hiroaki_Okoshi 0:a21b8a29df03 56 _request_builder = new HttpRequestBuilder(method, _parsed_url);
Hiroaki_Okoshi 0:a21b8a29df03 57 _response = NULL;
Hiroaki_Okoshi 0:a21b8a29df03 58 _debug = false;
Hiroaki_Okoshi 0:a21b8a29df03 59
Hiroaki_Okoshi 0:a21b8a29df03 60 _tlssocket = new TLSSocket(net_iface, _parsed_url->host(), _parsed_url->port(), ssl_ca_pem);
Hiroaki_Okoshi 0:a21b8a29df03 61 _we_created_the_socket = true;
Hiroaki_Okoshi 0:a21b8a29df03 62 }
Hiroaki_Okoshi 0:a21b8a29df03 63
Hiroaki_Okoshi 0:a21b8a29df03 64 /**
Hiroaki_Okoshi 0:a21b8a29df03 65 * HttpsRequest Constructor
Hiroaki_Okoshi 0:a21b8a29df03 66 * Sets up event handlers and flags.
Hiroaki_Okoshi 0:a21b8a29df03 67 *
Hiroaki_Okoshi 0:a21b8a29df03 68 * @param[in] socket A connected TLSSocket
Hiroaki_Okoshi 0:a21b8a29df03 69 * @param[in] method HTTP method to use
Hiroaki_Okoshi 0:a21b8a29df03 70 * @param[in] url URL to the resource
Hiroaki_Okoshi 0:a21b8a29df03 71 * @param[in] body_callback Callback on which to retrieve chunks of the response body.
Hiroaki_Okoshi 0:a21b8a29df03 72 If not set, the complete body will be allocated on the HttpResponse object,
Hiroaki_Okoshi 0:a21b8a29df03 73 which might use lots of memory.
Hiroaki_Okoshi 0:a21b8a29df03 74 */
Hiroaki_Okoshi 0:a21b8a29df03 75 HttpsRequest(TLSSocket* socket,
Hiroaki_Okoshi 0:a21b8a29df03 76 http_method method,
Hiroaki_Okoshi 0:a21b8a29df03 77 const char* url,
Hiroaki_Okoshi 0:a21b8a29df03 78 Callback<void(const char *at, size_t length)> body_callback = 0)
Hiroaki_Okoshi 0:a21b8a29df03 79 {
Hiroaki_Okoshi 0:a21b8a29df03 80 _parsed_url = new ParsedUrl(url);
Hiroaki_Okoshi 0:a21b8a29df03 81 _body_callback = body_callback;
Hiroaki_Okoshi 0:a21b8a29df03 82 _request_builder = new HttpRequestBuilder(method, _parsed_url);
Hiroaki_Okoshi 0:a21b8a29df03 83 _response = NULL;
Hiroaki_Okoshi 0:a21b8a29df03 84 _debug = false;
Hiroaki_Okoshi 0:a21b8a29df03 85
Hiroaki_Okoshi 0:a21b8a29df03 86 _tlssocket = socket;
Hiroaki_Okoshi 0:a21b8a29df03 87 _we_created_the_socket = false;
Hiroaki_Okoshi 0:a21b8a29df03 88 }
Hiroaki_Okoshi 0:a21b8a29df03 89
Hiroaki_Okoshi 0:a21b8a29df03 90 /**
Hiroaki_Okoshi 0:a21b8a29df03 91 * HttpsRequest Destructor
Hiroaki_Okoshi 0:a21b8a29df03 92 */
Hiroaki_Okoshi 0:a21b8a29df03 93 ~HttpsRequest() {
Hiroaki_Okoshi 0:a21b8a29df03 94 if (_request_builder) {
Hiroaki_Okoshi 0:a21b8a29df03 95 delete _request_builder;
Hiroaki_Okoshi 0:a21b8a29df03 96 }
Hiroaki_Okoshi 0:a21b8a29df03 97
Hiroaki_Okoshi 0:a21b8a29df03 98 if (_tlssocket && _we_created_the_socket) {
Hiroaki_Okoshi 0:a21b8a29df03 99 delete _tlssocket;
Hiroaki_Okoshi 0:a21b8a29df03 100 }
Hiroaki_Okoshi 0:a21b8a29df03 101
Hiroaki_Okoshi 0:a21b8a29df03 102 if (_parsed_url) {
Hiroaki_Okoshi 0:a21b8a29df03 103 delete _parsed_url;
Hiroaki_Okoshi 0:a21b8a29df03 104 }
Hiroaki_Okoshi 0:a21b8a29df03 105
Hiroaki_Okoshi 0:a21b8a29df03 106 if (_response) {
Hiroaki_Okoshi 0:a21b8a29df03 107 delete _response;
Hiroaki_Okoshi 0:a21b8a29df03 108 }
Hiroaki_Okoshi 0:a21b8a29df03 109 }
Hiroaki_Okoshi 0:a21b8a29df03 110
Hiroaki_Okoshi 0:a21b8a29df03 111 /**
Hiroaki_Okoshi 0:a21b8a29df03 112 * Execute the HTTPS request.
Hiroaki_Okoshi 0:a21b8a29df03 113 *
Hiroaki_Okoshi 0:a21b8a29df03 114 * @param[in] body Pointer to the request body
Hiroaki_Okoshi 0:a21b8a29df03 115 * @param[in] body_size Size of the request body
Hiroaki_Okoshi 0:a21b8a29df03 116 * @return An HttpResponse pointer on success, or NULL on failure.
Hiroaki_Okoshi 0:a21b8a29df03 117 * See get_error() for the error code.
Hiroaki_Okoshi 0:a21b8a29df03 118 */
Hiroaki_Okoshi 0:a21b8a29df03 119 HttpResponse* send(const void* body = NULL, nsapi_size_t body_size = 0) {
Hiroaki_Okoshi 0:a21b8a29df03 120 // not tried to connect before?
Hiroaki_Okoshi 0:a21b8a29df03 121 if (_tlssocket->error() != 0) {
Hiroaki_Okoshi 0:a21b8a29df03 122 _error = _tlssocket->error();
Hiroaki_Okoshi 0:a21b8a29df03 123 return NULL;
Hiroaki_Okoshi 0:a21b8a29df03 124 }
Hiroaki_Okoshi 0:a21b8a29df03 125
Hiroaki_Okoshi 0:a21b8a29df03 126 bool socket_was_open = _tlssocket->connected();
Hiroaki_Okoshi 0:a21b8a29df03 127
Hiroaki_Okoshi 0:a21b8a29df03 128 if (!socket_was_open) {
Hiroaki_Okoshi 0:a21b8a29df03 129 nsapi_error_t r = _tlssocket->connect();
Hiroaki_Okoshi 0:a21b8a29df03 130 if (r != 0) {
Hiroaki_Okoshi 0:a21b8a29df03 131 _error = r;
Hiroaki_Okoshi 0:a21b8a29df03 132 return NULL;
Hiroaki_Okoshi 0:a21b8a29df03 133 }
Hiroaki_Okoshi 0:a21b8a29df03 134 }
Hiroaki_Okoshi 0:a21b8a29df03 135
Hiroaki_Okoshi 0:a21b8a29df03 136 int ret;
Hiroaki_Okoshi 0:a21b8a29df03 137
Hiroaki_Okoshi 0:a21b8a29df03 138 size_t request_size = 0;
Hiroaki_Okoshi 0:a21b8a29df03 139 char* request = _request_builder->build(body, body_size, request_size);
Hiroaki_Okoshi 0:a21b8a29df03 140
Hiroaki_Okoshi 0:a21b8a29df03 141 ret = mbedtls_ssl_write(_tlssocket->get_ssl_context(), (const unsigned char *) request, request_size);
Hiroaki_Okoshi 0:a21b8a29df03 142
Hiroaki_Okoshi 0:a21b8a29df03 143 free(request);
Hiroaki_Okoshi 0:a21b8a29df03 144
Hiroaki_Okoshi 0:a21b8a29df03 145 if (ret < 0) {
Hiroaki_Okoshi 0:a21b8a29df03 146 if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
Hiroaki_Okoshi 0:a21b8a29df03 147 ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
Hiroaki_Okoshi 0:a21b8a29df03 148 print_mbedtls_error("mbedtls_ssl_write", ret);
Hiroaki_Okoshi 0:a21b8a29df03 149 onError(_tlssocket->get_tcp_socket(), -1 );
Hiroaki_Okoshi 0:a21b8a29df03 150 }
Hiroaki_Okoshi 0:a21b8a29df03 151 else {
Hiroaki_Okoshi 0:a21b8a29df03 152 _error = ret;
Hiroaki_Okoshi 0:a21b8a29df03 153 }
Hiroaki_Okoshi 0:a21b8a29df03 154 return NULL;
Hiroaki_Okoshi 0:a21b8a29df03 155 }
Hiroaki_Okoshi 0:a21b8a29df03 156
Hiroaki_Okoshi 0:a21b8a29df03 157 // Create a response object
Hiroaki_Okoshi 0:a21b8a29df03 158 _response = new HttpResponse();
Hiroaki_Okoshi 0:a21b8a29df03 159 // And a response parser
Hiroaki_Okoshi 0:a21b8a29df03 160 HttpParser parser(_response, HTTP_RESPONSE, _body_callback);
Hiroaki_Okoshi 0:a21b8a29df03 161
Hiroaki_Okoshi 0:a21b8a29df03 162 // Set up a receive buffer (on the heap)
Hiroaki_Okoshi 0:a21b8a29df03 163 uint8_t* recv_buffer = (uint8_t*)malloc(HTTP_RECEIVE_BUFFER_SIZE);
Hiroaki_Okoshi 0:a21b8a29df03 164
Hiroaki_Okoshi 0:a21b8a29df03 165 /* Read data out of the socket */
Hiroaki_Okoshi 0:a21b8a29df03 166 while ((ret = mbedtls_ssl_read(_tlssocket->get_ssl_context(), (unsigned char *) recv_buffer, HTTP_RECEIVE_BUFFER_SIZE)) > 0) {
Hiroaki_Okoshi 0:a21b8a29df03 167 // Don't know if this is actually needed, but OK
Hiroaki_Okoshi 0:a21b8a29df03 168 size_t _bpos = static_cast<size_t>(ret);
Hiroaki_Okoshi 0:a21b8a29df03 169 recv_buffer[_bpos] = 0;
Hiroaki_Okoshi 0:a21b8a29df03 170
Hiroaki_Okoshi 0:a21b8a29df03 171 size_t nparsed = parser.execute((const char*)recv_buffer, _bpos);
Hiroaki_Okoshi 0:a21b8a29df03 172 if (nparsed != _bpos) {
Hiroaki_Okoshi 0:a21b8a29df03 173 print_mbedtls_error("parser_error", nparsed);
Hiroaki_Okoshi 0:a21b8a29df03 174 // parser error...
Hiroaki_Okoshi 0:a21b8a29df03 175 _error = -2101;
Hiroaki_Okoshi 0:a21b8a29df03 176 free(recv_buffer);
Hiroaki_Okoshi 0:a21b8a29df03 177 return NULL;
Hiroaki_Okoshi 0:a21b8a29df03 178 }
Hiroaki_Okoshi 0:a21b8a29df03 179
Hiroaki_Okoshi 0:a21b8a29df03 180 if (_response->is_message_complete()) {
Hiroaki_Okoshi 0:a21b8a29df03 181 break;
Hiroaki_Okoshi 0:a21b8a29df03 182 }
Hiroaki_Okoshi 0:a21b8a29df03 183 }
Hiroaki_Okoshi 0:a21b8a29df03 184 if (ret < 0) {
Hiroaki_Okoshi 0:a21b8a29df03 185 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
Hiroaki_Okoshi 0:a21b8a29df03 186 print_mbedtls_error("mbedtls_ssl_read", ret);
Hiroaki_Okoshi 0:a21b8a29df03 187 onError(_tlssocket->get_tcp_socket(), -1 );
Hiroaki_Okoshi 0:a21b8a29df03 188 }
Hiroaki_Okoshi 0:a21b8a29df03 189 else {
Hiroaki_Okoshi 0:a21b8a29df03 190 _error = ret;
Hiroaki_Okoshi 0:a21b8a29df03 191 }
Hiroaki_Okoshi 0:a21b8a29df03 192 free(recv_buffer);
Hiroaki_Okoshi 0:a21b8a29df03 193 return NULL;
Hiroaki_Okoshi 0:a21b8a29df03 194 }
Hiroaki_Okoshi 0:a21b8a29df03 195
Hiroaki_Okoshi 0:a21b8a29df03 196 parser.finish();
Hiroaki_Okoshi 0:a21b8a29df03 197
Hiroaki_Okoshi 0:a21b8a29df03 198 if (!socket_was_open) {
Hiroaki_Okoshi 0:a21b8a29df03 199 _tlssocket->get_tcp_socket()->close();
Hiroaki_Okoshi 0:a21b8a29df03 200 }
Hiroaki_Okoshi 0:a21b8a29df03 201
Hiroaki_Okoshi 0:a21b8a29df03 202 free(recv_buffer);
Hiroaki_Okoshi 0:a21b8a29df03 203
Hiroaki_Okoshi 0:a21b8a29df03 204 return _response;
Hiroaki_Okoshi 0:a21b8a29df03 205 }
Hiroaki_Okoshi 0:a21b8a29df03 206
Hiroaki_Okoshi 0:a21b8a29df03 207 /**
Hiroaki_Okoshi 0:a21b8a29df03 208 * Closes the underlying TCP socket
Hiroaki_Okoshi 0:a21b8a29df03 209 */
Hiroaki_Okoshi 0:a21b8a29df03 210 void close() {
Hiroaki_Okoshi 0:a21b8a29df03 211 _tlssocket->get_tcp_socket()->close();
Hiroaki_Okoshi 0:a21b8a29df03 212 }
Hiroaki_Okoshi 0:a21b8a29df03 213
Hiroaki_Okoshi 0:a21b8a29df03 214 /**
Hiroaki_Okoshi 0:a21b8a29df03 215 * Set a header for the request.
Hiroaki_Okoshi 0:a21b8a29df03 216 *
Hiroaki_Okoshi 0:a21b8a29df03 217 * The 'Host' and 'Content-Length' headers are set automatically.
Hiroaki_Okoshi 0:a21b8a29df03 218 * Setting the same header twice will overwrite the previous entry.
Hiroaki_Okoshi 0:a21b8a29df03 219 *
Hiroaki_Okoshi 0:a21b8a29df03 220 * @param[in] key Header key
Hiroaki_Okoshi 0:a21b8a29df03 221 * @param[in] value Header value
Hiroaki_Okoshi 0:a21b8a29df03 222 */
Hiroaki_Okoshi 0:a21b8a29df03 223 void set_header(string key, string value) {
Hiroaki_Okoshi 0:a21b8a29df03 224 _request_builder->set_header(key, value);
Hiroaki_Okoshi 0:a21b8a29df03 225 }
Hiroaki_Okoshi 0:a21b8a29df03 226
Hiroaki_Okoshi 0:a21b8a29df03 227 /**
Hiroaki_Okoshi 0:a21b8a29df03 228 * Get the error code.
Hiroaki_Okoshi 0:a21b8a29df03 229 *
Hiroaki_Okoshi 0:a21b8a29df03 230 * When send() fails, this error is set.
Hiroaki_Okoshi 0:a21b8a29df03 231 */
Hiroaki_Okoshi 0:a21b8a29df03 232 nsapi_error_t get_error() {
Hiroaki_Okoshi 0:a21b8a29df03 233 return _error;
Hiroaki_Okoshi 0:a21b8a29df03 234 }
Hiroaki_Okoshi 0:a21b8a29df03 235
Hiroaki_Okoshi 0:a21b8a29df03 236 /**
Hiroaki_Okoshi 0:a21b8a29df03 237 * Set the debug flag.
Hiroaki_Okoshi 0:a21b8a29df03 238 *
Hiroaki_Okoshi 0:a21b8a29df03 239 * If this flag is set, debug information from mbed TLS will be logged to stdout.
Hiroaki_Okoshi 0:a21b8a29df03 240 */
Hiroaki_Okoshi 0:a21b8a29df03 241 void set_debug(bool debug) {
Hiroaki_Okoshi 0:a21b8a29df03 242 _debug = debug;
Hiroaki_Okoshi 0:a21b8a29df03 243
Hiroaki_Okoshi 0:a21b8a29df03 244 _tlssocket->set_debug(debug);
Hiroaki_Okoshi 0:a21b8a29df03 245 }
Hiroaki_Okoshi 0:a21b8a29df03 246
Hiroaki_Okoshi 0:a21b8a29df03 247
Hiroaki_Okoshi 0:a21b8a29df03 248 protected:
Hiroaki_Okoshi 0:a21b8a29df03 249 /**
Hiroaki_Okoshi 0:a21b8a29df03 250 * Helper for pretty-printing mbed TLS error codes
Hiroaki_Okoshi 0:a21b8a29df03 251 */
Hiroaki_Okoshi 0:a21b8a29df03 252 static void print_mbedtls_error(const char *name, int err) {
Hiroaki_Okoshi 0:a21b8a29df03 253 char buf[128];
Hiroaki_Okoshi 0:a21b8a29df03 254 mbedtls_strerror(err, buf, sizeof (buf));
Hiroaki_Okoshi 0:a21b8a29df03 255 mbedtls_printf("%s() failed: -0x%04x (%d): %s\r\n", name, -err, err, buf);
Hiroaki_Okoshi 0:a21b8a29df03 256 }
Hiroaki_Okoshi 0:a21b8a29df03 257
Hiroaki_Okoshi 0:a21b8a29df03 258 void onError(TCPSocket *s, int error) {
Hiroaki_Okoshi 0:a21b8a29df03 259 s->close();
Hiroaki_Okoshi 0:a21b8a29df03 260 _error = error;
Hiroaki_Okoshi 0:a21b8a29df03 261 }
Hiroaki_Okoshi 0:a21b8a29df03 262
Hiroaki_Okoshi 0:a21b8a29df03 263 protected:
Hiroaki_Okoshi 0:a21b8a29df03 264 TLSSocket* _tlssocket;
Hiroaki_Okoshi 0:a21b8a29df03 265 bool _we_created_the_socket;
Hiroaki_Okoshi 0:a21b8a29df03 266
Hiroaki_Okoshi 0:a21b8a29df03 267 Callback<void(const char *at, size_t length)> _body_callback;
Hiroaki_Okoshi 0:a21b8a29df03 268 ParsedUrl* _parsed_url;
Hiroaki_Okoshi 0:a21b8a29df03 269 HttpRequestBuilder* _request_builder;
Hiroaki_Okoshi 0:a21b8a29df03 270 HttpResponse* _response;
Hiroaki_Okoshi 0:a21b8a29df03 271
Hiroaki_Okoshi 0:a21b8a29df03 272 nsapi_error_t _error;
Hiroaki_Okoshi 0:a21b8a29df03 273 bool _debug;
Hiroaki_Okoshi 0:a21b8a29df03 274
Hiroaki_Okoshi 0:a21b8a29df03 275 };
Hiroaki_Okoshi 0:a21b8a29df03 276
Hiroaki_Okoshi 0:a21b8a29df03 277 #endif // _MBED_HTTPS_REQUEST_H_