http

Committer:
reeml3
Date:
Mon Apr 15 18:12:24 2019 +0000
Revision:
1:ce6ccd14af4c
Parent:
0:a49e37a83a7a
http

Who changed what in which revision?

UserRevisionLine numberNew contents of line
DuaaAbusharkh 0:a49e37a83a7a 1 /*
DuaaAbusharkh 0:a49e37a83a7a 2 * PackageLicenseDeclared: Apache-2.0
DuaaAbusharkh 0:a49e37a83a7a 3 * Copyright (c) 2017 ARM Limited
DuaaAbusharkh 0:a49e37a83a7a 4 *
DuaaAbusharkh 0:a49e37a83a7a 5 * Licensed under the Apache License, Version 2.0 (the "License");
DuaaAbusharkh 0:a49e37a83a7a 6 * you may not use this file except in compliance with the License.
DuaaAbusharkh 0:a49e37a83a7a 7 * You may obtain a copy of the License at
DuaaAbusharkh 0:a49e37a83a7a 8 *
DuaaAbusharkh 0:a49e37a83a7a 9 * http://www.apache.org/licenses/LICENSE-2.0
DuaaAbusharkh 0:a49e37a83a7a 10 *
DuaaAbusharkh 0:a49e37a83a7a 11 * Unless required by applicable law or agreed to in writing, software
DuaaAbusharkh 0:a49e37a83a7a 12 * distributed under the License is distributed on an "AS IS" BASIS,
DuaaAbusharkh 0:a49e37a83a7a 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
DuaaAbusharkh 0:a49e37a83a7a 14 * See the License for the specific language governing permissions and
DuaaAbusharkh 0:a49e37a83a7a 15 * limitations under the License.
DuaaAbusharkh 0:a49e37a83a7a 16 */
DuaaAbusharkh 0:a49e37a83a7a 17
DuaaAbusharkh 0:a49e37a83a7a 18 #ifndef _MBED_HTTP_RESPONSE_BUILDER_
DuaaAbusharkh 0:a49e37a83a7a 19 #define _MBED_HTTP_RESPONSE_BUILDER_
DuaaAbusharkh 0:a49e37a83a7a 20
DuaaAbusharkh 0:a49e37a83a7a 21 #include <string>
DuaaAbusharkh 0:a49e37a83a7a 22 #include <map>
DuaaAbusharkh 0:a49e37a83a7a 23 #include "http_parser.h"
DuaaAbusharkh 0:a49e37a83a7a 24 #include "http_parsed_url.h"
DuaaAbusharkh 0:a49e37a83a7a 25
DuaaAbusharkh 0:a49e37a83a7a 26 static const char* get_http_status_string(uint16_t status_code) {
DuaaAbusharkh 0:a49e37a83a7a 27 switch (status_code) {
DuaaAbusharkh 0:a49e37a83a7a 28 case 100: return "Continue";
DuaaAbusharkh 0:a49e37a83a7a 29 case 101: return "Switching Protocols";
DuaaAbusharkh 0:a49e37a83a7a 30 case 102: return "Processing";
DuaaAbusharkh 0:a49e37a83a7a 31 case 200: return "OK";
DuaaAbusharkh 0:a49e37a83a7a 32 case 201: return "Created";
DuaaAbusharkh 0:a49e37a83a7a 33 case 202: return "Accepted";
DuaaAbusharkh 0:a49e37a83a7a 34 case 203: return "Non-Authoritative Information";
DuaaAbusharkh 0:a49e37a83a7a 35 case 204: return "No Content";
DuaaAbusharkh 0:a49e37a83a7a 36 case 205: return "Reset Content";
DuaaAbusharkh 0:a49e37a83a7a 37 case 206: return "Partial Content";
DuaaAbusharkh 0:a49e37a83a7a 38 case 207: return "Multi-Status";
DuaaAbusharkh 0:a49e37a83a7a 39 case 208: return "Already Reported";
DuaaAbusharkh 0:a49e37a83a7a 40 case 226: return "IM Used";
DuaaAbusharkh 0:a49e37a83a7a 41 case 300: return "Multiple Choices";
DuaaAbusharkh 0:a49e37a83a7a 42 case 301: return "Moved Permanently";
DuaaAbusharkh 0:a49e37a83a7a 43 case 302: return "Found";
DuaaAbusharkh 0:a49e37a83a7a 44 case 303: return "See Other";
DuaaAbusharkh 0:a49e37a83a7a 45 case 304: return "Not Modified";
DuaaAbusharkh 0:a49e37a83a7a 46 case 305: return "Use Proxy";
DuaaAbusharkh 0:a49e37a83a7a 47 case 307: return "Temporary Redirect";
DuaaAbusharkh 0:a49e37a83a7a 48 case 308: return "Permanent Redirect";
DuaaAbusharkh 0:a49e37a83a7a 49 case 400: return "Bad Request";
DuaaAbusharkh 0:a49e37a83a7a 50 case 401: return "Unauthorized";
DuaaAbusharkh 0:a49e37a83a7a 51 case 402: return "Payment Required";
DuaaAbusharkh 0:a49e37a83a7a 52 case 403: return "Forbidden";
DuaaAbusharkh 0:a49e37a83a7a 53 case 404: return "Not Found";
DuaaAbusharkh 0:a49e37a83a7a 54 case 405: return "Method Not Allowed";
DuaaAbusharkh 0:a49e37a83a7a 55 case 406: return "Not Acceptable";
DuaaAbusharkh 0:a49e37a83a7a 56 case 407: return "Proxy Authentication Required";
DuaaAbusharkh 0:a49e37a83a7a 57 case 408: return "Request Timeout";
DuaaAbusharkh 0:a49e37a83a7a 58 case 409: return "Conflict";
DuaaAbusharkh 0:a49e37a83a7a 59 case 410: return "Gone";
DuaaAbusharkh 0:a49e37a83a7a 60 case 411: return "Length Required";
DuaaAbusharkh 0:a49e37a83a7a 61 case 412: return "Precondition Failed";
DuaaAbusharkh 0:a49e37a83a7a 62 case 413: return "Payload Too Large";
DuaaAbusharkh 0:a49e37a83a7a 63 case 414: return "URI Too Long";
DuaaAbusharkh 0:a49e37a83a7a 64 case 415: return "Unsupported Media Type";
DuaaAbusharkh 0:a49e37a83a7a 65 case 416: return "Range Not Satisfiable";
DuaaAbusharkh 0:a49e37a83a7a 66 case 417: return "Expectation Failed";
DuaaAbusharkh 0:a49e37a83a7a 67 case 421: return "Misdirected Request";
DuaaAbusharkh 0:a49e37a83a7a 68 case 422: return "Unprocessable Entity";
DuaaAbusharkh 0:a49e37a83a7a 69 case 423: return "Locked";
DuaaAbusharkh 0:a49e37a83a7a 70 case 424: return "Failed Dependency";
DuaaAbusharkh 0:a49e37a83a7a 71 case 426: return "Upgrade Required";
DuaaAbusharkh 0:a49e37a83a7a 72 case 428: return "Precondition Required";
DuaaAbusharkh 0:a49e37a83a7a 73 case 429: return "Too Many Requests";
DuaaAbusharkh 0:a49e37a83a7a 74 case 431: return "Request Header Fields Too Large";
DuaaAbusharkh 0:a49e37a83a7a 75 case 451: return "Unavailable For Legal Reasons";
DuaaAbusharkh 0:a49e37a83a7a 76 case 500: return "Internal Server Error";
DuaaAbusharkh 0:a49e37a83a7a 77 case 501: return "Not Implemented";
DuaaAbusharkh 0:a49e37a83a7a 78 case 502: return "Bad Gateway";
DuaaAbusharkh 0:a49e37a83a7a 79 case 503: return "Service Unavailable";
DuaaAbusharkh 0:a49e37a83a7a 80 case 504: return "Gateway Timeout";
DuaaAbusharkh 0:a49e37a83a7a 81 case 505: return "HTTP Version Not Supported";
DuaaAbusharkh 0:a49e37a83a7a 82 case 506: return "Variant Also Negotiates";
DuaaAbusharkh 0:a49e37a83a7a 83 case 507: return "Insufficient Storage";
DuaaAbusharkh 0:a49e37a83a7a 84 case 508: return "Loop Detected";
DuaaAbusharkh 0:a49e37a83a7a 85 case 510: return "Not Extended";
DuaaAbusharkh 0:a49e37a83a7a 86 case 511: return "Network Authentication Required";
DuaaAbusharkh 0:a49e37a83a7a 87 default : return "Unknown";
DuaaAbusharkh 0:a49e37a83a7a 88 }
DuaaAbusharkh 0:a49e37a83a7a 89 }
DuaaAbusharkh 0:a49e37a83a7a 90
DuaaAbusharkh 0:a49e37a83a7a 91 class HttpResponseBuilder {
DuaaAbusharkh 0:a49e37a83a7a 92 public:
DuaaAbusharkh 0:a49e37a83a7a 93 HttpResponseBuilder(uint16_t a_status_code)
DuaaAbusharkh 0:a49e37a83a7a 94 : status_code(a_status_code), status_message(get_http_status_string(a_status_code))
DuaaAbusharkh 0:a49e37a83a7a 95 {
DuaaAbusharkh 0:a49e37a83a7a 96 }
DuaaAbusharkh 0:a49e37a83a7a 97
DuaaAbusharkh 0:a49e37a83a7a 98 /**
DuaaAbusharkh 0:a49e37a83a7a 99 * Set a header for the request
DuaaAbusharkh 0:a49e37a83a7a 100 * If the key already exists, it will be overwritten...
DuaaAbusharkh 0:a49e37a83a7a 101 */
DuaaAbusharkh 0:a49e37a83a7a 102 void set_header(string key, string value) {
DuaaAbusharkh 0:a49e37a83a7a 103 map<string, string>::iterator it = headers.find(key);
DuaaAbusharkh 0:a49e37a83a7a 104
DuaaAbusharkh 0:a49e37a83a7a 105 if (it != headers.end()) {
DuaaAbusharkh 0:a49e37a83a7a 106 it->second = value;
DuaaAbusharkh 0:a49e37a83a7a 107 }
DuaaAbusharkh 0:a49e37a83a7a 108 else {
DuaaAbusharkh 0:a49e37a83a7a 109 headers.insert(headers.end(), pair<string, string>(key, value));
DuaaAbusharkh 0:a49e37a83a7a 110 }
DuaaAbusharkh 0:a49e37a83a7a 111 }
DuaaAbusharkh 0:a49e37a83a7a 112
DuaaAbusharkh 0:a49e37a83a7a 113 char* build(const void* body, size_t body_size, size_t* size) {
DuaaAbusharkh 0:a49e37a83a7a 114 char buffer[10];
DuaaAbusharkh 0:a49e37a83a7a 115 snprintf(buffer, sizeof(buffer), "%d", body_size);
DuaaAbusharkh 0:a49e37a83a7a 116 set_header("Content-Length", string(buffer));
DuaaAbusharkh 0:a49e37a83a7a 117
DuaaAbusharkh 0:a49e37a83a7a 118 char status_code_buffer[5];
DuaaAbusharkh 0:a49e37a83a7a 119 snprintf(status_code_buffer, sizeof(status_code_buffer), "%d", status_code /* max 5 digits */);
DuaaAbusharkh 0:a49e37a83a7a 120
DuaaAbusharkh 0:a49e37a83a7a 121 *size = 0;
DuaaAbusharkh 0:a49e37a83a7a 122
DuaaAbusharkh 0:a49e37a83a7a 123 // first line is HTTP/1.1 200 OK\r\n
DuaaAbusharkh 0:a49e37a83a7a 124 *size += 8 + 1 + strlen(status_code_buffer) + 1 + strlen(status_message) + 2;
DuaaAbusharkh 0:a49e37a83a7a 125
DuaaAbusharkh 0:a49e37a83a7a 126 // after that we'll do the headers
DuaaAbusharkh 0:a49e37a83a7a 127 typedef map<string, string>::iterator it_type;
DuaaAbusharkh 0:a49e37a83a7a 128 for(it_type it = headers.begin(); it != headers.end(); it++) {
DuaaAbusharkh 0:a49e37a83a7a 129 // line is KEY: VALUE\r\n
DuaaAbusharkh 0:a49e37a83a7a 130 *size += it->first.length() + 1 + 1 + it->second.length() + 2;
DuaaAbusharkh 0:a49e37a83a7a 131 }
DuaaAbusharkh 0:a49e37a83a7a 132
DuaaAbusharkh 0:a49e37a83a7a 133 // then the body, first an extra newline
DuaaAbusharkh 0:a49e37a83a7a 134 *size += 2;
DuaaAbusharkh 0:a49e37a83a7a 135
DuaaAbusharkh 0:a49e37a83a7a 136 // body
DuaaAbusharkh 0:a49e37a83a7a 137 *size += body_size;
DuaaAbusharkh 0:a49e37a83a7a 138
DuaaAbusharkh 0:a49e37a83a7a 139 // Now let's print it
DuaaAbusharkh 0:a49e37a83a7a 140 char* res = (char*)calloc(*size + 1, 1);
DuaaAbusharkh 0:a49e37a83a7a 141 char* originalRes = res;
DuaaAbusharkh 0:a49e37a83a7a 142
DuaaAbusharkh 0:a49e37a83a7a 143 res += sprintf(res, "HTTP/1.1 %s %s\r\n", status_code_buffer, status_message);
DuaaAbusharkh 0:a49e37a83a7a 144
DuaaAbusharkh 0:a49e37a83a7a 145 typedef map<string, string>::iterator it_type;
DuaaAbusharkh 0:a49e37a83a7a 146 for(it_type it = headers.begin(); it != headers.end(); it++) {
DuaaAbusharkh 0:a49e37a83a7a 147 // line is KEY: VALUE\r\n
DuaaAbusharkh 0:a49e37a83a7a 148 res += sprintf(res, "%s: %s\r\n", it->first.c_str(), it->second.c_str());
DuaaAbusharkh 0:a49e37a83a7a 149 }
DuaaAbusharkh 0:a49e37a83a7a 150
DuaaAbusharkh 0:a49e37a83a7a 151 res += sprintf(res, "\r\n");
DuaaAbusharkh 0:a49e37a83a7a 152
DuaaAbusharkh 0:a49e37a83a7a 153 if (body_size > 0) {
DuaaAbusharkh 0:a49e37a83a7a 154 memcpy(res, body, body_size);
DuaaAbusharkh 0:a49e37a83a7a 155 }
DuaaAbusharkh 0:a49e37a83a7a 156 res += body_size;
DuaaAbusharkh 0:a49e37a83a7a 157
DuaaAbusharkh 0:a49e37a83a7a 158 // Uncomment to debug...
DuaaAbusharkh 0:a49e37a83a7a 159 // printf("----- BEGIN RESPONSE -----\n");
DuaaAbusharkh 0:a49e37a83a7a 160 // printf("%s", originalRes);
DuaaAbusharkh 0:a49e37a83a7a 161 // printf("----- END RESPONSE -----\n");
DuaaAbusharkh 0:a49e37a83a7a 162
DuaaAbusharkh 0:a49e37a83a7a 163 return originalRes;
DuaaAbusharkh 0:a49e37a83a7a 164 }
DuaaAbusharkh 0:a49e37a83a7a 165
DuaaAbusharkh 0:a49e37a83a7a 166 nsapi_error_t send(TCPSocket* socket, const void* body, size_t body_size) {
DuaaAbusharkh 0:a49e37a83a7a 167 if (!socket) return NSAPI_ERROR_NO_SOCKET;
DuaaAbusharkh 0:a49e37a83a7a 168
DuaaAbusharkh 0:a49e37a83a7a 169 size_t res_size;
DuaaAbusharkh 0:a49e37a83a7a 170 char* response = build(body, body_size, &res_size);
DuaaAbusharkh 0:a49e37a83a7a 171
DuaaAbusharkh 0:a49e37a83a7a 172 nsapi_error_t r = socket->send(response, res_size);
DuaaAbusharkh 0:a49e37a83a7a 173
DuaaAbusharkh 0:a49e37a83a7a 174 free(response);
DuaaAbusharkh 0:a49e37a83a7a 175
DuaaAbusharkh 0:a49e37a83a7a 176 return r;
DuaaAbusharkh 0:a49e37a83a7a 177 }
DuaaAbusharkh 0:a49e37a83a7a 178
DuaaAbusharkh 0:a49e37a83a7a 179 private:
DuaaAbusharkh 0:a49e37a83a7a 180 uint16_t status_code;
DuaaAbusharkh 0:a49e37a83a7a 181 const char* status_message;
DuaaAbusharkh 0:a49e37a83a7a 182 map<string, string> headers;
DuaaAbusharkh 0:a49e37a83a7a 183 };
DuaaAbusharkh 0:a49e37a83a7a 184
DuaaAbusharkh 0:a49e37a83a7a 185 #endif // _MBED_HTTP_RESPONSE_BUILDER_