Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
source/http_response_builder.h@0:a21b8a29df03, 2021-10-09 (annotated)
- 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?
| User | Revision | Line number | New 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_ |