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