mbed-http
Fork of mbed-http by
Embed:
(wiki syntax)
Show/hide line numbers
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 #include <string> 00022 #include <vector> 00023 #include <map> 00024 #include "http_parser.h" 00025 #include "http_response.h" 00026 #include "http_request_builder.h" 00027 #include "http_request_parser.h" 00028 #include "http_parsed_url.h" 00029 #include "tls_socket.h" 00030 00031 #ifndef HTTP_RECEIVE_BUFFER_SIZE 00032 #define HTTP_RECEIVE_BUFFER_SIZE 8 * 1024 00033 #endif 00034 00035 /** 00036 * \brief HttpsRequest implements the logic for interacting with HTTPS servers. 00037 */ 00038 class HttpsRequest { 00039 public: 00040 /** 00041 * HttpsRequest Constructor 00042 * Initializes the TCP socket, sets up event handlers and flags. 00043 * 00044 * @param[in] net_iface The network interface 00045 * @param[in] ssl_ca_pem String containing the trusted CAs 00046 * @param[in] method HTTP method to use 00047 * @param[in] url URL to the resource 00048 * @param[in] body_callback Callback on which to retrieve chunks of the response body. 00049 If not set, the complete body will be allocated on the HttpResponse object, 00050 which might use lots of memory. 00051 */ 00052 HttpsRequest(NetworkInterface* net_iface, 00053 const char* ssl_ca_pem, 00054 http_method method, 00055 const char* url, 00056 Callback<void(const char *at, size_t length)> body_callback = 0) 00057 { 00058 _parsed_url = new ParsedUrl(url); 00059 _body_callback = body_callback; 00060 _request_builder = new HttpRequestBuilder(method, _parsed_url); 00061 _response = NULL; 00062 _debug = false; 00063 00064 _tlssocket = new TLSSocket(net_iface, _parsed_url->host(), _parsed_url->port(), ssl_ca_pem); 00065 _we_created_the_socket = true; 00066 } 00067 00068 /** 00069 * HttpsRequest Constructor 00070 * Sets up event handlers and flags. 00071 * 00072 * @param[in] socket A connected TLSSocket 00073 * @param[in] method HTTP method to use 00074 * @param[in] url URL to the resource 00075 * @param[in] body_callback Callback on which to retrieve chunks of the response body. 00076 If not set, the complete body will be allocated on the HttpResponse object, 00077 which might use lots of memory. 00078 */ 00079 HttpsRequest(TLSSocket* socket, 00080 http_method method, 00081 const char* url, 00082 Callback<void(const char *at, size_t length)> body_callback = 0) 00083 { 00084 _parsed_url = new ParsedUrl(url); 00085 _body_callback = body_callback; 00086 _request_builder = new HttpRequestBuilder(method, _parsed_url); 00087 _response = NULL; 00088 _debug = false; 00089 00090 _tlssocket = socket; 00091 _we_created_the_socket = false; 00092 } 00093 00094 /** 00095 * HttpsRequest Destructor 00096 */ 00097 ~HttpsRequest() { 00098 if (_request_builder) { 00099 delete _request_builder; 00100 } 00101 00102 if (_tlssocket && _we_created_the_socket) { 00103 delete _tlssocket; 00104 } 00105 00106 if (_parsed_url) { 00107 delete _parsed_url; 00108 } 00109 00110 if (_response) { 00111 delete _response; 00112 } 00113 } 00114 00115 /** 00116 * Execute the HTTPS request. 00117 * 00118 * @param[in] body Pointer to the request body 00119 * @param[in] body_size Size of the request body 00120 * @return An HttpResponse pointer on success, or NULL on failure. 00121 * See get_error() for the error code. 00122 */ 00123 HttpResponse* send(const void* body = NULL, nsapi_size_t body_size = 0) { 00124 // not tried to connect before? 00125 if (_tlssocket->error() != 0) { 00126 _error = _tlssocket->error(); 00127 return NULL; 00128 } 00129 00130 bool socket_was_open = _tlssocket->connected(); 00131 00132 if (!socket_was_open) { 00133 nsapi_error_t r = _tlssocket->connect(); 00134 if (r != 0) { 00135 _error = r; 00136 return NULL; 00137 } 00138 } 00139 00140 int ret; 00141 00142 size_t request_size = 0; 00143 char* request = _request_builder->build(body, body_size, request_size); 00144 00145 ret = mbedtls_ssl_write(_tlssocket->get_ssl_context(), (const unsigned char *) request, request_size); 00146 00147 free(request); 00148 00149 if (ret < 0) { 00150 if (ret != MBEDTLS_ERR_SSL_WANT_READ && 00151 ret != MBEDTLS_ERR_SSL_WANT_WRITE) { 00152 print_mbedtls_error("mbedtls_ssl_write", ret); 00153 onError(_tlssocket->get_tcp_socket(), -1 ); 00154 } 00155 else { 00156 _error = ret; 00157 } 00158 return NULL; 00159 } 00160 00161 // Create a response object 00162 _response = new HttpResponse(); 00163 // And a response parser 00164 HttpParser parser(_response, HTTP_RESPONSE, _body_callback); 00165 00166 // Set up a receive buffer (on the heap) 00167 uint8_t* recv_buffer = (uint8_t*)malloc(HTTP_RECEIVE_BUFFER_SIZE); 00168 00169 /* Read data out of the socket */ 00170 while ((ret = mbedtls_ssl_read(_tlssocket->get_ssl_context(), (unsigned char *) recv_buffer, HTTP_RECEIVE_BUFFER_SIZE)) > 0) { 00171 // Don't know if this is actually needed, but OK 00172 size_t _bpos = static_cast<size_t>(ret); 00173 recv_buffer[_bpos] = 0; 00174 00175 size_t nparsed = parser.execute((const char*)recv_buffer, _bpos); 00176 if (nparsed != _bpos) { 00177 print_mbedtls_error("parser_error", nparsed); 00178 // parser error... 00179 _error = -2101; 00180 free(recv_buffer); 00181 return NULL; 00182 } 00183 00184 if (_response->is_message_complete()) { 00185 break; 00186 } 00187 } 00188 if (ret < 0) { 00189 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { 00190 print_mbedtls_error("mbedtls_ssl_read", ret); 00191 onError(_tlssocket->get_tcp_socket(), -1 ); 00192 } 00193 else { 00194 _error = ret; 00195 } 00196 free(recv_buffer); 00197 return NULL; 00198 } 00199 00200 parser.finish(); 00201 00202 if (!socket_was_open) { 00203 _tlssocket->get_tcp_socket()->close(); 00204 } 00205 00206 free(recv_buffer); 00207 00208 return _response; 00209 } 00210 00211 /** 00212 * Closes the underlying TCP socket 00213 */ 00214 void close() { 00215 _tlssocket->get_tcp_socket()->close(); 00216 } 00217 00218 /** 00219 * Set a header for the request. 00220 * 00221 * The 'Host' and 'Content-Length' headers are set automatically. 00222 * Setting the same header twice will overwrite the previous entry. 00223 * 00224 * @param[in] key Header key 00225 * @param[in] value Header value 00226 */ 00227 void set_header(string key, string value) { 00228 _request_builder->set_header(key, value); 00229 } 00230 00231 /** 00232 * Get the error code. 00233 * 00234 * When send() fails, this error is set. 00235 */ 00236 nsapi_error_t get_error() { 00237 return _error; 00238 } 00239 00240 /** 00241 * Set the debug flag. 00242 * 00243 * If this flag is set, debug information from mbed TLS will be logged to stdout. 00244 */ 00245 void set_debug(bool debug) { 00246 _debug = debug; 00247 00248 _tlssocket->set_debug(debug); 00249 } 00250 00251 00252 protected: 00253 /** 00254 * Helper for pretty-printing mbed TLS error codes 00255 */ 00256 static void print_mbedtls_error(const char *name, int err) { 00257 char buf[128]; 00258 mbedtls_strerror(err, buf, sizeof (buf)); 00259 mbedtls_printf("%s() failed: -0x%04x (%d): %s\r\n", name, -err, err, buf); 00260 } 00261 00262 void onError(TCPSocket *s, int error) { 00263 s->close(); 00264 _error = error; 00265 } 00266 00267 protected: 00268 TLSSocket* _tlssocket; 00269 bool _we_created_the_socket; 00270 00271 Callback<void(const char *at, size_t length)> _body_callback; 00272 ParsedUrl* _parsed_url; 00273 HttpRequestBuilder* _request_builder; 00274 HttpResponse* _response; 00275 00276 nsapi_error_t _error; 00277 bool _debug; 00278 00279 }; 00280 00281 #endif // _MBED_HTTPS_REQUEST_H_
Generated on Thu Jul 14 2022 16:38:26 by 1.7.2