This library is used to make HTTP and HTTPS calls from mbed OS 5 applications.

Fork of mbed-http by sandbox

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers http_request.h Source File

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 
00036 /**
00037  * \brief HttpRequest implements the logic for interacting with HTTP 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         // And a response parser
00151         HttpParser parser(response, HTTP_RESPONSE, body_callback);
00152 
00153         // Set up a receive buffer (on the heap)
00154         uint8_t* recv_buffer = (uint8_t*)malloc(HTTP_RECEIVE_BUFFER_SIZE);
00155 
00156         // TCPSocket::recv is called until we don't have any data anymore
00157         nsapi_size_or_error_t recv_ret;
00158         while ((recv_ret = socket->recv(recv_buffer, HTTP_RECEIVE_BUFFER_SIZE)) > 0) {
00159 
00160             // Pass the chunk into the http_parser
00161             size_t nparsed = parser.execute((const char*)recv_buffer, recv_ret);
00162             if (nparsed != recv_ret) {
00163                 // printf("Parsing failed... parsed %d bytes, received %d bytes\n", nparsed, recv_ret);
00164                 error = -2101;
00165                 free(recv_buffer);
00166                 return NULL;
00167             }
00168 
00169             if (response->is_message_complete()) {
00170                 break;
00171             }
00172         }
00173         // error?
00174         if (recv_ret < 0) {
00175             error = recv_ret;
00176             free(recv_buffer);
00177             return NULL;
00178         }
00179 
00180         // When done, call parser.finish()
00181         parser.finish();
00182 
00183         // Free the receive buffer
00184         free(recv_buffer);
00185 
00186         if (we_created_socket) {
00187             // Close the socket
00188             socket->close();
00189         }
00190 
00191         return response;
00192     }
00193 
00194     /**
00195      * Set a header for the request.
00196      *
00197      * The 'Host' and 'Content-Length' headers are set automatically.
00198      * Setting the same header twice will overwrite the previous entry.
00199      *
00200      * @param[in] key Header key
00201      * @param[in] value Header value
00202      */
00203     void set_header(string key, string value) {
00204         request_builder->set_header(key, value);
00205     }
00206 
00207     /**
00208      * Get the error code.
00209      *
00210      * When send() fails, this error is set.
00211      */
00212     nsapi_error_t get_error() {
00213         return error;
00214     }
00215 
00216 private:
00217     NetworkInterface* network;
00218     TCPSocket* socket;
00219     http_method method;
00220     Callback<void(const char *at, size_t length)> body_callback;
00221 
00222     ParsedUrl* parsed_url;
00223 
00224     HttpRequestBuilder* request_builder;
00225     HttpResponse* response;
00226 
00227     bool we_created_socket;
00228 
00229     nsapi_error_t error;
00230 };
00231 
00232 #endif // _HTTP_REQUEST_