Skip to content

Commit 4ffca31

Browse files
Initial commit, create application
0 parents  commit 4ffca31

File tree

11 files changed

+583
-0
lines changed

11 files changed

+583
-0
lines changed

.github/workflows/compile.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Example GitHub Actions workflow which provides a CI build for your Mbed CE project.
2+
3+
name: Test that this Mbed project compiles
4+
5+
on: push
6+
7+
jobs:
8+
compile:
9+
runs-on: ubuntu-latest
10+
container: ghcr.io/armmbed/mbed-os-env:master-latest
11+
12+
strategy:
13+
matrix:
14+
mbed_target:
15+
# Change the below to match the target you want to compile the project for.
16+
- LPC1768
17+
18+
steps:
19+
- name: Checkout
20+
uses: actions/checkout@v4
21+
with:
22+
submodules: recursive
23+
24+
- name: Install python3-venv
25+
run: |
26+
apt-get update
27+
apt-get install -y python3-venv
28+
29+
- name: Build project for ${{ matrix.mbed_target }}
30+
run: |
31+
mkdir build && cd build
32+
cmake .. -GNinja -DMBED_TARGET=${{ matrix.mbed_target }}
33+
ninja

.gitignore

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# CLion build dirs
2+
cmake-build-*/
3+
4+
# User-specific CLion stuff
5+
.idea/**/workspace.xml
6+
.idea/**/tasks.xml
7+
.idea/**/usage.statistics.xml
8+
.idea/**/dictionaries
9+
.idea/**/shelf
10+
.idea/runConfigurations
11+
12+
# Generated CLion files
13+
.idea/**/contentModel.xml
14+
15+
# Sensitive or high-churn CLion files
16+
.idea/**/dataSources/
17+
.idea/**/dataSources.ids
18+
.idea/**/dataSources.local.xml
19+
.idea/**/sqlDataSources.xml
20+
.idea/**/dynamic.xml
21+
.idea/**/uiDesigner.xml
22+
.idea/**/dbnavigator.xml
23+
24+
# Gradle
25+
.idea/**/gradle.xml
26+
.idea/**/libraries
27+
28+
# VS Code build dir
29+
build/
30+
31+
# VS Code config files
32+
.vscode/
33+
34+
# Python stuff
35+
*.pyc
36+
37+
# Mac stuff
38+
.DS_Store

.gitmodules

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[submodule "mbed-os"]
2+
path = mbed-os
3+
url = https://github.com/mbed-ce/mbed-os.git
4+
[submodule "mbed-http"]
5+
path = mbed-http
6+
url = https://github.com/mbed-ce-libraries-examples/mbed-http

CMakeLists.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
cmake_minimum_required(VERSION 3.19)
2+
cmake_policy(VERSION 3.19...3.22)
3+
4+
set(MBED_APP_JSON_PATH mbed_app.json5)
5+
6+
include(mbed-os/tools/cmake/mbed_toolchain_setup.cmake)
7+
project(mbed-http-server-example # here you can change your project name
8+
LANGUAGES C CXX ASM)
9+
include(mbed_project_setup)
10+
11+
add_subdirectory(mbed-os)
12+
13+
add_subdirectory(mbed-http)
14+
15+
add_executable(${PROJECT_NAME} src/main.cpp)
16+
17+
target_link_libraries(${PROJECT_NAME} mbed-os mbed-netsocket mbed-http)
18+
mbed_set_post_build(${PROJECT_NAME})

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# HTTP Server Example
2+
3+
This project is a conversion of the [http webserver example](https://os.mbed.com/teams/sandbox/code/http-webserver-example/) by Jan Jongboom to Mbed CE.
4+
5+
Note: As currently written, this project should work with any Mbed board that has an Ethernet connection. Support for wifi boards is also possible, but you will need to instantiate the wi-fi interface with the right credentials.
6+
7+
## How to set up this project:
8+
9+
1. Clone it to your machine. Don't forget to use `--recursive` to clone the submodules: `git clone --recursive https://github.com/mbed-ce-libraries-examples/mbed-http-server-example.git`
10+
2. Set up the GNU ARM toolchain (and other programs) on your machine using [the toolchain setup guide](https://github.com/mbed-ce/mbed-os/wiki/Toolchain-Setup-Guide).
11+
3. Set up the CMake project for editing. We have three ways to do this:
12+
- On the [command line](https://github.com/mbed-ce/mbed-os/wiki/Project-Setup:-Command-Line)
13+
- Using the [CLion IDE](https://github.com/mbed-ce/mbed-os/wiki/Project-Setup:-CLion)
14+
- Using the [VS Code IDE](https://github.com/mbed-ce/mbed-os/wiki/Project-Setup:-VS-Code)
15+
4. Build the `flash-mbed-http-server-example` target to upload the code to a connected device.

mbed-http

Submodule mbed-http added at b365dc2

mbed-os

Submodule mbed-os added at e420c07

mbed_app.json5

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"target_overrides": {
3+
"*": {
4+
"platform.stdio-baud-rate": 115200,
5+
"platform.stdio-buffered-serial": 1,
6+
7+
"mbed-http.http-buffer-size": 2048
8+
}
9+
}
10+
}

src/http_response_builder.h

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

0 commit comments

Comments
 (0)