First

Dependencies:   CPU_Usage NetworkManager RestAPI_Manager

Committer:
asaewing
Date:
Mon Oct 08 00:50:33 2018 +0000
Revision:
0:8eda451f71fa
First

Who changed what in which revision?

UserRevisionLine numberNew contents of line
asaewing 0:8eda451f71fa 1 #ifndef _HTTP_REQUEST_
asaewing 0:8eda451f71fa 2 #define _HTTP_REQUEST_
asaewing 0:8eda451f71fa 3
asaewing 0:8eda451f71fa 4 #include <string>
asaewing 0:8eda451f71fa 5 #include <vector>
asaewing 0:8eda451f71fa 6 #include <map>
asaewing 0:8eda451f71fa 7 #include "http_parser.h"
asaewing 0:8eda451f71fa 8 #include "http_response.h"
asaewing 0:8eda451f71fa 9 #include "http_request_builder.h"
asaewing 0:8eda451f71fa 10 #include "http_response_parser.h"
asaewing 0:8eda451f71fa 11 #include "http_parsed_url.h"
asaewing 0:8eda451f71fa 12
asaewing 0:8eda451f71fa 13 /**
asaewing 0:8eda451f71fa 14 * @todo:
asaewing 0:8eda451f71fa 15 * - Userinfo parameter is not handled
asaewing 0:8eda451f71fa 16 * - Allow socket re-use
asaewing 0:8eda451f71fa 17 */
asaewing 0:8eda451f71fa 18
asaewing 0:8eda451f71fa 19
asaewing 0:8eda451f71fa 20 /**
asaewing 0:8eda451f71fa 21 * \brief HttpRequest implements the logic for interacting with HTTPS servers.
asaewing 0:8eda451f71fa 22 */
asaewing 0:8eda451f71fa 23 class HttpRequest {
asaewing 0:8eda451f71fa 24 public:
asaewing 0:8eda451f71fa 25 /**
asaewing 0:8eda451f71fa 26 * HttpRequest Constructor
asaewing 0:8eda451f71fa 27 *
asaewing 0:8eda451f71fa 28 * @param[in] aNetwork The network interface
asaewing 0:8eda451f71fa 29 * @param[in] aMethod HTTP method to use
asaewing 0:8eda451f71fa 30 * @param[in] url URL to the resource
asaewing 0:8eda451f71fa 31 * @param[in] aBodyCallback Callback on which to retrieve chunks of the response body.
asaewing 0:8eda451f71fa 32 If not set, the complete body will be allocated on the HttpResponse object,
asaewing 0:8eda451f71fa 33 which might use lots of memory.
asaewing 0:8eda451f71fa 34 */
asaewing 0:8eda451f71fa 35 HttpRequest(NetworkInterface* aNetwork, http_method aMethod, const char* url, Callback<void(const char *at, size_t length)> aBodyCallback = 0)
asaewing 0:8eda451f71fa 36 : network(aNetwork), method(aMethod), body_callback(aBodyCallback)
asaewing 0:8eda451f71fa 37 {
asaewing 0:8eda451f71fa 38 error = 0;
asaewing 0:8eda451f71fa 39 response = NULL;
asaewing 0:8eda451f71fa 40
asaewing 0:8eda451f71fa 41 parsed_url = new ParsedUrl(url);
asaewing 0:8eda451f71fa 42 request_builder = new HttpRequestBuilder(method, parsed_url);
asaewing 0:8eda451f71fa 43 }
asaewing 0:8eda451f71fa 44
asaewing 0:8eda451f71fa 45 /**
asaewing 0:8eda451f71fa 46 * HttpRequest Constructor
asaewing 0:8eda451f71fa 47 */
asaewing 0:8eda451f71fa 48 ~HttpRequest() {
asaewing 0:8eda451f71fa 49 // should response be owned by us? Or should user free it?
asaewing 0:8eda451f71fa 50 // maybe implement copy constructor on response...
asaewing 0:8eda451f71fa 51 if (response) {
asaewing 0:8eda451f71fa 52 delete response;
asaewing 0:8eda451f71fa 53 }
asaewing 0:8eda451f71fa 54
asaewing 0:8eda451f71fa 55 if (parsed_url) {
asaewing 0:8eda451f71fa 56 delete parsed_url;
asaewing 0:8eda451f71fa 57 }
asaewing 0:8eda451f71fa 58
asaewing 0:8eda451f71fa 59 if (request_builder) {
asaewing 0:8eda451f71fa 60 delete request_builder;
asaewing 0:8eda451f71fa 61 }
asaewing 0:8eda451f71fa 62 }
asaewing 0:8eda451f71fa 63
asaewing 0:8eda451f71fa 64 /**
asaewing 0:8eda451f71fa 65 * Execute the request and receive the response.
asaewing 0:8eda451f71fa 66 */
asaewing 0:8eda451f71fa 67 HttpResponse* send(const void* body = NULL, nsapi_size_t body_size = 0) {
asaewing 0:8eda451f71fa 68 if (response != NULL) {
asaewing 0:8eda451f71fa 69 // already executed this response
asaewing 0:8eda451f71fa 70 error = -2100; // @todo, make a lookup table with errors
asaewing 0:8eda451f71fa 71 return NULL;
asaewing 0:8eda451f71fa 72 }
asaewing 0:8eda451f71fa 73
asaewing 0:8eda451f71fa 74 error = 0;
asaewing 0:8eda451f71fa 75
asaewing 0:8eda451f71fa 76 TCPSocket socket;
asaewing 0:8eda451f71fa 77
asaewing 0:8eda451f71fa 78 nsapi_error_t open_result = socket.open(network);
asaewing 0:8eda451f71fa 79 if (open_result != 0) {
asaewing 0:8eda451f71fa 80 error = open_result;
asaewing 0:8eda451f71fa 81 return NULL;
asaewing 0:8eda451f71fa 82 }
asaewing 0:8eda451f71fa 83
asaewing 0:8eda451f71fa 84 nsapi_error_t connection_result = socket.connect(parsed_url->host(), parsed_url->port());
asaewing 0:8eda451f71fa 85 if (connection_result != 0) {
asaewing 0:8eda451f71fa 86 error = connection_result;
asaewing 0:8eda451f71fa 87 return NULL;
asaewing 0:8eda451f71fa 88 }
asaewing 0:8eda451f71fa 89
asaewing 0:8eda451f71fa 90 char* request = request_builder->build(body, body_size);
asaewing 0:8eda451f71fa 91 size_t request_size = strlen(request);
asaewing 0:8eda451f71fa 92
asaewing 0:8eda451f71fa 93 nsapi_size_or_error_t send_result = socket.send(request, request_size);
asaewing 0:8eda451f71fa 94
asaewing 0:8eda451f71fa 95 free(request);
asaewing 0:8eda451f71fa 96
asaewing 0:8eda451f71fa 97 if (send_result != request_size) {
asaewing 0:8eda451f71fa 98 error = send_result;
asaewing 0:8eda451f71fa 99 return NULL;
asaewing 0:8eda451f71fa 100 }
asaewing 0:8eda451f71fa 101
asaewing 0:8eda451f71fa 102 // Create a response object
asaewing 0:8eda451f71fa 103 response = new HttpResponse();
asaewing 0:8eda451f71fa 104 // And a response parser
asaewing 0:8eda451f71fa 105 HttpResponseParser parser(response, body_callback);
asaewing 0:8eda451f71fa 106
asaewing 0:8eda451f71fa 107 // Set up a receive buffer (on the heap)
asaewing 0:8eda451f71fa 108 uint8_t* recv_buffer = (uint8_t*)malloc(HTTP_RECEIVE_BUFFER_SIZE);
asaewing 0:8eda451f71fa 109
asaewing 0:8eda451f71fa 110 // TCPSocket::recv is called until we don't have any data anymore
asaewing 0:8eda451f71fa 111 nsapi_size_or_error_t recv_ret;
asaewing 0:8eda451f71fa 112 while ((recv_ret = socket.recv(recv_buffer, HTTP_RECEIVE_BUFFER_SIZE)) > 0) {
asaewing 0:8eda451f71fa 113 // Pass the chunk into the http_parser
asaewing 0:8eda451f71fa 114 size_t nparsed = parser.execute((const char*)recv_buffer, recv_ret);
asaewing 0:8eda451f71fa 115 if (nparsed != recv_ret) {
asaewing 0:8eda451f71fa 116 // printf("Parsing failed... parsed %d bytes, received %d bytes\n", nparsed, recv_ret);
asaewing 0:8eda451f71fa 117 error = -2101;
asaewing 0:8eda451f71fa 118 free(recv_buffer);
asaewing 0:8eda451f71fa 119 return NULL;
asaewing 0:8eda451f71fa 120 }
asaewing 0:8eda451f71fa 121 // No more chunks? break out of this loop
asaewing 0:8eda451f71fa 122 if (recv_ret < HTTP_RECEIVE_BUFFER_SIZE) {
asaewing 0:8eda451f71fa 123 break;
asaewing 0:8eda451f71fa 124 }
asaewing 0:8eda451f71fa 125 }
asaewing 0:8eda451f71fa 126 // error?
asaewing 0:8eda451f71fa 127 if (recv_ret < 0) {
asaewing 0:8eda451f71fa 128 error = recv_ret;
asaewing 0:8eda451f71fa 129 free(recv_buffer);
asaewing 0:8eda451f71fa 130 return NULL;
asaewing 0:8eda451f71fa 131 }
asaewing 0:8eda451f71fa 132
asaewing 0:8eda451f71fa 133 // When done, call parser.finish()
asaewing 0:8eda451f71fa 134 parser.finish();
asaewing 0:8eda451f71fa 135
asaewing 0:8eda451f71fa 136 // Free the receive buffer
asaewing 0:8eda451f71fa 137 free(recv_buffer);
asaewing 0:8eda451f71fa 138
asaewing 0:8eda451f71fa 139 // Close the socket
asaewing 0:8eda451f71fa 140 socket.close();
asaewing 0:8eda451f71fa 141
asaewing 0:8eda451f71fa 142 return response;
asaewing 0:8eda451f71fa 143 }
asaewing 0:8eda451f71fa 144
asaewing 0:8eda451f71fa 145 /**
asaewing 0:8eda451f71fa 146 * Set a header for the request.
asaewing 0:8eda451f71fa 147 *
asaewing 0:8eda451f71fa 148 * The 'Host' and 'Content-Length' headers are set automatically.
asaewing 0:8eda451f71fa 149 * Setting the same header twice will overwrite the previous entry.
asaewing 0:8eda451f71fa 150 *
asaewing 0:8eda451f71fa 151 * @param[in] key Header key
asaewing 0:8eda451f71fa 152 * @param[in] value Header value
asaewing 0:8eda451f71fa 153 */
asaewing 0:8eda451f71fa 154 void set_header(string key, string value) {
asaewing 0:8eda451f71fa 155 request_builder->set_header(key, value);
asaewing 0:8eda451f71fa 156 }
asaewing 0:8eda451f71fa 157
asaewing 0:8eda451f71fa 158 /**
asaewing 0:8eda451f71fa 159 * Get the error code.
asaewing 0:8eda451f71fa 160 *
asaewing 0:8eda451f71fa 161 * When send() fails, this error is set.
asaewing 0:8eda451f71fa 162 */
asaewing 0:8eda451f71fa 163 nsapi_error_t get_error() {
asaewing 0:8eda451f71fa 164 return error;
asaewing 0:8eda451f71fa 165 }
asaewing 0:8eda451f71fa 166
asaewing 0:8eda451f71fa 167 private:
asaewing 0:8eda451f71fa 168 NetworkInterface* network;
asaewing 0:8eda451f71fa 169 http_method method;
asaewing 0:8eda451f71fa 170 Callback<void(const char *at, size_t length)> body_callback;
asaewing 0:8eda451f71fa 171
asaewing 0:8eda451f71fa 172 ParsedUrl* parsed_url;
asaewing 0:8eda451f71fa 173
asaewing 0:8eda451f71fa 174 HttpRequestBuilder* request_builder;
asaewing 0:8eda451f71fa 175 HttpResponse* response;
asaewing 0:8eda451f71fa 176
asaewing 0:8eda451f71fa 177 nsapi_error_t error;
asaewing 0:8eda451f71fa 178 };
asaewing 0:8eda451f71fa 179
asaewing 0:8eda451f71fa 180 #endif // _HTTP_REQUEST_