mbed-http
Fork of mbed-http by
Embed:
(wiki syntax)
Show/hide line numbers
http_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 _HTTP_REQUEST_ 00019 #define _HTTP_REQUEST_ 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 00030 /** 00031 * @todo: 00032 * - Userinfo parameter is not handled 00033 */ 00034 00035 #ifndef HTTP_RECEIVE_BUFFER_SIZE 00036 #define HTTP_RECEIVE_BUFFER_SIZE 8 * 1024 00037 #endif 00038 00039 /** 00040 * \brief HttpRequest implements the logic for interacting with HTTP servers. 00041 */ 00042 class HttpRequest { 00043 public: 00044 /** 00045 * HttpRequest Constructor 00046 * 00047 * @param[in] aNetwork The network interface 00048 * @param[in] aMethod HTTP method to use 00049 * @param[in] url URL to the resource 00050 * @param[in] aBodyCallback Callback on which to retrieve chunks of the response body. 00051 If not set, the complete body will be allocated on the HttpResponse object, 00052 which might use lots of memory. 00053 */ 00054 HttpRequest(NetworkInterface* aNetwork, http_method aMethod, const char* url, Callback<void(const char *at, size_t length)> aBodyCallback = 0) 00055 : network(aNetwork), method(aMethod), body_callback(aBodyCallback) 00056 { 00057 error = 0; 00058 response = NULL; 00059 00060 parsed_url = new ParsedUrl(url); 00061 request_builder = new HttpRequestBuilder(method, parsed_url); 00062 00063 socket = new TCPSocket(); 00064 we_created_socket = true; 00065 } 00066 00067 /** 00068 * HttpRequest Constructor 00069 * 00070 * @param[in] aSocket An open TCPSocket 00071 * @param[in] aMethod HTTP method to use 00072 * @param[in] url URL to the resource 00073 * @param[in] aBodyCallback Callback on which to retrieve chunks of the response body. 00074 If not set, the complete body will be allocated on the HttpResponse object, 00075 which might use lots of memory. 00076 */ 00077 HttpRequest(TCPSocket* aSocket, http_method aMethod, const char* url, Callback<void(const char *at, size_t length)> aBodyCallback = 0) 00078 : socket(aSocket), method(aMethod), body_callback(aBodyCallback) 00079 { 00080 error = 0; 00081 response = NULL; 00082 network = NULL; 00083 00084 parsed_url = new ParsedUrl(url); 00085 request_builder = new HttpRequestBuilder(method, parsed_url); 00086 00087 we_created_socket = false; 00088 } 00089 00090 /** 00091 * HttpRequest Constructor 00092 */ 00093 ~HttpRequest() { 00094 // should response be owned by us? Or should user free it? 00095 // maybe implement copy constructor on response... 00096 if (response) { 00097 delete response; 00098 } 00099 00100 if (parsed_url) { 00101 delete parsed_url; 00102 } 00103 00104 if (request_builder) { 00105 delete request_builder; 00106 } 00107 00108 if (socket && we_created_socket) { 00109 delete socket; 00110 } 00111 } 00112 00113 /** 00114 * Execute the request and receive the response. 00115 */ 00116 HttpResponse* send(const void* body = NULL, nsapi_size_t body_size = 0) { 00117 if (response != NULL) { 00118 // already executed this response 00119 error = -2100; // @todo, make a lookup table with errors 00120 return NULL; 00121 } 00122 00123 error = 0; 00124 00125 if (we_created_socket) { 00126 nsapi_error_t open_result = socket->open(network); 00127 if (open_result != 0) { 00128 error = open_result; 00129 return NULL; 00130 } 00131 00132 nsapi_error_t connection_result = socket->connect(parsed_url->host(), parsed_url->port()); 00133 if (connection_result != 0) { 00134 error = connection_result; 00135 return NULL; 00136 } 00137 } 00138 00139 size_t request_size = 0; 00140 char* request = request_builder->build(body, body_size, request_size); 00141 00142 nsapi_size_or_error_t send_result = socket->send(request, request_size); 00143 00144 free(request); 00145 00146 if (send_result != request_size) { 00147 error = send_result; 00148 return NULL; 00149 } 00150 00151 // Create a response object 00152 response = new HttpResponse(); 00153 // And a response parser 00154 HttpParser parser(response, HTTP_RESPONSE, body_callback); 00155 00156 // Set up a receive buffer (on the heap) 00157 uint8_t* recv_buffer = (uint8_t*)malloc(HTTP_RECEIVE_BUFFER_SIZE); 00158 00159 // TCPSocket::recv is called until we don't have any data anymore 00160 nsapi_size_or_error_t recv_ret; 00161 while ((recv_ret = socket->recv(recv_buffer, HTTP_RECEIVE_BUFFER_SIZE)) > 0) { 00162 00163 // Pass the chunk into the http_parser 00164 size_t nparsed = parser.execute((const char*)recv_buffer, recv_ret); 00165 if (nparsed != recv_ret) { 00166 // printf("Parsing failed... parsed %d bytes, received %d bytes\n", nparsed, recv_ret); 00167 error = -2101; 00168 free(recv_buffer); 00169 return NULL; 00170 } 00171 00172 if (response->is_message_complete()) { 00173 break; 00174 } 00175 } 00176 // error? 00177 if (recv_ret < 0) { 00178 error = recv_ret; 00179 free(recv_buffer); 00180 return NULL; 00181 } 00182 00183 // When done, call parser.finish() 00184 parser.finish(); 00185 00186 // Free the receive buffer 00187 free(recv_buffer); 00188 00189 if (we_created_socket) { 00190 // Close the socket 00191 socket->close(); 00192 } 00193 00194 return response; 00195 } 00196 00197 /** 00198 * Set a header for the request. 00199 * 00200 * The 'Host' and 'Content-Length' headers are set automatically. 00201 * Setting the same header twice will overwrite the previous entry. 00202 * 00203 * @param[in] key Header key 00204 * @param[in] value Header value 00205 */ 00206 void set_header(string key, string value) { 00207 request_builder->set_header(key, value); 00208 } 00209 00210 /** 00211 * Get the error code. 00212 * 00213 * When send() fails, this error is set. 00214 */ 00215 nsapi_error_t get_error() { 00216 return error; 00217 } 00218 00219 private: 00220 NetworkInterface* network; 00221 TCPSocket* socket; 00222 http_method method; 00223 Callback<void(const char *at, size_t length)> body_callback; 00224 00225 ParsedUrl* parsed_url; 00226 00227 HttpRequestBuilder* request_builder; 00228 HttpResponse* response; 00229 00230 bool we_created_socket; 00231 00232 nsapi_error_t error; 00233 }; 00234 00235 #endif // _HTTP_REQUEST_
Generated on Thu Jul 14 2022 16:38:26 by 1.7.2