HTTP and HTTPS library for Mbed OS 5

Dependents:   MQTTGateway2 MQTTGatewayK64 http-example-wnc GuardRoom ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers http_request_builder.h Source File

http_request_builder.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 _MBED_HTTP_REQUEST_BUILDER_H_
00019 #define _MBED_HTTP_REQUEST_BUILDER_H_
00020 
00021 #include <string>
00022 #include <map>
00023 #include "http_parser.h"
00024 #include "http_parsed_url.h"
00025 
00026 class HttpRequestBuilder {
00027 public:
00028     HttpRequestBuilder(http_method a_method, ParsedUrl* a_parsed_url)
00029         : method(a_method), parsed_url(a_parsed_url)
00030     {
00031         string host(parsed_url->host());
00032 
00033         char port_str[10];
00034         sprintf(port_str, ":%d", parsed_url->port());
00035 
00036         if (strcmp(parsed_url->schema(), "http") == 0 && parsed_url->port() != 80) {
00037             host += string(port_str);
00038         }
00039         else if (strcmp(parsed_url->schema(), "https") == 0 && parsed_url->port() != 443) {
00040             host += string(port_str);
00041         }
00042         else if (strcmp(parsed_url->schema(), "ws") == 0 && parsed_url->port() != 80) {
00043             host += string(port_str);
00044         }
00045         else if (strcmp(parsed_url->schema(), "wss") == 0 && parsed_url->port() != 443) {
00046             host += string(port_str);
00047         }
00048 
00049         set_header("Host", host);
00050     }
00051 
00052     /**
00053      * Set a header for the request
00054      * If the key already exists, it will be overwritten...
00055      */
00056     void set_header(string key, string value) {
00057         map<string, string>::iterator it = headers.find(key);
00058 
00059         if (it != headers.end()) {
00060             it->second = value;
00061         }
00062         else {
00063             headers.insert(headers.end(), pair<string, string>(key, value));
00064         }
00065     }
00066 
00067     char* build(const void* body, uint32_t body_size, uint32_t &size, bool skip_content_length = false) {
00068         const char* method_str = http_method_str(method);
00069 
00070         bool is_chunked = has_header("Transfer-Encoding", "chunked");
00071 
00072         if (!is_chunked && (method == HTTP_POST || method == HTTP_PUT || method == HTTP_DELETE || body_size > 0)) {
00073             char buffer[10];
00074             snprintf(buffer, 10, "%lu", body_size);
00075             set_header("Content-Length", string(buffer));
00076         }
00077 
00078         size = 0;
00079 
00080         // first line is METHOD PATH+QUERY HTTP/1.1\r\n
00081         size += strlen(method_str) + 1 + strlen(parsed_url->path()) + (strlen(parsed_url->query()) ? strlen(parsed_url->query()) + 1 : 0) + 1 + 8 + 2;
00082 
00083         // after that we'll do the headers
00084         typedef map<string, string>::iterator it_type;
00085         for(it_type it = headers.begin(); it != headers.end(); it++) {
00086             // line is KEY: VALUE\r\n
00087             size += it->first.length() + 1 + 1 + it->second.length() + 2;
00088         }
00089 
00090         // then the body, first an extra newline
00091         size += 2;
00092 
00093         if (!is_chunked) {
00094             // body
00095             size += body_size;
00096         }
00097 
00098         // Now let's print it
00099         char* req = (char*)calloc(size + 1, 1);
00100         char* originalReq = req;
00101 
00102         if (strlen(parsed_url->query())) {
00103             sprintf(req, "%s %s?%s HTTP/1.1\r\n", method_str, parsed_url->path(), parsed_url->query());
00104         } else {
00105             sprintf(req, "%s %s%s HTTP/1.1\r\n", method_str, parsed_url->path(), parsed_url->query());
00106         }
00107         req += strlen(method_str) + 1 + strlen(parsed_url->path()) + (strlen(parsed_url->query()) ? strlen(parsed_url->query()) + 1 : 0) + 1 + 8 + 2;
00108 
00109         typedef map<string, string>::iterator it_type;
00110         for(it_type it = headers.begin(); it != headers.end(); it++) {
00111             // line is KEY: VALUE\r\n
00112             sprintf(req, "%s: %s\r\n", it->first.c_str(), it->second.c_str());
00113             req += it->first.length() + 1 + 1 + it->second.length() + 2;
00114         }
00115 
00116         sprintf(req, "\r\n");
00117         req += 2;
00118 
00119         if (body_size > 0) {
00120             memcpy(req, body, body_size);
00121         }
00122         req += body_size;
00123 
00124         // Uncomment to debug...
00125         // printf("----- BEGIN REQUEST -----\n");
00126         // printf("%s", originalReq);
00127         // printf("----- END REQUEST -----\n");
00128 
00129         return originalReq;
00130     }
00131 
00132 private:
00133     bool has_header(const char* key, const char* value = NULL) {
00134         typedef map<string, string>::iterator it_type;
00135         for(it_type it = headers.begin(); it != headers.end(); it++) {
00136             if (strcmp(it->first.c_str(), key) == 0) { // key matches
00137                 if (value == NULL || (strcmp(it->second.c_str(), value) == 0)) { // value is NULL or matches
00138                     return true;
00139                 }
00140             }
00141         }
00142 
00143         return false;
00144     }
00145 
00146     http_method method;
00147     ParsedUrl* parsed_url;
00148     map<string, string> headers;
00149 };
00150 
00151 #endif // _MBED_HTTP_REQUEST_BUILDER_H_