Reem M
/
http-server-example1
http
source/http_response_builder.h@1:ce6ccd14af4c, 2019-04-15 (annotated)
- Committer:
- reeml3
- Date:
- Mon Apr 15 18:12:24 2019 +0000
- Revision:
- 1:ce6ccd14af4c
- Parent:
- 0:a49e37a83a7a
http
Who changed what in which revision?
User | Revision | Line number | New 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_ |