Simple Webserver example for wiznet W5500 (SPI Ethernet chip) mbed OS 5 - HTTP 1.1 and multi-threaded
Dependencies: W5500Interface easy-connect mbed-http
Fork of http-webserver-example by
mbed-os-example-http-server
This application demonstrates how to run an HTTP server on an mbed OS 5 device & WIZnet W5500 Ethernet components.
Request parsing is done through [nodejs/http-parser](https://github.com/nodejs/http-parser).
To build
- Open ``mbed_app.json`` and change the `network-interface` option to your connectivity method ([more info](https://github.com/ARMmbed/easy-connect)).
- Build the project in the online compiler or using mbed CLI.
- Flash the project to your development board.
- Attach a serial monitor to your board to see the debug messages.
Tested on
- NUCLEO_F411RE with W5500 Ethernet shield.
- For W5500, you need the following libraries.
Import libraryW5500Interface
W5500 driver for mbed OS 5
Import libraryeasy-connect
Modified version of easy-connect for W5500 Ethernet components
But every networking stack that supports the [mbed OS 5 NetworkInterface API](https://docs.mbed.com/docs/mbed-os-api-reference/en/latest/APIs/communication/network_sockets/) should work.
Test Result
source/http_response_builder.h
- Committer:
- Jan Jongboom
- Date:
- 2017-07-31
- Revision:
- 0:41f820ea137a
- Child:
- 1:fe3df398bdf5
File content as of revision 0:41f820ea137a:
/*
* PackageLicenseDeclared: Apache-2.0
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _MBED_HTTP_RESPONSE_BUILDER_
#define _MBED_HTTP_RESPONSE_BUILDER_
#include <string>
#include <map>
#include "http_parser.h"
#include "http_parsed_url.h"
static const char* get_http_status_string(uint16_t status_code) {
switch (status_code) {
case 100: return "Continue";
case 101: return "Switching Protocols";
case 102: return "Processing";
case 200: return "OK";
case 201: return "Created";
case 202: return "Accepted";
case 203: return "Non-Authoritative Information";
case 204: return "No Content";
case 205: return "Reset Content";
case 206: return "Partial Content";
case 207: return "Multi-Status";
case 208: return "Already Reported";
case 226: return "IM Used";
case 300: return "Multiple Choices";
case 301: return "Moved Permanently";
case 302: return "Found";
case 303: return "See Other";
case 304: return "Not Modified";
case 305: return "Use Proxy";
case 307: return "Temporary Redirect";
case 308: return "Permanent Redirect";
case 400: return "Bad Request";
case 401: return "Unauthorized";
case 402: return "Payment Required";
case 403: return "Forbidden";
case 404: return "Not Found";
case 405: return "Method Not Allowed";
case 406: return "Not Acceptable";
case 407: return "Proxy Authentication Required";
case 408: return "Request Timeout";
case 409: return "Conflict";
case 410: return "Gone";
case 411: return "Length Required";
case 412: return "Precondition Failed";
case 413: return "Payload Too Large";
case 414: return "URI Too Long";
case 415: return "Unsupported Media Type";
case 416: return "Range Not Satisfiable";
case 417: return "Expectation Failed";
case 421: return "Misdirected Request";
case 422: return "Unprocessable Entity";
case 423: return "Locked";
case 424: return "Failed Dependency";
case 426: return "Upgrade Required";
case 428: return "Precondition Required";
case 429: return "Too Many Requests";
case 431: return "Request Header Fields Too Large";
case 451: return "Unavailable For Legal Reasons";
case 500: return "Internal Server Error";
case 501: return "Not Implemented";
case 502: return "Bad Gateway";
case 503: return "Service Unavailable";
case 504: return "Gateway Timeout";
case 505: return "HTTP Version Not Supported";
case 506: return "Variant Also Negotiates";
case 507: return "Insufficient Storage";
case 508: return "Loop Detected";
case 510: return "Not Extended";
case 511: return "Network Authentication Required";
default : return "Unknown";
}
}
class HttpResponseBuilder {
public:
HttpResponseBuilder(uint16_t a_status_code)
: status_code(a_status_code), status_message(get_http_status_string(a_status_code))
{
}
/**
* Set a header for the request
* If the key already exists, it will be overwritten...
*/
void set_header(string key, string value) {
map<string, string>::iterator it = headers.find(key);
if (it != headers.end()) {
it->second = value;
}
else {
headers.insert(headers.end(), pair<string, string>(key, value));
}
}
char* build(const void* body, size_t body_size, size_t* size) {
char buffer[10];
snprintf(buffer, sizeof(buffer), "%d", body_size);
set_header("Content-Length", string(buffer));
char status_code_buffer[5];
snprintf(status_code_buffer, sizeof(status_code_buffer), "%d", status_code /* max 5 digits */);
*size = 0;
// first line is HTTP/1.1 200 OK\r\n
*size += 8 + 1 + strlen(status_code_buffer) + 1 + strlen(status_message) + 2;
// after that we'll do the headers
typedef map<string, string>::iterator it_type;
for(it_type it = headers.begin(); it != headers.end(); it++) {
// line is KEY: VALUE\r\n
*size += it->first.length() + 1 + 1 + it->second.length() + 2;
}
// then the body, first an extra newline
*size += 2;
// body
*size += body_size;
// Now let's print it
char* res = (char*)calloc(*size + 1, 1);
char* originalRes = res;
res += sprintf(res, "HTTP/1.1 %s %s\r\n", status_code_buffer, status_message);
typedef map<string, string>::iterator it_type;
for(it_type it = headers.begin(); it != headers.end(); it++) {
// line is KEY: VALUE\r\n
res += sprintf(res, "%s: %s\r\n", it->first.c_str(), it->second.c_str());
}
res += sprintf(res, "\r\n");
if (body_size > 0) {
memcpy(res, body, body_size);
}
res += body_size;
// Uncomment to debug...
// printf("----- BEGIN RESPONSE -----\n");
// printf("%s", originalRes);
// printf("----- END RESPONSE -----\n");
return originalRes;
}
nsapi_error_t send(TCPSocket* socket, const void* body, size_t body_size) {
if (!socket) return NSAPI_ERROR_NO_SOCKET;
size_t res_size;
char* response = build(body, body_size, &res_size);
return socket->send(response, res_size);
}
private:
uint16_t status_code;
const char* status_message;
map<string, string> headers;
};
#endif // _MBED_HTTP_RESPONSE_BUILDER_
Bongjun Hur

