Compare commits

..
45 Commits
Author SHA1 Message Date
cpq 452bcc68a4 Add mg_mqtt_next_unsub() signature 2021-03-09 11:29:53 +00:00
cpq 829827d46f Add mg_mqtt_next_unsub 2021-03-09 09:54:02 +00:00
cpq ff9d0e462e Tiny refactor in walkchunks() 2021-03-09 08:22:52 +00:00
cpq e84ea91a4a Process chunked body before sending MG_EV_HTTP_MSG 2021-03-09 08:21:29 +00:00
cpq 2dcb10ef36 Less verbose test 2021-03-08 15:45:09 +00:00
cpq 99fa7f0851 2020 -> 2021 2021-03-08 15:44:57 +00:00
cpq 1b5cc341a5 Add streaming client support, MG_EV_HTTP_CHUNK 2021-03-08 15:41:16 +00:00
cpq d50dc288cd Add mg_crc32 2021-03-08 15:40:39 +00:00
cpq 060bb29cdc Restore mg_mqtt_{ping,pong,disconnect} 2021-03-07 12:21:59 +00:00
cpq 366426e8bb Avoid extra allocation for static HTTP handling 2021-03-07 11:56:20 +00:00
cpq e710df4c80 Define WEAK to nothing on Cygwin 2021-03-04 14:25:50 +00:00
cpq 79e5841483 Fix QNX build 2021-03-04 11:09:57 +00:00
cpq 374ab4ecf0 Add struct mg_mgr::userdata 2021-02-28 16:40:27 +00:00
cpq 56980be48c Do not reveal full root dir path 2021-02-17 16:07:18 +00:00
cpq 602c5c0866 Refactor mg_url_encode 2021-02-15 14:42:55 +00:00
cpq 7ce5009de1 Remove reduntant code 2021-02-15 14:42:22 +00:00
cpq 51e3a1304b Fix TLS build 2021-02-13 10:45:27 +00:00
cpq d5a1d5a5e8 Stricter realpath checks 2021-02-11 15:03:22 +00:00
cpq ae5f6c0920 Increase conn label size 32 -> 50 2021-02-10 11:09:13 +00:00
cpq 0a9303bb07 Stricter mg_http_parse() 2021-02-09 21:16:33 +00:00
cpq 42bc7b1f47 Add "struct mg_http_message::head" attr 2021-02-09 13:27:17 +00:00
cpq 4844ed60bd Remove fflush in logging 2021-02-09 00:16:13 +00:00
cpq 41f5daeb47 Fix mg_random 2021-02-08 19:43:01 +00:00
cpq a3f8f33d50 Allow mbedtls CA being inline PEM 2021-02-08 17:50:00 +00:00
cpq fd8db5c53a Better unicode handling on win32 2021-02-07 22:43:49 +00:00
cpq a2f027e798 Change mws binary link 2021-02-07 14:51:37 +00:00
novlean dad5c8fe87 Update README.md 2021-02-05 16:56:06 +00:00
novlean 98783a41ba Update README.md 2021-02-05 16:55:26 +00:00
cpq 1517d2985a Update README 2021-02-04 10:40:33 +00:00
Sergey Lyubka acc0564957 Merge pull request #1213 from csimons/drainig
README.md: fix typo: is_drainig -> is_draining
2021-02-03 08:30:55 +00:00
Christopher Simons 421bc126b5 README.md: fix typo: is_drainig -> is_draining 2021-02-02 22:17:15 -05:00
cpq ed1a98c381 Remove debug logs 2021-02-03 02:19:17 +00:00
cpq 457d76b049 Fix #1211 - adjust ESP32 example to serve FS 2021-02-03 02:13:05 +00:00
cpq 6827972f71 Fix #1210 - on win32, open upload file in binary mode 2021-02-02 08:43:56 +00:00
cpq 7eb998891e Show served dir in the start message 2021-02-01 00:02:33 +00:00
cpq 582fde5c6e Fix #1209 2021-01-31 19:54:42 +00:00
cpq d327ee9834 Improve SNI 2021-01-30 13:03:11 +00:00
cpq 31cf6f8969 https://localhost -> http://0.0.0.0 2021-01-29 13:18:34 +00:00
cpq 86b1053678 Add error check for iobuf allocation 2021-01-29 12:32:34 +00:00
cpq 6678e36278 Use openssl/ssl.h 2021-01-28 08:45:24 +00:00
cpq 5118355732 Use 64bit file ops even on 32bit systems 2021-01-26 17:43:31 +00:00
cpq 5b4b7f7dc5 Fix test 2021-01-26 17:01:43 +00:00
cpq 7614a8101f Wrap util funcs that use FILE into MG_ENABLE_FS 2021-01-26 16:34:42 +00:00
cpq 3c851bcfc3 mg_file_write -> mg_file_printf 2021-01-26 16:30:44 +00:00
cpq 01691dafa0 Released 7.1, move HEAD to 7.2 2021-01-26 13:07:42 +00:00
42 changed files with 1863 additions and 604 deletions

No files matched your search

+1 -1
View File
@@ -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))
+8 -7
View File
@@ -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
View File
@@ -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`.
+1 -1
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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
}
+5
View File
@@ -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,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x6000
3 phy_init data phy 0xf000 0x1000
4 storage data spiffs 0x10000 0x10000
5 factory app factory 0x100000 1M
+3
View File
@@ -0,0 +1,3 @@
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
+9 -6
View File
@@ -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)
+18 -9
View File
@@ -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
+1 -1
View File
@@ -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) {
+1 -1
View File
@@ -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;
+22
View File
@@ -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
+507
View File
@@ -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-----
+65
View File
@@ -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
View File
File diff suppressed because it is too large. Load diff
+70 -48
View File
@@ -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 *);
+5
View File
@@ -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
+1
View File
@@ -8,5 +8,6 @@
#include <stdbool.h>
#include <sys/time.h>
#define MG_DIRSEP '/'
#define MG_INT64_FMT "%lld"
#endif
+1
View File
@@ -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
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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>.
-1
View File
@@ -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
View File
@@ -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) {
+5
View File
@@ -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 *);
+2 -1
View File
@@ -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
View File
@@ -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));
+5 -4
View File
@@ -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) {
+26 -16
View File
@@ -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));
+5 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -1,2 +1,2 @@
#pragma once
#define MG_VERSION "7.1"
#define MG_VERSION "7.2"
+165 -9
View File
@@ -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();