mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-26 12:14:56 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
452bcc68a4 | ||
|
|
829827d46f | ||
|
|
ff9d0e462e | ||
|
|
e84ea91a4a | ||
|
|
2dcb10ef36 | ||
|
|
99fa7f0851 | ||
|
|
1b5cc341a5 | ||
|
|
d50dc288cd | ||
|
|
060bb29cdc | ||
|
|
366426e8bb | ||
|
|
e710df4c80 | ||
|
|
79e5841483 | ||
|
|
374ab4ecf0 | ||
|
|
56980be48c | ||
|
|
602c5c0866 | ||
|
|
7ce5009de1 | ||
|
|
51e3a1304b | ||
|
|
d5a1d5a5e8 | ||
|
|
ae5f6c0920 | ||
|
|
0a9303bb07 | ||
|
|
42bc7b1f47 | ||
|
|
4844ed60bd | ||
|
|
41f5daeb47 | ||
|
|
a3f8f33d50 | ||
|
|
fd8db5c53a | ||
|
|
a2f027e798 | ||
|
|
dad5c8fe87 | ||
|
|
98783a41ba | ||
|
|
1517d2985a | ||
|
|
acc0564957 | ||
|
|
421bc126b5 | ||
|
|
ed1a98c381 | ||
|
|
457d76b049 | ||
|
|
6827972f71 | ||
|
|
7eb998891e | ||
|
|
582fde5c6e | ||
|
|
d327ee9834 | ||
|
|
31cf6f8969 | ||
|
|
86b1053678 | ||
|
|
6678e36278 | ||
|
|
5118355732 | ||
|
|
5b4b7f7dc5 | ||
|
|
7614a8101f | ||
|
|
3c851bcfc3 | ||
|
|
01691dafa0 |
No files matched your search
@@ -1,6 +1,6 @@
|
||||
SRCS = $(wildcard src/*.c)
|
||||
HDRS = $(wildcard src/*.h)
|
||||
DEFS ?= -DMG_MAX_HTTP_HEADERS=5 -DMG_ENABLE_LINES -DMG_ENABLE_HTTP_DEBUG_ENDPOINT=1 -DMG_ENABLE_DIRECTORY_LISTING=1 -DMG_ENABLE_SSI=1
|
||||
DEFS ?= -DMG_MAX_HTTP_HEADERS=5 -DMG_ENABLE_LINES -DMG_ENABLE_DIRECTORY_LISTING=1 -DMG_ENABLE_SSI=1
|
||||
CFLAGS ?= -W -Wall -Werror -Isrc -I. -O0 -g $(DEFS) $(TFLAGS) $(EXTRA)
|
||||
SSL ?= MBEDTLS
|
||||
CDIR ?= $(realpath $(CURDIR))
|
||||
|
||||
@@ -21,7 +21,10 @@ on the top 9 things to avoid when embedding a web server.
|
||||
|
||||
- [Download “9 Things NOT to do when embedding a web server” white paper here](https://www.cesanta.com/whitepaper.html)
|
||||
|
||||
Looking for a complete IoT solution? Check out
|
||||
# Looking for a pre-compiled Mongoose web server Windows or Mac binary?
|
||||
- [Download pre-compiled Mongoose web server binary](https://mongoose.ws/)
|
||||
|
||||
# Looking for a complete IoT solution? Check out
|
||||
- [VCON](https://vcon.io) - Arduino compatible MCU modules with built-in firmware OTA updates
|
||||
- [Mongoose OS](https://mongoose-os.com) - open source embedded operating system for low-power connected microcontrollers. Secure, designed for commercial Internet of Things products
|
||||
|
||||
@@ -33,11 +36,10 @@ Looking for a complete IoT solution? Check out
|
||||
|
||||
# Features
|
||||
|
||||
* Cross-platform: works on Linux/UNIX, MacOS, QNX, eCos, Windows, Android,
|
||||
iPhone, FreeRTOS, etc
|
||||
* Supported embedded architectures: ESP32, ESP8266, TI CC3200, TI MSP432, NRF52, STM32, PIC32, NXP, and more
|
||||
* Cross-platform: works on Linux/UNIX, MacOS, Windows, Android, FreeRTOS, etc
|
||||
* Supported embedded architectures: ESP32, ESP8266, TI, NRF52, STM32, PIC32, NXP, and more
|
||||
* Builtin protocols: plain TCP/UDP, HTTP, MQTT, Websocket
|
||||
* SSL/TLS support: mbedTLS, OpenSSL or custom via API
|
||||
* SSL/TLS support: mbedTLS, OpenSSL or custom (via API)
|
||||
* Asynchronous DNS resolver
|
||||
* Tiny static and run-time footprint
|
||||
* Source code is both ISO C and ISO C++ compliant
|
||||
@@ -70,5 +72,4 @@ Contributions are welcome! Please follow the guidelines below:
|
||||
- When making pull requests, please make sure that it has only one commit,
|
||||
and imlements/fixes only one piece of functionality
|
||||
|
||||
# Looking for a pre-compiled Mongoose web server Windows or Mac binary?
|
||||
- [Download pre-compiled Mongoose web server binary.](https://www.cesanta.com/binary.html)
|
||||
|
||||
+69
-20
@@ -159,10 +159,10 @@ enum {
|
||||
they can be either 0 or 1. Some flags are set by Mongoose and must be not
|
||||
changed by an application code, for example `is_udp` flag tells application if
|
||||
that connection is UDP or not. Some flags can be changed by application, for
|
||||
example, `is_drainig` flag, if set by an application, tells Mongoose to send
|
||||
example, `is_draining` flag, if set by an application, tells Mongoose to send
|
||||
the remaining data to peer, and when everything is sent, close the connection.
|
||||
|
||||
User-changeable flags are: `is_hexdumping`, `is_drainig`, `is_closing`.
|
||||
User-changeable flags are: `is_hexdumping`, `is_draining`, `is_closing`.
|
||||
|
||||
This is taken from `mongoose.h` as-is:
|
||||
|
||||
@@ -223,7 +223,6 @@ Here is a list of build constants and their default values:
|
||||
|`MG_ENABLE_LOG` | 1 | Enable `LOG()` macro |
|
||||
|`MG_ENABLE_MD5` | 0 | Use native MD5 implementation |
|
||||
|`MG_ENABLE_DIRECTORY_LISTING` | 0 | Enable directory listing for HTTP server |
|
||||
|`MG_ENABLE_HTTP_DEBUG_ENDPOINT` | 0 | Enable `/debug/info` debug URI |
|
||||
|`MG_ENABLE_SOCKETPAIR` | 0 | Enable `mg_socketpair()` for multi-threading |
|
||||
|`MG_ENABLE_SSI` | 0 | Enable serving SSI files by `mg_http_serve_dir()` |
|
||||
|`MG_IO_SIZE` | 512 | Granularity of the send/recv IO buffer growth |
|
||||
@@ -528,21 +527,23 @@ by `buf`, and `len` specifies number of bytes currently stored.
|
||||
### mg\_iobuf\_init()
|
||||
|
||||
```c
|
||||
void mg_iobuf_init(struct mg_iobuf *io, size_t size);
|
||||
int mg_iobuf_init(struct mg_iobuf *io, size_t size);
|
||||
```
|
||||
|
||||
Initialise IO buffer, allocate `size` bytes.
|
||||
Initialise IO buffer, allocate `size` bytes. Return 1 on success,
|
||||
0 on allocation failure.
|
||||
|
||||
|
||||
### mg\_iobuf\_resize()
|
||||
|
||||
```c
|
||||
void mg_iobuf_resize(struct mg_iobuf *io, size_t size);
|
||||
int mg_iobuf_resize(struct mg_iobuf *io, size_t size);
|
||||
```
|
||||
|
||||
Resize IO buffer, set the new size to `size`. The `io->buf` pointer could
|
||||
change after this, for example if the buffer grows. If `size` is 0, then the
|
||||
`io->buf` is freed and set to NULL, and both `size` and `len` are set to 0.
|
||||
Return 1 on success, 0 on allocation failure.
|
||||
|
||||
|
||||
### mg\_iobuf\_free()
|
||||
@@ -947,10 +948,45 @@ void mg_mqtt_sub(struct mg_connection *, struct mg_str *topic);
|
||||
|
||||
Subscribe to topic `topic`.
|
||||
|
||||
### mg\_mqtt\_next\_sub()
|
||||
|
||||
```c
|
||||
int mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic,
|
||||
uint8_t *qos, int pos);
|
||||
```
|
||||
|
||||
Traverse list of subscribed topics.
|
||||
Used to implement MQTT server when `MQTT_CMD_SUBSCRIBE` is received.
|
||||
Return next position. Initial position `pos` should be 4. Example:
|
||||
|
||||
```c
|
||||
if (ev == MG_EV_MQTT_CMD) {
|
||||
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
|
||||
if (mm->cmd == MQTT_CMD_SUBSCRIBE) {
|
||||
int pos = 4;
|
||||
uint8_t qos;
|
||||
struct mg_str topic;
|
||||
while ((pos = mg_mqtt_next_sub(mm, &topic, &qos, pos)) > 0) {
|
||||
LOG(LL_INFO, ("SUB [%.*s]", c->id, (int) topic.len, topic.ptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### mg\_mqtt\_next\_unsub()
|
||||
|
||||
```c
|
||||
int mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic,
|
||||
int pos);
|
||||
```
|
||||
|
||||
Same as `mg_mqtt_next_sub()`, but for unsubscribed topics. The difference
|
||||
is that there is no QoS in unsubscribe request.
|
||||
|
||||
|
||||
## TLS
|
||||
|
||||
### struct mg\_tls\_opts
|
||||
### mg\_tls\_init()
|
||||
|
||||
```c
|
||||
struct mg_tls_opts {
|
||||
@@ -958,20 +994,12 @@ struct mg_tls_opts {
|
||||
const char *cert; // Certificate
|
||||
const char *certkey; // Certificate key
|
||||
const char *ciphers; // Cipher list
|
||||
const char *srvname; // If not NULL, enables server name verification
|
||||
struct mg_str srvname; // If not empty, enables server name verification
|
||||
};
|
||||
```
|
||||
|
||||
Describes TLS parameters
|
||||
|
||||
|
||||
### mg\_tls\_init()
|
||||
|
||||
```c
|
||||
int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts);
|
||||
```
|
||||
|
||||
Turns on TLS on a given connection.
|
||||
Initialise TLS on a given connection.
|
||||
|
||||
|
||||
## Timers
|
||||
@@ -1049,14 +1077,26 @@ size_t mg_file_size(const char *path);
|
||||
|
||||
Return file size, or 0 on failure. Empty files also report 0 length.
|
||||
|
||||
|
||||
### mg\_file\_write()
|
||||
|
||||
```c
|
||||
int mg_file_write(const char *path, const char *fmt, ...);
|
||||
bool mg_file_write(const char *path, const void *buf, size_t len);
|
||||
```
|
||||
|
||||
Write into a file `path` using `printf()` semantics. Return number of bytes written.
|
||||
Write data to a file, return `true` if written, `false` otherwise.
|
||||
The write is atomic, i.e. data gets written to a temporary file first,
|
||||
then `rename()-ed` to a destination file name.
|
||||
|
||||
|
||||
### mg\_file\_printf()
|
||||
|
||||
```c
|
||||
int mg_file_printf(const char *path, const char *fmt, ...);
|
||||
```
|
||||
|
||||
Write into a file `path` using `printf()` semantics.
|
||||
Return `true` on success, `false` otherwise. This function prints data to
|
||||
a temporary in-memory buffer first, then calls `mg_file_write()`.
|
||||
|
||||
|
||||
### mg\_random()
|
||||
@@ -1235,3 +1275,12 @@ void mg_usleep(unsigned long usecs);
|
||||
```
|
||||
|
||||
Block for a given number of microseconds.
|
||||
|
||||
### mg\_crc32()
|
||||
|
||||
```c
|
||||
uint32_t mg_crc32(uint32_t crc, const uint8_t *buf, size_t len);
|
||||
```
|
||||
|
||||
Calculate CRC32 checksum for a given buffer. An initial `crc` value should
|
||||
be `0`.
|
||||
@@ -9,7 +9,7 @@ example: main/main.c Makefile
|
||||
COMPORT ?= /dev/cu.SLAB_USBtoUART
|
||||
ESPTOOL ?= esptool.py
|
||||
flash:
|
||||
cd build && $(ESPTOOL) --chip esp32 -p $(COMPORT) -b 460800 --before=default_reset --after=hard_reset write_flash --flash_mode dio --flash_freq 40m --flash_size 2MB 0x8000 partition_table/partition-table.bin 0x1000 bootloader/bootloader.bin 0x10000 mongoose-esp32-example.bin
|
||||
cd build && $(ESPTOOL) --chip esp32 -p $(COMPORT) -b 460800 --before=default_reset --after=hard_reset write_flash --flash_mode dio --flash_freq 40m --flash_size 2MB 0x8000 partition_table/partition-table.bin 0x1000 bootloader/bootloader.bin 0x100000 mongoose-esp32-example.bin
|
||||
|
||||
clean:
|
||||
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb mongoose mongoose_* mongoose.* build sdkconfig
|
||||
@@ -2,3 +2,4 @@ idf_component_register(SRCS "main.c"
|
||||
"wifi.c"
|
||||
"../../../mongoose.c"
|
||||
INCLUDE_DIRS "../../..")
|
||||
component_compile_options(-DMG_ENABLE_DIRECTORY_LISTING=1 -DMG_ENABLE_LINES)
|
||||
+31
-32
@@ -1,54 +1,53 @@
|
||||
// Copyright (c) 2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#include "esp_spiffs.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "mongoose.h"
|
||||
|
||||
#define WIFI_SSID "WIFI_NETWORK" // SET THIS!
|
||||
#define WIFI_PASS "WIFI_PASSWORD" // SET THIS!
|
||||
#define FS_ROOT "/spiffs"
|
||||
|
||||
#define SERVER_URL "http://0.0.0.0:80"
|
||||
#define CLIENT_URL "http://info.cern.ch"
|
||||
|
||||
// Event handler for an server (accepted) connection
|
||||
// Event handler for an server (accepted) connection. Implemented endpoints:
|
||||
// /api/stats - return JSON object with ESP32 stats (free RAM)
|
||||
// any other - serve files from the filesystem
|
||||
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
mg_http_reply(c, 200, "", "Hello from ESP!\n");
|
||||
struct mg_http_message *hm = ev_data;
|
||||
if (mg_http_match_uri(hm, "/api/stats")) {
|
||||
mg_http_reply(c, 200, "", "{\"ram\": %lu}\n", xPortGetFreeHeapSize());
|
||||
} else {
|
||||
struct mg_http_serve_opts opts = {.root_dir = FS_ROOT};
|
||||
mg_http_serve_dir(c, hm, &opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Event handler for a client connection - fetch the first web page in history
|
||||
// To enable TLS for HTTP,
|
||||
// 1. Copy "ca.pem" file to the ESP32 flash FS
|
||||
// 2. Add TLS init snippet for the connection, see examples/http-client
|
||||
static void cb2(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_CONNECT) {
|
||||
struct mg_str s = mg_url_host(CLIENT_URL);
|
||||
mg_printf(c, "GET / HTTP/1.0\r\nHost: %.*s\r\n\r\n", (int) s.len, s.ptr);
|
||||
} else if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = ev_data; // Print HTTP response
|
||||
LOG(LL_INFO, ("Fetched:\n%.*s", (int) hm->message.len, hm->message.ptr));
|
||||
c->is_closing = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Called after we're connected to WiFi network
|
||||
static void run_mongoose(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_log_set("3");
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, SERVER_URL, cb, &mgr); // Listening server
|
||||
mg_http_connect(&mgr, CLIENT_URL, cb2, &mgr); // Example client
|
||||
LOG(LL_INFO, ("Starting Mongoose web server v%s", MG_VERSION));
|
||||
for (;;) mg_mgr_poll(&mgr, 1000);
|
||||
mg_mgr_free(&mgr);
|
||||
// SPIFFS is flat, so tell Mongoose that the FS root is a directory
|
||||
// This cludge is not required for filesystems with directory support
|
||||
bool mg_is_dir(const char *path) {
|
||||
return strcmp(path, FS_ROOT) == 0;
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
// Mount filesystem
|
||||
esp_vfs_spiffs_conf_t conf = {
|
||||
.base_path = FS_ROOT, .max_files = 20, .format_if_mount_failed = true};
|
||||
int res = esp_vfs_spiffs_register(&conf);
|
||||
LOG(res == ESP_OK ? LL_INFO : LL_ERROR, ("FS %s, %d", conf.base_path, res));
|
||||
mg_file_printf(FS_ROOT "/hello.txt", "%s", "hello from ESP");
|
||||
|
||||
// Setup wifi. This function is implemented in wifi.c
|
||||
// It blocks until connected to the configured WiFi network
|
||||
void wifi_init(const char *ssid, const char *pass);
|
||||
wifi_init(WIFI_SSID, WIFI_PASS);
|
||||
|
||||
// Done connecting to WiFi, now start HTTP server
|
||||
run_mongoose();
|
||||
// Connected to WiFi, now start HTTP server
|
||||
struct mg_mgr mgr;
|
||||
mg_log_set("3");
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0:80", cb, &mgr); // Listening server
|
||||
LOG(LL_INFO, ("Starting Mongoose web server v%s", MG_VERSION));
|
||||
for (;;) mg_mgr_poll(&mgr, 1000); // Infinite event loop
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
storage, data, spiffs, 0x10000, 0x10000,
|
||||
factory, app, factory, 0x100000, 1M,
|
||||
|
@@ -0,0 +1,3 @@
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
@@ -1,11 +1,14 @@
|
||||
PROG ?= example
|
||||
CFLAGS ?= -DMG_ENABLE_LINES $(CFLAGS_EXTRA)
|
||||
MBEDTLS_DIR ?=
|
||||
CFLAGS ?= -DMG_ENABLE_LINES $(EXTRA)
|
||||
|
||||
ifeq "$(MBEDTLS_DIR)" ""
|
||||
else
|
||||
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS_DIR)/include -I/usr/include
|
||||
CFLAGS += -L$(MBEDTLS_DIR)/lib -lmbedtls -lmbedcrypto -lmbedx509
|
||||
ifneq ($(MBEDTLS),)
|
||||
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS)/include -I/usr/include
|
||||
CFLAGS += -L$(MBEDTLS)/lib -lmbedtls -lmbedcrypto -lmbedx509
|
||||
endif
|
||||
|
||||
ifneq ($(OPENSSL),)
|
||||
CFLAGS += -DMG_ENABLE_OPENSSL=1 -I$(OPENSSL)/include
|
||||
CFLAGS += -L$(OPENSSL)/lib -lssl -lcrypto
|
||||
endif
|
||||
|
||||
all: $(PROG)
|
||||
|
||||
@@ -1,43 +1,52 @@
|
||||
// Copyright (c) 2020 Cesanta Software Limited
|
||||
// Copyright (c) 2021 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// Example HTTP client. Connect to `s_url`, send request, wait for a response,
|
||||
// print the response and exit.
|
||||
// You can change `s_url` from the command line by executing: ./example YOUR_URL
|
||||
//
|
||||
// To enable SSL/TLS for this client, build it like this:
|
||||
// make MBEDTLS_DIR=/path/to/your/mbedtls/installation
|
||||
// make MBEDTLS=/path/to/your/mbedtls/installation
|
||||
// make OPENSSL=/path/to/your/openssl/installation
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
// The very first web page in history
|
||||
// The very first web page in history. You can replace it from command line
|
||||
static const char *s_url = "http://info.cern.ch";
|
||||
|
||||
// Print HTTP response and signal that we're done
|
||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_CONNECT) {
|
||||
// Connected to server
|
||||
// Connected to server. Extract host name from URL
|
||||
struct mg_str host = mg_url_host(s_url);
|
||||
|
||||
// If s_url is https://, tell client connection to use TLS
|
||||
if (mg_url_is_ssl(s_url)) {
|
||||
// If s_url is https://, tell client connection to use TLS
|
||||
struct mg_tls_opts opts = {.ca = "ca.pem"};
|
||||
struct mg_tls_opts opts = {.ca = "ca.pem", .srvname = host};
|
||||
mg_tls_init(c, &opts);
|
||||
}
|
||||
|
||||
// Send request
|
||||
mg_printf(c, "GET %s HTTP/1.0\r\nHost: %.*s\r\n\r\n", mg_url_uri(s_url),
|
||||
(int) host.len, host.ptr);
|
||||
mg_printf(c,
|
||||
"GET %s HTTP/1.0\r\n"
|
||||
"Host: %.*s\r\n"
|
||||
"\r\n",
|
||||
mg_url_uri(s_url), (int) host.len, host.ptr);
|
||||
} else if (ev == MG_EV_HTTP_MSG) {
|
||||
// Response is received. Print it
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
printf("%.*s", (int) hm->message.len, hm->message.ptr);
|
||||
c->is_closing = 1; // Tell mongoose to close this connection
|
||||
*(bool *) fn_data = true; // Tell event loop to stop
|
||||
} else if (ev == MG_EV_ERROR) {
|
||||
*(bool *) fn_data = true; // Error, tell event loop to stop
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int main(int argc, char *argv[]) {
|
||||
struct mg_mgr mgr; // Event manager
|
||||
bool done = false; // Event handler flips it to true
|
||||
if (argc > 1) s_url = argv[1]; // Use URL from command line
|
||||
mg_log_set("3"); // Set to 0 to disable debug
|
||||
mg_mgr_init(&mgr); // Initialise event manager
|
||||
mg_http_connect(&mgr, s_url, fn, &done); // Create client connection
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
static const char *s_listen_on = "https://localhost:8000";
|
||||
static const char *s_listen_on = "http://0.0.0.0:8000";
|
||||
static const char *s_web_directory = ".";
|
||||
|
||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
|
||||
@@ -64,7 +64,7 @@ int main(int argc, char *argv[]) {
|
||||
if (mg_casecmp(s_enable_hexdump, "yes") == 0) c->is_hexdumping = 1;
|
||||
|
||||
// Start infinite event loop
|
||||
LOG(LL_INFO, ("Starting Mongoose web server v%s", MG_VERSION));
|
||||
LOG(LL_INFO, ("Starting Mongoose v%s, serving [%s]", MG_VERSION, s_root_dir));
|
||||
for (;;) mg_mgr_poll(&mgr, 1000);
|
||||
mg_mgr_free(&mgr);
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
PROG ?= example
|
||||
CFLAGS ?= -DMG_ENABLE_LINES $(EXTRA)
|
||||
|
||||
ifneq ($(MBEDTLS),)
|
||||
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS)/include -I/usr/include
|
||||
CFLAGS += -L$(MBEDTLS)/lib -lmbedtls -lmbedcrypto -lmbedx509
|
||||
endif
|
||||
|
||||
ifneq ($(OPENSSL),)
|
||||
CFLAGS += -DMG_ENABLE_OPENSSL=1 -I$(OPENSSL)/include
|
||||
CFLAGS += -L$(OPENSSL)/lib -lssl -lcrypto
|
||||
endif
|
||||
|
||||
all: $(PROG)
|
||||
$(DEBUGGER) ./$(PROG) $(ARGS)
|
||||
|
||||
|
||||
$(PROG): main.c
|
||||
$(CC) ../../mongoose.c -I../.. -W -Wall $(CFLAGS) -o $(PROG) main.c
|
||||
|
||||
clean:
|
||||
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb
|
||||
@@ -0,0 +1,507 @@
|
||||
Subject: O=Digital Signature Trust Co., CN=DST Root CA X3
|
||||
Not Before: Sep 30 21:12:19 2000 GMT
|
||||
Not After : Sep 30 14:01:15 2021 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
|
||||
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
||||
DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
|
||||
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
|
||||
Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
|
||||
rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
|
||||
OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
|
||||
xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
|
||||
7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
|
||||
aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
|
||||
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
|
||||
SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
|
||||
ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
|
||||
AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
|
||||
R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
|
||||
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
|
||||
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Subject: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root
|
||||
Not Before: May 12 18:46:00 2000 GMT
|
||||
Not After : May 12 23:59:00 2025 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
|
||||
RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
|
||||
VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
|
||||
DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
|
||||
ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
|
||||
VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
|
||||
mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
|
||||
IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
|
||||
mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
|
||||
XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
|
||||
dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
|
||||
jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
|
||||
BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
|
||||
DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
|
||||
9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
|
||||
jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
|
||||
Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
|
||||
ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
|
||||
R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA
|
||||
Not Before: May 21 04:00:00 2002 GMT
|
||||
Not After : May 21 04:00:00 2022 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
|
||||
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
|
||||
YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
|
||||
EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
|
||||
R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
|
||||
9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
|
||||
fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
|
||||
iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
|
||||
1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
|
||||
bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
|
||||
MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
|
||||
ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
|
||||
uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
|
||||
Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
|
||||
tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
|
||||
PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
|
||||
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
|
||||
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Subject: C=US, O=Symantec Corporation, OU=Symantec Trust Network, CN=Symantec Class 3 ECC 256 bit SSL CA - G2
|
||||
Not Before: May 12 00:00:00 2015 GMT
|
||||
Not After : May 11 23:59:59 2025 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEajCCA1KgAwIBAgIQP5KHvp0dpKN6nfYoLndaxDANBgkqhkiG9w0BAQsFADCB
|
||||
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
|
||||
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
|
||||
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
|
||||
aG9yaXR5IC0gRzUwHhcNMTUwNTEyMDAwMDAwWhcNMjUwNTExMjM1OTU5WjCBgDEL
|
||||
MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD
|
||||
VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMTEwLwYDVQQDEyhTeW1hbnRlYyBD
|
||||
bGFzcyAzIEVDQyAyNTYgYml0IFNTTCBDQSAtIEcyMFkwEwYHKoZIzj0CAQYIKoZI
|
||||
zj0DAQcDQgAEDxukkdfnrOfRTk63ZFvhj39uBNOrONtEt0Bcbb2WljffeYmGZ/ex
|
||||
Hwie/WM7RoyfvVPoFdyXPiuBRq2Gfw4BOaOCAV0wggFZMC4GCCsGAQUFBwEBBCIw
|
||||
IDAeBggrBgEFBQcwAYYSaHR0cDovL3Muc3ltY2QuY29tMBIGA1UdEwEB/wQIMAYB
|
||||
Af8CAQAwZQYDVR0gBF4wXDBaBgpghkgBhvhFAQc2MEwwIwYIKwYBBQUHAgEWF2h0
|
||||
dHBzOi8vZC5zeW1jYi5jb20vY3BzMCUGCCsGAQUFBwICMBkaF2h0dHBzOi8vZC5z
|
||||
eW1jYi5jb20vcnBhMC8GA1UdHwQoMCYwJKAioCCGHmh0dHA6Ly9zLnN5bWNiLmNv
|
||||
bS9wY2EzLWc1LmNybDAOBgNVHQ8BAf8EBAMCAQYwKwYDVR0RBCQwIqQgMB4xHDAa
|
||||
BgNVBAMTE1NZTUMtRUNDLUNBLXAyNTYtMjIwHQYDVR0OBBYEFCXwiuFLetkBlQrt
|
||||
xlPxjHgf2fP4MB8GA1UdIwQYMBaAFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG
|
||||
SIb3DQEBCwUAA4IBAQAMMGUXBaWTdaLxsTGtcB/naqjIQrLvoV9NG+7MoHpGd/69
|
||||
dZ/h2zOy7sGFUHoG/0HGRA9rxT/5w5GkEVIVkxtWyIWWq6rs4CTZt8Bej/KHYRbo
|
||||
jtEDUkCTZSTLiCvguPyvinXgxy+LHT+PmdtEfXsvcdbeBSWUYpOsDYvD2hNtz9dw
|
||||
Od5nBosMApmdxt+z7LQyZu8wMnfI1U6IMO+RWowxZ8uy0oswdFYd32l9xe+aAE/k
|
||||
y9alLu/M9pvxiUKufqHJRgDBKA6uDjHLMPX+/nxXaNCPX3SI4KVZ1stHQ/U5oNlM
|
||||
dHN9umAvlU313g0IgJrjsQ2nIdf9dsdP+6lrmP7s
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5
|
||||
Not Before: Nov 8 00:00:00 2006 GMT
|
||||
Not After : Jul 16 23:59:59 2036 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
|
||||
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
|
||||
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
|
||||
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
|
||||
aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
|
||||
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
|
||||
ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
|
||||
biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
|
||||
U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
|
||||
aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
|
||||
nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
|
||||
t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
|
||||
SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
|
||||
BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
|
||||
rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
|
||||
NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
|
||||
BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
|
||||
BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
|
||||
aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
|
||||
MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
|
||||
p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
|
||||
5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
|
||||
WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
|
||||
4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
|
||||
hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Subject: C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority
|
||||
Not Before: Jun 29 17:06:20 2004 GMT
|
||||
Not After : Jun 29 17:06:20 2034 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
|
||||
MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
|
||||
YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
|
||||
MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
|
||||
ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
|
||||
MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
|
||||
ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
|
||||
PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
|
||||
wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
|
||||
EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
|
||||
avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
|
||||
YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
|
||||
sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
|
||||
/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
|
||||
IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
|
||||
YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
|
||||
ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
|
||||
OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
|
||||
TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
|
||||
HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
|
||||
dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
|
||||
ReYNnyicsbkqWletNw+vHX/bvZ8=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Note: Amazon ATS endpoint uses this (2018/12/18)
|
||||
Subject: C=US, O=Starfield Technologies, Inc., OU=Starfield Class 2 Certification Authority
|
||||
Not Before: Jun 29 17:39:16 2004 GMT
|
||||
Not After : Jun 29 17:39:16 2034 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
|
||||
MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
|
||||
U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
|
||||
NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
|
||||
ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
|
||||
ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
|
||||
8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
|
||||
+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
|
||||
X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
|
||||
K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
|
||||
1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
|
||||
A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
|
||||
zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
|
||||
YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
|
||||
bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
|
||||
DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
|
||||
L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
|
||||
eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
|
||||
xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
|
||||
VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
|
||||
WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Not Before: Sep 1 00:00:00 2009 GMT
|
||||
Not After : Dec 31 23:59:59 2037 GMT
|
||||
Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Root Certificate Authority - G2
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx
|
||||
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
|
||||
HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs
|
||||
ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw
|
||||
MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
|
||||
b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj
|
||||
aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp
|
||||
Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||
ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg
|
||||
nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1
|
||||
HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N
|
||||
Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN
|
||||
dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0
|
||||
HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
|
||||
BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G
|
||||
CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU
|
||||
sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3
|
||||
4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg
|
||||
8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
|
||||
pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1
|
||||
mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Services Root Certificate Authority - G2
|
||||
Not Before: Sep 1 00:00:00 2009 GMT
|
||||
Not After : Dec 31 23:59:59 2037 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
|
||||
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
|
||||
HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs
|
||||
ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
|
||||
MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD
|
||||
VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy
|
||||
ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy
|
||||
dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
|
||||
hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p
|
||||
OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2
|
||||
8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K
|
||||
Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe
|
||||
hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk
|
||||
6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw
|
||||
DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q
|
||||
AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI
|
||||
bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB
|
||||
ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z
|
||||
qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
|
||||
iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn
|
||||
0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN
|
||||
sSi6
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Subject: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign
|
||||
Not Before: Dec 15 08:00:00 2006 GMT
|
||||
Not After : Dec 15 08:00:00 2021 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
|
||||
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
|
||||
Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
|
||||
MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
|
||||
A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
|
||||
hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
|
||||
v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
|
||||
eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
|
||||
tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
|
||||
C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
|
||||
zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
|
||||
mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
|
||||
V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
|
||||
bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
|
||||
3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
|
||||
J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
|
||||
291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
|
||||
ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
|
||||
AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
|
||||
TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA
|
||||
Not Before: Nov 10 00:00:00 2006 GMT
|
||||
Not After : Nov 10 00:00:00 2031 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||
ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
|
||||
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
||||
LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
|
||||
RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
|
||||
+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
|
||||
PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
|
||||
xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
|
||||
Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
|
||||
hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
|
||||
EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
|
||||
MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
|
||||
FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
|
||||
nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
|
||||
eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
|
||||
hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
|
||||
Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
|
||||
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
|
||||
+OkuE6N36B9K
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA
|
||||
Not Before: Nov 10 00:00:00 2006 GMT
|
||||
Not After : Nov 10 00:00:00 2031 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# *.azure-devices.de use this root.
|
||||
Subject: C = DE, O = D-Trust GmbH, CN = D-TRUST Root Class 3 CA 2 2009
|
||||
Not Before: Nov 5 08:35:58 2009 GMT
|
||||
Not After : Nov 5 08:35:58 2029 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF
|
||||
MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD
|
||||
bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha
|
||||
ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM
|
||||
HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB
|
||||
BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03
|
||||
UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42
|
||||
tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R
|
||||
ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM
|
||||
lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp
|
||||
/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G
|
||||
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G
|
||||
A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj
|
||||
dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy
|
||||
MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl
|
||||
cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js
|
||||
L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL
|
||||
BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni
|
||||
acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
|
||||
o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K
|
||||
zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8
|
||||
PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y
|
||||
Johw1+qRzT65ysCQblrGXnRl11z+o+I=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# https://www.amazontrust.com/repository/
|
||||
Subject: C = US, O = Amazon, CN = Amazon Root CA 1
|
||||
Not Before: May 26 00:00:00 2015 GMT
|
||||
Not After : Jan 17 00:00:00 2038 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
|
||||
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
|
||||
b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
|
||||
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
|
||||
b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
|
||||
ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
|
||||
9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
|
||||
IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
|
||||
VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
|
||||
93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
|
||||
jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
|
||||
AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
|
||||
A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
|
||||
U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
|
||||
N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
|
||||
o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
|
||||
5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
|
||||
rqXRfboQnoZsG4q5WTP468SQvvG5
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Subject: C = US, O = Amazon, CN = Amazon Root CA 2
|
||||
Not Before: May 26 00:00:00 2015 GMT
|
||||
Not After : May 26 00:00:00 2040 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF
|
||||
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
|
||||
b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL
|
||||
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
|
||||
b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK
|
||||
gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ
|
||||
W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg
|
||||
1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K
|
||||
8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r
|
||||
2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me
|
||||
z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR
|
||||
8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj
|
||||
mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz
|
||||
7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6
|
||||
+XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI
|
||||
0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB
|
||||
Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm
|
||||
UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2
|
||||
LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY
|
||||
+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS
|
||||
k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl
|
||||
7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm
|
||||
btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl
|
||||
urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+
|
||||
fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63
|
||||
n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE
|
||||
76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H
|
||||
9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT
|
||||
4PsJYGw=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Not Before: May 26 00:00:00 2015 GMT
|
||||
Not After : May 26 00:00:00 2040 GMT
|
||||
Subject: C = US, O = Amazon, CN = Amazon Root CA 3
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5
|
||||
MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
|
||||
Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
|
||||
A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
|
||||
Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl
|
||||
ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j
|
||||
QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr
|
||||
ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr
|
||||
BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM
|
||||
YyRIHN8wfdVoOw==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Not Before: May 26 00:00:00 2015 GMT
|
||||
Not After : May 26 00:00:00 2040 GMT
|
||||
Subject: C = US, O = Amazon, CN = Amazon Root CA 4
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5
|
||||
MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
|
||||
Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
|
||||
A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
|
||||
Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi
|
||||
9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk
|
||||
M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB
|
||||
/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB
|
||||
MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw
|
||||
CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW
|
||||
1KyLa2tJElMzrdfkviT8tQp21KW8EA==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Not Before: Nov 10 00:00:00 2006 GMT
|
||||
Not After : Nov 10 00:00:00 2031 GMT
|
||||
Subject: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Not Before: Nov 13 00:00:00 2012 GMT
|
||||
Not After : Jan 19 03:14:07 2038 GMT
|
||||
Subject: OU = GlobalSign ECC Root CA - R4, O = GlobalSign, CN = GlobalSign
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk
|
||||
MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH
|
||||
bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
|
||||
DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
|
||||
QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
|
||||
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ
|
||||
FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw
|
||||
DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F
|
||||
uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX
|
||||
kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs
|
||||
ewv4n4Q=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Not Before: Nov 1 00:00:42 2018 GMT
|
||||
Not After : Nov 1 00:00:42 2042 GMT
|
||||
Subject: C = US, O = Google Trust Services LLC, CN = GTS LTSR
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBxTCCAWugAwIBAgINAfD3nVndblD3QnNxUDAKBggqhkjOPQQDAjBEMQswCQYD
|
||||
VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzERMA8G
|
||||
A1UEAxMIR1RTIExUU1IwHhcNMTgxMTAxMDAwMDQyWhcNNDIxMTAxMDAwMDQyWjBE
|
||||
MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
|
||||
QzERMA8GA1UEAxMIR1RTIExUU1IwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATN
|
||||
8YyO2u+yCQoZdwAkUNv5c3dokfULfrA6QJgFV2XMuENtQZIG5HUOS6jFn8f0ySlV
|
||||
eORCxqFyjDJyRn86d+Iko0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUw
|
||||
AwEB/zAdBgNVHQ4EFgQUPv7/zFLrvzQ+PfNA0OQlsV+4u1IwCgYIKoZIzj0EAwID
|
||||
SAAwRQIhAPKuf/VtBHqGw3TUwUIq7TfaExp3bH7bjCBmVXJupT9FAiBr0SmCtsuk
|
||||
miGgpajjf/gFigGM34F9021bCWs1MbL0SA==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2021 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// Example HTTP client.
|
||||
// Instead of buffering the whole HTTP response in memory and wait for the
|
||||
// MG_EV_HTTP_MSG event, this client catches MG_EV_HTTP_CHUNK events and
|
||||
// prints them. This is useful to download large content without spooling
|
||||
// everything to memory, or catch chunked content.
|
||||
//
|
||||
// You can change `s_url` from the command line by executing: ./example YOUR_URL
|
||||
//
|
||||
// To enable SSL/TLS for this client, build it like this:
|
||||
// make MBEDTLS=/path/to/your/mbedtls/installation
|
||||
// make OPENSSL=/path/to/your/openssl/installation
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
// The very first web page in history. You can replace it from command line
|
||||
static const char *s_url = "http://info.cern.ch";
|
||||
|
||||
// Print HTTP response and signal that we're done
|
||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_CONNECT) {
|
||||
// Connected to server. Extract host name from URL
|
||||
struct mg_str host = mg_url_host(s_url);
|
||||
|
||||
// If s_url is https://, tell client connection to use TLS
|
||||
if (mg_url_is_ssl(s_url)) {
|
||||
struct mg_tls_opts opts = {.ca = "ca.pem", .srvname = host};
|
||||
mg_tls_init(c, &opts);
|
||||
}
|
||||
|
||||
// Send request
|
||||
mg_printf(c,
|
||||
"GET %s HTTP/1.0\r\n"
|
||||
"Host: %.*s\r\n"
|
||||
"\r\n",
|
||||
mg_url_uri(s_url), (int) host.len, host.ptr);
|
||||
} else if (ev == MG_EV_HTTP_CHUNK) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
LOG(LL_INFO, ("%.*s", (int) hm->chunk.len, hm->chunk.ptr));
|
||||
mg_http_delete_chunk(c, hm);
|
||||
if (hm->chunk.len == 0) *(bool *) fn_data = true; // Last chunk
|
||||
} else if (ev == MG_EV_HTTP_MSG) {
|
||||
// Response is received. Print it
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
LOG(LL_INFO, ("%.*s", (int) hm->body.len, hm->body.ptr));
|
||||
c->is_closing = 1; // Tell mongoose to close this connection
|
||||
*(bool *) fn_data = true; // Tell event loop to stop
|
||||
} else if (ev == MG_EV_ERROR) {
|
||||
*(bool *) fn_data = true; // Error, tell event loop to stop
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct mg_mgr mgr; // Event manager
|
||||
bool done = false; // Event handler flips it to true
|
||||
if (argc > 1) s_url = argv[1]; // Use URL from command line
|
||||
mg_log_set("3"); // Set to 0 to disable debug
|
||||
mg_mgr_init(&mgr); // Initialise event manager
|
||||
mg_http_connect(&mgr, s_url, fn, &done); // Create client connection
|
||||
while (!done) mg_mgr_poll(&mgr, 1000); // Infinite event loop
|
||||
mg_mgr_free(&mgr); // Free resources
|
||||
return 0;
|
||||
}
|
||||
+408
-211
File diff suppressed because it is too large.
Load diff
+70
-48
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) 2004-2013 Sergey Lyubka
|
||||
// Copyright (c) 2013-2020 Cesanta Software Limited
|
||||
// Copyright (c) 2013-2021 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// This software is dual-licensed: you can redistribute it and/or modify
|
||||
@@ -14,9 +14,8 @@
|
||||
//
|
||||
// Alternatively, you can license this software under a commercial
|
||||
// license, as set out in <https://www.cesanta.com/license>.
|
||||
|
||||
#pragma once
|
||||
#define MG_VERSION "7.1"
|
||||
#define MG_VERSION "7.2"
|
||||
|
||||
|
||||
#define MG_ARCH_CUSTOM 0
|
||||
@@ -120,7 +119,12 @@
|
||||
|
||||
#include <dirent.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/stat.h>
|
||||
#define MG_DIRSEP '/'
|
||||
#define MG_INT64_FMT "%lld"
|
||||
#ifndef MG_PATH_MAX
|
||||
#define MG_PATH_MAX 128
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -133,6 +137,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <sys/time.h>
|
||||
#define MG_DIRSEP '/'
|
||||
#define MG_INT64_FMT "%lld"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -146,6 +151,7 @@
|
||||
#include <FreeRTOS_Sockets.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define MG_INT64_FMT "%lld"
|
||||
#define MG_DIRSEP '/'
|
||||
#define IPPROTO_TCP FREERTOS_IPPROTO_TCP
|
||||
#define IPPROTO_UDP FREERTOS_IPPROTO_UDP
|
||||
@@ -206,6 +212,7 @@ static inline int ff_vfprintf(FF_FILE *fp, const char *fmt, va_list ap) {
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <dirent.h>
|
||||
#include <inttypes.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <signal.h>
|
||||
@@ -217,6 +224,7 @@ static inline int ff_vfprintf(FF_FILE *fp, const char *fmt, va_list ap) {
|
||||
#include <unistd.h>
|
||||
#define MG_DIRSEP '/'
|
||||
#define MG_ENABLE_POSIX 1
|
||||
#define MG_INT64_FMT "%" PRId64
|
||||
|
||||
#endif
|
||||
|
||||
@@ -261,7 +269,7 @@ typedef int socklen_t;
|
||||
#ifndef EWOULDBLOCK
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#endif
|
||||
#define realpath(a, b) _fullpath((b), (a), 512)
|
||||
#define realpath(a, b) _fullpath((b), (a), MG_PATH_MAX)
|
||||
#ifndef va_copy
|
||||
#ifdef __va_copy
|
||||
#define va_copy __va_copy
|
||||
@@ -273,6 +281,8 @@ typedef int socklen_t;
|
||||
#define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR)
|
||||
#endif
|
||||
|
||||
#define MG_INT64_FMT "%I64d"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -322,10 +332,6 @@ typedef int socklen_t;
|
||||
#define MG_ENABLE_DIRECTORY_LISTING 0
|
||||
#endif
|
||||
|
||||
#ifndef MG_ENABLE_HTTP_DEBUG_ENDPOINT
|
||||
#define MG_ENABLE_HTTP_DEBUG_ENDPOINT 0
|
||||
#endif
|
||||
|
||||
#ifndef MG_ENABLE_SOCKETPAIR
|
||||
#define MG_ENABLE_SOCKETPAIR 0
|
||||
#endif
|
||||
@@ -344,6 +350,10 @@ typedef int socklen_t;
|
||||
#define MG_MAX_HTTP_HEADERS 40
|
||||
#endif
|
||||
|
||||
#ifndef MG_PATH_MAX
|
||||
#define MG_PATH_MAX PATH_MAX
|
||||
#endif
|
||||
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
@@ -413,13 +423,15 @@ void mg_timer_poll(unsigned long uptime_ms);
|
||||
|
||||
|
||||
char *mg_file_read(const char *path);
|
||||
size_t mg_file_size(const char *path);
|
||||
int mg_file_write(const char *path, const char *fmt, ...);
|
||||
int64_t mg_file_size(const char *path);
|
||||
bool mg_file_write(const char *path, const void *buf, size_t len);
|
||||
bool mg_file_printf(const char *path, const char *fmt, ...);
|
||||
void mg_random(void *buf, size_t len);
|
||||
bool mg_globmatch(const char *pattern, int plen, const char *s, int n);
|
||||
bool mg_next_comma_entry(struct mg_str *s, struct mg_str *k, struct mg_str *v);
|
||||
uint16_t mg_ntohs(uint16_t net);
|
||||
uint32_t mg_ntohl(uint32_t net);
|
||||
uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len);
|
||||
char *mg_hexdump(const void *buf, size_t len);
|
||||
char *mg_hex(const void *buf, int len, char *dst);
|
||||
void mg_unhex(const char *buf, int len, unsigned char *to);
|
||||
@@ -431,6 +443,16 @@ double mg_time(void);
|
||||
unsigned long mg_millis(void);
|
||||
void mg_usleep(unsigned long usecs);
|
||||
|
||||
#if MG_ENABLE_FS
|
||||
#ifdef _WIN32
|
||||
typedef struct _stati64 mg_stat_t;
|
||||
#else
|
||||
typedef struct stat mg_stat_t;
|
||||
#endif
|
||||
int mg_stat(const char *path, mg_stat_t *);
|
||||
FILE *mg_fopen(const char *fp, const char *mode);
|
||||
#endif
|
||||
|
||||
#define mg_htons(x) mg_ntohs(x)
|
||||
#define mg_htonl(x) mg_ntohl(x)
|
||||
|
||||
@@ -441,7 +463,7 @@ void mg_usleep(unsigned long usecs);
|
||||
#if !defined(WEAK)
|
||||
#if (defined(__GNUC__) || defined(__clang__) || \
|
||||
defined(__TI_COMPILER_VERSION__)) && \
|
||||
!defined(_WIN32)
|
||||
!defined(_WIN32) && !defined(__CYGWIN__)
|
||||
#define WEAK __attribute__((weak))
|
||||
#else
|
||||
#define WEAK
|
||||
@@ -498,8 +520,8 @@ struct mg_iobuf {
|
||||
size_t size, len;
|
||||
};
|
||||
|
||||
void mg_iobuf_init(struct mg_iobuf *, size_t);
|
||||
void mg_iobuf_resize(struct mg_iobuf *, size_t);
|
||||
int mg_iobuf_init(struct mg_iobuf *, size_t);
|
||||
int mg_iobuf_resize(struct mg_iobuf *, size_t);
|
||||
void mg_iobuf_free(struct mg_iobuf *);
|
||||
size_t mg_iobuf_append(struct mg_iobuf *, const void *, size_t, size_t);
|
||||
size_t mg_iobuf_delete(struct mg_iobuf *, size_t);
|
||||
@@ -542,38 +564,28 @@ void mg_hmac_sha1(const unsigned char *key, size_t key_len,
|
||||
struct mg_connection;
|
||||
typedef void (*mg_event_handler_t)(struct mg_connection *, int ev,
|
||||
void *ev_data, void *fn_data);
|
||||
#if 0
|
||||
struct mg_fn {
|
||||
struct mg_fn *next;
|
||||
mg_event_handler_t fn;
|
||||
void *fn_data;
|
||||
};
|
||||
|
||||
void mg_fn_add(struct mg_connection *c, mg_event_handler_t fn, void *fn_data);
|
||||
void mg_fn_del(struct mg_connection *c, mg_event_handler_t fn);
|
||||
#endif
|
||||
|
||||
void mg_call(struct mg_connection *c, int ev, void *ev_data);
|
||||
void mg_error(struct mg_connection *c, const char *fmt, ...);
|
||||
|
||||
enum {
|
||||
MG_EV_ERROR, // Error char *error_message
|
||||
MG_EV_POLL, // mg_mgr_poll iteration unsigned long *millis
|
||||
MG_EV_RESOLVE, // Host name is resolved NULL
|
||||
MG_EV_CONNECT, // Connection established NULL
|
||||
MG_EV_ACCEPT, // Connection accepted NULL
|
||||
MG_EV_READ, // Data received from socket struct mg_str *
|
||||
MG_EV_WRITE, // Data written to socket int *num_bytes_written
|
||||
MG_EV_CLOSE, // Connection closed NULL
|
||||
MG_EV_HTTP_MSG, // HTTP request/response struct mg_http_message *
|
||||
MG_EV_WS_OPEN, // Websocket handshake done struct mg_http_message *
|
||||
MG_EV_WS_MSG, // Websocket msg, text or bin struct mg_ws_message *
|
||||
MG_EV_WS_CTL, // Websocket control msg struct mg_ws_message *
|
||||
MG_EV_MQTT_CMD, // MQTT low-level command struct mg_mqtt_message *
|
||||
MG_EV_MQTT_MSG, // MQTT PUBLISH received struct mg_mqtt_message *
|
||||
MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code
|
||||
MG_EV_SNTP_TIME, // SNTP time received struct timeval *
|
||||
MG_EV_USER, // Starting ID for user events
|
||||
MG_EV_ERROR, // Error char *error_message
|
||||
MG_EV_POLL, // mg_mgr_poll iteration unsigned long *millis
|
||||
MG_EV_RESOLVE, // Host name is resolved NULL
|
||||
MG_EV_CONNECT, // Connection established NULL
|
||||
MG_EV_ACCEPT, // Connection accepted NULL
|
||||
MG_EV_READ, // Data received from socket struct mg_str *
|
||||
MG_EV_WRITE, // Data written to socket int *num_bytes_written
|
||||
MG_EV_CLOSE, // Connection closed NULL
|
||||
MG_EV_HTTP_MSG, // HTTP request/response struct mg_http_message *
|
||||
MG_EV_HTTP_CHUNK, // HTTP chunk (partial msg) struct mg_http_message *
|
||||
MG_EV_WS_OPEN, // Websocket handshake done struct mg_http_message *
|
||||
MG_EV_WS_MSG, // Websocket msg, text or bin struct mg_ws_message *
|
||||
MG_EV_WS_CTL, // Websocket control msg struct mg_ws_message *
|
||||
MG_EV_MQTT_CMD, // MQTT low-level command struct mg_mqtt_message *
|
||||
MG_EV_MQTT_MSG, // MQTT PUBLISH received struct mg_mqtt_message *
|
||||
MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code
|
||||
MG_EV_SNTP_TIME, // SNTP time received struct timeval *
|
||||
MG_EV_USER, // Starting ID for user events
|
||||
};
|
||||
|
||||
|
||||
@@ -600,6 +612,7 @@ struct mg_mgr {
|
||||
struct mg_dns dns6; // DNS for IPv6
|
||||
int dnstimeout; // DNS resolve timeout in milliseconds
|
||||
unsigned long nextid; // Next connection ID
|
||||
void *userdata; // Arbitrary user data pointer
|
||||
#if MG_ARCH == MG_ARCH_FREERTOS
|
||||
SocketSet_t ss; // NOTE(lsm): referenced from socket struct
|
||||
#endif
|
||||
@@ -617,7 +630,7 @@ struct mg_connection {
|
||||
void *fn_data; // User-speficied function parameter
|
||||
mg_event_handler_t pfn; // Protocol-specific handler function
|
||||
void *pfn_data; // Protocol-specific function parameter
|
||||
char label[32]; // Arbitrary label
|
||||
char label[50]; // Arbitrary label
|
||||
void *tls; // TLS specific data
|
||||
unsigned is_listening : 1; // Listening connection
|
||||
unsigned is_client : 1; // Outbound (client) connection
|
||||
@@ -668,7 +681,9 @@ struct mg_http_message {
|
||||
struct mg_str method, uri, query, proto; // Request/response line
|
||||
struct mg_http_header headers[MG_MAX_HTTP_HEADERS]; // Headers
|
||||
struct mg_str body; // Body
|
||||
struct mg_str message; // Request line + headers + body
|
||||
struct mg_str head; // Request + headers
|
||||
struct mg_str chunk; // Chunk for chunked encoding, or partial body
|
||||
struct mg_str message; // Request + headers + body
|
||||
};
|
||||
|
||||
// Parameter for mg_http_serve_dir()
|
||||
@@ -681,6 +696,7 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *);
|
||||
int mg_http_get_request_len(const unsigned char *buf, size_t buf_len);
|
||||
void mg_http_printf_chunk(struct mg_connection *cnn, const char *fmt, ...);
|
||||
void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len);
|
||||
void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm);
|
||||
struct mg_connection *mg_http_listen(struct mg_mgr *, const char *url,
|
||||
mg_event_handler_t fn, void *fn_data);
|
||||
struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url,
|
||||
@@ -695,6 +711,7 @@ struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name);
|
||||
void mg_http_event_handler(struct mg_connection *c, int ev);
|
||||
int mg_http_get_var(const struct mg_str *, const char *name, char *, int);
|
||||
int mg_url_decode(const char *s, size_t n, char *to, size_t to_len, int form);
|
||||
int mg_url_encode(const char *s, size_t n, char *buf, size_t len);
|
||||
void mg_http_creds(struct mg_http_message *, char *user, int, char *pass, int);
|
||||
bool mg_http_match_uri(const struct mg_http_message *, const char *glob);
|
||||
int mg_http_upload(struct mg_connection *, struct mg_http_message *hm,
|
||||
@@ -708,11 +725,11 @@ void mg_http_serve_ssi(struct mg_connection *c, const char *root,
|
||||
|
||||
|
||||
struct mg_tls_opts {
|
||||
const char *ca; // CA certificate file. For both listeners and clients
|
||||
const char *cert; // Certificate
|
||||
const char *certkey; // Certificate key
|
||||
const char *ciphers; // Cipher list
|
||||
const char *srvname; // If not NULL, enables server name verification
|
||||
const char *ca; // CA certificate file. For both listeners and clients
|
||||
const char *cert; // Certificate
|
||||
const char *certkey; // Certificate key
|
||||
const char *ciphers; // Cipher list
|
||||
struct mg_str srvname; // If not empty, enables server name verification
|
||||
};
|
||||
|
||||
int mg_tls_init(struct mg_connection *, struct mg_tls_opts *);
|
||||
@@ -810,6 +827,11 @@ void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags,
|
||||
uint32_t len);
|
||||
int mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic,
|
||||
uint8_t *qos, int pos);
|
||||
int mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic,
|
||||
int pos);
|
||||
void mg_mqtt_ping(struct mg_connection *);
|
||||
void mg_mqtt_pong(struct mg_connection *);
|
||||
void mg_mqtt_disconnect(struct mg_connection *);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
|
||||
#include <dirent.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/stat.h>
|
||||
#define MG_DIRSEP '/'
|
||||
#define MG_INT64_FMT "%lld"
|
||||
#ifndef MG_PATH_MAX
|
||||
#define MG_PATH_MAX 128
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -8,5 +8,6 @@
|
||||
#include <stdbool.h>
|
||||
#include <sys/time.h>
|
||||
#define MG_DIRSEP '/'
|
||||
#define MG_INT64_FMT "%lld"
|
||||
|
||||
#endif
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <FreeRTOS_Sockets.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define MG_INT64_FMT "%lld"
|
||||
#define MG_DIRSEP '/'
|
||||
#define IPPROTO_TCP FREERTOS_IPPROTO_TCP
|
||||
#define IPPROTO_UDP FREERTOS_IPPROTO_UDP
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <dirent.h>
|
||||
#include <inttypes.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <signal.h>
|
||||
@@ -17,5 +18,6 @@
|
||||
#include <unistd.h>
|
||||
#define MG_DIRSEP '/'
|
||||
#define MG_ENABLE_POSIX 1
|
||||
#define MG_INT64_FMT "%" PRId64
|
||||
|
||||
#endif
|
||||
+3
-1
@@ -40,7 +40,7 @@ typedef int socklen_t;
|
||||
#ifndef EWOULDBLOCK
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#endif
|
||||
#define realpath(a, b) _fullpath((b), (a), 512)
|
||||
#define realpath(a, b) _fullpath((b), (a), MG_PATH_MAX)
|
||||
#ifndef va_copy
|
||||
#ifdef __va_copy
|
||||
#define va_copy __va_copy
|
||||
@@ -52,4 +52,6 @@ typedef int socklen_t;
|
||||
#define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR)
|
||||
#endif
|
||||
|
||||
#define MG_INT64_FMT "%I64d"
|
||||
|
||||
#endif
|
||||
+4
-4
@@ -46,10 +46,6 @@
|
||||
#define MG_ENABLE_DIRECTORY_LISTING 0
|
||||
#endif
|
||||
|
||||
#ifndef MG_ENABLE_HTTP_DEBUG_ENDPOINT
|
||||
#define MG_ENABLE_HTTP_DEBUG_ENDPOINT 0
|
||||
#endif
|
||||
|
||||
#ifndef MG_ENABLE_SOCKETPAIR
|
||||
#define MG_ENABLE_SOCKETPAIR 0
|
||||
#endif
|
||||
@@ -67,3 +63,7 @@
|
||||
#ifndef MG_MAX_HTTP_HEADERS
|
||||
#define MG_MAX_HTTP_HEADERS 40
|
||||
#endif
|
||||
|
||||
#ifndef MG_PATH_MAX
|
||||
#define MG_PATH_MAX PATH_MAX
|
||||
#endif
|
||||
@@ -156,7 +156,9 @@ static void dns_cb(struct mg_connection *c, int ev, void *ev_data,
|
||||
if (d->c->is_resolving) {
|
||||
d->c->is_resolving = 0;
|
||||
if (dm.resolved) {
|
||||
#if MG_ENABLE_LOG
|
||||
char buf[100];
|
||||
#endif
|
||||
dm.addr.port = d->c->peer.port; // Save port
|
||||
d->c->peer = dm.addr; // Copy resolved address
|
||||
LOG(LL_DEBUG, ("%lu %s resolved to %s", d->c->id, dm.name,
|
||||
|
||||
+18
-28
@@ -3,36 +3,26 @@
|
||||
struct mg_connection;
|
||||
typedef void (*mg_event_handler_t)(struct mg_connection *, int ev,
|
||||
void *ev_data, void *fn_data);
|
||||
#if 0
|
||||
struct mg_fn {
|
||||
struct mg_fn *next;
|
||||
mg_event_handler_t fn;
|
||||
void *fn_data;
|
||||
};
|
||||
|
||||
void mg_fn_add(struct mg_connection *c, mg_event_handler_t fn, void *fn_data);
|
||||
void mg_fn_del(struct mg_connection *c, mg_event_handler_t fn);
|
||||
#endif
|
||||
|
||||
void mg_call(struct mg_connection *c, int ev, void *ev_data);
|
||||
void mg_error(struct mg_connection *c, const char *fmt, ...);
|
||||
|
||||
enum {
|
||||
MG_EV_ERROR, // Error char *error_message
|
||||
MG_EV_POLL, // mg_mgr_poll iteration unsigned long *millis
|
||||
MG_EV_RESOLVE, // Host name is resolved NULL
|
||||
MG_EV_CONNECT, // Connection established NULL
|
||||
MG_EV_ACCEPT, // Connection accepted NULL
|
||||
MG_EV_READ, // Data received from socket struct mg_str *
|
||||
MG_EV_WRITE, // Data written to socket int *num_bytes_written
|
||||
MG_EV_CLOSE, // Connection closed NULL
|
||||
MG_EV_HTTP_MSG, // HTTP request/response struct mg_http_message *
|
||||
MG_EV_WS_OPEN, // Websocket handshake done struct mg_http_message *
|
||||
MG_EV_WS_MSG, // Websocket msg, text or bin struct mg_ws_message *
|
||||
MG_EV_WS_CTL, // Websocket control msg struct mg_ws_message *
|
||||
MG_EV_MQTT_CMD, // MQTT low-level command struct mg_mqtt_message *
|
||||
MG_EV_MQTT_MSG, // MQTT PUBLISH received struct mg_mqtt_message *
|
||||
MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code
|
||||
MG_EV_SNTP_TIME, // SNTP time received struct timeval *
|
||||
MG_EV_USER, // Starting ID for user events
|
||||
MG_EV_ERROR, // Error char *error_message
|
||||
MG_EV_POLL, // mg_mgr_poll iteration unsigned long *millis
|
||||
MG_EV_RESOLVE, // Host name is resolved NULL
|
||||
MG_EV_CONNECT, // Connection established NULL
|
||||
MG_EV_ACCEPT, // Connection accepted NULL
|
||||
MG_EV_READ, // Data received from socket struct mg_str *
|
||||
MG_EV_WRITE, // Data written to socket int *num_bytes_written
|
||||
MG_EV_CLOSE, // Connection closed NULL
|
||||
MG_EV_HTTP_MSG, // HTTP request/response struct mg_http_message *
|
||||
MG_EV_HTTP_CHUNK, // HTTP chunk (partial msg) struct mg_http_message *
|
||||
MG_EV_WS_OPEN, // Websocket handshake done struct mg_http_message *
|
||||
MG_EV_WS_MSG, // Websocket msg, text or bin struct mg_ws_message *
|
||||
MG_EV_WS_CTL, // Websocket control msg struct mg_ws_message *
|
||||
MG_EV_MQTT_CMD, // MQTT low-level command struct mg_mqtt_message *
|
||||
MG_EV_MQTT_MSG, // MQTT PUBLISH received struct mg_mqtt_message *
|
||||
MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code
|
||||
MG_EV_SNTP_TIME, // SNTP time received struct timeval *
|
||||
MG_EV_USER, // Starting ID for user events
|
||||
};
|
||||
+258
-152
@@ -9,11 +9,6 @@
|
||||
#include "version.h"
|
||||
#include "ws.h"
|
||||
|
||||
struct http_data {
|
||||
void *old_pfn_data; // Previous pfn_data
|
||||
FILE *fp; // For static file serving
|
||||
};
|
||||
|
||||
// Multipart POST example:
|
||||
// https://gist.github.com/cpq/b8dd247571e6ee9c54ef7e8dfcfecf48
|
||||
|
||||
@@ -63,7 +58,7 @@ int mg_http_get_var(const struct mg_str *buf, const char *name, char *dst,
|
||||
s = (const char *) memchr(p, '&', (size_t)(e - p));
|
||||
if (s == NULL) s = e;
|
||||
len = mg_url_decode(p, (size_t)(s - p), dst, dst_len, 1);
|
||||
if (len == -1) len = -3; // Failed to decode
|
||||
if (len < 0) len = -3; // Failed to decode
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -91,7 +86,7 @@ int mg_url_decode(const char *src, size_t src_len, char *dst, size_t dst_len,
|
||||
}
|
||||
}
|
||||
if (j < dst_len) dst[j] = '\0'; // Null-terminate the destination
|
||||
return i >= src_len ? (int) j : -1;
|
||||
return i >= src_len && j < dst_len ? (int) j : -1;
|
||||
}
|
||||
|
||||
int mg_http_get_request_len(const unsigned char *buf, size_t buf_len) {
|
||||
@@ -106,12 +101,12 @@ int mg_http_get_request_len(const unsigned char *buf, size_t buf_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *skip(const char *s, const char *end, const char *delims,
|
||||
static const char *skip(const char *s, const char *e, const char *d,
|
||||
struct mg_str *v) {
|
||||
v->ptr = s;
|
||||
while (s < end && strchr(delims, *(unsigned char *) s) == NULL) s++;
|
||||
while (s < e && *s != '\n' && strchr(d, *s) == NULL) s++;
|
||||
v->len = s - v->ptr;
|
||||
while (s < end && strchr(delims, *(unsigned char *) s) != NULL) s++;
|
||||
while (s < e && strchr(d, *s) != NULL) s++;
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -150,15 +145,19 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
|
||||
memset(hm, 0, sizeof(*hm));
|
||||
if (req_len <= 0) return req_len;
|
||||
|
||||
hm->message.ptr = s;
|
||||
hm->body.ptr = s + req_len;
|
||||
hm->message.ptr = hm->head.ptr = s;
|
||||
hm->body.ptr = end;
|
||||
hm->head.len = req_len;
|
||||
hm->chunk.ptr = end;
|
||||
hm->message.len = hm->body.len = (size_t) ~0; // Set body length to infinite
|
||||
|
||||
// Parse request line
|
||||
s = skip(s, end, " ", &hm->method);
|
||||
s = skip(s, end, " ", &hm->uri);
|
||||
s = skip(s, end, "\r\n", &hm->proto);
|
||||
if (hm->uri.ptr <= hm->method.ptr || hm->proto.ptr <= hm->uri.ptr) return -1;
|
||||
|
||||
// Sanity check
|
||||
if (hm->method.len == 0 || hm->uri.len == 0 || hm->proto.len == 0) return -1;
|
||||
|
||||
// If URI contains '?' character, setup query string
|
||||
if ((qs = (const char *) memchr(hm->uri.ptr, '?', hm->uri.len)) != NULL) {
|
||||
@@ -244,16 +243,14 @@ void mg_http_reply(struct mg_connection *c, int code, const char *headers,
|
||||
#if MG_ENABLE_FS
|
||||
static void http_cb(struct mg_connection *, int, void *, void *);
|
||||
static void restore_http_cb(struct mg_connection *c) {
|
||||
struct http_data *d = (struct http_data *) c->pfn_data;
|
||||
if (d->fp != NULL) fclose(d->fp);
|
||||
c->pfn_data = d->old_pfn_data;
|
||||
if (c->pfn_data != NULL) fclose((FILE *) c->pfn_data);
|
||||
c->pfn_data = NULL;
|
||||
c->pfn = http_cb;
|
||||
free(d);
|
||||
}
|
||||
|
||||
char *mg_http_etag(char *buf, size_t len, struct stat *st) {
|
||||
snprintf(buf, len, "\"%lx.%lu\"", (unsigned long) st->st_mtime,
|
||||
(unsigned long) st->st_size);
|
||||
char *mg_http_etag(char *buf, size_t len, mg_stat_t *st) {
|
||||
snprintf(buf, len, "\"%lx." MG_INT64_FMT "\"", (unsigned long) st->st_mtime,
|
||||
(int64_t) st->st_size);
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -271,7 +268,7 @@ int mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
|
||||
snprintf(path, sizeof(path), "%s%c%s", dir, MG_DIRSEP, name);
|
||||
LOG(LL_DEBUG,
|
||||
("%p %d bytes @ %d [%s]", c->fd, (int) hm->body.len, (int) oft, name));
|
||||
if ((fp = fopen(path, oft == 0 ? "wb" : "a")) == NULL) {
|
||||
if ((fp = mg_fopen(path, oft == 0 ? "wb" : "ab")) == NULL) {
|
||||
mg_http_reply(c, 400, "", "fopen(%s): %d", name, errno);
|
||||
return -2;
|
||||
} else {
|
||||
@@ -286,12 +283,12 @@ int mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
|
||||
static void static_cb(struct mg_connection *c, int ev, void *ev_data,
|
||||
void *fn_data) {
|
||||
if (ev == MG_EV_WRITE || ev == MG_EV_POLL) {
|
||||
struct http_data *d = (struct http_data *) fn_data;
|
||||
FILE *fp = (FILE *) fn_data;
|
||||
// Read to send IO buffer directly, avoid extra on-stack buffer
|
||||
size_t n, max = 2 * MG_IO_SIZE;
|
||||
if (c->send.size < max) mg_iobuf_resize(&c->send, max);
|
||||
if (c->send.len >= c->send.size) return; // Rate limit
|
||||
n = fread(c->send.buf + c->send.len, 1, c->send.size - c->send.len, d->fp);
|
||||
n = fread(c->send.buf + c->send.len, 1, c->send.size - c->send.len, fp);
|
||||
if (n > 0) c->send.len += n;
|
||||
if (c->send.len < c->send.size) restore_http_cb(c);
|
||||
} else if (ev == MG_EV_CLOSE) {
|
||||
@@ -309,9 +306,9 @@ static const char *guess_content_type(const char *filename) {
|
||||
size_t ext_len;
|
||||
const char *type;
|
||||
} * t, types[] = {
|
||||
MIME_ENTRY("html", "text/html"),
|
||||
MIME_ENTRY("htm", "text/html"),
|
||||
MIME_ENTRY("shtml", "text/html"),
|
||||
MIME_ENTRY("html", "text/html; charset=utf-8"),
|
||||
MIME_ENTRY("htm", "text/html; charset=utf-8"),
|
||||
MIME_ENTRY("shtml", "text/html; charset=utf-8"),
|
||||
MIME_ENTRY("css", "text/css"),
|
||||
MIME_ENTRY("js", "text/javascript"),
|
||||
MIME_ENTRY("mjs", "text/javascript"),
|
||||
@@ -322,7 +319,7 @@ static const char *guess_content_type(const char *filename) {
|
||||
MIME_ENTRY("jpeg", "image/jpeg"),
|
||||
MIME_ENTRY("png", "image/png"),
|
||||
MIME_ENTRY("svg", "image/svg+xml"),
|
||||
MIME_ENTRY("txt", "text/plain"),
|
||||
MIME_ENTRY("txt", "text/plain; charset=utf-8"),
|
||||
MIME_ENTRY("wav", "audio/wav"),
|
||||
MIME_ENTRY("mp3", "audio/mpeg"),
|
||||
MIME_ENTRY("mid", "audio/mid"),
|
||||
@@ -359,38 +356,34 @@ static const char *guess_content_type(const char *filename) {
|
||||
if (mg_ncasecmp(t->ext, &filename[n - t->ext_len], t->ext_len)) continue;
|
||||
return t->type;
|
||||
}
|
||||
return "text/plain";
|
||||
return "text/plain; charset=utf-8";
|
||||
}
|
||||
|
||||
void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
|
||||
const char *path, const char *mime, const char *hdrs) {
|
||||
struct mg_str *inm = mg_http_get_header(hm, "If-None-Match");
|
||||
struct stat st;
|
||||
FILE *fp = fopen(path, "rb");
|
||||
mg_stat_t st;
|
||||
char etag[64];
|
||||
if (fp == NULL || stat(path, &st) != 0 ||
|
||||
FILE *fp = mg_fopen(path, "rb");
|
||||
if (fp == NULL || mg_stat(path, &st) != 0 ||
|
||||
mg_http_etag(etag, sizeof(etag), &st) != etag) {
|
||||
LOG(LL_DEBUG,
|
||||
("404 [%.*s] [%s] %p", (int) hm->uri.len, hm->uri.ptr, path, fp));
|
||||
mg_http_reply(c, 404, "", "%s", "Not found\n");
|
||||
if (fp != NULL) fclose(fp);
|
||||
} else if (inm != NULL && mg_vcasecmp(inm, etag) == 0) {
|
||||
fclose(fp);
|
||||
mg_printf(c, "HTTP/1.1 304 Not Modified\r\nContent-Length: 0\r\n\r\n");
|
||||
} else {
|
||||
mg_printf(c,
|
||||
"HTTP/1.1 200 OK\r\nContent-Type: %s\r\n"
|
||||
"Etag: %s\r\nContent-Length: %lu\r\n%s\r\n",
|
||||
mime, etag, (unsigned long) st.st_size, hdrs ? hdrs : "");
|
||||
"Etag: %s\r\nContent-Length: " MG_INT64_FMT "\r\n%s\r\n",
|
||||
mime, etag, (int64_t) st.st_size, hdrs ? hdrs : "");
|
||||
if (mg_vcasecmp(&hm->method, "HEAD") == 0) {
|
||||
fclose(fp);
|
||||
} else {
|
||||
struct http_data *d = (struct http_data *) calloc(1, sizeof(*d));
|
||||
if (d == NULL) {
|
||||
mg_error(c, "static HTTP OOM");
|
||||
} else {
|
||||
d->fp = fp;
|
||||
d->old_pfn_data = c->pfn_data;
|
||||
c->pfn = static_cb;
|
||||
c->pfn_data = d;
|
||||
}
|
||||
c->pfn = static_cb;
|
||||
c->pfn_data = fp;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -399,21 +392,23 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
|
||||
MG_ARCH == MG_ARCH_FREERTOS
|
||||
char *realpath(const char *src, char *dst) {
|
||||
int len = strlen(src);
|
||||
if (len > PATH_MAX - 1) len = PATH_MAX - 1;
|
||||
if (len > MG_PATH_MAX - 1) len = MG_PATH_MAX - 1;
|
||||
strncpy(dst, src, len);
|
||||
dst[len] = '\0';
|
||||
LOG(LL_DEBUG, ("[%s] -> [%s]", src, dst));
|
||||
return dst;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Try to avoid dirent API
|
||||
static int mg_is_dir(const char *path) {
|
||||
// Allow user to override this function
|
||||
bool mg_is_dir(const char *path) WEAK;
|
||||
bool mg_is_dir(const char *path) {
|
||||
#if MG_ARCH == MG_ARCH_FREERTOS
|
||||
struct FF_STAT st;
|
||||
return (ff_stat(path, &st) == 0) && (st.st_mode & FF_IFDIR);
|
||||
#else
|
||||
struct stat st;
|
||||
return (stat(path, &st) == 0) && (st.st_mode & S_IFDIR);
|
||||
mg_stat_t st;
|
||||
return mg_stat(path, &st) == 0 && S_ISDIR(st.st_mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -528,10 +523,10 @@ struct dirent *readdir(DIR *d) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static void printdirentry(struct mg_connection *c, struct mg_http_message *hm,
|
||||
const char *name, struct stat *stp) {
|
||||
char size[64], mod[64]; //, path[PATH_MAX];
|
||||
int is_dir = S_ISDIR(stp->st_mode);
|
||||
static void printdirentry(struct mg_connection *c, const char *name,
|
||||
mg_stat_t *stp) {
|
||||
char size[64], mod[64], path[MG_PATH_MAX];
|
||||
int is_dir = S_ISDIR(stp->st_mode), n = 0;
|
||||
const char *slash = is_dir ? "/" : "";
|
||||
|
||||
if (is_dir) {
|
||||
@@ -548,114 +543,156 @@ static void printdirentry(struct mg_connection *c, struct mg_http_message *hm,
|
||||
}
|
||||
}
|
||||
strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&stp->st_mtime));
|
||||
// mg_escape(file_name, path, sizeof(path));
|
||||
// href = mg_url_encode(mg_mk_str(file_name));
|
||||
mg_http_printf_chunk(c,
|
||||
" <tr><td><a href=\"%.*s%s%s\">%s%s</a></td>"
|
||||
"<td>%s</td><td>%s</td></tr>\n",
|
||||
(int) hm->uri.len, hm->uri.ptr, name, slash, name, slash,
|
||||
mod, size);
|
||||
// free((void *) href.p);
|
||||
n = mg_url_encode(name, strlen(name), path, sizeof(path));
|
||||
mg_printf(c,
|
||||
" <tr><td><a href=\"%.*s%s\">%s%s</a></td>"
|
||||
"<td>%s</td><td>%s</td></tr>\n",
|
||||
n, path, slash, name, slash, mod, size);
|
||||
}
|
||||
|
||||
static void listdir(struct mg_connection *c, struct mg_http_message *hm,
|
||||
char *dir) {
|
||||
char path[PATH_MAX + 1], *p = &dir[strlen(dir) - 1];
|
||||
char path[MG_PATH_MAX], *p = &dir[strlen(dir) - 1], tmp[10];
|
||||
struct dirent *dp;
|
||||
DIR *dirp;
|
||||
static const char *sort_js_code =
|
||||
"<script>function srt(tb, sc, so, d) {"
|
||||
"var tr = Array.prototype.slice.call(tb.rows, 0),"
|
||||
"tr = tr.sort(function (a, b) { var c1 = a.cells[sc], c2 = b.cells[sc],"
|
||||
"n1 = c1.getAttribute('name'), n2 = c2.getAttribute('name'), "
|
||||
"t1 = a.cells[2].getAttribute('name'), "
|
||||
"t2 = b.cells[2].getAttribute('name'); "
|
||||
"return so * (t1 < 0 && t2 >= 0 ? -1 : t2 < 0 && t1 >= 0 ? 1 : "
|
||||
"n1 ? parseInt(n2) - parseInt(n1) : "
|
||||
"c1.textContent.trim().localeCompare(c2.textContent.trim())); });";
|
||||
static const char *sort_js_code2 =
|
||||
"for (var i = 0; i < tr.length; i++) tb.appendChild(tr[i]); "
|
||||
"if (!d) window.location.hash = ('sc=' + sc + '&so=' + so); "
|
||||
"};"
|
||||
"window.onload = function() {"
|
||||
"var tb = document.getElementById('tb');"
|
||||
"var m = /sc=([012]).so=(1|-1)/.exec(window.location.hash) || [0, 2, 1];"
|
||||
"var sc = m[1], so = m[2]; document.onclick = function(ev) { "
|
||||
"var c = ev.target.rel; if (c) {if (c == sc) so *= -1; srt(tb, c, so); "
|
||||
"sc = c; ev.preventDefault();}};"
|
||||
"srt(tb, sc, so, true);"
|
||||
"}"
|
||||
"</script>";
|
||||
|
||||
while (p > dir && *p != '/') *p-- = '\0';
|
||||
if ((dirp = (opendir(dir))) != NULL) {
|
||||
mg_printf(c, "%s\r\n", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n");
|
||||
mg_http_printf_chunk(
|
||||
c,
|
||||
"<!DOCTYPE html><html><head><title>Index of %.*s</title>"
|
||||
"<style>th,td {text-align: left; padding-right: 1em; "
|
||||
"font-family: monospace; }</style></head>"
|
||||
"<body><h1>Index of %.*s</h1><table cellpadding=\"0\"><thead>"
|
||||
"<tr><th>Name</th><th>Modified</th><th>Size</th></tr>"
|
||||
"<tr><td colspan=\"3\"><hr></td></tr></thead><tbody>\n",
|
||||
(int) hm->uri.len, hm->uri.ptr, (int) hm->uri.len, hm->uri.ptr);
|
||||
size_t off, n;
|
||||
mg_printf(c, "%s\r\n",
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: text/html; charset=utf-8\r\n"
|
||||
"Content-Length: \r\n");
|
||||
off = c->send.len; // Start of body
|
||||
mg_printf(c,
|
||||
"<!DOCTYPE html><html><head><title>Index of %.*s</title>%s%s"
|
||||
"<style>th,td {text-align: left; padding-right: 1em; "
|
||||
"font-family: monospace; }</style></head>"
|
||||
"<body><h1>Index of %.*s</h1><table cellpadding=\"0\"><thead>"
|
||||
"<tr><th><a href=\"#\" rel=\"0\">Name</a></th><th>"
|
||||
"<a href=\"#\" rel=\"1\">Modified</a></th>"
|
||||
"<th><a href=\"#\" rel=\"2\">Size</a></th></tr>"
|
||||
"<tr><td colspan=\"3\"><hr></td></tr>"
|
||||
"</thead>"
|
||||
"<tbody id=\"tb\">\n",
|
||||
(int) hm->uri.len, hm->uri.ptr, sort_js_code, sort_js_code2,
|
||||
(int) hm->uri.len, hm->uri.ptr);
|
||||
|
||||
while ((dp = readdir(dirp)) != NULL) {
|
||||
struct stat st;
|
||||
mg_stat_t st;
|
||||
const char *sep = dp->d_name[0] == MG_DIRSEP ? "/" : "";
|
||||
// Do not show current dir and hidden files
|
||||
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue;
|
||||
snprintf(path, sizeof(path), "%s/%s", dir, dp->d_name);
|
||||
if (stat(path, &st) != 0) {
|
||||
// SPIFFS can report "/foo.txt" in the dp->d_name
|
||||
if (snprintf(path, sizeof(path), "%s%s%s", dir, sep, dp->d_name) < 0) {
|
||||
LOG(LL_ERROR, ("%s truncated", dp->d_name));
|
||||
} else if (mg_stat(path, &st) != 0) {
|
||||
LOG(LL_ERROR, ("%lu stat(%s): %d", c->id, path, errno));
|
||||
continue;
|
||||
} else {
|
||||
printdirentry(c, dp->d_name, &st);
|
||||
}
|
||||
printdirentry(c, hm, dp->d_name, &st);
|
||||
}
|
||||
closedir(dirp);
|
||||
mg_http_printf_chunk(
|
||||
c,
|
||||
"</tbody><tfoot><tr><td colspan=\"3\"><hr></td></tr></tfoot>"
|
||||
"</table><address>Mongoose v.%s</address></body></html>\n",
|
||||
MG_VERSION);
|
||||
mg_http_write_chunk(c, "", 0);
|
||||
mg_printf(c,
|
||||
"</tbody><tfoot><tr><td colspan=\"3\"><hr></td></tr></tfoot>"
|
||||
"</table><address>Mongoose v.%s</address></body></html>\n",
|
||||
MG_VERSION);
|
||||
n = snprintf(tmp, sizeof(tmp), "%lu", (unsigned long) (c->send.len - off));
|
||||
memcpy(c->send.buf + off - 10, tmp, n); // Set content length
|
||||
} else {
|
||||
mg_http_reply(c, 400, "", "Cannot open dir");
|
||||
LOG(LL_DEBUG, ("%lu opendir(%s) -> %d", c->id, dir, errno));
|
||||
LOG(LL_ERROR, ("%lu opendir(%s) -> %d", c->id, dir, errno));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
|
||||
struct mg_http_serve_opts *opts) {
|
||||
char path[PATH_MAX + 2], root[sizeof(path) - 2], real[sizeof(path) - 2];
|
||||
path[0] = root[0] = real[0] = '\0';
|
||||
if (realpath(opts->root_dir, root) == NULL)
|
||||
LOG(LL_DEBUG, ("realpath(%s): %d", opts->root_dir, errno));
|
||||
if (!mg_is_dir(root)) {
|
||||
mg_http_reply(c, 400, "", "Bad web root [%s]\n", root);
|
||||
char t1[MG_PATH_MAX], t2[sizeof(t1)];
|
||||
t1[0] = t2[0] = '\0';
|
||||
|
||||
if (realpath(opts->root_dir, t1) == NULL) {
|
||||
LOG(LL_ERROR, ("realpath(%s): %d", opts->root_dir, errno));
|
||||
mg_http_reply(c, 400, "", "Bad web root [%s]\n", opts->root_dir);
|
||||
} else if (!mg_is_dir(t1)) {
|
||||
mg_http_reply(c, 400, "", "Invalid web root [%s]\n", t1);
|
||||
} else {
|
||||
char dec[PATH_MAX];
|
||||
// NOTE(lsm): Xilinx snprintf does not 0-terminate the detination for
|
||||
// the %.*s specifier, if the length is zero. Make sure hm->uri.len > 0
|
||||
bool is_index = false;
|
||||
int ndec = mg_url_decode(hm->uri.ptr, hm->uri.len, dec, sizeof(dec), 0);
|
||||
size_t n =
|
||||
snprintf(path, sizeof(path), "%s%.*s", root, ndec < 0 ? 0 : ndec, dec);
|
||||
while (n > 0 && n < sizeof(path) && path[n - 1] == '/') path[--n] = 0;
|
||||
if (realpath(path, real) == NULL)
|
||||
LOG(LL_DEBUG, ("realpath(%s): %d", path, errno));
|
||||
// LOG(LL_INFO, ("[%s] [%s] [%s] [%s]", dir, root, path, real));
|
||||
if (mg_is_dir(real)) {
|
||||
strncat(real, "/index.html", sizeof(real) - strlen(real) - 1);
|
||||
real[sizeof(real) - 1] = '\0';
|
||||
size_t n1 = strlen(t1), n2;
|
||||
|
||||
mg_url_decode(hm->uri.ptr, hm->uri.len, t1 + n1, sizeof(t1) - n1, 0);
|
||||
t1[sizeof(t1) - 1] = '\0';
|
||||
n2 = strlen(t1);
|
||||
while (n2 > 0 && t1[n2 - 1] == '/') t1[--n2] = 0;
|
||||
|
||||
if (realpath(t1, t2) == NULL) {
|
||||
LOG(LL_ERROR, ("realpath(%s): %d", t1, errno));
|
||||
mg_http_reply(c, 404, "", "Not found [%.*s]\n", (int) hm->uri.len,
|
||||
hm->uri.ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mg_is_dir(t2)) {
|
||||
strncat(t2, "/index.html", sizeof(t2) - strlen(t2) - 1);
|
||||
t2[sizeof(t2) - 1] = '\0';
|
||||
is_index = true;
|
||||
}
|
||||
if (strlen(real) < strlen(root) || memcmp(real, root, strlen(root)) != 0) {
|
||||
mg_http_reply(c, 404, "", "Not found %.*s\n", hm->uri.len, hm->uri.ptr);
|
||||
|
||||
if (strlen(t2) < n1 || memcmp(t1, t2, n1) != 0) {
|
||||
// Requested file is located outside root directory, fail
|
||||
mg_http_reply(c, 404, "", "Invalid URI [%.*s]\n", (int) hm->uri.len,
|
||||
hm->uri.ptr);
|
||||
} else {
|
||||
FILE *fp = fopen(real, "r");
|
||||
FILE *fp = mg_fopen(t2, "r");
|
||||
#if MG_ENABLE_SSI
|
||||
if (is_index && fp == NULL) {
|
||||
char *p = real + strlen(real);
|
||||
while (p > real && p[-1] != '/') p--;
|
||||
strncpy(p, "index.shtml", &real[sizeof(real)] - p - 2);
|
||||
real[sizeof(real) - 1] = '\0';
|
||||
fp = fopen(real, "r");
|
||||
char *p = t2 + strlen(t2);
|
||||
while (p > t2 && p[-1] != '/') p--;
|
||||
strncpy(p, "index.shtml", &t2[sizeof(t2)] - p - 2);
|
||||
t2[sizeof(t2) - 1] = '\0';
|
||||
fp = mg_fopen(t2, "r");
|
||||
}
|
||||
#endif
|
||||
#if MG_ENABLE_HTTP_DEBUG_ENDPOINT
|
||||
snprintf(c->label, sizeof(c->label) - 1, "<-F %s", real);
|
||||
#endif
|
||||
if (is_index && fp == NULL) {
|
||||
#if MG_ENABLE_DIRECTORY_LISTING
|
||||
listdir(c, hm, real);
|
||||
listdir(c, hm, t2);
|
||||
#else
|
||||
mg_http_reply(c, 403, "", "%s", "Directory listing not supported");
|
||||
#endif
|
||||
#if MG_ENABLE_SSI
|
||||
} else if (opts->ssi_pattern != NULL &&
|
||||
mg_globmatch(opts->ssi_pattern, strlen(opts->ssi_pattern),
|
||||
real, strlen(real))) {
|
||||
mg_http_serve_ssi(c, root, real);
|
||||
mg_globmatch(opts->ssi_pattern, strlen(opts->ssi_pattern), t2,
|
||||
strlen(t2))) {
|
||||
t1[n1] = '\0';
|
||||
mg_http_serve_ssi(c, t1, t2);
|
||||
#endif
|
||||
} else {
|
||||
mg_http_serve_file(c, hm, real, guess_content_type(real), NULL);
|
||||
mg_http_serve_file(c, hm, t2, guess_content_type(t2), NULL);
|
||||
}
|
||||
if (fp != NULL) fclose(fp);
|
||||
}
|
||||
@@ -663,6 +700,27 @@ void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool mg_is_url_safe(int c) {
|
||||
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
|
||||
(c >= 'A' && c <= 'Z') || c == '.' || c == '_' || c == '-' || c == '~';
|
||||
}
|
||||
|
||||
int mg_url_encode(const char *s, size_t sl, char *buf, size_t len) {
|
||||
size_t i, n = 0;
|
||||
for (i = 0; i < sl; i++) {
|
||||
int c = *(unsigned char *) &s[i];
|
||||
if (n + 4 >= len) return 0;
|
||||
if (mg_is_url_safe(c)) {
|
||||
buf[n++] = s[i];
|
||||
} else {
|
||||
buf[n++] = '%';
|
||||
mg_hex(&s[i], 1, &buf[n]);
|
||||
n += 2;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void mg_http_creds(struct mg_http_message *hm, char *user, int userlen,
|
||||
char *pass, int passlen) {
|
||||
struct mg_str *v = mg_http_get_header(hm, "Authorization");
|
||||
@@ -696,73 +754,121 @@ bool mg_http_match_uri(const struct mg_http_message *hm, const char *glob) {
|
||||
return mg_globmatch(glob, strlen(glob), hm->uri.ptr, hm->uri.len);
|
||||
}
|
||||
|
||||
static void http_cb(struct mg_connection *c, int ev, void *ev_data,
|
||||
void *fn_data) {
|
||||
static size_t get_chunk_length(const char *buf, size_t len, size_t *ll) {
|
||||
size_t i = 0, n;
|
||||
while (i < len && buf[i] != '\r' && i != '\n') i++;
|
||||
n = mg_unhexn((char *) buf, i);
|
||||
while (i < len && (buf[i] == '\r' || i == '\n')) i++;
|
||||
// LOG(LL_INFO, ("len %zu i %zu n %zu ", len, i, n));
|
||||
if (ll != NULL) *ll = i + 1;
|
||||
if (i < len && i + n + 2 < len) return i + n + 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Walk through all chunks in the chunked body. For each chunk, fire
|
||||
// an MG_EV_HTTP_CHUNK event.
|
||||
static void walkchunks(struct mg_connection *c, struct mg_http_message *hm,
|
||||
int reqlen) {
|
||||
size_t off = 0, bl, ll;
|
||||
while (off + reqlen < c->recv.len) {
|
||||
char *buf = (char *) &c->recv.buf[reqlen];
|
||||
size_t memo = c->recv.len;
|
||||
size_t cl = get_chunk_length(&buf[off], memo - reqlen - off, &ll);
|
||||
// LOG(LL_INFO, ("len %zu off %zu cl %zu ll %zu", len, off, cl, ll));
|
||||
if (cl == 0) break;
|
||||
hm->chunk = mg_str_n(&buf[off + ll], cl < ll + 2 ? 0 : cl - ll - 2);
|
||||
mg_call(c, MG_EV_HTTP_CHUNK, hm);
|
||||
// Increase offset only if user has not deleted this chunk
|
||||
if (memo == c->recv.len) off += cl;
|
||||
if (cl <= 5) {
|
||||
// Zero chunk - last one. Prepare body - cut off chunk lengths
|
||||
off = bl = 0;
|
||||
while (off + reqlen < c->recv.len) {
|
||||
char *buf = (char *) &c->recv.buf[reqlen];
|
||||
size_t memo = c->recv.len;
|
||||
size_t cl = get_chunk_length(&buf[off], memo - reqlen - off, &ll);
|
||||
size_t n = cl < ll + 2 ? 0 : cl - ll - 2;
|
||||
if (cl <= 5) break;
|
||||
memmove(buf + bl, buf + off + ll, n);
|
||||
bl += n;
|
||||
off += cl;
|
||||
}
|
||||
// Set message length to indicate we've received
|
||||
// everything, to fire MG_EV_HTTP_MSG
|
||||
hm->message.len = bl + reqlen;
|
||||
hm->body.len = bl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool mg_is_chunked(struct mg_http_message *hm) {
|
||||
struct mg_str needle = mg_str_n("chunked", 7);
|
||||
struct mg_str *te = mg_http_get_header(hm, "Transfer-Encoding");
|
||||
return te != NULL && mg_strstr(*te, needle) != NULL;
|
||||
}
|
||||
|
||||
void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
struct mg_str ch = hm->chunk;
|
||||
if (mg_is_chunked(hm)) {
|
||||
ch.len += 4; // \r\n before and after the chunk
|
||||
ch.ptr -= 2;
|
||||
while (ch.ptr > hm->body.ptr && *ch.ptr != '\n') ch.ptr--, ch.len++;
|
||||
}
|
||||
{
|
||||
const char *end = &ch.ptr[ch.len];
|
||||
size_t n = end - (char *) c->recv.buf;
|
||||
if (c->recv.len > n) memmove((char *) ch.ptr, end, c->recv.len - n);
|
||||
// LOG(LL_INFO, ("DELETING CHUNK: %zu %zu %zu\n%.*s", c->recv.len, n,
|
||||
// ch.len, (int) ch.len, ch.ptr));
|
||||
}
|
||||
c->recv.len -= ch.len;
|
||||
}
|
||||
|
||||
static void http_cb(struct mg_connection *c, int ev, void *evd, void *fnd) {
|
||||
if (ev == MG_EV_READ || ev == MG_EV_CLOSE) {
|
||||
struct mg_http_message hm;
|
||||
for (;;) {
|
||||
int n = mg_http_parse((char *) c->recv.buf, c->recv.len, &hm);
|
||||
bool is_chunked = n > 0 && mg_is_chunked(&hm);
|
||||
if (ev == MG_EV_CLOSE) {
|
||||
hm.message.len = c->recv.len;
|
||||
hm.body.len = hm.message.len - (hm.body.ptr - hm.message.ptr);
|
||||
} else if (is_chunked) {
|
||||
walkchunks(c, &hm, n);
|
||||
}
|
||||
// LOG(LL_INFO,
|
||||
//("---->%d %d\n%.*s", n, is_chunked, (int) c->recv.len, c->recv.buf));
|
||||
if (n < 0 && ev == MG_EV_READ) {
|
||||
LOG(LL_ERROR, ("%lu HTTP parse error", c->id));
|
||||
c->is_closing = 1;
|
||||
break;
|
||||
} else if (n > 0 && (size_t) c->recv.len >= hm.message.len) {
|
||||
#if MG_ENABLE_HTTP_DEBUG_ENDPOINT
|
||||
snprintf(c->label, sizeof(c->label) - 1, "<-[%.*s]", (int) hm.uri.len,
|
||||
hm.uri.ptr);
|
||||
if (mg_http_match_uri(&hm, "/debug/info")) {
|
||||
struct mg_mgr *mgr = (struct mg_mgr *) fn_data;
|
||||
struct mg_connection *x;
|
||||
mg_printf(c, "%s\r\n",
|
||||
"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n");
|
||||
for (x = mgr->conns; x != NULL; x = x->next) {
|
||||
// LOG(LL_INFO, ("%p %s", x->fd, x->label));
|
||||
mg_http_printf_chunk(
|
||||
c,
|
||||
"%-4p %-12s %04d.%04d/%04d.%04d"
|
||||
" %d%d%d%d%d%d%d%d%d%d%d%d%d%d\n",
|
||||
x->fd, x->label, x->recv.len, x->recv.size, x->send.len,
|
||||
x->send.size, c->is_listening, c->is_client, c->is_accepted,
|
||||
c->is_resolving, c->is_connecting, c->is_tls, c->is_tls_hs,
|
||||
c->is_udp, c->is_websocket, c->is_hexdumping, c->is_draining,
|
||||
c->is_closing, c->is_readable, c->is_writable);
|
||||
}
|
||||
mg_http_write_chunk(c, "", 0);
|
||||
mg_iobuf_delete(&c->recv, hm.message.len);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
mg_call(c, MG_EV_HTTP_MSG, &hm);
|
||||
mg_iobuf_delete(&c->recv, hm.message.len);
|
||||
} else {
|
||||
if (n > 0 && !is_chunked) {
|
||||
hm.chunk = mg_str_n((char *) &c->recv.buf[n], c->recv.len - n);
|
||||
mg_call(c, MG_EV_HTTP_CHUNK, &hm);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
(void) fn_data;
|
||||
(void) ev_data;
|
||||
(void) fnd;
|
||||
(void) evd;
|
||||
}
|
||||
|
||||
struct mg_connection *mg_http_connect(struct mg_mgr *mgr, const char *url,
|
||||
mg_event_handler_t fn, void *fn_data) {
|
||||
struct mg_connection *c = mg_connect(mgr, url, fn, fn_data);
|
||||
if (c != NULL) c->pfn = http_cb, c->pfn_data = mgr;
|
||||
#if MG_ENABLE_HTTP_DEBUG_ENDPOINT
|
||||
snprintf(c->label, sizeof(c->label) - 1, "->%s", url);
|
||||
#endif
|
||||
if (c != NULL) c->pfn = http_cb;
|
||||
return c;
|
||||
}
|
||||
|
||||
struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url,
|
||||
mg_event_handler_t fn, void *fn_data) {
|
||||
struct mg_connection *c = mg_listen(mgr, url, fn, fn_data);
|
||||
if (c != NULL) c->pfn = http_cb, c->pfn_data = mgr;
|
||||
#if MG_ENABLE_HTTP_DEBUG_ENDPOINT
|
||||
if (c != NULL) snprintf(c->label, sizeof(c->label) - 1, "<-LSN");
|
||||
#endif
|
||||
if (c != NULL) c->pfn = http_cb;
|
||||
return c;
|
||||
}
|
||||
+5
-1
@@ -16,7 +16,9 @@ struct mg_http_message {
|
||||
struct mg_str method, uri, query, proto; // Request/response line
|
||||
struct mg_http_header headers[MG_MAX_HTTP_HEADERS]; // Headers
|
||||
struct mg_str body; // Body
|
||||
struct mg_str message; // Request line + headers + body
|
||||
struct mg_str head; // Request + headers
|
||||
struct mg_str chunk; // Chunk for chunked encoding, or partial body
|
||||
struct mg_str message; // Request + headers + body
|
||||
};
|
||||
|
||||
// Parameter for mg_http_serve_dir()
|
||||
@@ -29,6 +31,7 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *);
|
||||
int mg_http_get_request_len(const unsigned char *buf, size_t buf_len);
|
||||
void mg_http_printf_chunk(struct mg_connection *cnn, const char *fmt, ...);
|
||||
void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len);
|
||||
void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm);
|
||||
struct mg_connection *mg_http_listen(struct mg_mgr *, const char *url,
|
||||
mg_event_handler_t fn, void *fn_data);
|
||||
struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url,
|
||||
@@ -43,6 +46,7 @@ struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name);
|
||||
void mg_http_event_handler(struct mg_connection *c, int ev);
|
||||
int mg_http_get_var(const struct mg_str *, const char *name, char *, int);
|
||||
int mg_url_decode(const char *s, size_t n, char *to, size_t to_len, int form);
|
||||
int mg_url_encode(const char *s, size_t n, char *buf, size_t len);
|
||||
void mg_http_creds(struct mg_http_message *, char *user, int, char *pass, int);
|
||||
bool mg_http_match_uri(const struct mg_http_message *, const char *glob);
|
||||
int mg_http_upload(struct mg_connection *, struct mg_http_message *hm,
|
||||
|
||||
+7
-7
@@ -3,7 +3,8 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
|
||||
int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
|
||||
int ok = 1;
|
||||
if (new_size == 0) {
|
||||
free(io->buf);
|
||||
io->buf = NULL;
|
||||
@@ -18,16 +19,16 @@ void mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
|
||||
io->buf = (unsigned char *) p;
|
||||
io->size = new_size;
|
||||
} else {
|
||||
ok = 0;
|
||||
LOG(LL_ERROR,
|
||||
("%lu->%lu", (unsigned long) io->size, (unsigned long) new_size));
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
void mg_iobuf_init(struct mg_iobuf *io, size_t size) {
|
||||
io->buf = NULL;
|
||||
io->len = io->size = 0;
|
||||
if (size > 0) mg_iobuf_resize(io, size);
|
||||
int mg_iobuf_init(struct mg_iobuf *io, size_t size) {
|
||||
return mg_iobuf_resize(io, size);
|
||||
}
|
||||
|
||||
size_t mg_iobuf_append(struct mg_iobuf *io, const void *buf, size_t len,
|
||||
@@ -49,6 +50,5 @@ size_t mg_iobuf_delete(struct mg_iobuf *io, size_t len) {
|
||||
}
|
||||
|
||||
void mg_iobuf_free(struct mg_iobuf *io) {
|
||||
free(io->buf);
|
||||
mg_iobuf_init(io, 0);
|
||||
mg_iobuf_resize(io, 0);
|
||||
}
|
||||
+2
-2
@@ -7,8 +7,8 @@ struct mg_iobuf {
|
||||
size_t size, len;
|
||||
};
|
||||
|
||||
void mg_iobuf_init(struct mg_iobuf *, size_t);
|
||||
void mg_iobuf_resize(struct mg_iobuf *, size_t);
|
||||
int mg_iobuf_init(struct mg_iobuf *, size_t);
|
||||
int mg_iobuf_resize(struct mg_iobuf *, size_t);
|
||||
void mg_iobuf_free(struct mg_iobuf *);
|
||||
size_t mg_iobuf_append(struct mg_iobuf *, const void *, size_t, size_t);
|
||||
size_t mg_iobuf_delete(struct mg_iobuf *, size_t);
|
||||
+1
-2
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) 2004-2013 Sergey Lyubka
|
||||
// Copyright (c) 2013-2020 Cesanta Software Limited
|
||||
// Copyright (c) 2013-2021 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// This software is dual-licensed: you can redistribute it and/or modify
|
||||
@@ -14,4 +14,3 @@
|
||||
//
|
||||
// Alternatively, you can license this software under a commercial
|
||||
// license, as set out in <https://www.cesanta.com/license>.
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
static void mg_log_stdout(const void *buf, int len, void *userdata) {
|
||||
(void) userdata;
|
||||
fwrite(buf, 1, len, stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static const char *s_spec = "2";
|
||||
|
||||
+27
-4
@@ -176,20 +176,31 @@ int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m) {
|
||||
return MQTT_OK;
|
||||
}
|
||||
|
||||
int mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic,
|
||||
uint8_t *qos, int pos) {
|
||||
static int mg_mqtt_next_topic(struct mg_mqtt_message *msg, struct mg_str *topic,
|
||||
uint8_t *qos, int pos) {
|
||||
unsigned char *buf = (unsigned char *) msg->dgram.ptr + pos;
|
||||
int new_pos;
|
||||
if ((size_t) pos >= msg->dgram.len) return -1;
|
||||
|
||||
topic->len = buf[0] << 8 | buf[1];
|
||||
topic->ptr = (char *) buf + 2;
|
||||
new_pos = pos + 2 + topic->len + 1;
|
||||
new_pos = pos + 2 + topic->len + (qos == NULL ? 0 : 1);
|
||||
if ((size_t) new_pos > msg->dgram.len) return -1;
|
||||
*qos = buf[2 + topic->len];
|
||||
if (qos != NULL) *qos = buf[2 + topic->len];
|
||||
return new_pos;
|
||||
}
|
||||
|
||||
int mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic,
|
||||
uint8_t *qos, int pos) {
|
||||
uint8_t tmp;
|
||||
return mg_mqtt_next_topic(msg, topic, qos == NULL ? &tmp : qos, pos);
|
||||
}
|
||||
|
||||
int mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic,
|
||||
int pos) {
|
||||
return mg_mqtt_next_topic(msg, topic, NULL, pos);
|
||||
}
|
||||
|
||||
static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data,
|
||||
void *fn_data) {
|
||||
if (ev == MG_EV_READ) {
|
||||
@@ -232,6 +243,18 @@ static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data,
|
||||
(void) fn_data;
|
||||
}
|
||||
|
||||
void mg_mqtt_ping(struct mg_connection *nc) {
|
||||
mg_mqtt_send_header(nc, MQTT_CMD_PINGREQ, 0, 0);
|
||||
}
|
||||
|
||||
void mg_mqtt_pong(struct mg_connection *nc) {
|
||||
mg_mqtt_send_header(nc, MQTT_CMD_PINGRESP, 0, 0);
|
||||
}
|
||||
|
||||
void mg_mqtt_disconnect(struct mg_connection *nc) {
|
||||
mg_mqtt_send_header(nc, MQTT_CMD_DISCONNECT, 0, 0);
|
||||
}
|
||||
|
||||
struct mg_connection *mg_mqtt_connect(struct mg_mgr *mgr, const char *url,
|
||||
struct mg_mqtt_opts *opts,
|
||||
mg_event_handler_t fn, void *fn_data) {
|
||||
|
||||
@@ -55,3 +55,8 @@ void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags,
|
||||
uint32_t len);
|
||||
int mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic,
|
||||
uint8_t *qos, int pos);
|
||||
int mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic,
|
||||
int pos);
|
||||
void mg_mqtt_ping(struct mg_connection *);
|
||||
void mg_mqtt_pong(struct mg_connection *);
|
||||
void mg_mqtt_disconnect(struct mg_connection *);
|
||||
@@ -23,6 +23,7 @@ struct mg_mgr {
|
||||
struct mg_dns dns6; // DNS for IPv6
|
||||
int dnstimeout; // DNS resolve timeout in milliseconds
|
||||
unsigned long nextid; // Next connection ID
|
||||
void *userdata; // Arbitrary user data pointer
|
||||
#if MG_ARCH == MG_ARCH_FREERTOS
|
||||
SocketSet_t ss; // NOTE(lsm): referenced from socket struct
|
||||
#endif
|
||||
@@ -40,7 +41,7 @@ struct mg_connection {
|
||||
void *fn_data; // User-speficied function parameter
|
||||
mg_event_handler_t pfn; // Protocol-specific handler function
|
||||
void *pfn_data; // Protocol-specific function parameter
|
||||
char label[32]; // Arbitrary label
|
||||
char label[50]; // Arbitrary label
|
||||
void *tls; // TLS specific data
|
||||
unsigned is_listening : 1; // Listening connection
|
||||
unsigned is_client : 1; // Outbound (client) connection
|
||||
|
||||
+7
-5
@@ -135,7 +135,7 @@ static int ll_read(struct mg_connection *c, void *buf, int len, int *fail) {
|
||||
MG_SOCK_ERRNO, *fail));
|
||||
if (n > 0 && c->is_hexdumping) {
|
||||
char *s = mg_hexdump(buf, n);
|
||||
// LOG(LL_INFO, ("\n-- %lu %s %s %d\n%s--", c->id, c->label, "<-", n, s));
|
||||
LOG(LL_INFO, ("\n-- %lu %s %s %d\n%s--", c->id, c->label, "<-", n, s));
|
||||
free(s);
|
||||
}
|
||||
return n;
|
||||
@@ -151,7 +151,7 @@ static int ll_write(struct mg_connection *c, const void *buf, int len,
|
||||
MG_SOCK_ERRNO));
|
||||
if (n > 0 && c->is_hexdumping) {
|
||||
char *s = mg_hexdump(buf, len);
|
||||
// LOG(LL_INFO, ("\n-- %lu %s %s %d\n%s--", c->id, c->label, "->", len, s));
|
||||
LOG(LL_INFO, ("\n-- %lu %s %s %d\n%s--", c->id, c->label, "->", len, s));
|
||||
free(s);
|
||||
}
|
||||
return n;
|
||||
@@ -161,6 +161,7 @@ int mg_send(struct mg_connection *c, const void *buf, size_t len) {
|
||||
int fail, n = c->is_udp
|
||||
? ll_write(c, buf, (SOCKET) len, &fail)
|
||||
: (int) mg_iobuf_append(&c->send, buf, len, MG_IO_SIZE);
|
||||
if (len > 0 && n == 0) fail = 1;
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -235,8 +236,9 @@ static void read_conn(struct mg_connection *c,
|
||||
// NOTE(lsm): do only one iteration of reads, cause some systems
|
||||
// (e.g. FreeRTOS stack) return 0 instead of -1/EWOULDBLOCK when no data
|
||||
if (c->recv.size - c->recv.len < MG_IO_SIZE &&
|
||||
c->recv.size < MG_MAX_RECV_BUF_SIZE) {
|
||||
mg_iobuf_resize(&c->recv, c->recv.size + MG_IO_SIZE);
|
||||
c->recv.size < MG_MAX_RECV_BUF_SIZE &&
|
||||
!mg_iobuf_resize(&c->recv, c->recv.size + MG_IO_SIZE)) {
|
||||
c->is_closing = 1;
|
||||
}
|
||||
buf = c->recv.buf + c->recv.len;
|
||||
len = (int) (c->recv.size - c->recv.len);
|
||||
@@ -301,7 +303,7 @@ static void setsockopts(struct mg_connection *c) {
|
||||
int idle = 60;
|
||||
setsockopt(FD(c), IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle));
|
||||
#endif
|
||||
#ifndef _WIN32
|
||||
#if !defined(_WIN32) && !defined(__QNX__)
|
||||
{
|
||||
int cnt = 3, intvl = 20;
|
||||
setsockopt(FD(c), IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt));
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "log.h"
|
||||
#include "ssi.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifndef MG_MAX_SSI_DEPTH
|
||||
#define MG_MAX_SSI_DEPTH 5
|
||||
@@ -8,7 +9,7 @@
|
||||
#if MG_ENABLE_SSI
|
||||
static char *mg_ssi(const char *path, const char *root, int depth) {
|
||||
struct mg_iobuf b = {NULL, 0, 0};
|
||||
FILE *fp = fopen(path, "rb");
|
||||
FILE *fp = mg_fopen(path, "rb");
|
||||
if (fp != NULL) {
|
||||
char buf[BUFSIZ], arg[sizeof(buf)];
|
||||
int ch, intag = 0;
|
||||
@@ -17,7 +18,7 @@ static char *mg_ssi(const char *path, const char *root, int depth) {
|
||||
if (intag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') {
|
||||
buf[len++] = ch & 0xff;
|
||||
if (sscanf(buf, "<!--#include file=\"%[^\"]", arg)) {
|
||||
char tmp[PATH_MAX], *p = (char *) path + strlen(path), *data;
|
||||
char tmp[MG_PATH_MAX], *p = (char *) path + strlen(path), *data;
|
||||
while (p > path && p[-1] != MG_DIRSEP && p[-1] != '/') p--;
|
||||
snprintf(tmp, sizeof(tmp), "%.*s%s", (int) (p - path), path, arg);
|
||||
if (depth < MG_MAX_SSI_DEPTH &&
|
||||
@@ -28,7 +29,7 @@ static char *mg_ssi(const char *path, const char *root, int depth) {
|
||||
LOG(LL_ERROR, ("%s: file=%s error or too deep", path, arg));
|
||||
}
|
||||
} else if (sscanf(buf, "<!--#include virtual=\"%[^\"]", arg)) {
|
||||
char tmp[PATH_MAX], *data;
|
||||
char tmp[MG_PATH_MAX], *data;
|
||||
snprintf(tmp, sizeof(tmp), "%s%s", root, arg);
|
||||
if (depth < MG_MAX_SSI_DEPTH &&
|
||||
(data = mg_ssi(tmp, root, depth + 1)) != NULL) {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <mbedtls/debug.h>
|
||||
#include <mbedtls/ssl.h>
|
||||
|
||||
// Different versions have those in different files, so declare here
|
||||
#ifndef EXTERN_C
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN_C extern "C"
|
||||
@@ -17,6 +16,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Different versions have those in different files, so declare here
|
||||
EXTERN_C int mbedtls_net_recv(void *, unsigned char *, size_t);
|
||||
EXTERN_C int mbedtls_net_send(void *, const unsigned char *, size_t);
|
||||
|
||||
@@ -64,12 +64,14 @@ static void debug_cb(void *c, int lev, const char *s, int n, const char *s2) {
|
||||
int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
|
||||
struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
|
||||
int rc = 0;
|
||||
const char *ca = opts->ca == NULL ? "-"
|
||||
: opts->ca[0] == '-' ? "(emb)"
|
||||
: opts->ca;
|
||||
if (tls == NULL) {
|
||||
mg_error(c, "TLS OOM");
|
||||
goto fail;
|
||||
}
|
||||
LOG(LL_DEBUG, ("%lu Setting TLS, CA: %s, cert: %s, key: %s", c->id,
|
||||
opts->ca == NULL ? "null" : opts->ca,
|
||||
LOG(LL_DEBUG, ("%lu Setting TLS, CA: %s, cert: %s, key: %s", c->id, ca,
|
||||
opts->cert == NULL ? "null" : opts->cert,
|
||||
opts->certkey == NULL ? "null" : opts->certkey));
|
||||
mbedtls_ssl_init(&tls->ssl);
|
||||
@@ -94,17 +96,26 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
|
||||
tls->cafile = strdup(opts->ca);
|
||||
rc = mbedtls_ssl_conf_ca_chain_file(&tls->conf, tls->cafile, NULL);
|
||||
if (rc != 0) {
|
||||
mg_error(c, "parse on-disk chain(%s) err %#x", opts->ca, -rc);
|
||||
mg_error(c, "parse on-disk chain(%s) err %#x", ca, -rc);
|
||||
goto fail;
|
||||
}
|
||||
#else
|
||||
mbedtls_x509_crt_init(&tls->ca);
|
||||
if ((rc = mbedtls_x509_crt_parse_file(&tls->ca, opts->ca)) != 0) {
|
||||
mg_error(c, "parse(%s) err %#x", opts->ca, -rc);
|
||||
rc = opts->ca[0] == '-'
|
||||
? mbedtls_x509_crt_parse(&tls->ca, (uint8_t *) opts->ca,
|
||||
strlen(opts->ca) + 1)
|
||||
: mbedtls_x509_crt_parse_file(&tls->ca, opts->ca);
|
||||
if (rc != 0) {
|
||||
mg_error(c, "parse(%s) err %#x", ca, -rc);
|
||||
goto fail;
|
||||
}
|
||||
mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, NULL);
|
||||
#endif
|
||||
if (opts->srvname.len > 0) {
|
||||
char buf[opts->srvname.len + 1];
|
||||
sprintf(buf, "%.*s", (int) opts->srvname.len, opts->srvname.ptr);
|
||||
mbedtls_ssl_set_hostname(&tls->ssl, buf);
|
||||
}
|
||||
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
}
|
||||
if (opts->cert != NULL && opts->cert[0] != '\0') {
|
||||
@@ -172,13 +183,8 @@ int mg_tls_free(struct mg_connection *c) {
|
||||
}
|
||||
#elif MG_ENABLE_OPENSSL ///////////////////////////////////////// OPENSSL
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ssl.h>
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1700
|
||||
typedef long ssize_t;
|
||||
#endif
|
||||
|
||||
extern void ERR_clear_error(void); // Defined in openssl/err.h, but
|
||||
extern void ERR_print_errors_fp(FILE *fp); // declare here for krypton
|
||||
|
||||
struct mg_tls {
|
||||
SSL_CTX *ctx;
|
||||
@@ -238,9 +244,9 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
|
||||
SSL_set_options(tls->ssl, SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||
#endif
|
||||
|
||||
SSL_set_verify(tls->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
||||
0);
|
||||
if (opts->ca != NULL && opts->ca[0] != '\0') {
|
||||
SSL_set_verify(tls->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
||||
NULL);
|
||||
if ((rc = SSL_CTX_load_verify_locations(tls->ctx, opts->ca, NULL)) != 1) {
|
||||
mg_error(c, "parse(%s): err %d", opts->ca, mg_tls_err(tls, rc));
|
||||
goto fail;
|
||||
@@ -269,7 +275,11 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
|
||||
}
|
||||
}
|
||||
if (opts->ciphers != NULL) SSL_set_cipher_list(tls->ssl, opts->ciphers);
|
||||
if (opts->srvname != NULL) SSL_set_tlsext_host_name(tls->ssl, opts->srvname);
|
||||
if (opts->srvname.len > 0) {
|
||||
char buf[opts->srvname.len + 1];
|
||||
sprintf(buf, "%.*s", (int) opts->srvname.len, opts->srvname.ptr);
|
||||
SSL_set_tlsext_host_name(tls->ssl, buf);
|
||||
}
|
||||
c->tls = tls;
|
||||
c->is_tls = 1;
|
||||
c->is_tls_hs = 1;
|
||||
@@ -288,7 +298,7 @@ fail:
|
||||
int mg_tls_handshake(struct mg_connection *c) {
|
||||
struct mg_tls *tls = (struct mg_tls *) c->tls;
|
||||
int rc;
|
||||
SSL_set_fd(tls->ssl, (ssize_t) c->fd);
|
||||
SSL_set_fd(tls->ssl, (long) c->fd);
|
||||
rc = c->is_client ? SSL_connect(tls->ssl) : SSL_accept(tls->ssl);
|
||||
if (rc == 1) {
|
||||
LOG(LL_DEBUG, ("%lu success", c->id));
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
#include "net.h"
|
||||
|
||||
struct mg_tls_opts {
|
||||
const char *ca; // CA certificate file. For both listeners and clients
|
||||
const char *cert; // Certificate
|
||||
const char *certkey; // Certificate key
|
||||
const char *ciphers; // Cipher list
|
||||
const char *srvname; // If not NULL, enables server name verification
|
||||
const char *ca; // CA certificate file. For both listeners and clients
|
||||
const char *cert; // Certificate
|
||||
const char *certkey; // Certificate key
|
||||
const char *ciphers; // Cipher list
|
||||
struct mg_str srvname; // If not empty, enables server name verification
|
||||
};
|
||||
|
||||
int mg_tls_init(struct mg_connection *, struct mg_tls_opts *);
|
||||
|
||||
+76
-21
@@ -1,20 +1,43 @@
|
||||
#include "config.h"
|
||||
#include "util.h"
|
||||
|
||||
size_t mg_file_size(const char *path) {
|
||||
#if MG_ENABLE_FS
|
||||
int mg_stat(const char *path, mg_stat_t *st) {
|
||||
#ifdef _WIN32
|
||||
wchar_t tmp[MG_PATH_MAX];
|
||||
MultiByteToWideChar(CP_UTF8, 0, path, -1, tmp, sizeof(tmp) / sizeof(tmp[0]));
|
||||
return _wstati64(tmp, st);
|
||||
#else
|
||||
return stat(path, st);
|
||||
#endif
|
||||
}
|
||||
|
||||
FILE *mg_fopen(const char *path, const char *mode) {
|
||||
#ifdef _WIN32
|
||||
wchar_t b1[MG_PATH_MAX], b2[10];
|
||||
MultiByteToWideChar(CP_UTF8, 0, path, -1, b1, sizeof(b1) / sizeof(b1[0]));
|
||||
MultiByteToWideChar(CP_UTF8, 0, mode, -1, b2, sizeof(b2) / sizeof(b2[0]));
|
||||
return _wfopen(b1, b2);
|
||||
#else
|
||||
return fopen(path, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t mg_file_size(const char *path) {
|
||||
#if MG_ARCH == MG_ARCH_FREERTOS
|
||||
struct FF_STAT st;
|
||||
return ff_stat(path, &st) == 0 ? st.st_size : 0;
|
||||
#else
|
||||
struct stat st;
|
||||
return stat(path, &st) == 0 ? st.st_size : 0;
|
||||
mg_stat_t st;
|
||||
return mg_stat(path, &st) == 0 ? st.st_size : 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
char *mg_file_read(const char *path) {
|
||||
FILE *fp;
|
||||
char *data = NULL;
|
||||
size_t size = mg_file_size(path);
|
||||
if ((fp = fopen(path, "rb")) != NULL) {
|
||||
size_t size = (size_t) mg_file_size(path);
|
||||
if ((fp = mg_fopen(path, "rb")) != NULL) {
|
||||
data = (char *) malloc(size + 1);
|
||||
if (data != NULL) {
|
||||
if (fread(data, 1, size, fp) != size) {
|
||||
@@ -29,32 +52,54 @@ char *mg_file_read(const char *path) {
|
||||
return data;
|
||||
}
|
||||
|
||||
int mg_file_write(const char *path, const char *fmt, ...) {
|
||||
char tmp[100];
|
||||
int written = 0;
|
||||
bool mg_file_write(const char *path, const void *buf, size_t len) {
|
||||
bool result = false;
|
||||
FILE *fp;
|
||||
char tmp[MG_PATH_MAX];
|
||||
snprintf(tmp, sizeof(tmp), "%s.%d", path, rand());
|
||||
fp = fopen(tmp, "wb");
|
||||
fp = mg_fopen(tmp, "wb");
|
||||
if (fp != NULL) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
written = vfprintf(fp, fmt, ap);
|
||||
va_end(ap);
|
||||
result = fwrite(buf, 1, len, fp) == len;
|
||||
fclose(fp);
|
||||
remove(path);
|
||||
rename(tmp, path);
|
||||
if (result) {
|
||||
remove(path);
|
||||
rename(tmp, path);
|
||||
} else {
|
||||
remove(tmp);
|
||||
}
|
||||
}
|
||||
return written;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool mg_file_printf(const char *path, const char *fmt, ...) {
|
||||
char tmp[256], *buf = tmp;
|
||||
bool result;
|
||||
size_t len;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
len = mg_vasprintf(&buf, sizeof(tmp), fmt, ap);
|
||||
va_end(ap);
|
||||
result = mg_file_write(path, buf, len);
|
||||
if (buf != tmp) free(buf);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
void mg_random(void *buf, size_t len) {
|
||||
FILE *fp = fopen("/dev/urandom", "rb");
|
||||
size_t i, n = 0;
|
||||
if (fp != NULL) n = fread(buf, 1, len, fp);
|
||||
if (fp == NULL || n <= 0) {
|
||||
bool done = false;
|
||||
#if MG_ENABLE_FS
|
||||
FILE *fp = mg_fopen("/dev/urandom", "rb");
|
||||
if (fp != NULL) {
|
||||
fread(buf, 1, len, fp);
|
||||
fclose(fp);
|
||||
done = true;
|
||||
}
|
||||
#endif
|
||||
if (!done) {
|
||||
// Fallback to a pseudo random gen
|
||||
size_t i;
|
||||
for (i = 0; i < len; i++) ((unsigned char *) buf)[i] = rand() % 0xff;
|
||||
}
|
||||
if (fp != NULL) fclose(fp);
|
||||
}
|
||||
|
||||
bool mg_globmatch(const char *s1, int n1, const char *s2, int n2) {
|
||||
@@ -228,6 +273,16 @@ int64_t mg_to64(struct mg_str str) {
|
||||
return result * neg;
|
||||
}
|
||||
|
||||
uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len) {
|
||||
int i;
|
||||
crc = ~crc;
|
||||
while (len--) {
|
||||
crc ^= *(unsigned char *) buf++;
|
||||
for (i = 0; i < 8; i++) crc = crc & 1 ? (crc >> 1) ^ 0xedb88320 : crc >> 1;
|
||||
}
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
double mg_time(void) {
|
||||
#if MG_ARCH == MG_ARCH_WIN32
|
||||
SYSTEMTIME sysnow;
|
||||
|
||||
+15
-3
@@ -4,13 +4,15 @@
|
||||
#include "str.h"
|
||||
|
||||
char *mg_file_read(const char *path);
|
||||
size_t mg_file_size(const char *path);
|
||||
int mg_file_write(const char *path, const char *fmt, ...);
|
||||
int64_t mg_file_size(const char *path);
|
||||
bool mg_file_write(const char *path, const void *buf, size_t len);
|
||||
bool mg_file_printf(const char *path, const char *fmt, ...);
|
||||
void mg_random(void *buf, size_t len);
|
||||
bool mg_globmatch(const char *pattern, int plen, const char *s, int n);
|
||||
bool mg_next_comma_entry(struct mg_str *s, struct mg_str *k, struct mg_str *v);
|
||||
uint16_t mg_ntohs(uint16_t net);
|
||||
uint32_t mg_ntohl(uint32_t net);
|
||||
uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len);
|
||||
char *mg_hexdump(const void *buf, size_t len);
|
||||
char *mg_hex(const void *buf, int len, char *dst);
|
||||
void mg_unhex(const char *buf, int len, unsigned char *to);
|
||||
@@ -22,6 +24,16 @@ double mg_time(void);
|
||||
unsigned long mg_millis(void);
|
||||
void mg_usleep(unsigned long usecs);
|
||||
|
||||
#if MG_ENABLE_FS
|
||||
#ifdef _WIN32
|
||||
typedef struct _stati64 mg_stat_t;
|
||||
#else
|
||||
typedef struct stat mg_stat_t;
|
||||
#endif
|
||||
int mg_stat(const char *path, mg_stat_t *);
|
||||
FILE *mg_fopen(const char *fp, const char *mode);
|
||||
#endif
|
||||
|
||||
#define mg_htons(x) mg_ntohs(x)
|
||||
#define mg_htonl(x) mg_ntohl(x)
|
||||
|
||||
@@ -32,7 +44,7 @@ void mg_usleep(unsigned long usecs);
|
||||
#if !defined(WEAK)
|
||||
#if (defined(__GNUC__) || defined(__clang__) || \
|
||||
defined(__TI_COMPILER_VERSION__)) && \
|
||||
!defined(_WIN32)
|
||||
!defined(_WIN32) && !defined(__CYGWIN__)
|
||||
#define WEAK __attribute__((weak))
|
||||
#else
|
||||
#define WEAK
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
#pragma once
|
||||
#define MG_VERSION "7.1"
|
||||
#define MG_VERSION "7.2"
|
||||
+165
-9
@@ -413,12 +413,15 @@ static int fetch(struct mg_mgr *mgr, char *buf, const char *url,
|
||||
ASSERT(c != NULL);
|
||||
if (mg_url_is_ssl(url)) {
|
||||
struct mg_tls_opts opts;
|
||||
struct mg_str host = mg_url_host(url);
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.ca = "./test/data/ca.pem";
|
||||
if (strstr(url, "127.0.0.1") != NULL) {
|
||||
// Local connection, use self-signed certificates
|
||||
opts.ca = "./test/data/ss_ca.pem";
|
||||
opts.cert = "./test/data/ss_client.pem";
|
||||
} else {
|
||||
opts.srvname = host;
|
||||
}
|
||||
mg_tls_init(c, &opts);
|
||||
// c->is_hexdumping = 1;
|
||||
@@ -451,7 +454,7 @@ static void test_http_server(void) {
|
||||
struct mg_mgr mgr;
|
||||
const char *url = "http://127.0.0.1:12346";
|
||||
char buf[FETCH_BUF_SIZE];
|
||||
struct stat st;
|
||||
mg_stat_t st;
|
||||
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, url, eh1, NULL);
|
||||
@@ -463,9 +466,9 @@ static void test_http_server(void) {
|
||||
ASSERT(cmpbody(buf, "hello\n") == 0);
|
||||
|
||||
{
|
||||
extern char *mg_http_etag(char *, size_t, struct stat *);
|
||||
extern char *mg_http_etag(char *, size_t, mg_stat_t *);
|
||||
char etag[100];
|
||||
ASSERT(stat("./test/data/a.txt", &st) == 0);
|
||||
ASSERT(mg_stat("./test/data/a.txt", &st) == 0);
|
||||
ASSERT(mg_http_etag(etag, sizeof(etag), &st) == etag);
|
||||
ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\nIf-None-Match: %s\n\n",
|
||||
etag) == 304);
|
||||
@@ -493,7 +496,7 @@ static void test_http_server(void) {
|
||||
|
||||
ASSERT(fetch(&mgr, buf, url, "GET /badroot HTTP/1.0\r\n\n") == 400);
|
||||
#if MG_ARCH == MG_ARCH_WIN32
|
||||
ASSERT(cmpbody(buf, "Bad web root [Z:\\BAAADDD!]\n") == 0);
|
||||
ASSERT(cmpbody(buf, "Invalid web root [Z:\\BAAADDD!]\n") == 0);
|
||||
#else
|
||||
// LOG(LL_INFO, ("--> [%s]", buf));
|
||||
ASSERT(cmpbody(buf, "Bad web root [/BAAADDD!]\n") == 0);
|
||||
@@ -571,8 +574,12 @@ static void test_http_server(void) {
|
||||
"POST /upload?name=uploaded.txt HTTP/1.0\r\n"
|
||||
"Content-Length: 5\r\n"
|
||||
"\r\nhello") == 200);
|
||||
ASSERT(fetch(&mgr, buf, url,
|
||||
"POST /upload?name=uploaded.txt&offset=5 HTTP/1.0\r\n"
|
||||
"Content-Length: 6\r\n"
|
||||
"\r\n\nworld") == 200);
|
||||
ASSERT((p = mg_file_read("uploaded.txt")) != NULL);
|
||||
ASSERT(strcmp(p, "hello") == 0);
|
||||
ASSERT(strcmp(p, "hello\nworld") == 0);
|
||||
free(p);
|
||||
remove("uploaded.txt");
|
||||
}
|
||||
@@ -841,6 +848,16 @@ static void test_http_parse(void) {
|
||||
ASSERT(mg_strcmp(hm.uri, mg_str("/foo")) == 0);
|
||||
ASSERT(mg_strcmp(hm.query, mg_str("bar=baz")) == 0);
|
||||
}
|
||||
|
||||
{
|
||||
struct mg_http_message hm;
|
||||
const char *req = "a b c\n\n";
|
||||
ASSERT(mg_http_parse(req, strlen(req), &hm) == (int) strlen(req));
|
||||
req = "a b\nc\n\n";
|
||||
ASSERT(mg_http_parse(req, strlen(req), &hm) < 0);
|
||||
req = "a\nb\nc\n\n";
|
||||
ASSERT(mg_http_parse(req, strlen(req), &hm) < 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_http_range(void) {
|
||||
@@ -853,7 +870,8 @@ static void test_http_range(void) {
|
||||
mg_http_listen(&mgr, url, eh1, NULL);
|
||||
|
||||
ASSERT(fetch(&mgr, buf, url, "GET /range.txt HTTP/1.0\n\n") == 200);
|
||||
mg_http_parse(buf, strlen(buf), &hm);
|
||||
ASSERT(mg_http_parse(buf, strlen(buf), &hm) > 0);
|
||||
LOG(LL_INFO, ("----%d\n[%s]", (int) hm.body.len, buf));
|
||||
ASSERT(hm.body.len == 312);
|
||||
// ASSERT(strlen(buf) == 312);
|
||||
|
||||
@@ -1045,12 +1063,16 @@ static void test_dns(void) {
|
||||
}
|
||||
|
||||
static void test_util(void) {
|
||||
char buf[100], *s = mg_hexdump("abc", 3);
|
||||
char buf[100], *s = mg_hexdump("abc", 3), *p;
|
||||
struct mg_addr a;
|
||||
ASSERT(s != NULL);
|
||||
free(s);
|
||||
memset(&a, 0, sizeof(a));
|
||||
ASSERT(mg_file_write("data.txt", "%s", "hi") == 2);
|
||||
ASSERT(mg_file_printf("data.txt", "%s", "hi") == true);
|
||||
ASSERT((p = mg_file_read("data.txt")) != NULL);
|
||||
ASSERT(strcmp(p, "hi") == 0);
|
||||
free(p);
|
||||
remove("data.txt");
|
||||
ASSERT(mg_aton(mg_str("0"), &a) == false);
|
||||
ASSERT(mg_aton(mg_str("0.0.0."), &a) == false);
|
||||
ASSERT(mg_aton(mg_str("0.0.0.256"), &a) == false);
|
||||
@@ -1102,10 +1124,145 @@ static void test_util(void) {
|
||||
ASSERT(strcmp(mg_hex("abc", 3, buf), "616263") == 0);
|
||||
ASSERT(mg_url_decode("a=%", 3, buf, sizeof(buf), 0) < 0);
|
||||
ASSERT(mg_url_decode("&&&a=%", 6, buf, sizeof(buf), 0) < 0);
|
||||
|
||||
{
|
||||
char buf[100];
|
||||
int n;
|
||||
ASSERT((n = mg_url_encode("", 0, buf, sizeof(buf))) == 0);
|
||||
ASSERT((n = mg_url_encode("a", 1, buf, 0)) == 0);
|
||||
ASSERT((n = mg_url_encode("a", 1, buf, sizeof(buf))) == 1);
|
||||
ASSERT(strncmp(buf, "a", n) == 0);
|
||||
ASSERT((n = mg_url_encode("._-~", 4, buf, sizeof(buf))) == 4);
|
||||
ASSERT(strncmp(buf, "._-~", n) == 0);
|
||||
ASSERT((n = mg_url_encode("a@%>", 4, buf, sizeof(buf))) == 10);
|
||||
ASSERT(strncmp(buf, "a%40%25%3e", n) == 0);
|
||||
ASSERT((n = mg_url_encode("a@b.c", 5, buf, sizeof(buf))) == 7);
|
||||
ASSERT(strncmp(buf, "a%40b.c", n) == 0);
|
||||
}
|
||||
|
||||
{
|
||||
char buf[100], *s = buf;
|
||||
mg_asprintf(&s, sizeof(buf), "%s", "%3d", 123);
|
||||
ASSERT(s == buf);
|
||||
ASSERT(strcmp(buf, "%3d") == 0);
|
||||
mg_asprintf(&s, sizeof(buf), "%.*s", 7, "a%40b.c");
|
||||
ASSERT(s == buf);
|
||||
ASSERT(strcmp(buf, "a%40b.c") == 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_crc32(void) {
|
||||
// echo -n aaa | cksum -o3
|
||||
ASSERT(mg_crc32(0, 0, 0) == 0);
|
||||
ASSERT(mg_crc32(0, "a", 1) == 3904355907);
|
||||
ASSERT(mg_crc32(0, "abc", 3) == 891568578);
|
||||
ASSERT(mg_crc32(mg_crc32(0, "ab", 2), "c", 1) == 891568578);
|
||||
}
|
||||
|
||||
// Streaming server event handler.
|
||||
// Send one chunk immediately, then drain, then send two chunks in one go
|
||||
static void eh2(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||
mg_http_printf_chunk(c, "chunk 0");
|
||||
c->label[0] = 1;
|
||||
} else if (ev == MG_EV_POLL) {
|
||||
if (c->label[0] > 0 && c->send.len == 0) c->label[0]++;
|
||||
if (c->label[0] > 10 && c->label[0] != 'x') {
|
||||
mg_http_printf_chunk(c, "chunk 1");
|
||||
mg_http_printf_chunk(c, "chunk 2");
|
||||
mg_http_printf_chunk(c, "");
|
||||
c->label[0] = 'x';
|
||||
}
|
||||
}
|
||||
(void) ev_data;
|
||||
(void) fn_data;
|
||||
}
|
||||
|
||||
// Non-streaming client event handler. Make sure we've got full body
|
||||
static void eh3(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_CONNECT) {
|
||||
mg_printf(c, "GET / HTTP/1.0\n\n");
|
||||
} else if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
// LOG(LL_INFO, ("----> [%.*s]", (int) hm->body.len, hm->body.ptr));
|
||||
c->is_closing = 1;
|
||||
*(uint32_t *) fn_data = mg_crc32(0, hm->body.ptr, hm->body.len);
|
||||
}
|
||||
}
|
||||
|
||||
// Streaming client event handler. Make sure we've got all chunks
|
||||
static void eh4(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_CONNECT) {
|
||||
mg_printf(c, "GET / HTTP/1.0\n\n");
|
||||
} else if (ev == MG_EV_HTTP_CHUNK) {
|
||||
uint32_t *crc = (uint32_t *) c->label;
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
*crc = mg_crc32(*crc, hm->chunk.ptr, hm->chunk.len);
|
||||
} else if (ev == MG_EV_HTTP_MSG) {
|
||||
uint32_t *crc = (uint32_t *) c->label;
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
// LOG(LL_INFO, ("MSG [%.*s]", (int) hm->body.len, hm->body.ptr));
|
||||
c->is_closing = 1;
|
||||
*(int *) fn_data = mg_crc32(*crc, hm->body.ptr, hm->body.len);
|
||||
}
|
||||
(void) ev_data;
|
||||
}
|
||||
|
||||
// Streaming client event handler. Delete chunks as they arrive
|
||||
static void eh5(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_CONNECT) {
|
||||
mg_printf(c, "GET / HTTP/1.0\n\n");
|
||||
} else if (ev == MG_EV_HTTP_CHUNK) {
|
||||
uint32_t *crc = (uint32_t *) c->label;
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
*crc = mg_crc32(*crc, hm->chunk.ptr, hm->chunk.len);
|
||||
// LOG(LL_INFO, ("CHUNK [%.*s]", (int) hm->chunk.len, hm->chunk.ptr));
|
||||
mg_http_delete_chunk(c, hm);
|
||||
} else if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
uint32_t *crc = (uint32_t *) c->label;
|
||||
c->is_closing = 1;
|
||||
*(int *) fn_data = mg_crc32(*crc, hm->body.ptr, hm->body.len);
|
||||
// LOG(LL_INFO, ("MSG [%.*s]", (int) hm->body.len, hm->body.ptr));
|
||||
}
|
||||
(void) ev_data;
|
||||
}
|
||||
|
||||
static void test_http_chunked(void) {
|
||||
struct mg_mgr mgr;
|
||||
const char *data, *url = "http://127.0.0.1:12344";
|
||||
uint32_t i, done = 0;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, url, eh2, NULL);
|
||||
|
||||
mg_http_connect(&mgr, url, eh3, &done);
|
||||
for (i = 0; i < 50 && done == 0; i++) mg_mgr_poll(&mgr, 1);
|
||||
ASSERT(i < 50);
|
||||
data = "chunk 0chunk 1chunk 2";
|
||||
ASSERT(done == mg_crc32(0, data, strlen(data)));
|
||||
|
||||
done = 0;
|
||||
mg_http_connect(&mgr, url, eh4, &done);
|
||||
for (i = 0; i < 50 && done == 0; i++) mg_mgr_poll(&mgr, 1);
|
||||
data = "chunk 0chunk 0chunk 1chunk 2chunk 0chunk 1chunk 2";
|
||||
ASSERT(done == mg_crc32(0, data, strlen(data)));
|
||||
|
||||
done = 0;
|
||||
mg_http_connect(&mgr, url, eh5, &done);
|
||||
for (i = 0; i < 50 && done == 0; i++) mg_mgr_poll(&mgr, 1);
|
||||
data = "chunk 0chunk 1chunk 2";
|
||||
ASSERT(done == mg_crc32(0, data, strlen(data)));
|
||||
|
||||
mg_mgr_free(&mgr);
|
||||
ASSERT(mgr.conns == NULL);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
mg_log_set("3");
|
||||
test_crc32();
|
||||
test_http_chunked();
|
||||
test_http_parse();
|
||||
test_util();
|
||||
test_sntp();
|
||||
test_dns();
|
||||
@@ -1120,7 +1277,6 @@ int main(void) {
|
||||
test_http_get_var();
|
||||
test_tls();
|
||||
test_ws();
|
||||
test_http_parse();
|
||||
test_http_server();
|
||||
test_http_client();
|
||||
test_http_no_content_length();
|
||||
|
||||
Reference in new issue
Block a user