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