fix the problem http request with '\0' and fixx query string in url

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