mirror of
https://github.com/cesanta/mongoose.git
synced 2026-11-14 19:03:20 +00:00
Compare commits
13
Commits
c835c72202
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
053b8ed824 | ||
|
|
2ea1cf6817 | ||
|
|
323326ce8b | ||
|
|
c5344af9fc | ||
|
|
d73b009bbc | ||
|
|
dba6479b23 | ||
|
|
28ca01eb2b | ||
|
|
e999239ca7 | ||
|
|
d545526ba2 | ||
|
|
0b888e8f3f | ||
|
|
27a87dee8b | ||
|
|
94ccc4a130 | ||
|
|
454bf4036f |
No files matched your search
@@ -13,6 +13,7 @@ GitHub repo: https://github.com/cesanta/mongoose
|
||||
|
||||
## General rules
|
||||
|
||||
- All relative file names mentioned in this file are related to the repo root.
|
||||
- Always re-read files before editing, so you do not overwrite existing changes.
|
||||
- Never guess. If you don't know, say you don't know and stop.
|
||||
- Resolve relative paths from the repo root: https://github.com/cesanta/mongoose
|
||||
@@ -39,6 +40,7 @@ This is a navigation aid, not an API reference. Read `mongoose.h` for exact
|
||||
function signatures, structs, options, examples, and constraints.
|
||||
|
||||
- `mg_mgr_*` - event manager and polling loop
|
||||
- `mg_dash_*` - dashboard API for device web UIs, fieldsets, and live updates
|
||||
- `mg_http_*` - HTTP server, HTTP client, uploads, serving files
|
||||
- `mg_ws_*` - WebSocket server and client
|
||||
- `mg_mqtt_*` - MQTT client
|
||||
@@ -229,12 +231,41 @@ xTaskCreate(net_task, "net", 8192, NULL, tskIDLE_PRIORITY + 1, NULL);
|
||||
|
||||
## HTTP / Web Device Dashboard
|
||||
|
||||
For a web UI with real-time device state over WebSocket, use the Mongoose
|
||||
device dashboard.
|
||||
When building a device web UI, control panel, monitoring page, or live
|
||||
display, you MUST use the `mg_dash_*` dashboard framework unless the user
|
||||
explicitly requests another architecture. Do not add your own HTTP event handler.
|
||||
|
||||
Read the dashboard declarations in `mongoose.h` before implementing the UI.
|
||||
Use only the dashboard files listed below. Download missing reference files;
|
||||
preserve existing files. Integrate the dashboard into the existing application
|
||||
and build files.
|
||||
|
||||
Start from the minimal reference implementation and adapt its fields and UI.
|
||||
Keep dashboard fieldsets, callbacks, update timers, and small metric helpers
|
||||
in `dashboard.c`. Do not create `dashboard.h`, or other dashboard
|
||||
helper modules. `mongoose.h` already declares `mg_dash_init()` and
|
||||
`mg_dash_poll()`. Reuse existing board/HAL helpers for hardware measurements;
|
||||
if none exists, put a small private helper in `dashboard.c` or extend the
|
||||
existing board/HAL implementation.
|
||||
|
||||
Expose device state through mg_field / mg_field_set.
|
||||
Call mg_dash_init() once and mg_dash_poll() in the event loop.
|
||||
For live updates, call mg_dash_send_change() from a backend timer.
|
||||
Display values using dashboard.js and HTML data-bind attributes.
|
||||
|
||||
Example: free RAM updated every 50 ms means a read-only fieldset pushed
|
||||
over the dashboard WebSocket every 50 ms. Do not implement browser polling,
|
||||
fetch(), setInterval(), or a custom WebSocket client for dashboard state.
|
||||
|
||||
### Required files
|
||||
|
||||
The following files must exist at these exact paths, regardless of the build environment:
|
||||
Keep all the following Mongoose files together in one project directory.
|
||||
The example uses `mongoose/`; you may choose another directory name.
|
||||
If Mongoose is already installed, use the directory containing the actual
|
||||
`mongoose.c` and `mongoose.h` files, including an existing CubeMX middleware
|
||||
directory. Add the dashboard files there and update the build paths. Do not
|
||||
create a second Mongoose directory or use symlinks, forwarding headers, or
|
||||
duplicate library copies to make files appear colocated.
|
||||
|
||||
```
|
||||
your_project/
|
||||
@@ -244,6 +275,7 @@ your_project/
|
||||
├── mongoose.c # single source file
|
||||
├── dashboard.c # C-side dashboard logic
|
||||
├── dashboard.html # HTML/JS UI (source)
|
||||
├── html2c.js # HTML-to-C generator
|
||||
└── file_data.c # generated from dashboard.html (see below)
|
||||
```
|
||||
|
||||
@@ -255,16 +287,24 @@ node html2c.js dashboard.html -o file_data.c
|
||||
|
||||
`html2c.js` is at https://github.com/cesanta/mongoose/blob/master/resources/html2c.js
|
||||
|
||||
If the project does not yet have `dashboard.c` and `dashboard.html`, fetch the
|
||||
minimal reference versions:
|
||||
For each missing `dashboard.c`, `dashboard.html`, or `html2c.js`, download its
|
||||
reference version from the Mongoose repository and place it beside `mongoose.c`
|
||||
and `mongoose.h`:
|
||||
|
||||
```
|
||||
https://github.com/cesanta/mongoose/blob/master/tutorials/device-dashboard/minimal/dashboard.c
|
||||
https://github.com/cesanta/mongoose/blob/master/tutorials/device-dashboard/minimal/dashboard.html
|
||||
https://github.com/cesanta/mongoose/blob/master/resources/html2c.js
|
||||
```
|
||||
|
||||
If the project already has `dashboard.c` and `dashboard.html`, do **not** fetch
|
||||
anything from the repository.
|
||||
Add a build rule that regenerates `file_data.c` whenever `dashboard.html` or
|
||||
`html2c.js` changes. Keep the upstream generator unchanged; it already inlines
|
||||
the script referenced by the HTML, so the served page does not need internet
|
||||
access. Do not download a separate `dashboard.js` or add a local `--use`
|
||||
override unless the user explicitly requests offline builds or local assets.
|
||||
Compile both `dashboard.c` and `file_data.c` into the
|
||||
application. Call `mg_dash_init()` once and `mg_dash_poll()` on every iteration
|
||||
of the existing Mongoose event loop, from the same task or thread.
|
||||
|
||||
### C integration (bare metal or RTOS main loop)
|
||||
|
||||
@@ -283,15 +323,17 @@ for (;;) {
|
||||
|
||||
### dashboard.html rules
|
||||
|
||||
- Use `dashboard.js` from `https://mongoose.ws/resources/dashboard.js`
|
||||
- Reference `<script src="https://mongoose.ws/resources/dashboard.js"></script>`
|
||||
in the source HTML. Let `html2c.js` inline it into the generated asset.
|
||||
- Call `Dashboard.init({ data: { ... } })` once - this is the only direct
|
||||
Dashboard API call. Treat the rest of Dashboard as a black box.
|
||||
- Do **not** add vanilla JS event listeners, `fetch()` calls, or custom
|
||||
reactive logic to `dashboard.html`.
|
||||
- Do **not** modify `dashboard.html` unless the user explicitly asks.
|
||||
- Modify `dashboard.html` only for requested UI work. A request to create or
|
||||
modify the web UI authorizes the necessary `dashboard.html` edits.
|
||||
- Bind controls to device state using `data-bind` attributes
|
||||
- The `__status` object in evaluations is read-only, do not alter it
|
||||
- If you need to pass data between the UI and backend.c, add extra
|
||||
- If you need to pass data between the UI and `dashboard.c`, add extra
|
||||
fieldsets/fields - see next section about it
|
||||
- If you want to display device data in HTML, use `${}` evaluations
|
||||
|
||||
@@ -315,17 +357,24 @@ for (;;) {
|
||||
|
||||
### dashboard.c rules
|
||||
|
||||
Mongoose backend exports device data as a collection of "fieldsets". Each fieldset groups several fields
|
||||
Mongoose exports device data as fieldsets. Each fieldset groups several fields
|
||||
and has one `bool fn(enum mg_dash_op, struct mg_dash_user *)` callback for
|
||||
read/write/add/delete operations. Use the declarations in the project's
|
||||
`mongoose.h`; do not copy older descriptors with separate reader/writer
|
||||
members or positional access-level arguments. Use designated initializers.
|
||||
|
||||
Example fieldset:
|
||||
|
||||
```c
|
||||
static struct mg_dash s_dash;
|
||||
static bool settings_fn(enum mg_dash_op op, struct mg_dash_user *u);
|
||||
|
||||
static struct settings {
|
||||
double volume;
|
||||
char name[10];
|
||||
int log_level;
|
||||
bool enable_login;
|
||||
} s_settings = {2.7, "Dublin", 2, false, false};
|
||||
} s_settings = {2.7, "Dublin", 2, false};
|
||||
|
||||
static struct mg_field fields_settings[] = {
|
||||
{"volume", MG_VAL_DBL, &s_settings.volume, sizeof(s_settings.volume)},
|
||||
@@ -336,14 +385,12 @@ static struct mg_field fields_settings[] = {
|
||||
};
|
||||
|
||||
static struct mg_field_set set_settings = {
|
||||
"settings", fields_settings, read_settings, write_settings, 3, 7, NULL,
|
||||
.name = "settings", .fields = fields_settings, .fn = settings_fn,
|
||||
};
|
||||
```
|
||||
|
||||
To enable user authentication, set `authenticate` function for the dashboard descriptor:
|
||||
```c
|
||||
static struct mg_dash s_dash;
|
||||
|
||||
// Signature: (char *user, size_t userlen, const char *pass)
|
||||
// `user` is both input (username from the login form) and output: the function
|
||||
// may overwrite it with the canonical username. Return access level > 0 on
|
||||
@@ -360,24 +407,34 @@ static int authenticate(char *user, size_t userlen, const char *pass) {
|
||||
return level;
|
||||
}
|
||||
|
||||
static void write_settings(void) {
|
||||
s_dash.authenticate = s_settings.enable_login ? authenticate : NULL;
|
||||
static bool settings_fn(enum mg_dash_op op, struct mg_dash_user *u) {
|
||||
(void) u;
|
||||
if (op == MG_DASH_WRITE) {
|
||||
s_dash.authenticate = s_settings.enable_login ? authenticate : NULL;
|
||||
return true;
|
||||
}
|
||||
return op == MG_DASH_READ;
|
||||
}
|
||||
```
|
||||
|
||||
Fieldset may have reader and writer function, which acts as a hardware glue. For example, "led1" variable may reflect real LED status using reader and writer:
|
||||
Use the fieldset callback as hardware glue. For example, `led1` can reflect
|
||||
the real LED state:
|
||||
|
||||
```c
|
||||
static struct leds {
|
||||
bool led1;
|
||||
} s_leds = {false};
|
||||
|
||||
static void write_leds(void) {
|
||||
gpio_write(LED1_PIN, s_leds.led1);
|
||||
}
|
||||
|
||||
static void read_leds(void) {
|
||||
s_leds.led1 = gpio_read(LED1_PIN);
|
||||
static bool leds_fn(enum mg_dash_op op, struct mg_dash_user *u) {
|
||||
(void) u;
|
||||
if (op == MG_DASH_READ) {
|
||||
s_leds.led1 = gpio_read(LED1_PIN);
|
||||
} else if (op == MG_DASH_WRITE) {
|
||||
gpio_write(LED1_PIN, s_leds.led1);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct mg_field fields_leds[] = {
|
||||
@@ -386,7 +443,7 @@ static struct mg_field fields_leds[] = {
|
||||
};
|
||||
|
||||
static struct mg_field_set set_leds = {
|
||||
"leds", fields_leds, read_leds, write_leds, 0, 0, NULL,
|
||||
.name = "leds", .fields = fields_leds, .fn = leds_fn,
|
||||
};
|
||||
```
|
||||
|
||||
@@ -412,7 +469,8 @@ static struct event {
|
||||
} s_event;
|
||||
|
||||
static struct mg_field_set field_set_event = {
|
||||
"event", fields_event, event_fn, &s_event.index, 0, 0, 0
|
||||
.name = "event", .fields = fields_event,
|
||||
.fn = event_fn, .index = &s_event.index,
|
||||
};
|
||||
```
|
||||
|
||||
@@ -432,6 +490,20 @@ Do not rename, wrap, relocate, or replace these files or functions. Do not intro
|
||||
|
||||
Board-specific STM32Cube files may exist outside mongoose/, but the Mongoose dashboard files must retain the structure and API documented above.
|
||||
|
||||
### Dashboard completion checks
|
||||
|
||||
- Verify actual file locations, including symlink targets, against the required
|
||||
layout. Check that no extra dashboard source/header/JS files were introduced.
|
||||
- Check the source HTML for the upstream script reference, a single
|
||||
`Dashboard.init()`, and declarative bindings. Networking code in the upstream
|
||||
script inlined into `file_data.c` is expected; do not replace or edit it.
|
||||
- Verify fieldsets are registered with `MG_DASH_ADD_FIELD_SET()`, listeners use
|
||||
`mg_dash_ev_handler`, and live metrics use `mg_dash_send_change()` on the
|
||||
requested backend schedule. Do not resend unrelated fieldsets at that rate.
|
||||
- Regenerate `file_data.c` and build the real firmware. Report separately which
|
||||
behavior was verified on hardware; host mocks do not establish physical LED,
|
||||
Ethernet, RAM measurement, or refresh-rate correctness.
|
||||
|
||||
## Filesystem
|
||||
|
||||
| Define | Use when |
|
||||
|
||||
+26
-15
@@ -4906,11 +4906,15 @@ static bool uri2path(const char *r, struct mg_str uri, char *buf, size_t len) {
|
||||
n = mg_snprintf(buf, len, "%.*s", (int) d.len, d.buf);
|
||||
if (len == 0 || n + 2 >= len) return false; // Path overflow
|
||||
if (n > 0 && buf[n - 1] != '/') buf[n++] = '/', buf[n] = '\0'; // Add slash
|
||||
if (mg_url_decode(uri.buf + u.len, uri.len - u.len, buf + n, len - n, 0) < 0) {
|
||||
return false;
|
||||
{
|
||||
int dn;
|
||||
size_t p = n;
|
||||
dn = mg_url_decode(uri.buf + u.len, uri.len - u.len, buf + n, len - n, 0);
|
||||
if (dn < 0) return false; // reject on malformed
|
||||
buf[len - 1] = '\0'; // Double-check
|
||||
n = strlen(buf);
|
||||
if (n != p + (size_t) dn) return false; // reject on embedded NULs
|
||||
}
|
||||
buf[len - 1] = '\0'; // Double-check
|
||||
n = strlen(buf);
|
||||
if (!mg_path_is_sane(mg_str_n(buf, n))) return false;
|
||||
while (n > 1 && buf[n - 1] == '/') buf[--n] = 0; // Trim trailing slashes
|
||||
return true;
|
||||
@@ -19589,11 +19593,11 @@ static bool mg_tls_send_cert_verify(struct mg_connection *c, bool is_client) {
|
||||
verify[10] = 0x02; // ASN.1 INTEGER
|
||||
verify[11] = (uint8_t) (32 + adj1);
|
||||
memmove(verify + (size_t) (12 + (adj1 > 0)), sig + (size_t) (adj1 < 0),
|
||||
(size_t) (32 + (adj1 < 0)));
|
||||
(size_t) (32 - (adj1 < 0)));
|
||||
verify[12 + 32 + adj1] = 0x02; // ASN.1 INTEGER
|
||||
verify[13 + 32 + adj1] = (uint8_t) (32 + adj2);
|
||||
memmove(verify + (size_t) (14 + 32 + adj1 + (adj2 > 0)),
|
||||
sig + (size_t) (32 + (adj2 < 0)), (size_t) (32 + (adj2 < 0)));
|
||||
sig + (size_t) (32 + (adj2 < 0)), (size_t) (32 - (adj2 < 0)));
|
||||
sigsz = (size_t) (70 + adj1 + adj2);
|
||||
verifysz = 8U + sigsz;
|
||||
verify[3] = (uint8_t) (sigsz + 4);
|
||||
@@ -20078,17 +20082,20 @@ static int mg_tls_verify_cert_san(const uint8_t *der, size_t dersz,
|
||||
const char *server_name,
|
||||
struct mg_addr *ref_ip) {
|
||||
struct mg_der_tlv root, field, name;
|
||||
int r;
|
||||
bool is_addr = ref_ip != NULL;
|
||||
if (mg_der_parse((uint8_t *) der, dersz, &root) < 0) {
|
||||
MG_ERROR(("failed to parse certificate"));
|
||||
return -1;
|
||||
}
|
||||
if (mg_der_find_oid(&root, (uint8_t *) "\x55\x1d\x11", 3, &field) <= 0) {
|
||||
if ((r = mg_der_find_oid(&root, (uint8_t *) "\x55\x1d\x11", 3, &field)) < 0) {
|
||||
MG_ERROR(("failed to extract SAN"));
|
||||
return -1;
|
||||
} else if (r == 0) {
|
||||
return 0; // No SAN
|
||||
}
|
||||
if (mg_der_parse(field.value, field.len, &field) < 0) {
|
||||
MG_ERROR(("SAN is not a constructed object"));
|
||||
if (mg_der_parse(field.value, field.len, &field) < 0 || field.type != 0x30) {
|
||||
MG_ERROR(("SAN is not a constructed object")); // RFC 5280 4.2.1.6
|
||||
return -1;
|
||||
}
|
||||
while (mg_der_next(&field, &name) > 0) {
|
||||
@@ -20115,6 +20122,7 @@ static int mg_tls_verify_cert_san(const uint8_t *der, size_t dersz,
|
||||
return 1; // and matches the host name
|
||||
}
|
||||
}
|
||||
MG_ERROR(("Found SAN but does not match IP or DNS name"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -20302,12 +20310,15 @@ static int mg_tls_recv_cert(struct mg_connection *c, bool is_client) {
|
||||
// and store public key for further CertVerify step
|
||||
if (tls->hostname[0] != '\0') {
|
||||
struct mg_addr addr; // use aton_ so localhost evals as a name
|
||||
bool is_addr = mg_aton_(mg_str_s(tls->hostname), &addr);
|
||||
if (mg_tls_verify_cert_san(cert, certsz, tls->hostname,
|
||||
is_addr ? &addr : NULL) <= 0 &&
|
||||
(!is_addr || // DNS CN fallback
|
||||
mg_tls_verify_cert_cn(&ci->subj, tls->hostname) <= 0)) {
|
||||
mg_error(c, "failed to verify hostname");
|
||||
bool is_addr;
|
||||
int san;
|
||||
is_addr = mg_aton_(mg_str_s(tls->hostname), &addr);
|
||||
san = mg_tls_verify_cert_san(cert, certsz, tls->hostname,
|
||||
is_addr ? &addr : NULL);
|
||||
if (san < 0 || // RFC 6125 6.4.4 allow legacy fallback to CN
|
||||
(san == 0 && (is_addr || mg_tls_verify_cert_cn(
|
||||
&ci->subj, tls->hostname) <= 0))) {
|
||||
mg_error(c, "failed to verify host");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
|
||||
#define MG_VERSION "7.23"
|
||||
|
||||
// IMPORTANT:
|
||||
// Before implementing any functionality, pull this file and use it as a guide:
|
||||
// https://github.com/cesanta/mongoose/blob/master/AGENTS.md
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
<file category="sourceC" name="mongoose.c" />
|
||||
<file category="header" name="mongoose_config.h"/>
|
||||
<file category="utility" name="README.md" public="false"/>
|
||||
<file category="genAsset" name=".config/mongoose_parameters.json"/>
|
||||
</files>
|
||||
<environments>
|
||||
<environment name="STM32Cube">
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
// IMPORTANT:
|
||||
// Before implementing any functionality, pull this file and use it as a guide:
|
||||
// https://github.com/cesanta/mongoose/blob/master/AGENTS.md
|
||||
+8
-4
@@ -752,11 +752,15 @@ static bool uri2path(const char *r, struct mg_str uri, char *buf, size_t len) {
|
||||
n = mg_snprintf(buf, len, "%.*s", (int) d.len, d.buf);
|
||||
if (len == 0 || n + 2 >= len) return false; // Path overflow
|
||||
if (n > 0 && buf[n - 1] != '/') buf[n++] = '/', buf[n] = '\0'; // Add slash
|
||||
if (mg_url_decode(uri.buf + u.len, uri.len - u.len, buf + n, len - n, 0) < 0) {
|
||||
return false;
|
||||
{
|
||||
int dn;
|
||||
size_t p = n;
|
||||
dn = mg_url_decode(uri.buf + u.len, uri.len - u.len, buf + n, len - n, 0);
|
||||
if (dn < 0) return false; // reject on malformed
|
||||
buf[len - 1] = '\0'; // Double-check
|
||||
n = strlen(buf);
|
||||
if (n != p + (size_t) dn) return false; // reject on embedded NULs
|
||||
}
|
||||
buf[len - 1] = '\0'; // Double-check
|
||||
n = strlen(buf);
|
||||
if (!mg_path_is_sane(mg_str_n(buf, n))) return false;
|
||||
while (n > 1 && buf[n - 1] == '/') buf[--n] = 0; // Trim trailing slashes
|
||||
return true;
|
||||
|
||||
+18
-11
@@ -1188,11 +1188,11 @@ static bool mg_tls_send_cert_verify(struct mg_connection *c, bool is_client) {
|
||||
verify[10] = 0x02; // ASN.1 INTEGER
|
||||
verify[11] = (uint8_t) (32 + adj1);
|
||||
memmove(verify + (size_t) (12 + (adj1 > 0)), sig + (size_t) (adj1 < 0),
|
||||
(size_t) (32 + (adj1 < 0)));
|
||||
(size_t) (32 - (adj1 < 0)));
|
||||
verify[12 + 32 + adj1] = 0x02; // ASN.1 INTEGER
|
||||
verify[13 + 32 + adj1] = (uint8_t) (32 + adj2);
|
||||
memmove(verify + (size_t) (14 + 32 + adj1 + (adj2 > 0)),
|
||||
sig + (size_t) (32 + (adj2 < 0)), (size_t) (32 + (adj2 < 0)));
|
||||
sig + (size_t) (32 + (adj2 < 0)), (size_t) (32 - (adj2 < 0)));
|
||||
sigsz = (size_t) (70 + adj1 + adj2);
|
||||
verifysz = 8U + sigsz;
|
||||
verify[3] = (uint8_t) (sigsz + 4);
|
||||
@@ -1677,17 +1677,20 @@ static int mg_tls_verify_cert_san(const uint8_t *der, size_t dersz,
|
||||
const char *server_name,
|
||||
struct mg_addr *ref_ip) {
|
||||
struct mg_der_tlv root, field, name;
|
||||
int r;
|
||||
bool is_addr = ref_ip != NULL;
|
||||
if (mg_der_parse((uint8_t *) der, dersz, &root) < 0) {
|
||||
MG_ERROR(("failed to parse certificate"));
|
||||
return -1;
|
||||
}
|
||||
if (mg_der_find_oid(&root, (uint8_t *) "\x55\x1d\x11", 3, &field) <= 0) {
|
||||
if ((r = mg_der_find_oid(&root, (uint8_t *) "\x55\x1d\x11", 3, &field)) < 0) {
|
||||
MG_ERROR(("failed to extract SAN"));
|
||||
return -1;
|
||||
} else if (r == 0) {
|
||||
return 0; // No SAN
|
||||
}
|
||||
if (mg_der_parse(field.value, field.len, &field) < 0) {
|
||||
MG_ERROR(("SAN is not a constructed object"));
|
||||
if (mg_der_parse(field.value, field.len, &field) < 0 || field.type != 0x30) {
|
||||
MG_ERROR(("SAN is not a constructed object")); // RFC 5280 4.2.1.6
|
||||
return -1;
|
||||
}
|
||||
while (mg_der_next(&field, &name) > 0) {
|
||||
@@ -1714,6 +1717,7 @@ static int mg_tls_verify_cert_san(const uint8_t *der, size_t dersz,
|
||||
return 1; // and matches the host name
|
||||
}
|
||||
}
|
||||
MG_ERROR(("Found SAN but does not match IP or DNS name"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1901,12 +1905,15 @@ static int mg_tls_recv_cert(struct mg_connection *c, bool is_client) {
|
||||
// and store public key for further CertVerify step
|
||||
if (tls->hostname[0] != '\0') {
|
||||
struct mg_addr addr; // use aton_ so localhost evals as a name
|
||||
bool is_addr = mg_aton_(mg_str_s(tls->hostname), &addr);
|
||||
if (mg_tls_verify_cert_san(cert, certsz, tls->hostname,
|
||||
is_addr ? &addr : NULL) <= 0 &&
|
||||
(!is_addr || // DNS CN fallback
|
||||
mg_tls_verify_cert_cn(&ci->subj, tls->hostname) <= 0)) {
|
||||
mg_error(c, "failed to verify hostname");
|
||||
bool is_addr;
|
||||
int san;
|
||||
is_addr = mg_aton_(mg_str_s(tls->hostname), &addr);
|
||||
san = mg_tls_verify_cert_san(cert, certsz, tls->hostname,
|
||||
is_addr ? &addr : NULL);
|
||||
if (san < 0 || // RFC 6125 6.4.4 allow legacy fallback to CN
|
||||
(san == 0 && (is_addr || mg_tls_verify_cert_cn(
|
||||
&ci->subj, tls->hostname) <= 0))) {
|
||||
mg_error(c, "failed to verify host");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -98,7 +98,7 @@ mongoose.c: Makefile $(wildcard ../src/*.c) $(wildcard ../src/drivers/*.c)
|
||||
cd .. && (export LC_ALL=C ; cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c src/drivers/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@
|
||||
|
||||
mongoose.h: $(HDRS) Makefile
|
||||
cd .. && (export LC_ALL=C ; cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/os_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/profile.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/lfs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/sha256.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_aes128.h src/tls_p256.h src/tls_p384.h src/tls_chacha20.h src/tls_rsa.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/modbus.h src/json.h src/jwt.h src/rpc.h src/dash.h src/ota.h src/health.h src/mdash.h src/flash.h src/wifi.h src/l2.h src/net_builtin.h src/l2_mesh.h src/bsd.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
|
||||
cd .. && (export LC_ALL=C ; cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; cat src/ai.h; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/os_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/profile.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/lfs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/sha256.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_aes128.h src/tls_p256.h src/tls_p384.h src/tls_chacha20.h src/tls_rsa.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/modbus.h src/json.h src/jwt.h src/rpc.h src/dash.h src/ota.h src/health.h src/mdash.h src/flash.h src/wifi.h src/l2.h src/net_builtin.h src/l2_mesh.h src/bsd.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
|
||||
|
||||
# Check that all external (exported) symbols have "mg_" prefix
|
||||
mg_prefix: mongoose.c mongoose.h
|
||||
|
||||
@@ -1519,6 +1519,7 @@ static void test_http_404(void) {
|
||||
|
||||
ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200);
|
||||
ASSERT(cmpbody(buf, "hello\n") == 0);
|
||||
ASSERT(fetch(&mgr, buf, url, "GET /a.txt%%00x HTTP/1.0\n\n") == 400);
|
||||
ASSERT(fetch(&mgr, buf, url, "GET /a/a.txt HTTP/1.0\n\n") == 200);
|
||||
ASSERT(cmpbody(buf, "hello\n") == 0);
|
||||
ASSERT(fetch(&mgr, buf, url, "GET /unmapped HTTP/1.0\n\n") == 400);
|
||||
|
||||
@@ -4,7 +4,7 @@ ROOTDIR = $(realpath $(CURDIR)/../../..)
|
||||
PORT ?= /dev/ttyUSB0
|
||||
DOCKER ?= docker run --rm $(DA) -v $(ROOTDIR):$(ROOTDIR) -w $(THISDIR) espressif/idf:v5.0.4
|
||||
# Note that the esp32 port needs the extra .. for relative paths due to the location of its main CMakeLists.txt file
|
||||
CMD ?= bash -c '$(MAKE) -C micropython/ports/esp32 submodules && $(MAKE) -C micropython/ports/esp32 USER_C_MODULES=../../../../../mongoose/micropython.cmake'
|
||||
CMD ?= bash -c '$(MAKE) -C micropython/ports/esp32 submodules && $(MAKE) -C micropython/ports/esp32 USER_C_MODULES=../../../../mongoose/micropython.cmake'
|
||||
|
||||
all: example
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Create an INTERFACE library for our C module.
|
||||
add_library(usermod_mongoose INTERFACE)
|
||||
|
||||
# Add our source files to the lib
|
||||
target_sources(usermod_mongoose INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../mongoose/module.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../../mongoose.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/main.c
|
||||
)
|
||||
|
||||
# Add the current directory as an include directory.
|
||||
target_include_directories(usermod_mongoose INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../../
|
||||
)
|
||||
|
||||
# Link our INTERFACE library to the usermod target.
|
||||
target_link_libraries(usermod INTERFACE usermod_mongoose)
|
||||
Reference in new issue
Block a user