Hiroaki Okoshi / Mbed OS http-webserver-example-mbed-os-5-odin-w2
Committer:
Hiroaki_Okoshi
Date:
Sat Oct 09 14:23:23 2021 +0000
Revision:
0:a21b8a29df03
Sample web server via WiFi program. for mbed os 5.15

Who changed what in which revision?

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