Initial setup for TheKsystem.

Dependencies:   mbed-http HTS221

Committer:
Jan Jongboom
Date:
Thu Feb 16 11:13:40 2017 +0100
Revision:
1:3bff14db67c7
Add mbed-http

Who changed what in which revision?

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