mbed-http

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 #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_