HTTP and HTTPS library for Mbed OS 5
Dependents: MQTTGateway2 MQTTGatewayK64 http-example-wnc GuardRoom ... more
http_request_base.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 _HTTP_REQUEST_BASE_H_ 00019 #define _HTTP_REQUEST_BASE_H_ 00020 00021 #include <map> 00022 #include <string> 00023 #include <vector> 00024 #include "mbed.h" 00025 #include "http_parser.h" 00026 #include "http_parsed_url.h" 00027 #include "http_request_builder.h" 00028 #include "http_request_parser.h" 00029 #include "http_response.h" 00030 #include "NetworkInterface.h" 00031 #include "netsocket/Socket.h" 00032 00033 /** 00034 * @todo: 00035 * - Userinfo parameter is not handled 00036 */ 00037 00038 #ifndef HTTP_RECEIVE_BUFFER_SIZE 00039 #define HTTP_RECEIVE_BUFFER_SIZE 8 * 1024 00040 #endif 00041 00042 class HttpRequest; 00043 class HttpsRequest; 00044 00045 /** 00046 * \brief HttpRequest implements the logic for interacting with HTTP servers. 00047 */ 00048 class HttpRequestBase { 00049 friend class HttpRequest; 00050 friend class HttpsRequest; 00051 00052 public: 00053 HttpRequestBase(Socket *socket, Callback<void(const char *at, uint32_t length)> bodyCallback) 00054 : _socket(socket), _body_callback(bodyCallback), _request_buffer(NULL), _request_buffer_ix(0) 00055 {} 00056 00057 /** 00058 * HttpRequest Constructor 00059 */ 00060 virtual ~HttpRequestBase() { 00061 // should response be owned by us? Or should user free it? 00062 // maybe implement copy constructor on response... 00063 if (_response) { 00064 delete _response; 00065 } 00066 00067 if (_parsed_url) { 00068 delete _parsed_url; 00069 } 00070 00071 if (_request_builder) { 00072 delete _request_builder; 00073 } 00074 00075 if (_socket && _we_created_socket) { 00076 delete _socket; 00077 } 00078 } 00079 00080 /** 00081 * Execute the request and receive the response. 00082 * This adds a Content-Length header to the request (when body_size is set), and sends the data to the server. 00083 * @param body Pointer to the body to be sent 00084 * @param body_size Size of the body to be sent 00085 * @return An HttpResponse pointer on success, or NULL on failure. 00086 * See get_error() for the error code. 00087 */ 00088 HttpResponse* send(const void* body = NULL, nsapi_size_t body_size = 0) { 00089 nsapi_size_or_error_t ret = connect_socket(); 00090 00091 if (ret != NSAPI_ERROR_OK) { 00092 _error = ret; 00093 return NULL; 00094 } 00095 00096 _request_buffer_ix = 0; 00097 00098 uint32_t request_size = 0; 00099 char* request = _request_builder->build(body, body_size, request_size); 00100 00101 ret = send_buffer(request, request_size); 00102 00103 free(request); 00104 00105 if (ret < 0) { 00106 _error = ret; 00107 return NULL; 00108 } 00109 00110 return create_http_response(); 00111 } 00112 00113 /** 00114 * Execute the request and receive the response. 00115 * This sends the request through chunked-encoding. 00116 * @param body_cb Callback which generates the next chunk of the request 00117 * @return An HttpResponse pointer on success, or NULL on failure. 00118 * See get_error() for the error code. 00119 */ 00120 HttpResponse* send(Callback<const void*(uint32_t*)> body_cb) { 00121 00122 nsapi_error_t ret; 00123 00124 if ((ret = connect_socket()) != NSAPI_ERROR_OK) { 00125 _error = ret; 00126 return NULL; 00127 } 00128 00129 _request_buffer_ix = 0; 00130 00131 set_header("Transfer-Encoding", "chunked"); 00132 00133 uint32_t request_size = 0; 00134 char* request = _request_builder->build(NULL, 0, request_size); 00135 00136 // first... send this request headers without the body 00137 nsapi_size_or_error_t total_send_count = send_buffer(request, request_size); 00138 00139 if (total_send_count < 0) { 00140 free(request); 00141 _error = total_send_count; 00142 return NULL; 00143 } 00144 00145 // ok... now it's time to start sending chunks... 00146 while (1) { 00147 uint32_t size; 00148 const void *buffer = body_cb(&size); 00149 00150 if (size == 0) break; 00151 00152 // so... size in HEX, \r\n, data, \r\n again 00153 char size_buff[10]; // if sending length of more than 8 digits, you have another problem on a microcontroller... 00154 int size_buff_size = sprintf(size_buff, "%X\r\n", static_cast<size_t>(size)); 00155 if ((total_send_count = send_buffer(size_buff, static_cast<uint32_t>(size_buff_size))) < 0) { 00156 free(request); 00157 _error = total_send_count; 00158 return NULL; 00159 } 00160 00161 // now send the normal buffer... and then \r\n at the end 00162 total_send_count = send_buffer((char*)buffer, size); 00163 if (total_send_count < 0) { 00164 free(request); 00165 _error = total_send_count; 00166 return NULL; 00167 } 00168 00169 // and... \r\n 00170 const char* rn = "\r\n"; 00171 if ((total_send_count = send_buffer((char*)rn, 2)) < 0) { 00172 free(request); 00173 _error = total_send_count; 00174 return NULL; 00175 } 00176 } 00177 00178 // finalize...? 00179 const char* fin = "0\r\n\r\n"; 00180 if ((total_send_count = send_buffer((char*)fin, strlen(fin))) < 0) { 00181 free(request); 00182 _error = total_send_count; 00183 return NULL; 00184 } 00185 00186 free(request); 00187 00188 return create_http_response(); 00189 } 00190 00191 /** 00192 * Set a header for the request. 00193 * 00194 * The 'Host', 'Content-Length', and (optionally) 'Transfer-Encoding: chunked' 00195 * headers are set automatically. 00196 * Setting the same header twice will overwrite the previous entry. 00197 * 00198 * @param key Header key 00199 * @param value Header value 00200 */ 00201 void set_header(string key, string value) { 00202 _request_builder->set_header(key, value); 00203 } 00204 00205 /** 00206 * Get the error code. 00207 * 00208 * When send() fails, this error is set. 00209 */ 00210 nsapi_error_t get_error() { 00211 return _error; 00212 } 00213 00214 /** 00215 * Set the request log buffer, all bytes that are sent for this request are logged here. 00216 * If the buffer would overflow logging is stopped. 00217 * 00218 * @param buffer Pointer to a buffer to store the data in 00219 * @param buffer_size Size of the buffer 00220 */ 00221 void set_request_log_buffer(uint8_t *buffer, size_t buffer_size) { 00222 _request_buffer = buffer; 00223 _request_buffer_size = buffer_size; 00224 _request_buffer_ix = 0; 00225 } 00226 00227 /** 00228 * Get the number of bytes written to the request log buffer, since the last request. 00229 * If no request was sent, or if the request log buffer is NULL, then this returns 0. 00230 */ 00231 size_t get_request_log_buffer_length() { 00232 return _request_buffer_ix; 00233 } 00234 00235 protected: 00236 virtual nsapi_error_t connect_socket(char *host, uint16_t port) = 0; 00237 00238 private: 00239 nsapi_error_t connect_socket( ) { 00240 if (_response != NULL) { 00241 // already executed this response 00242 return -2100; // @todo, make a lookup table with errors 00243 } 00244 00245 00246 if (_we_created_socket) { 00247 nsapi_error_t connection_result = connect_socket(_parsed_url->host(), _parsed_url->port()); 00248 if (connection_result != NSAPI_ERROR_OK) { 00249 return connection_result; 00250 } 00251 } 00252 00253 return NSAPI_ERROR_OK; 00254 } 00255 00256 nsapi_size_or_error_t send_buffer(char* buffer, uint32_t buffer_size) { 00257 nsapi_size_or_error_t total_send_count = 0; 00258 while (total_send_count < buffer_size) { 00259 00260 // get a slice of the buffer 00261 char *buffer_slice = buffer + total_send_count; 00262 uint32_t buffer_slice_size = buffer_size - total_send_count; 00263 00264 // if request buffer was set, copy it there 00265 if (_request_buffer != NULL && _request_buffer_ix + buffer_slice_size < _request_buffer_size) { 00266 memcpy(_request_buffer + _request_buffer_ix, buffer_slice, buffer_slice_size); 00267 _request_buffer_ix += buffer_slice_size; 00268 } 00269 00270 nsapi_size_or_error_t send_result = _socket->send(buffer_slice, buffer_slice_size); 00271 00272 if (send_result < 0) { 00273 total_send_count = send_result; 00274 break; 00275 } 00276 00277 if (send_result == 0) { 00278 break; 00279 } 00280 00281 total_send_count += send_result; 00282 } 00283 00284 return total_send_count; 00285 } 00286 00287 HttpResponse* create_http_response() { 00288 // Create a response object 00289 _response = new HttpResponse(); 00290 // And a response parser 00291 HttpParser parser(_response, HTTP_RESPONSE, _body_callback); 00292 00293 // Set up a receive buffer (on the heap) 00294 uint8_t* recv_buffer = (uint8_t*)malloc(HTTP_RECEIVE_BUFFER_SIZE); 00295 00296 // Socket::recv is called until we don't have any data anymore 00297 nsapi_size_or_error_t recv_ret; 00298 while ((recv_ret = _socket->recv(recv_buffer, HTTP_RECEIVE_BUFFER_SIZE)) > 0) { 00299 00300 // Pass the chunk into the http_parser 00301 uint32_t nparsed = parser.execute((const char*)recv_buffer, recv_ret); 00302 if (nparsed != recv_ret) { 00303 // printf("Parsing failed... parsed %d bytes, received %d bytes\n", nparsed, recv_ret); 00304 _error = -2101; 00305 free(recv_buffer); 00306 return NULL; 00307 } 00308 00309 if (_response->is_message_complete()) { 00310 break; 00311 } 00312 } 00313 // error? 00314 if (recv_ret < 0) { 00315 _error = recv_ret; 00316 free(recv_buffer); 00317 return NULL; 00318 } 00319 00320 // When done, call parser.finish() 00321 parser.finish(); 00322 00323 // Free the receive buffer 00324 free(recv_buffer); 00325 00326 if (_we_created_socket) { 00327 // Close the socket 00328 _socket->close(); 00329 } 00330 00331 return _response; 00332 } 00333 00334 private: 00335 Socket* _socket; 00336 Callback<void(const char *at, uint32_t length)> _body_callback; 00337 00338 ParsedUrl* _parsed_url; 00339 00340 HttpRequestBuilder* _request_builder; 00341 HttpResponse* _response; 00342 00343 bool _we_created_socket; 00344 00345 nsapi_error_t _error; 00346 00347 uint8_t *_request_buffer; 00348 size_t _request_buffer_size; 00349 size_t _request_buffer_ix; 00350 }; 00351 00352 #endif // _HTTP_REQUEST_BASE_H_
Generated on Wed Jul 13 2022 00:40:26 by 1.7.2