mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-26 12:14:56 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
452bcc68a4 | ||
|
|
829827d46f | ||
|
|
ff9d0e462e | ||
|
|
e84ea91a4a | ||
|
|
2dcb10ef36 | ||
|
|
99fa7f0851 | ||
|
|
1b5cc341a5 | ||
|
|
d50dc288cd | ||
|
|
060bb29cdc | ||
|
|
366426e8bb | ||
|
|
e710df4c80 | ||
|
|
79e5841483 | ||
|
|
374ab4ecf0 | ||
|
|
56980be48c | ||
|
|
602c5c0866 | ||
|
|
7ce5009de1 | ||
|
|
51e3a1304b | ||
|
|
d5a1d5a5e8 | ||
|
|
ae5f6c0920 | ||
|
|
0a9303bb07 | ||
|
|
42bc7b1f47 | ||
|
|
4844ed60bd | ||
|
|
41f5daeb47 | ||
|
|
a3f8f33d50 | ||
|
|
fd8db5c53a | ||
|
|
a2f027e798 | ||
|
|
dad5c8fe87 | ||
|
|
98783a41ba | ||
|
|
1517d2985a | ||
|
|
acc0564957 | ||
|
|
421bc126b5 | ||
|
|
ed1a98c381 | ||
|
|
457d76b049 | ||
|
|
6827972f71 | ||
|
|
7eb998891e | ||
|
|
582fde5c6e | ||
|
|
d327ee9834 | ||
|
|
31cf6f8969 | ||
|
|
86b1053678 | ||
|
|
6678e36278 | ||
|
|
5118355732 | ||
|
|
5b4b7f7dc5 | ||
|
|
7614a8101f | ||
|
|
3c851bcfc3 | ||
|
|
01691dafa0 | ||
|
|
8e52075636 | ||
|
|
7200f079bf | ||
|
|
d155db81de | ||
|
|
25e3bbf039 | ||
|
|
eecf3d854b | ||
|
|
7c2499fc06 | ||
|
|
1aa605c620 | ||
|
|
66287ad6c1 | ||
|
|
9a19485454 | ||
|
|
7d67d578fd | ||
|
|
960d3c7880 | ||
|
|
9eabf3fa81 | ||
|
|
89beadd2ce | ||
|
|
6ecb6c1500 | ||
|
|
51bc5f70c5 | ||
|
|
be62ac9c14 | ||
|
|
161c34384d | ||
|
|
89784ab90a | ||
|
|
d83e547fa9 | ||
|
|
30d86928d5 | ||
|
|
12c32d09fb | ||
|
|
ae6fd6aa35 | ||
|
|
72d3a49352 | ||
|
|
87b62390b7 | ||
|
|
6c93446a1f | ||
|
|
83c106a857 | ||
|
|
facb2846fd | ||
|
|
596c70d3dc | ||
|
|
7beff0201d | ||
|
|
a4c9d1ecb7 | ||
|
|
b7a79a556a | ||
|
|
03ab9e4e0d | ||
|
|
7e855f5c8f | ||
|
|
9e510d5831 | ||
|
|
1689a0d56b | ||
|
|
9ff774e7df | ||
|
|
c78ad0b574 | ||
|
|
117aeaa15d | ||
|
|
e135743efa | ||
|
|
2c1324dc0a | ||
|
|
c7e09bd7b4 | ||
|
|
86824795a0 | ||
|
|
1b0636c2d2 | ||
|
|
2f9d2bbdf6 | ||
|
|
21a1b2c15c | ||
|
|
bdef3d6afd | ||
|
|
a882aab30e | ||
|
|
788b577d65 | ||
|
|
71a22adc06 | ||
|
|
7d1ef2ffe8 | ||
|
|
55f5f74658 | ||
|
|
e1fd82bc46 | ||
|
|
49b8480bfb | ||
|
|
b2ab484883 | ||
|
|
4c3b97be7d | ||
|
|
60e1b64455 | ||
|
|
6bcd02bb1c | ||
|
|
66f302a613 | ||
|
|
1716af6c72 | ||
|
|
749326c83a | ||
|
|
9657577c00 | ||
|
|
9f5216d259 | ||
|
|
c8826e8f9c | ||
|
|
25bc13ef1e | ||
|
|
4d123a15f9 | ||
|
|
2cf1b09767 | ||
|
|
abfd81cb9d | ||
|
|
3895678bee | ||
|
|
e0a1feafe0 | ||
|
|
c75eb24eb8 | ||
|
|
c3aae185df | ||
|
|
2e87783246 | ||
|
|
fbab767b9f | ||
|
|
7bc38b5eaa | ||
|
|
b93456f512 | ||
|
|
ddb700eee5 | ||
|
|
1052ee0766 | ||
|
|
29534218d7 | ||
|
|
d7abd53062 | ||
|
|
aede72fa37 | ||
|
|
b0a5165b44 | ||
|
|
4919f792f2 | ||
|
|
d5927f5d50 | ||
|
|
e68330e045 | ||
|
|
b5d5b3763f | ||
|
|
b6a6687c1e | ||
|
|
3843b670a5 | ||
|
|
249efdd378 | ||
|
|
18ce1669fc | ||
|
|
e8d3b8030e | ||
|
|
a752abf318 | ||
|
|
d3ebcaf5d2 | ||
|
|
0abb8322d9 | ||
|
|
99ed58ec4d | ||
|
|
04450ec659 | ||
|
|
82a378e519 | ||
|
|
29d31ba919 | ||
|
|
4519ea568d | ||
|
|
9f88f31f01 | ||
|
|
4bdea2b467 | ||
|
|
2252a74cd7 | ||
|
|
d1fa7b88e0 | ||
|
|
9ecf42578c | ||
|
|
754fc25924 | ||
|
|
d9551c75b1 | ||
|
|
8d45cf6972 | ||
|
|
f176e1ae59 | ||
|
|
fa8f62fb5d | ||
|
|
0c142f20d7 | ||
|
|
b641fc6b79 | ||
|
|
1252a61479 | ||
|
|
5f631c0b96 | ||
|
|
348c579521 | ||
|
|
7ce9cdf0b9 | ||
|
|
09beadb98a | ||
|
|
5b265a76bd | ||
|
|
c5a4a1c6f2 | ||
|
|
88ada54045 | ||
|
|
c5b1c08d05 | ||
|
|
a0765ade6b |
No files matched your search
@@ -0,0 +1,40 @@
|
|||||||
|
name: build
|
||||||
|
on: [push, pull_request]
|
||||||
|
jobs:
|
||||||
|
linux:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Install packages
|
||||||
|
run: sudo apt-get install libmbedtls-dev
|
||||||
|
- name: make
|
||||||
|
run: make test test++ IPV6=0
|
||||||
|
- name: openssl
|
||||||
|
run: make test SSL=OPENSSL IPV6=0
|
||||||
|
- name: examples
|
||||||
|
run: make ex
|
||||||
|
macos:
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Install packages
|
||||||
|
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install jq mbedtls openssl
|
||||||
|
- name: make
|
||||||
|
run: make test++ upload-coverage IPV6=0
|
||||||
|
- name: openssl
|
||||||
|
run: make test SSL=OPENSSL IPV6=0
|
||||||
|
- name: exports
|
||||||
|
run: make mg_prefix
|
||||||
|
windows:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: vc98
|
||||||
|
run: make vc98
|
||||||
|
- name: vc2017
|
||||||
|
run: make vc2017
|
||||||
|
- name: mingw
|
||||||
|
run: make mingw
|
||||||
|
- name: mingw++
|
||||||
|
run: make mingw++
|
||||||
|
|
||||||
-23
@@ -1,23 +0,0 @@
|
|||||||
language: c
|
|
||||||
sudo: false
|
|
||||||
after_success: bash <(curl -s https://codecov.io/bash)
|
|
||||||
install:
|
|
||||||
- if test "$TRAVIS_OS_NAME" = linux; then sudo apt-get install libmbedtls-dev; else brew install jq mbedtls; fi
|
|
||||||
os:
|
|
||||||
- linux
|
|
||||||
- osx
|
|
||||||
compiler:
|
|
||||||
- clang
|
|
||||||
- gcc
|
|
||||||
script: make test test++ ex
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: osx
|
|
||||||
compiler: clang
|
|
||||||
script: make mg_prefix
|
|
||||||
- os: linux
|
|
||||||
compiler: msvc98
|
|
||||||
script: make vc98 vc2017
|
|
||||||
sudo: required
|
|
||||||
services:
|
|
||||||
- docker
|
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
SRCS = $(wildcard src/*.c)
|
SRCS = $(wildcard src/*.c)
|
||||||
HDRS = $(wildcard src/*.h)
|
HDRS = $(wildcard src/*.h)
|
||||||
DEFS ?= -DMG_MAX_HTTP_HEADERS=5 -DMG_ENABLE_LINES -DMG_ENABLE_HTTP_DEBUG_ENDPOINT=1 -DMG_ENABLE_DIRECTORY_LISTING=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)
|
CFLAGS ?= -W -Wall -Werror -Isrc -I. -O0 -g $(DEFS) $(TFLAGS) $(EXTRA)
|
||||||
SSL ?= MBEDTLS
|
SSL ?= MBEDTLS
|
||||||
CDIR ?= $(realpath $(CURDIR))
|
CDIR ?= $(realpath $(CURDIR))
|
||||||
VC98 = docker run --rm -e WINEDEBUG=-all -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/vc98
|
VC98 = docker run --rm -e WINEDEBUG=-all -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/vc98
|
||||||
VC2017 = docker run --rm -e WINEDEBUG=-all -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/vc2017
|
VC2017 = docker run --rm -e WINEDEBUG=-all -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/vc2017
|
||||||
|
MINGW = docker run --rm -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/mingw
|
||||||
GCC = docker run --rm -v $(CDIR):$(CDIR) -w $(CDIR) mdashnet/cc2
|
GCC = docker run --rm -v $(CDIR):$(CDIR) -w $(CDIR) mdashnet/cc2
|
||||||
VCFLAGS = /nologo /W3 /O2 /I. $(DEFS) $(TFLAGS)
|
VCFLAGS = /nologo /W3 /O2 /I. $(DEFS) $(TFLAGS)
|
||||||
CLANG ?= clang # /usr/local/opt/llvm\@9/bin/clang
|
CLANG ?= clang # /usr/local/opt/llvm\@9/bin/clang
|
||||||
|
IPV6 ?= 1
|
||||||
ASAN_OPTIONS ?=
|
ASAN_OPTIONS ?=
|
||||||
EXAMPLES := $(wildcard examples/*)
|
EXAMPLES := $(wildcard examples/*)
|
||||||
EXAMPLE_TARGET ?= example
|
EXAMPLE_TARGET ?= example
|
||||||
@@ -22,12 +24,14 @@ CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS)/include -I/usr/include
|
|||||||
LDFLAGS ?= -L$(MBEDTLS)/lib -lmbedtls -lmbedcrypto -lmbedx509
|
LDFLAGS ?= -L$(MBEDTLS)/lib -lmbedtls -lmbedcrypto -lmbedx509
|
||||||
endif
|
endif
|
||||||
ifeq "$(SSL)" "OPENSSL"
|
ifeq "$(SSL)" "OPENSSL"
|
||||||
OPENSSLDIR ?= $(shell "$(brew --cellar openssl)/$(brew info openssl --json | jq -j .[0].installed[0].version)")
|
OPENSSL_DIR ?= $(shell brew --cellar openssl)
|
||||||
CFLAGS += -DMG_ENABLE_OPENSSL=1 -I$(OPENSSLDIR)/include
|
OPENSSL_VER ?= $(shell brew info openssl --json | jq -j .[0].installed[0].version)
|
||||||
LDFLAGS ?= -L$(OPENSSLDIR)/lib -lssl -lcrypto
|
OPENSSL ?= $(OPENSSL_DIR)/$(OPENSSL_VER)
|
||||||
|
CFLAGS += -DMG_ENABLE_OPENSSL=1 -I$(OPENSSL)/include
|
||||||
|
LDFLAGS ?= -L$(OPENSSL)/lib -lssl -lcrypto
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: mg_prefix test test++ ex vc98 vc2017 linux linux++ infer fuzz
|
all: mg_prefix test test++ ex vc98 vc2017 mingw mingw++ linux linux++ infer fuzz
|
||||||
|
|
||||||
ex:
|
ex:
|
||||||
@for X in $(EXAMPLES); do $(MAKE) -C $$X $(EXAMPLE_TARGET); done
|
@for X in $(EXAMPLES); do $(MAKE) -C $$X $(EXAMPLE_TARGET); done
|
||||||
@@ -45,11 +49,11 @@ unamalgamated: $(SRCS) $(HDRS) Makefile
|
|||||||
$(CLANG) src/*.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -g -o unit_test
|
$(CLANG) src/*.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -g -o unit_test
|
||||||
|
|
||||||
fuzz: mongoose.c mongoose.h Makefile test/fuzz.c
|
fuzz: mongoose.c mongoose.h Makefile test/fuzz.c
|
||||||
$(CLANG) mongoose.c test/fuzz.c $(CFLAGS) -DMG_ENABLE_LOG=0 -fsanitize=fuzzer,signed-integer-overflow,address $(LDFLAGS) -g -o fuzzer
|
$(CLANG) mongoose.c test/fuzz.c $(CFLAGS) -DMG_ENABLE_LINES -DMG_ENABLE_LOG=0 -fsanitize=fuzzer,signed-integer-overflow,address $(LDFLAGS) -g -o fuzzer
|
||||||
$(DEBUGGER) ./fuzzer
|
$(DEBUGGER) ./fuzzer
|
||||||
|
|
||||||
# make CLANG=/usr/local/opt/llvm\@8/bin/clang ASAN_OPTIONS=detect_leaks=1
|
# make CLANG=/usr/local/opt/llvm\@8/bin/clang ASAN_OPTIONS=detect_leaks=1
|
||||||
test: CFLAGS += -DMG_ENABLE_IPV6=1 -fsanitize=address#,undefined
|
test: CFLAGS += -DMG_ENABLE_IPV6=$(IPV6) -fsanitize=address#,undefined
|
||||||
test: mongoose.c mongoose.h Makefile test/unit_test.c
|
test: mongoose.c mongoose.h Makefile test/unit_test.c
|
||||||
$(CLANG) mongoose.c test/unit_test.c $(CFLAGS) -coverage $(LDFLAGS) -g -o unit_test
|
$(CLANG) mongoose.c test/unit_test.c $(CFLAGS) -coverage $(LDFLAGS) -g -o unit_test
|
||||||
ASAN_OPTIONS=$(ASAN_OPTIONS) $(DEBUGGER) ./unit_test
|
ASAN_OPTIONS=$(ASAN_OPTIONS) $(DEBUGGER) ./unit_test
|
||||||
@@ -58,6 +62,9 @@ coverage: test
|
|||||||
gcov -l -n *.gcno | sed '/^$$/d' | sed 'N;s/\n/ /'
|
gcov -l -n *.gcno | sed '/^$$/d' | sed 'N;s/\n/ /'
|
||||||
gcov mongoose.gcno >/dev/null
|
gcov mongoose.gcno >/dev/null
|
||||||
|
|
||||||
|
upload-coverage: coverage
|
||||||
|
curl -s https://codecov.io/bash | /bin/bash
|
||||||
|
|
||||||
infer:
|
infer:
|
||||||
infer run -- cc test/unit_test.c -c -W -Wall -Werror -Isrc -I. -O2 -DMG_ENABLE_MBEDTLS=1 -DMG_ENABLE_LINES -I/usr/local/Cellar/mbedtls/2.23.0/include -DMG_ENABLE_IPV6=1 -g -o /dev/null
|
infer run -- cc test/unit_test.c -c -W -Wall -Werror -Isrc -I. -O2 -DMG_ENABLE_MBEDTLS=1 -DMG_ENABLE_LINES -I/usr/local/Cellar/mbedtls/2.23.0/include -DMG_ENABLE_IPV6=1 -g -o /dev/null
|
||||||
|
|
||||||
@@ -66,12 +73,21 @@ vc98: Makefile mongoose.c mongoose.h test/unit_test.c
|
|||||||
$(VC98) wine cl mongoose.c test/unit_test.c $(VCFLAGS) ws2_32.lib /Fe$@.exe
|
$(VC98) wine cl mongoose.c test/unit_test.c $(VCFLAGS) ws2_32.lib /Fe$@.exe
|
||||||
$(VC98) wine $@.exe
|
$(VC98) wine $@.exe
|
||||||
|
|
||||||
vc2017: CFLAGS += -DMG_ENABLE_IPV6=1
|
#vc2017: VCFLAGS += -DMG_ENABLE_IPV6=1
|
||||||
vc2017: Makefile mongoose.c mongoose.h test/unit_test.c
|
vc2017: Makefile mongoose.c mongoose.h test/unit_test.c
|
||||||
$(VC2017) wine64 cl mongoose.c test/unit_test.c $(VCFLAGS) ws2_32.lib /Fe$@.exe
|
$(VC2017) wine64 cl mongoose.c test/unit_test.c $(VCFLAGS) ws2_32.lib /Fe$@.exe
|
||||||
$(VC2017) wine64 $@.exe
|
$(VC2017) wine64 $@.exe
|
||||||
|
|
||||||
linux: CFLAGS += -DMG_ENABLE_IPV6=1 -fsanitize=address,undefined
|
mingw: Makefile mongoose.c mongoose.h test/unit_test.c
|
||||||
|
$(MINGW) i686-w64-mingw32-gcc mongoose.c test/unit_test.c -W -Wall -Werror -I. $(DEFS) -lwsock32 -o test.exe
|
||||||
|
$(VC98) wine test.exe
|
||||||
|
|
||||||
|
mingw++: Makefile mongoose.c mongoose.h test/unit_test.c
|
||||||
|
$(MINGW) i686-w64-mingw32-g++ mongoose.c test/unit_test.c -W -Wall -Werror -I. $(DEFS) -lwsock32 -o test.exe
|
||||||
|
# Note: for some reason, a binary built with mingw g++, fails to run
|
||||||
|
|
||||||
|
#linux: CFLAGS += -DMG_ENABLE_IPV6=$(IPV6)
|
||||||
|
linux: CFLAGS += -fsanitize=address,undefined
|
||||||
linux: Makefile mongoose.c mongoose.h test/unit_test.c
|
linux: Makefile mongoose.c mongoose.h test/unit_test.c
|
||||||
$(GCC) $(CC) mongoose.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -o unit_test_gcc
|
$(GCC) $(CC) mongoose.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -o unit_test_gcc
|
||||||
$(GCC) ./unit_test_gcc
|
$(GCC) ./unit_test_gcc
|
||||||
@@ -83,7 +99,7 @@ mongoose.c: $(SRCS) Makefile
|
|||||||
(cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/private.h src/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@
|
(cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/private.h src/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@
|
||||||
|
|
||||||
mongoose.h: $(HDRS) Makefile
|
mongoose.h: $(HDRS) Makefile
|
||||||
(cat src/license.h src/version.h ; cat src/arch.h src/arch_*.h src/config.h src/str.h src/log.h src/timer.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/event.h src/net.h src/http.h src/tls.h src/ws.h src/sntp.h src/mqtt.h src/dns.h | sed -e 's,#include ".*,,' -e 's,^#pragma once,,')> $@
|
(cat src/license.h src/version.h ; cat src/arch.h src/arch_*.h src/config.h src/str.h src/log.h src/timer.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/ws.h src/sntp.h src/mqtt.h src/dns.h | sed -e 's,#include ".*,,' -e 's,^#pragma once,,')> $@
|
||||||
|
|
||||||
clean: EXAMPLE_TARGET = clean
|
clean: EXAMPLE_TARGET = clean
|
||||||
clean: ex
|
clean: ex
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
# Mongoose - Embedded Web Server / Embedded Networking Library
|
# Mongoose - Embedded Web Server / Embedded Networking Library
|
||||||
|
|
||||||

|

|
||||||
[](https://travis-ci.org/cesanta/mongoose)
|
[](https://github.com/cesanta/mongoose/actions)
|
||||||
[](https://codecov.io/gh/cesanta/mongoose)
|
[](https://codecov.io/gh/cesanta/mongoose)
|
||||||
|
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:mongoose)
|
||||||
|
|
||||||
Mongoose is a networking library for C/C++. It implements event-driven
|
Mongoose is a networking library for C/C++. It implements event-driven
|
||||||
non-blocking APIs for TCP, UDP, HTTP, WebSocket, MQTT. It has been designed
|
non-blocking APIs for TCP, UDP, HTTP, WebSocket, MQTT. It has been designed
|
||||||
@@ -20,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)
|
- [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
|
- [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
|
- [Mongoose OS](https://mongoose-os.com) - open source embedded operating system for low-power connected microcontrollers. Secure, designed for commercial Internet of Things products
|
||||||
|
|
||||||
@@ -32,17 +36,11 @@ Looking for a complete IoT solution? Check out
|
|||||||
|
|
||||||
# Features
|
# Features
|
||||||
|
|
||||||
* Cross-platform: works on Linux/UNIX, MacOS, QNX, eCos, Windows, Android,
|
* Cross-platform: works on Linux/UNIX, MacOS, Windows, Android, FreeRTOS, etc
|
||||||
iPhone, FreeRTOS, etc
|
* Supported embedded architectures: ESP32, ESP8266, TI, NRF52, STM32, PIC32, NXP, and more
|
||||||
* Supported hardware platforms: TI CC3200, TI MSP432, NRF52, STM32, PIC32, ESP8266, ESP32 and more
|
* Builtin protocols: plain TCP/UDP, HTTP, MQTT, Websocket
|
||||||
* Builtin protocols:
|
* SSL/TLS support: mbedTLS, OpenSSL or custom (via API)
|
||||||
- plain TCP, plain UDP, SSL/TLS (over TCP, one-way or two-way)
|
* Asynchronous DNS resolver
|
||||||
- HTTP client, HTTP server
|
|
||||||
- WebSocket client, WebSocket server
|
|
||||||
- MQTT client
|
|
||||||
- DNS client, async DNS resolver
|
|
||||||
* Single-threaded, asynchronous, non-blocking core with simple event-based API
|
|
||||||
* Native support for [LWIP embedded TCP/IP stack](https://en.wikipedia.org/wiki/LwIP)
|
|
||||||
* Tiny static and run-time footprint
|
* Tiny static and run-time footprint
|
||||||
* Source code is both ISO C and ISO C++ compliant
|
* Source code is both ISO C and ISO C++ compliant
|
||||||
* Very easy to integrate: just copy
|
* Very easy to integrate: just copy
|
||||||
@@ -74,5 +72,4 @@ Contributions are welcome! Please follow the guidelines below:
|
|||||||
- When making pull requests, please make sure that it has only one commit,
|
- When making pull requests, please make sure that it has only one commit,
|
||||||
and imlements/fixes only one piece of functionality
|
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)
|
|
||||||
+205
-49
@@ -133,18 +133,20 @@ to an event handler:
|
|||||||
|
|
||||||
```c
|
```c
|
||||||
enum {
|
enum {
|
||||||
MG_EV_ERROR, // Error char *error_message
|
MG_EV_ERROR, // Error char *error_message
|
||||||
MG_EV_POLL, // mg_mgr_poll iteration unsigned long *millis
|
MG_EV_POLL, // mg_mgr_poll iteration unsigned long *millis
|
||||||
MG_EV_RESOLVE, // Host name is resolved NULL
|
MG_EV_RESOLVE, // Host name is resolved NULL
|
||||||
MG_EV_CONNECT, // Connection established NULL
|
MG_EV_CONNECT, // Connection established NULL
|
||||||
MG_EV_ACCEPT, // Connection accepted NULL
|
MG_EV_ACCEPT, // Connection accepted NULL
|
||||||
MG_EV_READ, // Data received from socket struct mg_str *
|
MG_EV_READ, // Data received from socket struct mg_str *
|
||||||
MG_EV_WRITE, // Data written to socket int *num_bytes_written
|
MG_EV_WRITE, // Data written to socket int *num_bytes_written
|
||||||
MG_EV_CLOSE, // Connection closed NULL
|
MG_EV_CLOSE, // Connection closed NULL
|
||||||
MG_EV_HTTP_MSG, // HTTP request/response struct mg_http_message *
|
MG_EV_HTTP_MSG, // HTTP request/response struct mg_http_message *
|
||||||
MG_EV_WS_OPEN, // Websocket handshake done NULL
|
MG_EV_WS_OPEN, // Websocket handshake done struct mg_http_message *
|
||||||
MG_EV_WS_MSG, // Websocket message received struct mg_ws_message *
|
MG_EV_WS_MSG, // Websocket msg, text or bin struct mg_ws_message *
|
||||||
MG_EV_MQTT_MSG, // MQTT message struct mg_mqtt_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_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code
|
||||||
MG_EV_SNTP_TIME, // SNTP time received struct timeval *
|
MG_EV_SNTP_TIME, // SNTP time received struct timeval *
|
||||||
MG_EV_USER, // Starting ID for user events
|
MG_EV_USER, // Starting ID for user events
|
||||||
@@ -157,10 +159,10 @@ enum {
|
|||||||
they can be either 0 or 1. Some flags are set by Mongoose and must be not
|
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
|
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
|
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.
|
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:
|
This is taken from `mongoose.h` as-is:
|
||||||
|
|
||||||
@@ -221,12 +223,68 @@ Here is a list of build constants and their default values:
|
|||||||
|`MG_ENABLE_LOG` | 1 | Enable `LOG()` macro |
|
|`MG_ENABLE_LOG` | 1 | Enable `LOG()` macro |
|
||||||
|`MG_ENABLE_MD5` | 0 | Use native MD5 implementation |
|
|`MG_ENABLE_MD5` | 0 | Use native MD5 implementation |
|
||||||
|`MG_ENABLE_DIRECTORY_LISTING` | 0 | Enable directory listing for HTTP server |
|
|`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_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 |
|
|`MG_IO_SIZE` | 512 | Granularity of the send/recv IO buffer growth |
|
||||||
|`MG_MAX_RECV_BUF_SIZE` | (3 * 1024 * 1024) | Maximum recv buffer size |
|
|`MG_MAX_RECV_BUF_SIZE` | (3 * 1024 * 1024) | Maximum recv buffer size |
|
||||||
|`MG_MAX_HTTP_HEADERS` | 40 | Maximum number of HTTP headers |
|
|`MG_MAX_HTTP_HEADERS` | 40 | Maximum number of HTTP headers |
|
||||||
|
|
||||||
|
NOTE: `MG_IO_SIZE` controls the maximum UDP message size, see
|
||||||
|
https://github.com/cesanta/mongoose/issues/907 for details. If application
|
||||||
|
uses large UDP messages, increase the `MG_IO_SIZE` limit accordingly.
|
||||||
|
|
||||||
|
## Custom build
|
||||||
|
|
||||||
|
It is possible to use Mongoose on an architecture that is not yet supported
|
||||||
|
by the current codebase. In order to do so, follow these steps:
|
||||||
|
|
||||||
|
1. Create a file called `mongoose_custom.h`, with defines and includes that
|
||||||
|
are relevant to your platform. Mongoose uses `bool` type, `MG_DIRSEP` define,
|
||||||
|
and optionally other structures like `DIR *` depending on the functionality
|
||||||
|
you have enabled - see previous section. Below is an example:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include <dirent.h> // For DIR *
|
||||||
|
#include <stdbool.h> // For bool
|
||||||
|
#include <sys/time.h> // For gettimeofday()
|
||||||
|
#include <unistd.h> // For usleep()
|
||||||
|
#define MG_DIRSEP '/'
|
||||||
|
#define MG_ENABLE_SOCKET 0 // Disable BSD socket API, implement your own
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Add `-DMG_ARCH=MG_ARCH_CUSTOM` to your build flags.
|
||||||
|
|
||||||
|
3. This step is optional. If you have disabled BSD socket API, your build is
|
||||||
|
going to fail due to several undefined symbols. Create `mongoose_custom.c`
|
||||||
|
and implement the following functions (take a look at `src/sock.c` for the
|
||||||
|
reference implementation):
|
||||||
|
|
||||||
|
```c
|
||||||
|
struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
|
||||||
|
mg_event_handler_t fn, void *fn_data) {
|
||||||
|
// implement this!
|
||||||
|
}
|
||||||
|
|
||||||
|
void mg_connect_resolved(struct mg_connection *c) {
|
||||||
|
// implement this!
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url,
|
||||||
|
mg_event_handler_t fn, void *fn_data) {
|
||||||
|
// implement this!
|
||||||
|
}
|
||||||
|
|
||||||
|
void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
|
||||||
|
// implement this!
|
||||||
|
}
|
||||||
|
|
||||||
|
int mg_send(struct mg_connection *c, const void *buf, size_t len) {
|
||||||
|
// implement this!
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Minimal HTTP server
|
## Minimal HTTP server
|
||||||
|
|
||||||
This example is a simple static HTTP server that serves current directory:
|
This example is a simple static HTTP server that serves current directory:
|
||||||
@@ -238,7 +296,8 @@ static const char *s_web_root_dir = ".";
|
|||||||
static const char *s_listening_address = "http://localhost:8000";
|
static const char *s_listening_address = "http://localhost:8000";
|
||||||
|
|
||||||
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
if (ev == MG_EV_HTTP_MSG) mg_http_serve_dir(c, ev_data, s_web_root_dir);
|
struct mg_http_serve_opts opts = {.root_dir = s_web_root_dir};
|
||||||
|
if (ev == MG_EV_HTTP_MSG) mg_http_serve_dir(c, ev_data, &opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
@@ -362,7 +421,7 @@ protocol-specific handler is called before user-specific handler. It parses
|
|||||||
incoming data and may invoke protocol-specific events like `MG_EV_HTTP_MSG`.
|
incoming data and may invoke protocol-specific events like `MG_EV_HTTP_MSG`.
|
||||||
|
|
||||||
|
|
||||||
### mh\_mgr\_free()
|
### mg\_mgr\_free()
|
||||||
|
|
||||||
```c
|
```c
|
||||||
void mg_mgr_free(struct mg_mgr *mgr);
|
void mg_mgr_free(struct mg_mgr *mgr);
|
||||||
@@ -468,21 +527,23 @@ by `buf`, and `len` specifies number of bytes currently stored.
|
|||||||
### mg\_iobuf\_init()
|
### mg\_iobuf\_init()
|
||||||
|
|
||||||
```c
|
```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()
|
### mg\_iobuf\_resize()
|
||||||
|
|
||||||
```c
|
```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
|
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
|
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.
|
`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()
|
### mg\_iobuf\_free()
|
||||||
@@ -621,34 +682,52 @@ void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len);
|
|||||||
Write a chunk of data in chunked encoding format.
|
Write a chunk of data in chunked encoding format.
|
||||||
|
|
||||||
|
|
||||||
### mg\_serve\_dir()
|
### mg\_http\_serve\_dir()
|
||||||
|
|
||||||
```c
|
```c
|
||||||
|
struct mg_http_serve_opts {
|
||||||
|
const char *root_dir; // Web root directory, must be non-NULL
|
||||||
|
const char *ssi_pattern; // SSI filename pattern, e.g. #.shtml
|
||||||
|
};
|
||||||
void mg_http_serve_dir(struct mg_connection *, struct mg_http_message *hm,
|
void mg_http_serve_dir(struct mg_connection *, struct mg_http_message *hm,
|
||||||
const char *path);
|
const struct mg_http_serve_opts *opts);
|
||||||
```
|
```
|
||||||
|
|
||||||
Serve static files using `path` as a root directory.
|
Serve static files according to the given options. Note that in order to
|
||||||
|
enable SSI, set a `-DMG_ENABLE_SSI=1` build flag.
|
||||||
|
|
||||||
|
|
||||||
### mg\_serve\_file()
|
### mg\_http\_serve\_file()
|
||||||
|
|
||||||
```c
|
```c
|
||||||
void mg_http_serve_file(struct mg_connection *, struct mg_http_message *hm,
|
void mg_http_serve_file(struct mg_connection *, struct mg_http_message *hm,
|
||||||
const char *path, const char *mimetype);
|
const char *path, const char *mimetype,
|
||||||
|
const char *extra_headers);
|
||||||
```
|
```
|
||||||
|
|
||||||
Serve static file.
|
Serve static file. Note that the `extra_headers` must end with `\r\n`. Here
|
||||||
|
is an example call:
|
||||||
|
|
||||||
|
```c
|
||||||
|
mg_http_serve_file(c, hm, "a.png", "image/png", "AA: bb\r\nCC: dd\r\n");
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### mg\_http\_reply()
|
### mg\_http\_reply()
|
||||||
|
|
||||||
```c
|
```c
|
||||||
void mg_http_reply(struct mg_connection *c, int code, const char *fmt, ...);
|
void mg_http_reply(struct mg_connection *c, int status_code, const char *headers,
|
||||||
|
const char *body_fmt, ...);
|
||||||
```
|
```
|
||||||
|
|
||||||
Send simple HTTP response using `printf()` semantic.
|
Send simple HTTP response using `printf()` semantic. This function formats
|
||||||
`code` is HTTP response code, `fmt` is format for the HTTP body.
|
response body according to a `body_fmt`, and automatically appends a correct
|
||||||
|
`Content-Length` header. Extra headers could be passed via `headers`
|
||||||
|
parameter.
|
||||||
|
|
||||||
|
- `status_code` - an HTTP response code
|
||||||
|
- `headers` - extra headers, default NULL. If not NULL, must end with `\r\n`
|
||||||
|
- `fmt` - a format string for the HTTP body, in a printf semantics
|
||||||
|
|
||||||
|
|
||||||
### mg\_http\_header()
|
### mg\_http\_header()
|
||||||
@@ -712,8 +791,34 @@ int mg_http_upload(struct mg_connection *, struct mg_http_message *hm,
|
|||||||
const char *dir);
|
const char *dir);
|
||||||
```
|
```
|
||||||
|
|
||||||
Handle file upload. See file upload example.
|
Handle file upload. See [file upload example](https://github.com/cesanta/mongoose/tree/master/examples/file-upload).
|
||||||
|
|
||||||
|
This function expects a series of POST requests with file data. POST requests
|
||||||
|
should have `name` and `offset` query string parameters set:
|
||||||
|
|
||||||
|
```text
|
||||||
|
POST /whatever_uri?name=myfile.txt&offset=1234 HTTP/1.0
|
||||||
|
Content-Length: 5
|
||||||
|
|
||||||
|
hello
|
||||||
|
```
|
||||||
|
|
||||||
|
- `name` - a mandatory query string parameter, specifies a file name. It it
|
||||||
|
created in the `dir` directory
|
||||||
|
- `offset` - an optional parameter, default `0`. If it set to `0`, or omitted,
|
||||||
|
then a file gets truncated before write. Otherwise, the body of
|
||||||
|
the POST request gets appended to the file
|
||||||
|
- Server must call `mg_http_upload()` when `/whatever_uri` is hit
|
||||||
|
|
||||||
|
So, the expected usage of this API function is this:
|
||||||
|
- A client splits a file into small enough chunks, to ensure that a chunk
|
||||||
|
fits into the server's RAM
|
||||||
|
- Then, each chunk is POST-ed to the server with using URI like
|
||||||
|
`/some_uri?name=FILENAME&offset=OFFSET`
|
||||||
|
- Initial OFFSET is `0`, and subsequent offsets are non-zero
|
||||||
|
- Each chunk gets appended to the file
|
||||||
|
- When the last chunk is POSTed, upload finishes
|
||||||
|
- POST data must not be encoded in any way, it it saved as-is
|
||||||
|
|
||||||
### mg\_http\_bauth()
|
### mg\_http\_bauth()
|
||||||
|
|
||||||
@@ -756,10 +861,13 @@ Create client Websocket connection.
|
|||||||
### mg\_ws\_upgrade()
|
### mg\_ws\_upgrade()
|
||||||
|
|
||||||
```c
|
```c
|
||||||
void mg_ws_upgrade(struct mg_connection *, struct mg_http_message *);
|
void mg_ws_upgrade(struct mg_connection *, struct mg_http_message *,
|
||||||
|
const char *fmt, ...);
|
||||||
```
|
```
|
||||||
|
|
||||||
Upgrade given HTTP connection to Websocket.
|
Upgrade given HTTP connection to Websocket. The `fmt` is a printf-like
|
||||||
|
format string for the extra HTTP headers returned to the client in a
|
||||||
|
Websocket handshake. Set `fmt` to `NULL` if no extra headers needs to be passed.
|
||||||
|
|
||||||
|
|
||||||
### mg\_ws\_send()
|
### mg\_ws\_send()
|
||||||
@@ -840,10 +948,45 @@ void mg_mqtt_sub(struct mg_connection *, struct mg_str *topic);
|
|||||||
|
|
||||||
Subscribe to topic `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
|
## TLS
|
||||||
|
|
||||||
### struct mg\_tls\_opts
|
### mg\_tls\_init()
|
||||||
|
|
||||||
```c
|
```c
|
||||||
struct mg_tls_opts {
|
struct mg_tls_opts {
|
||||||
@@ -851,20 +994,12 @@ struct mg_tls_opts {
|
|||||||
const char *cert; // Certificate
|
const char *cert; // Certificate
|
||||||
const char *certkey; // Certificate key
|
const char *certkey; // Certificate key
|
||||||
const char *ciphers; // Cipher list
|
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);
|
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
|
## Timers
|
||||||
@@ -942,14 +1077,26 @@ size_t mg_file_size(const char *path);
|
|||||||
|
|
||||||
Return file size, or 0 on failure. Empty files also report 0 length.
|
Return file size, or 0 on failure. Empty files also report 0 length.
|
||||||
|
|
||||||
|
|
||||||
### mg\_file\_write()
|
### mg\_file\_write()
|
||||||
|
|
||||||
```c
|
```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()
|
### mg\_random()
|
||||||
@@ -1089,16 +1236,16 @@ Parse 64-bit integer value held by string `s`.
|
|||||||
### mg\_aton()
|
### mg\_aton()
|
||||||
|
|
||||||
```
|
```
|
||||||
bool mg_aton(const char *s, uint32_t *ipaddr);
|
bool mg_aton(struct mg_str str, uint32_t *ipaddr);
|
||||||
```
|
```
|
||||||
|
|
||||||
Parse IP address held by `s` and store it in `ipaddr`. Return true on success.
|
Parse IP address held by `str` and store it in `ipaddr`. Return true on success.
|
||||||
|
|
||||||
|
|
||||||
### mg\_ntoa()
|
### mg\_ntoa()
|
||||||
|
|
||||||
```c
|
```c
|
||||||
char *mg_ntoa(uint32_t ipaddr, char *buf, size_t len);
|
char *mg_ntoa(const struct mg_addr *, char *buf, size_t len);
|
||||||
```
|
```
|
||||||
|
|
||||||
Stringify IP address `ipaddr` into a buffer `buf`, `len`. Return `buf`.
|
Stringify IP address `ipaddr` into a buffer `buf`, `len`. Return `buf`.
|
||||||
@@ -1128,3 +1275,12 @@ void mg_usleep(unsigned long usecs);
|
|||||||
```
|
```
|
||||||
|
|
||||||
Block for a given number of microseconds.
|
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`.
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
PROG ?= example
|
||||||
|
CFLAGS ?= -DMG_IO_SIZE=8192 -DMG_ENABLE_LINES
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(DEBUGGER) ./$(PROG) $(ARGS)
|
||||||
|
|
||||||
|
$(PROG): main.c
|
||||||
|
$(CC) ../../mongoose.c -I../.. -W -Wall $(CFLAGS) -o $(PROG) main.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
// Copyright (c) 2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// Example captive DNS server (captive portal).
|
||||||
|
// 1. Run `make`. This builds and starts a server on port 5533
|
||||||
|
// 2. Run `dig -t A www.google.com -4 @localhost -p 5533`
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static const char *s_listen_url = "udp://0.0.0.0:5533";
|
||||||
|
|
||||||
|
// DNS answer section. We response with IP 1.2.3.4 - you can change it
|
||||||
|
// in the last 4 bytes of this array
|
||||||
|
uint8_t answer[] = {
|
||||||
|
0xc0, 0x0c, // Point to the name in the DNS question
|
||||||
|
0, 1, // 2 bytes - record type, A
|
||||||
|
0, 1, // 2 bytes - address class, INET
|
||||||
|
0, 0, 0, 120, // 4 bytes - TTL
|
||||||
|
0, 4, // 2 bytes - address length
|
||||||
|
1, 2, 3, 4 // 4 bytes - IP address
|
||||||
|
};
|
||||||
|
|
||||||
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_READ) {
|
||||||
|
struct mg_dns_rr rr; // Parse first question, offset 12 is header size
|
||||||
|
size_t n = mg_dns_parse_rr(c->recv.buf, c->recv.len, 12, true, &rr);
|
||||||
|
if (n > 0) {
|
||||||
|
char buf[12 + n + sizeof(answer)];
|
||||||
|
struct mg_dns_header *h = (struct mg_dns_header *) buf;
|
||||||
|
memset(buf, 0, sizeof(buf)); // Clear the whole datagram
|
||||||
|
h->txnid = ((struct mg_dns_header *) c->recv.buf)->txnid; // Copy tnxid
|
||||||
|
h->num_questions = mg_htons(1); // We use only the 1st question
|
||||||
|
h->num_answers = mg_htons(1); // And only one answer
|
||||||
|
h->flags = mg_htons(0x8400); // Authoritative response
|
||||||
|
memcpy(buf + sizeof(*h), c->recv.buf + sizeof(*h), n); // Copy question
|
||||||
|
memcpy(buf + sizeof(*h) + n, answer, sizeof(answer)); // And answer
|
||||||
|
mg_send(c, buf, sizeof(buf)); // And send it!
|
||||||
|
}
|
||||||
|
mg_iobuf_delete(&c->recv, c->recv.len);
|
||||||
|
}
|
||||||
|
(void) fn_data;
|
||||||
|
(void) ev_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_mgr mgr;
|
||||||
|
|
||||||
|
mg_log_set("3"); // Set log level
|
||||||
|
mg_mgr_init(&mgr); // Initialise event manager
|
||||||
|
mg_listen(&mgr, s_listen_url, fn, NULL); // Start DNS server
|
||||||
|
for (;;) mg_mgr_poll(&mgr, 1000); // Event loop
|
||||||
|
mg_mgr_free(&mgr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# A complete device dashboard
|
||||||
|
|
||||||
|
This example is a demonstration of how Mongoose Library could be integrated
|
||||||
|
into an embedded device and provide a complete device dashbord with the
|
||||||
|
following features:
|
||||||
|
|
||||||
|
- Multiple logins with different permissions (admin and user)
|
||||||
|
- Login screen for non-authenticated connections
|
||||||
|
- A [preact](https://preactjs.com/)-based dashboard with multiple pages
|
||||||
|
- Internal variables
|
||||||
|
- A form that changes those variables
|
||||||
|
- All changes are propagates to all connected clients
|
||||||
|
- Live log stream
|
||||||
|
- Live video stream
|
||||||
|
|
||||||
|
|
||||||
|
In essense, this example is a combination of several other examples
|
||||||
|
pulled together (multiple-logins, dashboard, live-log, video-stream).
|
||||||
|
|
||||||
|
# Screenshots
|
||||||
|
|
||||||
|
This is a login screen that prompts for user/password
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
# Main dashboard
|
||||||
|
|
||||||
|
A main dashboard page shows internal data, live video stream, and a form
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
A live log page shows live log stream coming from device
|
||||||
|
|
||||||
|

|
||||||
@@ -119,7 +119,7 @@ static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
"Pragma: no-cache\r\nExpires: Thu, 01 Dec 1994 16:00:00 GMT\r\n"
|
"Pragma: no-cache\r\nExpires: Thu, 01 Dec 1994 16:00:00 GMT\r\n"
|
||||||
"Content-Type: multipart/x-mixed-replace; boundary=--foo\r\n\r\n");
|
"Content-Type: multipart/x-mixed-replace; boundary=--foo\r\n\r\n");
|
||||||
} else if (mg_http_match_uri(hm, "/api/log/static")) {
|
} else if (mg_http_match_uri(hm, "/api/log/static")) {
|
||||||
mg_http_serve_file(c, hm, "log.txt", "text/plain");
|
mg_http_serve_file(c, hm, "log.txt", "text/plain", "");
|
||||||
} else if (mg_http_match_uri(hm, "/api/log/live")) {
|
} else if (mg_http_match_uri(hm, "/api/log/live")) {
|
||||||
c->label[0] = 'L'; // Mark that connection as live log listener
|
c->label[0] = 'L'; // Mark that connection as live log listener
|
||||||
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||||
@@ -129,7 +129,8 @@ static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
u->token);
|
u->token);
|
||||||
mg_http_printf_chunk(c, "");
|
mg_http_printf_chunk(c, "");
|
||||||
} else {
|
} else {
|
||||||
mg_http_serve_dir(c, ev_data, "web_root");
|
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
|
||||||
|
mg_http_serve_dir(c, ev_data, &opts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,7 +147,7 @@ static void broadcast_mjpeg_frame(struct mg_mgr *mgr) {
|
|||||||
char *data = mg_file_read(path); // Read next file
|
char *data = mg_file_read(path); // Read next file
|
||||||
struct mg_connection *c;
|
struct mg_connection *c;
|
||||||
for (c = mgr->conns; c != NULL; c = c->next) {
|
for (c = mgr->conns; c != NULL; c = c->next) {
|
||||||
if (c->label[0] != 'S') continue; // Skip non-stream connections
|
if (c->label[0] != 'S') continue; // Skip non-stream connections
|
||||||
if (data == NULL || size == 0) continue; // Skip on file read error
|
if (data == NULL || size == 0) continue; // Skip on file read error
|
||||||
mg_printf(c,
|
mg_printf(c,
|
||||||
"--foo\r\nContent-Type: image/jpeg\r\n"
|
"--foo\r\nContent-Type: image/jpeg\r\n"
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 134 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 122 KiB |
+2
-8
@@ -1,9 +1,3 @@
|
|||||||
/* axios v0.19.0-beta.1 | (c) 2018 by Matt Zabriskie */
|
/* axios v0.21.1 | (c) 2020 by Matt Zabriskie */
|
||||||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function r(e){var t=new i(e),n=s(i.prototype.request,t);return o.extend(n,i.prototype,t),o.extend(n,t),n}var o=n(2),s=n(3),i=n(5),a=n(22),u=n(11),c=r(u);c.Axios=i,c.create=function(e){return r(a(c.defaults,e))},c.Cancel=n(23),c.CancelToken=n(24),c.isCancel=n(10),c.all=function(e){return Promise.all(e)},c.spread=n(25),e.exports=c,e.exports.default=c},function(e,t,n){"use strict";function r(e){return"[object Array]"===j.call(e)}function o(e){return"[object ArrayBuffer]"===j.call(e)}function s(e){return"undefined"!=typeof FormData&&e instanceof FormData}function i(e){var t;return t="undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function a(e){return"string"==typeof e}function u(e){return"number"==typeof e}function c(e){return"undefined"==typeof e}function f(e){return null!==e&&"object"==typeof e}function p(e){return"[object Date]"===j.call(e)}function d(e){return"[object File]"===j.call(e)}function l(e){return"[object Blob]"===j.call(e)}function h(e){return"[object Function]"===j.call(e)}function m(e){return f(e)&&h(e.pipe)}function y(e){return"undefined"!=typeof URLSearchParams&&e instanceof URLSearchParams}function g(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function x(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product&&"NativeScript"!==navigator.product&&"NS"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)}function v(e,t){if(null!==e&&"undefined"!=typeof e)if("object"!=typeof e&&(e=[e]),r(e))for(var n=0,o=e.length;n<o;n++)t.call(null,e[n],n,e);else for(var s in e)Object.prototype.hasOwnProperty.call(e,s)&&t.call(null,e[s],s,e)}function w(){function e(e,n){"object"==typeof t[n]&&"object"==typeof e?t[n]=w(t[n],e):t[n]=e}for(var t={},n=0,r=arguments.length;n<r;n++)v(arguments[n],e);return t}function b(){function e(e,n){"object"==typeof t[n]&&"object"==typeof e?t[n]=b(t[n],e):"object"==typeof e?t[n]=b({},e):t[n]=e}for(var t={},n=0,r=arguments.length;n<r;n++)v(arguments[n],e);return t}function E(e,t,n){return v(t,function(t,r){n&&"function"==typeof t?e[r]=S(t,n):e[r]=t}),e}var S=n(3),R=n(4),j=Object.prototype.toString;e.exports={isArray:r,isArrayBuffer:o,isBuffer:R,isFormData:s,isArrayBufferView:i,isString:a,isNumber:u,isObject:f,isUndefined:c,isDate:p,isFile:d,isBlob:l,isFunction:h,isStream:m,isURLSearchParams:y,isStandardBrowserEnv:x,forEach:v,merge:w,deepMerge:b,extend:E,trim:g}},function(e,t){"use strict";e.exports=function(e,t){return function(){for(var n=new Array(arguments.length),r=0;r<n.length;r++)n[r]=arguments[r];return e.apply(t,n)}}},function(e,t){/*!
|
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function r(e){var t=new i(e),n=s(i.prototype.request,t);return o.extend(n,i.prototype,t),o.extend(n,t),n}var o=n(2),s=n(3),i=n(4),a=n(22),u=n(10),c=r(u);c.Axios=i,c.create=function(e){return r(a(c.defaults,e))},c.Cancel=n(23),c.CancelToken=n(24),c.isCancel=n(9),c.all=function(e){return Promise.all(e)},c.spread=n(25),c.isAxiosError=n(26),e.exports=c,e.exports.default=c},function(e,t,n){"use strict";function r(e){return"[object Array]"===R.call(e)}function o(e){return"undefined"==typeof e}function s(e){return null!==e&&!o(e)&&null!==e.constructor&&!o(e.constructor)&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}function i(e){return"[object ArrayBuffer]"===R.call(e)}function a(e){return"undefined"!=typeof FormData&&e instanceof FormData}function u(e){var t;return t="undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function c(e){return"string"==typeof e}function f(e){return"number"==typeof e}function p(e){return null!==e&&"object"==typeof e}function d(e){if("[object Object]"!==R.call(e))return!1;var t=Object.getPrototypeOf(e);return null===t||t===Object.prototype}function l(e){return"[object Date]"===R.call(e)}function h(e){return"[object File]"===R.call(e)}function m(e){return"[object Blob]"===R.call(e)}function y(e){return"[object Function]"===R.call(e)}function g(e){return p(e)&&y(e.pipe)}function v(e){return"undefined"!=typeof URLSearchParams&&e instanceof URLSearchParams}function x(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function w(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product&&"NativeScript"!==navigator.product&&"NS"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)}function b(e,t){if(null!==e&&"undefined"!=typeof e)if("object"!=typeof e&&(e=[e]),r(e))for(var n=0,o=e.length;n<o;n++)t.call(null,e[n],n,e);else for(var s in e)Object.prototype.hasOwnProperty.call(e,s)&&t.call(null,e[s],s,e)}function E(){function e(e,n){d(t[n])&&d(e)?t[n]=E(t[n],e):d(e)?t[n]=E({},e):r(e)?t[n]=e.slice():t[n]=e}for(var t={},n=0,o=arguments.length;n<o;n++)b(arguments[n],e);return t}function j(e,t,n){return b(t,function(t,r){n&&"function"==typeof t?e[r]=S(t,n):e[r]=t}),e}function C(e){return 65279===e.charCodeAt(0)&&(e=e.slice(1)),e}var S=n(3),R=Object.prototype.toString;e.exports={isArray:r,isArrayBuffer:i,isBuffer:s,isFormData:a,isArrayBufferView:u,isString:c,isNumber:f,isObject:p,isPlainObject:d,isUndefined:o,isDate:l,isFile:h,isBlob:m,isFunction:y,isStream:g,isURLSearchParams:v,isStandardBrowserEnv:w,forEach:b,merge:E,extend:j,trim:x,stripBOM:C}},function(e,t){"use strict";e.exports=function(e,t){return function(){for(var n=new Array(arguments.length),r=0;r<n.length;r++)n[r]=arguments[r];return e.apply(t,n)}}},function(e,t,n){"use strict";function r(e){this.defaults=e,this.interceptors={request:new i,response:new i}}var o=n(2),s=n(5),i=n(6),a=n(7),u=n(22);r.prototype.request=function(e){"string"==typeof e?(e=arguments[1]||{},e.url=arguments[0]):e=e||{},e=u(this.defaults,e),e.method?e.method=e.method.toLowerCase():this.defaults.method?e.method=this.defaults.method.toLowerCase():e.method="get";var t=[a,void 0],n=Promise.resolve(e);for(this.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),this.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)n=n.then(t.shift(),t.shift());return n},r.prototype.getUri=function(e){return e=u(this.defaults,e),s(e.url,e.params,e.paramsSerializer).replace(/^\?/,"")},o.forEach(["delete","get","head","options"],function(e){r.prototype[e]=function(t,n){return this.request(u(n||{},{method:e,url:t,data:(n||{}).data}))}}),o.forEach(["post","put","patch"],function(e){r.prototype[e]=function(t,n,r){return this.request(u(r||{},{method:e,url:t,data:n}))}}),e.exports=r},function(e,t,n){"use strict";function r(e){return encodeURIComponent(e).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var o=n(2);e.exports=function(e,t,n){if(!t)return e;var s;if(n)s=n(t);else if(o.isURLSearchParams(t))s=t.toString();else{var i=[];o.forEach(t,function(e,t){null!==e&&"undefined"!=typeof e&&(o.isArray(e)?t+="[]":e=[e],o.forEach(e,function(e){o.isDate(e)?e=e.toISOString():o.isObject(e)&&(e=JSON.stringify(e)),i.push(r(t)+"="+r(e))}))}),s=i.join("&")}if(s){var a=e.indexOf("#");a!==-1&&(e=e.slice(0,a)),e+=(e.indexOf("?")===-1?"?":"&")+s}return e}},function(e,t,n){"use stricLine truncated
|
||||||
* Determine if an object is a Buffer
|
|
||||||
*
|
|
||||||
* @author Feross Aboukhadijeh <https://feross.org>
|
|
||||||
* @license MIT
|
|
||||||
*/
|
|
||||||
e.exports=function(e){return null!=e&&null!=e.constructor&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}},function(e,t,n){"use strict";function r(e){this.defaults=e,this.interceptors={request:new i,response:new i}}var o=n(2),s=n(6),i=n(7),a=n(8),u=n(22);r.prototype.request=function(e){"string"==typeof e?(e=arguments[1]||{},e.url=arguments[0]):e=e||{},e=u(this.defaults,e),e.method=e.method?e.method.toLowerCase():"get";var t=[a,void 0],n=Promise.resolve(e);for(this.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),this.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)n=n.then(t.shift(),t.shift());return n},r.prototype.getUri=function(e){return e=u(this.defaults,e),s(e.url,e.params,e.paramsSerializer).replace(/^\?/,"")},o.forEach(["delete","get","head","options"],function(e){r.prototype[e]=function(t,n){return this.request(o.merge(n||{},{method:e,url:t}))}}),o.forEach(["post","put","patch"],function(e){r.prototype[e]=function(t,n,r){return this.request(o.merge(r||{},{method:e,url:t,data:n}))}}),e.exports=r},function(e,t,n){"use strict";function r(e){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var o=n(2);e.exports=function(e,t,n){if(!t)return e;var s;if(n)s=n(t);else if(o.isURLSearchParams(t))s=t.toString();else{var i=[];o.forEach(t,function(e,t){null!==e&&"undefined"!=typeof e&&(o.isArray(e)?t+="[]":e=[e],o.forEach(e,function(e){o.isDate(e)?e=e.toISOString():o.isObject(e)&&(e=JSON.stringify(e)),i.push(r(t)+"="+r(e))}))}),s=i.join("&")}return s&&(e+=(e.indexOf("?")===-1?"?":"&")+s),e}},function(e,t,n){"use strict";function r(){this.handlers=[]}var o=n(2);r.prototype.use=function(e,t){return this.handlers.push({fulfilled:e,rejected:t}),this.handlers.length-1},r.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)},r.prototype.forEach=function(e){o.forEach(this.handlers,function(t){null!==t&&e(t)})},e.exports=r},function(e,t,n){"use strict";function r(e){e.cancelToken&&e.cancelToken.throwIfRequested()}var o=n(2),s=n(9),i=n(10),a=n(11),u=n(20),c=n(21);e.exports=function(e){r(e),e.baseURL&&!u(e.url)&&(e.url=c(e.baseURL,e.url)),e.headers=e.headers||{},e.data=s(e.data,e.headers,e.transformRequest),e.headers=o.merge(e.headers.common||{},e.headers[e.method]||{},e.headers||{}),o.forEach(["delete","get","head","post","put","patch","common"],function(t){delete e.headers[t]});var t=e.adapter||a.adapter;return t(e).then(function(t){return r(e),t.data=s(t.data,t.headers,e.transformResponse),t},function(t){return i(t)||(r(e),t&&t.response&&(t.response.data=s(t.response.data,t.response.headers,e.transformResponse))),Promise.reject(t)})}},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t,n){return r.forEach(n,function(n){e=n(e,t)}),e}},function(e,t){"use strict";e.exports=function(e){return!(!e||!e.__CANCEL__)}},function(e,t,n){"use strict";function r(e,t){!s.isUndefined(e)&&s.isUndefined(e["Content-Type"])&&(e["Content-Type"]=t)}function o(){var e;return"undefined"!=typeof process&&"[object process]"===Object.prototype.toString.call(process)?e=n(13):"undefined"!=typeof XMLHttpRequest&&(e=n(13)),e}var s=n(2),i=n(12),a={"Content-Type":"application/x-www-form-urlencoded"},u={adapter:o(),transformRequest:[function(e,t){return i(t,"Accept"),i(t,"Content-Type"),s.isFormData(e)||s.isArrayBuffer(e)||s.isBuffer(e)||s.isStream(e)||s.isFile(e)||s.isBlob(e)?e:s.isArrayBufferView(e)?e.buffer:s.isURLSearchParams(e)?(r(t,"application/x-www-form-urlencoded;charset=utf-8"),e.toString()):s.isObject(e)?(r(t,"application/json;charset=utf-8"),JSON.stringify(e)):e}],transformResponse:[function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(e){}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,validateStatus:function(e){return e>=200&&e<300}};u.headers={common:{Accept:"application/json, text/plain, */*"}},s.forEach(["delete","get","head"],function(e){u.headers[e]={}}),s.forEach(["post","put","patch"],function(e){u.headers[e]=s.merge(a)}),e.exports=u},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t){r.forEach(e,function(n,r){r!==t&&r.toUpperCase()===t.toUpperCase()&&(e[t]=n,delete e[r])})}},function(e,t,n){"use strict";var r=n(2),o=n(14),s=n(6),i=n(17),a=n(18),u=n(15);e.exports=function(e){return new Promise(function(t,c){var f=e.data,p=e.headers;r.isFormData(f)&&delete p["Content-Type"];var d=new XMLHttpRequest;if(e.auth){var l=e.auth.username||"",h=e.auth.password||"";p.Authorization="Basic "+btoa(l+":"+h)}if(d.open(e.method.toUpperCase(),s(e.url,e.params,e.paramsSerializer),!0),d.timeout=e.timeout,d.onreadystatechange=function(){if(d&&4===d.readyState&&(0!==d.status||d.responseURL&&0===d.responseURL.indexOf("file:"))){var n="getAllResponseHeaders"in d?i(d.getAllResponseHeaders()):null,r=e.responseType&&"text"!==e.responseType?d.response:Line truncated
|
|
||||||
//# sourceMappingURL=axios.min.map
|
//# sourceMappingURL=axios.min.map
|
||||||
@@ -66,7 +66,8 @@ static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
c->label[0] = 'W'; // Mark ourselves as a config watcher
|
c->label[0] = 'W'; // Mark ourselves as a config watcher
|
||||||
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||||
} else {
|
} else {
|
||||||
mg_http_serve_dir(c, ev_data, "web_root");
|
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
|
||||||
|
mg_http_serve_dir(c, ev_data, &opts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-8
@@ -1,9 +1,3 @@
|
|||||||
/* axios v0.19.0-beta.1 | (c) 2018 by Matt Zabriskie */
|
/* axios v0.21.1 | (c) 2020 by Matt Zabriskie */
|
||||||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function r(e){var t=new i(e),n=s(i.prototype.request,t);return o.extend(n,i.prototype,t),o.extend(n,t),n}var o=n(2),s=n(3),i=n(5),a=n(22),u=n(11),c=r(u);c.Axios=i,c.create=function(e){return r(a(c.defaults,e))},c.Cancel=n(23),c.CancelToken=n(24),c.isCancel=n(10),c.all=function(e){return Promise.all(e)},c.spread=n(25),e.exports=c,e.exports.default=c},function(e,t,n){"use strict";function r(e){return"[object Array]"===j.call(e)}function o(e){return"[object ArrayBuffer]"===j.call(e)}function s(e){return"undefined"!=typeof FormData&&e instanceof FormData}function i(e){var t;return t="undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function a(e){return"string"==typeof e}function u(e){return"number"==typeof e}function c(e){return"undefined"==typeof e}function f(e){return null!==e&&"object"==typeof e}function p(e){return"[object Date]"===j.call(e)}function d(e){return"[object File]"===j.call(e)}function l(e){return"[object Blob]"===j.call(e)}function h(e){return"[object Function]"===j.call(e)}function m(e){return f(e)&&h(e.pipe)}function y(e){return"undefined"!=typeof URLSearchParams&&e instanceof URLSearchParams}function g(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function x(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product&&"NativeScript"!==navigator.product&&"NS"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)}function v(e,t){if(null!==e&&"undefined"!=typeof e)if("object"!=typeof e&&(e=[e]),r(e))for(var n=0,o=e.length;n<o;n++)t.call(null,e[n],n,e);else for(var s in e)Object.prototype.hasOwnProperty.call(e,s)&&t.call(null,e[s],s,e)}function w(){function e(e,n){"object"==typeof t[n]&&"object"==typeof e?t[n]=w(t[n],e):t[n]=e}for(var t={},n=0,r=arguments.length;n<r;n++)v(arguments[n],e);return t}function b(){function e(e,n){"object"==typeof t[n]&&"object"==typeof e?t[n]=b(t[n],e):"object"==typeof e?t[n]=b({},e):t[n]=e}for(var t={},n=0,r=arguments.length;n<r;n++)v(arguments[n],e);return t}function E(e,t,n){return v(t,function(t,r){n&&"function"==typeof t?e[r]=S(t,n):e[r]=t}),e}var S=n(3),R=n(4),j=Object.prototype.toString;e.exports={isArray:r,isArrayBuffer:o,isBuffer:R,isFormData:s,isArrayBufferView:i,isString:a,isNumber:u,isObject:f,isUndefined:c,isDate:p,isFile:d,isBlob:l,isFunction:h,isStream:m,isURLSearchParams:y,isStandardBrowserEnv:x,forEach:v,merge:w,deepMerge:b,extend:E,trim:g}},function(e,t){"use strict";e.exports=function(e,t){return function(){for(var n=new Array(arguments.length),r=0;r<n.length;r++)n[r]=arguments[r];return e.apply(t,n)}}},function(e,t){/*!
|
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function r(e){var t=new i(e),n=s(i.prototype.request,t);return o.extend(n,i.prototype,t),o.extend(n,t),n}var o=n(2),s=n(3),i=n(4),a=n(22),u=n(10),c=r(u);c.Axios=i,c.create=function(e){return r(a(c.defaults,e))},c.Cancel=n(23),c.CancelToken=n(24),c.isCancel=n(9),c.all=function(e){return Promise.all(e)},c.spread=n(25),c.isAxiosError=n(26),e.exports=c,e.exports.default=c},function(e,t,n){"use strict";function r(e){return"[object Array]"===R.call(e)}function o(e){return"undefined"==typeof e}function s(e){return null!==e&&!o(e)&&null!==e.constructor&&!o(e.constructor)&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}function i(e){return"[object ArrayBuffer]"===R.call(e)}function a(e){return"undefined"!=typeof FormData&&e instanceof FormData}function u(e){var t;return t="undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function c(e){return"string"==typeof e}function f(e){return"number"==typeof e}function p(e){return null!==e&&"object"==typeof e}function d(e){if("[object Object]"!==R.call(e))return!1;var t=Object.getPrototypeOf(e);return null===t||t===Object.prototype}function l(e){return"[object Date]"===R.call(e)}function h(e){return"[object File]"===R.call(e)}function m(e){return"[object Blob]"===R.call(e)}function y(e){return"[object Function]"===R.call(e)}function g(e){return p(e)&&y(e.pipe)}function v(e){return"undefined"!=typeof URLSearchParams&&e instanceof URLSearchParams}function x(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function w(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product&&"NativeScript"!==navigator.product&&"NS"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)}function b(e,t){if(null!==e&&"undefined"!=typeof e)if("object"!=typeof e&&(e=[e]),r(e))for(var n=0,o=e.length;n<o;n++)t.call(null,e[n],n,e);else for(var s in e)Object.prototype.hasOwnProperty.call(e,s)&&t.call(null,e[s],s,e)}function E(){function e(e,n){d(t[n])&&d(e)?t[n]=E(t[n],e):d(e)?t[n]=E({},e):r(e)?t[n]=e.slice():t[n]=e}for(var t={},n=0,o=arguments.length;n<o;n++)b(arguments[n],e);return t}function j(e,t,n){return b(t,function(t,r){n&&"function"==typeof t?e[r]=S(t,n):e[r]=t}),e}function C(e){return 65279===e.charCodeAt(0)&&(e=e.slice(1)),e}var S=n(3),R=Object.prototype.toString;e.exports={isArray:r,isArrayBuffer:i,isBuffer:s,isFormData:a,isArrayBufferView:u,isString:c,isNumber:f,isObject:p,isPlainObject:d,isUndefined:o,isDate:l,isFile:h,isBlob:m,isFunction:y,isStream:g,isURLSearchParams:v,isStandardBrowserEnv:w,forEach:b,merge:E,extend:j,trim:x,stripBOM:C}},function(e,t){"use strict";e.exports=function(e,t){return function(){for(var n=new Array(arguments.length),r=0;r<n.length;r++)n[r]=arguments[r];return e.apply(t,n)}}},function(e,t,n){"use strict";function r(e){this.defaults=e,this.interceptors={request:new i,response:new i}}var o=n(2),s=n(5),i=n(6),a=n(7),u=n(22);r.prototype.request=function(e){"string"==typeof e?(e=arguments[1]||{},e.url=arguments[0]):e=e||{},e=u(this.defaults,e),e.method?e.method=e.method.toLowerCase():this.defaults.method?e.method=this.defaults.method.toLowerCase():e.method="get";var t=[a,void 0],n=Promise.resolve(e);for(this.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),this.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)n=n.then(t.shift(),t.shift());return n},r.prototype.getUri=function(e){return e=u(this.defaults,e),s(e.url,e.params,e.paramsSerializer).replace(/^\?/,"")},o.forEach(["delete","get","head","options"],function(e){r.prototype[e]=function(t,n){return this.request(u(n||{},{method:e,url:t,data:(n||{}).data}))}}),o.forEach(["post","put","patch"],function(e){r.prototype[e]=function(t,n,r){return this.request(u(r||{},{method:e,url:t,data:n}))}}),e.exports=r},function(e,t,n){"use strict";function r(e){return encodeURIComponent(e).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var o=n(2);e.exports=function(e,t,n){if(!t)return e;var s;if(n)s=n(t);else if(o.isURLSearchParams(t))s=t.toString();else{var i=[];o.forEach(t,function(e,t){null!==e&&"undefined"!=typeof e&&(o.isArray(e)?t+="[]":e=[e],o.forEach(e,function(e){o.isDate(e)?e=e.toISOString():o.isObject(e)&&(e=JSON.stringify(e)),i.push(r(t)+"="+r(e))}))}),s=i.join("&")}if(s){var a=e.indexOf("#");a!==-1&&(e=e.slice(0,a)),e+=(e.indexOf("?")===-1?"?":"&")+s}return e}},function(e,t,n){"use stricLine truncated
|
||||||
* Determine if an object is a Buffer
|
|
||||||
*
|
|
||||||
* @author Feross Aboukhadijeh <https://feross.org>
|
|
||||||
* @license MIT
|
|
||||||
*/
|
|
||||||
e.exports=function(e){return null!=e&&null!=e.constructor&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}},function(e,t,n){"use strict";function r(e){this.defaults=e,this.interceptors={request:new i,response:new i}}var o=n(2),s=n(6),i=n(7),a=n(8),u=n(22);r.prototype.request=function(e){"string"==typeof e?(e=arguments[1]||{},e.url=arguments[0]):e=e||{},e=u(this.defaults,e),e.method=e.method?e.method.toLowerCase():"get";var t=[a,void 0],n=Promise.resolve(e);for(this.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),this.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)n=n.then(t.shift(),t.shift());return n},r.prototype.getUri=function(e){return e=u(this.defaults,e),s(e.url,e.params,e.paramsSerializer).replace(/^\?/,"")},o.forEach(["delete","get","head","options"],function(e){r.prototype[e]=function(t,n){return this.request(o.merge(n||{},{method:e,url:t}))}}),o.forEach(["post","put","patch"],function(e){r.prototype[e]=function(t,n,r){return this.request(o.merge(r||{},{method:e,url:t,data:n}))}}),e.exports=r},function(e,t,n){"use strict";function r(e){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var o=n(2);e.exports=function(e,t,n){if(!t)return e;var s;if(n)s=n(t);else if(o.isURLSearchParams(t))s=t.toString();else{var i=[];o.forEach(t,function(e,t){null!==e&&"undefined"!=typeof e&&(o.isArray(e)?t+="[]":e=[e],o.forEach(e,function(e){o.isDate(e)?e=e.toISOString():o.isObject(e)&&(e=JSON.stringify(e)),i.push(r(t)+"="+r(e))}))}),s=i.join("&")}return s&&(e+=(e.indexOf("?")===-1?"?":"&")+s),e}},function(e,t,n){"use strict";function r(){this.handlers=[]}var o=n(2);r.prototype.use=function(e,t){return this.handlers.push({fulfilled:e,rejected:t}),this.handlers.length-1},r.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)},r.prototype.forEach=function(e){o.forEach(this.handlers,function(t){null!==t&&e(t)})},e.exports=r},function(e,t,n){"use strict";function r(e){e.cancelToken&&e.cancelToken.throwIfRequested()}var o=n(2),s=n(9),i=n(10),a=n(11),u=n(20),c=n(21);e.exports=function(e){r(e),e.baseURL&&!u(e.url)&&(e.url=c(e.baseURL,e.url)),e.headers=e.headers||{},e.data=s(e.data,e.headers,e.transformRequest),e.headers=o.merge(e.headers.common||{},e.headers[e.method]||{},e.headers||{}),o.forEach(["delete","get","head","post","put","patch","common"],function(t){delete e.headers[t]});var t=e.adapter||a.adapter;return t(e).then(function(t){return r(e),t.data=s(t.data,t.headers,e.transformResponse),t},function(t){return i(t)||(r(e),t&&t.response&&(t.response.data=s(t.response.data,t.response.headers,e.transformResponse))),Promise.reject(t)})}},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t,n){return r.forEach(n,function(n){e=n(e,t)}),e}},function(e,t){"use strict";e.exports=function(e){return!(!e||!e.__CANCEL__)}},function(e,t,n){"use strict";function r(e,t){!s.isUndefined(e)&&s.isUndefined(e["Content-Type"])&&(e["Content-Type"]=t)}function o(){var e;return"undefined"!=typeof process&&"[object process]"===Object.prototype.toString.call(process)?e=n(13):"undefined"!=typeof XMLHttpRequest&&(e=n(13)),e}var s=n(2),i=n(12),a={"Content-Type":"application/x-www-form-urlencoded"},u={adapter:o(),transformRequest:[function(e,t){return i(t,"Accept"),i(t,"Content-Type"),s.isFormData(e)||s.isArrayBuffer(e)||s.isBuffer(e)||s.isStream(e)||s.isFile(e)||s.isBlob(e)?e:s.isArrayBufferView(e)?e.buffer:s.isURLSearchParams(e)?(r(t,"application/x-www-form-urlencoded;charset=utf-8"),e.toString()):s.isObject(e)?(r(t,"application/json;charset=utf-8"),JSON.stringify(e)):e}],transformResponse:[function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(e){}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,validateStatus:function(e){return e>=200&&e<300}};u.headers={common:{Accept:"application/json, text/plain, */*"}},s.forEach(["delete","get","head"],function(e){u.headers[e]={}}),s.forEach(["post","put","patch"],function(e){u.headers[e]=s.merge(a)}),e.exports=u},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t){r.forEach(e,function(n,r){r!==t&&r.toUpperCase()===t.toUpperCase()&&(e[t]=n,delete e[r])})}},function(e,t,n){"use strict";var r=n(2),o=n(14),s=n(6),i=n(17),a=n(18),u=n(15);e.exports=function(e){return new Promise(function(t,c){var f=e.data,p=e.headers;r.isFormData(f)&&delete p["Content-Type"];var d=new XMLHttpRequest;if(e.auth){var l=e.auth.username||"",h=e.auth.password||"";p.Authorization="Basic "+btoa(l+":"+h)}if(d.open(e.method.toUpperCase(),s(e.url,e.params,e.paramsSerializer),!0),d.timeout=e.timeout,d.onreadystatechange=function(){if(d&&4===d.readyState&&(0!==d.status||d.responseURL&&0===d.responseURL.indexOf("file:"))){var n="getAllResponseHeaders"in d?i(d.getAllResponseHeaders()):null,r=e.responseType&&"text"!==e.responseType?d.response:Line truncated
|
|
||||||
//# sourceMappingURL=axios.min.map
|
//# sourceMappingURL=axios.min.map
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
PROG ?= example
|
|
||||||
ROOT ?= $(realpath $(CURDIR)/../..)
|
|
||||||
DEFS ?= -DMG_ENABLE_LINES=1 -DMG_ENABLE_DIRECTORY_LISTING=1
|
|
||||||
CFLAGS ?= -I../.. -W -Wall -DMG_ENABLE_IPV6=1 $(DEFS) $(EXTRA)
|
|
||||||
VCFLAGS = /nologo /W3 /O2 /I../.. $(DEFS) $(EXTRA)
|
|
||||||
VC98 = docker run --rm -e WINEDEBUG=-all -v $(ROOT):$(ROOT) -w $(CURDIR) docker.io/mdashnet/vc98
|
|
||||||
GCC = docker run --rm -v $(ROOT):$(ROOT) -w $(CURDIR) mdashnet/cc2
|
|
||||||
|
|
||||||
all: $(PROG)
|
|
||||||
$(DEBUGGER) ./$(PROG)
|
|
||||||
|
|
||||||
$(PROG):
|
|
||||||
$(CC) ../../mongoose.c main.c -I../.. $(CFLAGS) $(EXTRA) -o $@
|
|
||||||
|
|
||||||
mongoose_mac: $(PROG)
|
|
||||||
cp $(PROG) $@
|
|
||||||
|
|
||||||
mongoose_linux: main.c
|
|
||||||
$(GCC) $(CC) ../../mongoose.c main.c $(CFLAGS) -o $@
|
|
||||||
|
|
||||||
mongoose.exe: main.c
|
|
||||||
$(VC98) wine cl ../../mongoose.c main.c $(VCFLAGS) ws2_32.lib /Fe$@
|
|
||||||
|
|
||||||
zip: mongoose.exe mongoose_linux mongoose_mac
|
|
||||||
rm -rf mongoose; mkdir mongoose
|
|
||||||
cp mongoose.exe mongoose_mac mongoose_linux mongoose
|
|
||||||
zip -r mongoose.zip mongoose
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb mongoose mongoose_* mongoose.*
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# The following lines of boilerplate have to be in your project's
|
||||||
|
# CMakeLists in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(mongoose-esp32-example)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
THISDIR = $(realpath $(CURDIR))
|
||||||
|
ROOTDIR = $(realpath $(CURDIR)/../..)
|
||||||
|
|
||||||
|
all: example
|
||||||
|
|
||||||
|
example: main/main.c Makefile
|
||||||
|
docker run --rm -v $(ROOTDIR):$(ROOTDIR) -w $(THISDIR) espressif/idf idf.py build
|
||||||
|
|
||||||
|
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 0x100000 mongoose-esp32-example.bin
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb mongoose mongoose_* mongoose.* build sdkconfig
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# An example ESP32 application
|
||||||
|
|
||||||
|
To build this application, follow these steps:
|
||||||
|
|
||||||
|
1. Make sure you have Docker installed
|
||||||
|
2. Clone whole mongoose repository on your machine:
|
||||||
|
```sh
|
||||||
|
git clone --depth 1 https://github.com/cesanta/mongoose.git
|
||||||
|
```
|
||||||
|
3. Start command line or terminal, and go into the example's directory:
|
||||||
|
```sh
|
||||||
|
cd mongoose/examples/esp32
|
||||||
|
```
|
||||||
|
4. Run `make`. This invokes a Docker-based build. A firmware will be built
|
||||||
|
in the `build/` directory:
|
||||||
|
```sh
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
# Flashing built firmware
|
||||||
|
|
||||||
|
If you have a real board to flash to, you can flash a built firmware.
|
||||||
|
First, make sure to have `esptool.py` script installed on your workstation.
|
||||||
|
Then, connect the board to your workstation and run the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make flash COMPORT=YOUR_USB_PORT
|
||||||
|
```
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
idf_component_register(SRCS "main.c"
|
||||||
|
"wifi.c"
|
||||||
|
"../../../mongoose.c"
|
||||||
|
INCLUDE_DIRS "../../..")
|
||||||
|
component_compile_options(-DMG_ENABLE_DIRECTORY_LISTING=1 -DMG_ENABLE_LINES)
|
||||||
@@ -0,0 +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"
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// Connected to WiFi, now start HTTP server
|
||||||
|
struct mg_mgr mgr;
|
||||||
|
mg_log_set("3");
|
||||||
|
mg_mgr_init(&mgr);
|
||||||
|
mg_http_listen(&mgr, "http://0.0.0.0:80", cb, &mgr); // Listening server
|
||||||
|
LOG(LL_INFO, ("Starting Mongoose web server v%s", MG_VERSION));
|
||||||
|
for (;;) mg_mgr_poll(&mgr, 1000); // Infinite event loop
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
// Code taken from the ESP32 IDF WiFi station Example
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "esp_event.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include "esp_wifi.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/event_groups.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
|
||||||
|
#include "lwip/err.h"
|
||||||
|
#include "lwip/sys.h"
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static EventGroupHandle_t s_wifi_event_group;
|
||||||
|
|
||||||
|
/* The event group allows multiple bits for each event, but we only care about
|
||||||
|
* two events:
|
||||||
|
* - we are connected to the AP with an IP
|
||||||
|
* - we failed to connect after the maximum amount of retries */
|
||||||
|
#define WIFI_CONNECTED_BIT BIT0
|
||||||
|
#define WIFI_FAIL_BIT BIT1
|
||||||
|
|
||||||
|
static int s_retry_num = 0;
|
||||||
|
|
||||||
|
static void event_handler(void *arg, esp_event_base_t event_base,
|
||||||
|
int32_t event_id, void *event_data) {
|
||||||
|
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||||
|
esp_wifi_connect();
|
||||||
|
} else if (event_base == WIFI_EVENT &&
|
||||||
|
event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||||
|
if (s_retry_num < 3) {
|
||||||
|
esp_wifi_connect();
|
||||||
|
s_retry_num++;
|
||||||
|
LOG(LL_INFO, ("retry to connect to the AP"));
|
||||||
|
} else {
|
||||||
|
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
|
||||||
|
}
|
||||||
|
LOG(LL_ERROR, ("connect to the AP fail"));
|
||||||
|
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||||
|
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
|
||||||
|
LOG(LL_INFO, ("got ip:" IPSTR, IP2STR(&event->ip_info.ip)));
|
||||||
|
s_retry_num = 0;
|
||||||
|
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_init(const char *ssid, const char *pass) {
|
||||||
|
esp_err_t ret = nvs_flash_init();
|
||||||
|
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
|
||||||
|
ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
|
ret = nvs_flash_init();
|
||||||
|
}
|
||||||
|
ESP_ERROR_CHECK(ret);
|
||||||
|
|
||||||
|
s_wifi_event_group = xEventGroupCreate();
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(esp_netif_init());
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||||
|
esp_netif_create_default_wifi_sta();
|
||||||
|
|
||||||
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||||
|
|
||||||
|
esp_event_handler_instance_t instance_any_id;
|
||||||
|
esp_event_handler_instance_t instance_got_ip;
|
||||||
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
||||||
|
WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id));
|
||||||
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
||||||
|
IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip));
|
||||||
|
|
||||||
|
wifi_config_t c = {.sta = {.threshold = {.authmode = WIFI_AUTH_WPA2_PSK},
|
||||||
|
.pmf_cfg = {.capable = true, .required = false}}};
|
||||||
|
snprintf((char *) c.sta.ssid, sizeof(c.sta.ssid), "%s", ssid);
|
||||||
|
snprintf((char *) c.sta.password, sizeof(c.sta.password), "%s", pass);
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &c));
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_start());
|
||||||
|
LOG(LL_DEBUG, ("wifi_init_sta finished."));
|
||||||
|
|
||||||
|
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
|
||||||
|
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
|
||||||
|
pdFALSE, pdFALSE, portMAX_DELAY);
|
||||||
|
|
||||||
|
if (bits & WIFI_CONNECTED_BIT) {
|
||||||
|
LOG(LL_INFO, ("connected to ap SSID:%s password:%s", ssid, pass));
|
||||||
|
} else if (bits & WIFI_FAIL_BIT) {
|
||||||
|
LOG(LL_ERROR, ("Failed to connect to SSID:%s, password:%s", ssid, pass));
|
||||||
|
} else {
|
||||||
|
LOG(LL_ERROR, ("UNEXPECTED EVENT"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The event will not be processed after unregister */
|
||||||
|
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(
|
||||||
|
IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
|
||||||
|
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(
|
||||||
|
WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
|
||||||
|
vEventGroupDelete(s_wifi_event_group);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
|
nvs, data, nvs, 0x9000, 0x6000,
|
||||||
|
phy_init, data, phy, 0xf000, 0x1000,
|
||||||
|
storage, data, spiffs, 0x10000, 0x10000,
|
||||||
|
factory, app, factory, 0x100000, 1M,
|
||||||
|
@@ -0,0 +1,3 @@
|
|||||||
|
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||||
|
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||||
|
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
THISDIR = $(realpath $(CURDIR))
|
||||||
|
ROOTDIR = $(realpath $(CURDIR)/../..)
|
||||||
|
|
||||||
|
all: example
|
||||||
|
|
||||||
|
example: src/main/main.c src/main/wifi.c Makefile
|
||||||
|
docker run --rm -v $(ROOTDIR):$(ROOTDIR) -w $(THISDIR) docker.io/mdashnet/8266 make -C src defconfig app
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb mongoose mongoose_* mongoose.* src/build src/sdkconfig
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# An example ESP8266 application
|
||||||
|
|
||||||
|
To build this application, follow these steps:
|
||||||
|
|
||||||
|
1. Make sure you have Docker installed
|
||||||
|
2. Clone whole mongoose repository on your machine:
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/cesanta/mongoose.git
|
||||||
|
```
|
||||||
|
3. Start command line or terminal, and go into the example's directory:
|
||||||
|
```sh
|
||||||
|
cd mongoose/examples/esp8266
|
||||||
|
```
|
||||||
|
4. Run `make`. This invokes a Docker-based build. A firmware will be built
|
||||||
|
in the `src/build/` directory:
|
||||||
|
```sh
|
||||||
|
make example
|
||||||
|
```
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#
|
||||||
|
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||||
|
# project subdirectory.
|
||||||
|
#
|
||||||
|
|
||||||
|
PROJECT_NAME := mongoose-example
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#
|
||||||
|
# Main component makefile.
|
||||||
|
#
|
||||||
|
# This Makefile can be left empty. By default, it will take the sources in the
|
||||||
|
# src/ directory, compile them and link them into lib(subdirectory_name).a
|
||||||
|
# in the build directory. This behaviour is entirely configurable,
|
||||||
|
# please read the ESP-IDF documents if you need to do this.
|
||||||
|
#
|
||||||
|
|
||||||
|
COMPONENT_INCLUDES += ../../../../..
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
// Copyright (c) 2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
#define WIFI_SSID "WIFI_NETWORK" // SET THIS!
|
||||||
|
#define WIFI_PASS "WIFI_PASSWORD" // SET THIS!
|
||||||
|
|
||||||
|
#define SERVER_URL "http://0.0.0.0:80"
|
||||||
|
#define CLIENT_URL "http://info.cern.ch"
|
||||||
|
|
||||||
|
// Event handler for an server (accepted) connection
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_main(void) {
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../../mongoose.c
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include "esp_event.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include "esp_wifi.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/event_groups.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
|
||||||
|
#include "lwip/err.h"
|
||||||
|
#include "lwip/sys.h"
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static EventGroupHandle_t s_wifi_event_group;
|
||||||
|
|
||||||
|
/* The event group allows multiple bits for each event, but we only care about
|
||||||
|
* two events:
|
||||||
|
* - we are connected to the AP with an IP
|
||||||
|
* - we failed to connect after the maximum amount of retries */
|
||||||
|
#define WIFI_CONNECTED_BIT BIT0
|
||||||
|
#define WIFI_FAIL_BIT BIT1
|
||||||
|
|
||||||
|
static int s_retry_num = 0;
|
||||||
|
|
||||||
|
static void event_handler(void *arg, esp_event_base_t event_base,
|
||||||
|
int32_t event_id, void *event_data) {
|
||||||
|
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||||
|
esp_wifi_connect();
|
||||||
|
} else if (event_base == WIFI_EVENT &&
|
||||||
|
event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||||
|
if (s_retry_num < 3) {
|
||||||
|
esp_wifi_connect();
|
||||||
|
s_retry_num++;
|
||||||
|
LOG(LL_DEBUG, ("retry to connect to the AP"));
|
||||||
|
} else {
|
||||||
|
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
|
||||||
|
}
|
||||||
|
LOG(LL_ERROR, ("connect to the AP fail"));
|
||||||
|
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||||
|
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
|
||||||
|
LOG(LL_INFO, ("got ip:%s", ip4addr_ntoa(&event->ip_info.ip)));
|
||||||
|
s_retry_num = 0;
|
||||||
|
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_init(const char *ssid, const char *pass) {
|
||||||
|
s_wifi_event_group = xEventGroupCreate();
|
||||||
|
tcpip_adapter_init();
|
||||||
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||||
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||||
|
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID,
|
||||||
|
&event_handler, NULL));
|
||||||
|
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP,
|
||||||
|
&event_handler, NULL));
|
||||||
|
|
||||||
|
wifi_config_t c = {};
|
||||||
|
snprintf((char *) c.sta.ssid, sizeof(c.sta.ssid), "%s", ssid);
|
||||||
|
snprintf((char *) c.sta.password, sizeof(c.sta.password), "%s", pass);
|
||||||
|
if (pass != NULL && pass[0] != '\0') {
|
||||||
|
c.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
|
||||||
|
}
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &c));
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_start());
|
||||||
|
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
|
||||||
|
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
|
||||||
|
pdFALSE, pdFALSE, portMAX_DELAY);
|
||||||
|
|
||||||
|
if (bits & WIFI_CONNECTED_BIT) {
|
||||||
|
LOG(LL_INFO, ("connected to ap SSID:%s password:%s", ssid, pass));
|
||||||
|
} else if (bits & WIFI_FAIL_BIT) {
|
||||||
|
LOG(LL_ERROR, ("Failed to connect to SSID:%s, password:%s", ssid, pass));
|
||||||
|
} else {
|
||||||
|
LOG(LL_ERROR, ("UNEXPECTED EVENT"));
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP,
|
||||||
|
&event_handler));
|
||||||
|
ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID,
|
||||||
|
&event_handler));
|
||||||
|
vEventGroupDelete(s_wifi_event_group);
|
||||||
|
}
|
||||||
@@ -12,7 +12,8 @@ static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
if (mg_http_match_uri(hm, "/upload")) {
|
if (mg_http_match_uri(hm, "/upload")) {
|
||||||
mg_http_upload(c, hm, "/tmp");
|
mg_http_upload(c, hm, "/tmp");
|
||||||
} else {
|
} else {
|
||||||
mg_http_serve_dir(c, ev_data, "web_root");
|
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
|
||||||
|
mg_http_serve_dir(c, ev_data, &opts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
PROG ?= example
|
PROG ?= example
|
||||||
ARGS ?= http://www.ladyada.net/
|
CFLAGS ?= -DMG_ENABLE_LINES $(EXTRA)
|
||||||
MBEDTLS_DIR ?=
|
|
||||||
|
|
||||||
ifeq "$(MBEDTLS_DIR)" ""
|
ifneq ($(MBEDTLS),)
|
||||||
else
|
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS)/include -I/usr/include
|
||||||
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS_DIR)/include -I/usr/include
|
CFLAGS += -L$(MBEDTLS)/lib -lmbedtls -lmbedcrypto -lmbedx509
|
||||||
CFLAGS += -L$(MBEDTLS_DIR)/lib -lmbedtls -lmbedcrypto -lmbedx509
|
endif
|
||||||
|
|
||||||
|
ifneq ($(OPENSSL),)
|
||||||
|
CFLAGS += -DMG_ENABLE_OPENSSL=1 -I$(OPENSSL)/include
|
||||||
|
CFLAGS += -L$(OPENSSL)/lib -lssl -lcrypto
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: $(PROG)
|
all: $(PROG)
|
||||||
|
|||||||
+39
-29
@@ -1,46 +1,56 @@
|
|||||||
// Copyright (c) 2020 Cesanta Software Limited
|
// Copyright (c) 2021 Cesanta Software Limited
|
||||||
// All rights reserved
|
// All rights reserved
|
||||||
//
|
//
|
||||||
// Example HTTP client. Usage:
|
// Example HTTP client. Connect to `s_url`, send request, wait for a response,
|
||||||
// make
|
// print the response and exit.
|
||||||
// ./example http://www.ladyada.net/
|
// 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:
|
// 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"
|
#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
|
// Print HTTP response and signal that we're done
|
||||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
if (ev == MG_EV_HTTP_MSG) {
|
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_MSG) {
|
||||||
|
// Response is received. Print it
|
||||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
printf("%.*s", (int) hm->message.len, hm->message.ptr);
|
printf("%.*s", (int) hm->message.len, hm->message.ptr);
|
||||||
c->is_closing = 1;
|
c->is_closing = 1; // Tell mongoose to close this connection
|
||||||
*(bool *) fn_data = true;
|
*(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[]) {
|
int main(int argc, char *argv[]) {
|
||||||
struct mg_mgr mgr; // Event manager
|
struct mg_mgr mgr; // Event manager
|
||||||
mg_mgr_init(&mgr); // Initialise event manager
|
bool done = false; // Event handler flips it to true
|
||||||
|
if (argc > 1) s_url = argv[1]; // Use URL from command line
|
||||||
if (argc != 2) {
|
mg_log_set("3"); // Set to 0 to disable debug
|
||||||
fprintf(stderr, "Usage: %s URL\n", argv[0]); // Print error
|
mg_mgr_init(&mgr); // Initialise event manager
|
||||||
} else {
|
mg_http_connect(&mgr, s_url, fn, &done); // Create client connection
|
||||||
bool done = false; // Event handler flips it to true
|
while (!done) mg_mgr_poll(&mgr, 1000); // Infinite event loop
|
||||||
struct mg_connection *c = mg_http_connect(&mgr, argv[1], fn, &done);
|
mg_mgr_free(&mgr); // Free resources
|
||||||
if (c != NULL) {
|
|
||||||
mg_printf(c, "GET %s HTTP/1.0\r\n\r\n", mg_url_uri(argv[1]));
|
|
||||||
// If target URL is SSL/TLS, command client connection to use TLS
|
|
||||||
if (mg_url_is_ssl(argv[1])) {
|
|
||||||
struct mg_tls_opts opts = {.ca = "ca.pem"};
|
|
||||||
mg_tls_init(c, &opts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (done == false) mg_mgr_poll(&mgr, 1000); // Event loop
|
|
||||||
}
|
|
||||||
|
|
||||||
mg_mgr_free(&mgr);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
PROG ?= example
|
||||||
|
ARGS ?= http://www.ladyada.net/
|
||||||
|
MBEDTLS_DIR ?=
|
||||||
|
|
||||||
|
ifeq "$(MBEDTLS_DIR)" ""
|
||||||
|
else
|
||||||
|
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS_DIR)/include -I/usr/include
|
||||||
|
CFLAGS += -L$(MBEDTLS_DIR)/lib -lmbedtls -lmbedcrypto -lmbedx509
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(DEBUGGER) ./$(PROG) $(ARGS)
|
||||||
|
|
||||||
|
|
||||||
|
$(PROG): main.c
|
||||||
|
$(CC) ../../mongoose.c -I../.. -W -Wall $(CFLAGS) -o $(PROG) main.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb
|
||||||
@@ -0,0 +1,507 @@
|
|||||||
|
Subject: O=Digital Signature Trust Co., CN=DST Root CA X3
|
||||||
|
Not Before: Sep 30 21:12:19 2000 GMT
|
||||||
|
Not After : Sep 30 14:01:15 2021 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
|
||||||
|
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
||||||
|
DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
|
||||||
|
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
|
||||||
|
Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||||
|
AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
|
||||||
|
rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
|
||||||
|
OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
|
||||||
|
xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
|
||||||
|
7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
|
||||||
|
aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
|
||||||
|
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
|
||||||
|
SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
|
||||||
|
ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
|
||||||
|
AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
|
||||||
|
R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
|
||||||
|
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
|
||||||
|
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root
|
||||||
|
Not Before: May 12 18:46:00 2000 GMT
|
||||||
|
Not After : May 12 23:59:00 2025 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
|
||||||
|
RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
|
||||||
|
VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
|
||||||
|
DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
|
||||||
|
ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
|
||||||
|
VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
|
||||||
|
mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
|
||||||
|
IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
|
||||||
|
mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
|
||||||
|
XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
|
||||||
|
dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
|
||||||
|
jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
|
||||||
|
BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
|
||||||
|
DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
|
||||||
|
9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
|
||||||
|
jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
|
||||||
|
Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
|
||||||
|
ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
|
||||||
|
R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA
|
||||||
|
Not Before: May 21 04:00:00 2002 GMT
|
||||||
|
Not After : May 21 04:00:00 2022 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
|
||||||
|
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
|
||||||
|
YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
|
||||||
|
EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
|
||||||
|
R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
|
||||||
|
9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
|
||||||
|
fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
|
||||||
|
iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
|
||||||
|
1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
|
||||||
|
bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
|
||||||
|
MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
|
||||||
|
ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
|
||||||
|
uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
|
||||||
|
Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
|
||||||
|
tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
|
||||||
|
PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
|
||||||
|
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
|
||||||
|
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=Symantec Corporation, OU=Symantec Trust Network, CN=Symantec Class 3 ECC 256 bit SSL CA - G2
|
||||||
|
Not Before: May 12 00:00:00 2015 GMT
|
||||||
|
Not After : May 11 23:59:59 2025 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEajCCA1KgAwIBAgIQP5KHvp0dpKN6nfYoLndaxDANBgkqhkiG9w0BAQsFADCB
|
||||||
|
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||||
|
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
|
||||||
|
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
|
||||||
|
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
|
||||||
|
aG9yaXR5IC0gRzUwHhcNMTUwNTEyMDAwMDAwWhcNMjUwNTExMjM1OTU5WjCBgDEL
|
||||||
|
MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD
|
||||||
|
VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMTEwLwYDVQQDEyhTeW1hbnRlYyBD
|
||||||
|
bGFzcyAzIEVDQyAyNTYgYml0IFNTTCBDQSAtIEcyMFkwEwYHKoZIzj0CAQYIKoZI
|
||||||
|
zj0DAQcDQgAEDxukkdfnrOfRTk63ZFvhj39uBNOrONtEt0Bcbb2WljffeYmGZ/ex
|
||||||
|
Hwie/WM7RoyfvVPoFdyXPiuBRq2Gfw4BOaOCAV0wggFZMC4GCCsGAQUFBwEBBCIw
|
||||||
|
IDAeBggrBgEFBQcwAYYSaHR0cDovL3Muc3ltY2QuY29tMBIGA1UdEwEB/wQIMAYB
|
||||||
|
Af8CAQAwZQYDVR0gBF4wXDBaBgpghkgBhvhFAQc2MEwwIwYIKwYBBQUHAgEWF2h0
|
||||||
|
dHBzOi8vZC5zeW1jYi5jb20vY3BzMCUGCCsGAQUFBwICMBkaF2h0dHBzOi8vZC5z
|
||||||
|
eW1jYi5jb20vcnBhMC8GA1UdHwQoMCYwJKAioCCGHmh0dHA6Ly9zLnN5bWNiLmNv
|
||||||
|
bS9wY2EzLWc1LmNybDAOBgNVHQ8BAf8EBAMCAQYwKwYDVR0RBCQwIqQgMB4xHDAa
|
||||||
|
BgNVBAMTE1NZTUMtRUNDLUNBLXAyNTYtMjIwHQYDVR0OBBYEFCXwiuFLetkBlQrt
|
||||||
|
xlPxjHgf2fP4MB8GA1UdIwQYMBaAFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG
|
||||||
|
SIb3DQEBCwUAA4IBAQAMMGUXBaWTdaLxsTGtcB/naqjIQrLvoV9NG+7MoHpGd/69
|
||||||
|
dZ/h2zOy7sGFUHoG/0HGRA9rxT/5w5GkEVIVkxtWyIWWq6rs4CTZt8Bej/KHYRbo
|
||||||
|
jtEDUkCTZSTLiCvguPyvinXgxy+LHT+PmdtEfXsvcdbeBSWUYpOsDYvD2hNtz9dw
|
||||||
|
Od5nBosMApmdxt+z7LQyZu8wMnfI1U6IMO+RWowxZ8uy0oswdFYd32l9xe+aAE/k
|
||||||
|
y9alLu/M9pvxiUKufqHJRgDBKA6uDjHLMPX+/nxXaNCPX3SI4KVZ1stHQ/U5oNlM
|
||||||
|
dHN9umAvlU313g0IgJrjsQ2nIdf9dsdP+6lrmP7s
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5
|
||||||
|
Not Before: Nov 8 00:00:00 2006 GMT
|
||||||
|
Not After : Jul 16 23:59:59 2036 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
|
||||||
|
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||||
|
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
|
||||||
|
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
|
||||||
|
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
|
||||||
|
aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
|
||||||
|
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
|
||||||
|
ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
|
||||||
|
biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
|
||||||
|
U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
|
||||||
|
aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
|
||||||
|
nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
|
||||||
|
t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
|
||||||
|
SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
|
||||||
|
BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
|
||||||
|
rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
|
||||||
|
NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
|
||||||
|
BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
|
||||||
|
BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
|
||||||
|
aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
|
||||||
|
MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
|
||||||
|
p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
|
||||||
|
5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
|
||||||
|
WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
|
||||||
|
4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
|
||||||
|
hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority
|
||||||
|
Not Before: Jun 29 17:06:20 2004 GMT
|
||||||
|
Not After : Jun 29 17:06:20 2034 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
|
||||||
|
MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
|
||||||
|
YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
|
||||||
|
MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
|
||||||
|
ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
|
||||||
|
MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
|
||||||
|
ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
|
||||||
|
PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
|
||||||
|
wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
|
||||||
|
EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
|
||||||
|
avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
|
||||||
|
YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
|
||||||
|
sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
|
||||||
|
/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
|
||||||
|
IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
|
||||||
|
YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
|
||||||
|
ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
|
||||||
|
OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
|
||||||
|
TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
|
||||||
|
HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
|
||||||
|
dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
|
||||||
|
ReYNnyicsbkqWletNw+vHX/bvZ8=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
# Note: Amazon ATS endpoint uses this (2018/12/18)
|
||||||
|
Subject: C=US, O=Starfield Technologies, Inc., OU=Starfield Class 2 Certification Authority
|
||||||
|
Not Before: Jun 29 17:39:16 2004 GMT
|
||||||
|
Not After : Jun 29 17:39:16 2034 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
|
||||||
|
MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
|
||||||
|
U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
|
||||||
|
NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
|
||||||
|
ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
|
||||||
|
ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
|
||||||
|
DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
|
||||||
|
8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
|
||||||
|
+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
|
||||||
|
X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
|
||||||
|
K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
|
||||||
|
1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
|
||||||
|
A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
|
||||||
|
zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
|
||||||
|
YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
|
||||||
|
bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
|
||||||
|
DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
|
||||||
|
L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
|
||||||
|
eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
|
||||||
|
xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
|
||||||
|
VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
|
||||||
|
WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Sep 1 00:00:00 2009 GMT
|
||||||
|
Not After : Dec 31 23:59:59 2037 GMT
|
||||||
|
Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Root Certificate Authority - G2
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx
|
||||||
|
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
|
||||||
|
HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs
|
||||||
|
ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw
|
||||||
|
MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
|
||||||
|
b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj
|
||||||
|
aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp
|
||||||
|
Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||||
|
ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg
|
||||||
|
nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1
|
||||||
|
HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N
|
||||||
|
Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN
|
||||||
|
dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0
|
||||||
|
HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
|
||||||
|
BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G
|
||||||
|
CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU
|
||||||
|
sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3
|
||||||
|
4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg
|
||||||
|
8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
|
||||||
|
pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1
|
||||||
|
mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Services Root Certificate Authority - G2
|
||||||
|
Not Before: Sep 1 00:00:00 2009 GMT
|
||||||
|
Not After : Dec 31 23:59:59 2037 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
|
||||||
|
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
|
||||||
|
HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs
|
||||||
|
ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
|
||||||
|
MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD
|
||||||
|
VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy
|
||||||
|
ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy
|
||||||
|
dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
|
||||||
|
hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p
|
||||||
|
OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2
|
||||||
|
8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K
|
||||||
|
Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe
|
||||||
|
hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk
|
||||||
|
6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw
|
||||||
|
DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q
|
||||||
|
AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI
|
||||||
|
bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB
|
||||||
|
ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z
|
||||||
|
qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
|
||||||
|
iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn
|
||||||
|
0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN
|
||||||
|
sSi6
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign
|
||||||
|
Not Before: Dec 15 08:00:00 2006 GMT
|
||||||
|
Not After : Dec 15 08:00:00 2021 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
|
||||||
|
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
|
||||||
|
Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
|
||||||
|
MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
|
||||||
|
A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
|
||||||
|
hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
|
||||||
|
v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
|
||||||
|
eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
|
||||||
|
tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
|
||||||
|
C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
|
||||||
|
zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
|
||||||
|
mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
|
||||||
|
V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
|
||||||
|
bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
|
||||||
|
3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
|
||||||
|
J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
|
||||||
|
291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
|
||||||
|
ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
|
||||||
|
AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
|
||||||
|
TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA
|
||||||
|
Not Before: Nov 10 00:00:00 2006 GMT
|
||||||
|
Not After : Nov 10 00:00:00 2031 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||||
|
ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
|
||||||
|
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
||||||
|
LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
|
||||||
|
RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
|
||||||
|
+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
|
||||||
|
PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
|
||||||
|
xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
|
||||||
|
Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
|
||||||
|
hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
|
||||||
|
EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
|
||||||
|
MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
|
||||||
|
FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
|
||||||
|
nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
|
||||||
|
eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
|
||||||
|
hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
|
||||||
|
Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
|
||||||
|
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
|
||||||
|
+OkuE6N36B9K
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA
|
||||||
|
Not Before: Nov 10 00:00:00 2006 GMT
|
||||||
|
Not After : Nov 10 00:00:00 2031 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||||
|
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||||
|
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||||
|
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||||
|
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||||
|
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||||
|
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||||
|
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||||
|
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||||
|
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||||
|
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||||
|
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||||
|
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||||
|
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||||
|
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||||
|
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||||
|
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||||
|
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
# *.azure-devices.de use this root.
|
||||||
|
Subject: C = DE, O = D-Trust GmbH, CN = D-TRUST Root Class 3 CA 2 2009
|
||||||
|
Not Before: Nov 5 08:35:58 2009 GMT
|
||||||
|
Not After : Nov 5 08:35:58 2029 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF
|
||||||
|
MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD
|
||||||
|
bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha
|
||||||
|
ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM
|
||||||
|
HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB
|
||||||
|
BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03
|
||||||
|
UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42
|
||||||
|
tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R
|
||||||
|
ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM
|
||||||
|
lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp
|
||||||
|
/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G
|
||||||
|
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G
|
||||||
|
A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj
|
||||||
|
dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy
|
||||||
|
MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl
|
||||||
|
cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js
|
||||||
|
L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL
|
||||||
|
BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni
|
||||||
|
acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
|
||||||
|
o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K
|
||||||
|
zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8
|
||||||
|
PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y
|
||||||
|
Johw1+qRzT65ysCQblrGXnRl11z+o+I=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
# https://www.amazontrust.com/repository/
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 1
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : Jan 17 00:00:00 2038 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
|
||||||
|
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
|
||||||
|
b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
|
||||||
|
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
|
||||||
|
b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
|
||||||
|
ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
|
||||||
|
9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
|
||||||
|
IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
|
||||||
|
VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
|
||||||
|
93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
|
||||||
|
jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
|
||||||
|
AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
|
||||||
|
A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
|
||||||
|
U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
|
||||||
|
N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
|
||||||
|
o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
|
||||||
|
5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
|
||||||
|
rqXRfboQnoZsG4q5WTP468SQvvG5
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 2
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : May 26 00:00:00 2040 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF
|
||||||
|
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
|
||||||
|
b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL
|
||||||
|
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
|
||||||
|
b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK
|
||||||
|
gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ
|
||||||
|
W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg
|
||||||
|
1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K
|
||||||
|
8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r
|
||||||
|
2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me
|
||||||
|
z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR
|
||||||
|
8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj
|
||||||
|
mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz
|
||||||
|
7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6
|
||||||
|
+XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI
|
||||||
|
0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB
|
||||||
|
Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm
|
||||||
|
UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2
|
||||||
|
LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY
|
||||||
|
+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS
|
||||||
|
k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl
|
||||||
|
7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm
|
||||||
|
btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl
|
||||||
|
urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+
|
||||||
|
fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63
|
||||||
|
n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE
|
||||||
|
76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H
|
||||||
|
9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT
|
||||||
|
4PsJYGw=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : May 26 00:00:00 2040 GMT
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 3
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5
|
||||||
|
MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
|
||||||
|
Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
|
||||||
|
A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
|
||||||
|
Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl
|
||||||
|
ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j
|
||||||
|
QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr
|
||||||
|
ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr
|
||||||
|
BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM
|
||||||
|
YyRIHN8wfdVoOw==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : May 26 00:00:00 2040 GMT
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 4
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5
|
||||||
|
MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
|
||||||
|
Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
|
||||||
|
A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
|
||||||
|
Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi
|
||||||
|
9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk
|
||||||
|
M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB
|
||||||
|
/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB
|
||||||
|
MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw
|
||||||
|
CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW
|
||||||
|
1KyLa2tJElMzrdfkviT8tQp21KW8EA==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Nov 10 00:00:00 2006 GMT
|
||||||
|
Not After : Nov 10 00:00:00 2031 GMT
|
||||||
|
Subject: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||||
|
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||||
|
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||||
|
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||||
|
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||||
|
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||||
|
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||||
|
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||||
|
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||||
|
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||||
|
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||||
|
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||||
|
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||||
|
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||||
|
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||||
|
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||||
|
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||||
|
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Nov 13 00:00:00 2012 GMT
|
||||||
|
Not After : Jan 19 03:14:07 2038 GMT
|
||||||
|
Subject: OU = GlobalSign ECC Root CA - R4, O = GlobalSign, CN = GlobalSign
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk
|
||||||
|
MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH
|
||||||
|
bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
|
||||||
|
DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
|
||||||
|
QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
|
||||||
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ
|
||||||
|
FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw
|
||||||
|
DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F
|
||||||
|
uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX
|
||||||
|
kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs
|
||||||
|
ewv4n4Q=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Nov 1 00:00:42 2018 GMT
|
||||||
|
Not After : Nov 1 00:00:42 2042 GMT
|
||||||
|
Subject: C = US, O = Google Trust Services LLC, CN = GTS LTSR
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBxTCCAWugAwIBAgINAfD3nVndblD3QnNxUDAKBggqhkjOPQQDAjBEMQswCQYD
|
||||||
|
VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzERMA8G
|
||||||
|
A1UEAxMIR1RTIExUU1IwHhcNMTgxMTAxMDAwMDQyWhcNNDIxMTAxMDAwMDQyWjBE
|
||||||
|
MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
|
||||||
|
QzERMA8GA1UEAxMIR1RTIExUU1IwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATN
|
||||||
|
8YyO2u+yCQoZdwAkUNv5c3dokfULfrA6QJgFV2XMuENtQZIG5HUOS6jFn8f0ySlV
|
||||||
|
eORCxqFyjDJyRn86d+Iko0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUw
|
||||||
|
AwEB/zAdBgNVHQ4EFgQUPv7/zFLrvzQ+PfNA0OQlsV+4u1IwCgYIKoZIzj0EAwID
|
||||||
|
SAAwRQIhAPKuf/VtBHqGw3TUwUIq7TfaExp3bH7bjCBmVXJupT9FAiBr0SmCtsuk
|
||||||
|
miGgpajjf/gFigGM34F9021bCWs1MbL0SA==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
// Copyright (c) 2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// Example HTTP client that uses a proxy server. Usage:
|
||||||
|
// make
|
||||||
|
// ./example PROXY:PORT http://www.ladyada.net
|
||||||
|
//
|
||||||
|
// To enable SSL/TLS for this client, build it like this:
|
||||||
|
// make MBEDTLS_DIR=/path/to/your/mbedtls/installation
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
// Print HTTP response and signal that we're done
|
||||||
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
const char *url = fn_data;
|
||||||
|
static bool connected;
|
||||||
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
printf("%.*s", (int) hm->message.len, hm->message.ptr);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
} else if (ev == MG_EV_CONNECT) {
|
||||||
|
// Proxy TCP connection established. Send CONNECT request
|
||||||
|
struct mg_str host = mg_url_host(url);
|
||||||
|
// c->is_hexdumping = 1;
|
||||||
|
mg_printf(c, "CONNECT %.*s:%hu HTTP/1.1\r\nHost: %.*s:%hu\r\n\r\n",
|
||||||
|
(int) host.len, host.ptr, mg_url_port(url), (int) host.len,
|
||||||
|
host.ptr, mg_url_port(url));
|
||||||
|
// If target URL is SSL/TLS, command client connection to use TLS
|
||||||
|
if (mg_url_is_ssl(url)) {
|
||||||
|
struct mg_tls_opts opts = {.ca = "ca.pem"};
|
||||||
|
mg_tls_init(c, &opts);
|
||||||
|
}
|
||||||
|
} else if (!connected && ev == MG_EV_READ) {
|
||||||
|
struct mg_http_message hm;
|
||||||
|
int n = mg_http_parse((char *) c->recv.buf, c->recv.len, &hm);
|
||||||
|
if (n > 0) {
|
||||||
|
struct mg_str host = mg_url_host(url);
|
||||||
|
// CONNECT response - tunnel is established
|
||||||
|
connected = true;
|
||||||
|
LOG(LL_DEBUG,
|
||||||
|
("Connected to proxy, status: %.*s", (int) hm.uri.len, hm.uri.ptr));
|
||||||
|
mg_iobuf_delete(&c->recv, n);
|
||||||
|
// Send request to the target server
|
||||||
|
mg_printf(c, "GET / HTTP/1.0\r\nHost: %.*s\r\n\r\n", (int) host.len,
|
||||||
|
host.ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
struct mg_mgr mgr;
|
||||||
|
|
||||||
|
if (argc != 3) {
|
||||||
|
fprintf(stderr, "Usage: %s PROXY_URL URL\n", argv[0]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mg_mgr_init(&mgr); // Initialise event manager
|
||||||
|
mg_http_connect(&mgr, argv[1], fn, argv[2]); // Connect to the proxy
|
||||||
|
for (;;) mg_mgr_poll(&mgr, 1000); // Event loop
|
||||||
|
mg_mgr_free(&mgr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
PROG ?= example
|
PROG ?= example
|
||||||
|
|
||||||
|
ifeq "$(MBEDTLS_DIR)" ""
|
||||||
|
else
|
||||||
|
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS_DIR)/include -I/usr/include
|
||||||
|
CFLAGS += -L$(MBEDTLS_DIR)/lib -lmbedtls -lmbedcrypto -lmbedx509
|
||||||
|
endif
|
||||||
|
|
||||||
all: $(PROG)
|
all: $(PROG)
|
||||||
$(DEBUGGER) ./$(PROG) $(ARGS)
|
$(DEBUGGER) ./$(PROG) $(ARGS)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
Certificate:
|
||||||
|
Data:
|
||||||
|
Version: 3 (0x2)
|
||||||
|
Serial Number:
|
||||||
|
11:2a:0e:3c:6a:8c:85:ff:6e:6a:bc:db:95:51:70:ce:b4:30:78:c7
|
||||||
|
Signature Algorithm: ecdsa-with-SHA256
|
||||||
|
Issuer: C = IE, L = Dublin, O = Cesanta, CN = Test Root
|
||||||
|
Validity
|
||||||
|
Not Before: May 9 21:51:44 2020 GMT
|
||||||
|
Not After : May 9 21:51:44 2050 GMT
|
||||||
|
Subject: C = IE, L = Dublin, O = Cesanta, CN = Test Root
|
||||||
|
Subject Public Key Info:
|
||||||
|
Public Key Algorithm: id-ecPublicKey
|
||||||
|
Public-Key: (256 bit)
|
||||||
|
pub:
|
||||||
|
04:2c:ab:d1:02:66:24:96:d7:12:3e:09:50:4f:f1:
|
||||||
|
50:ee:51:e8:55:03:5e:ba:b1:1d:98:b2:72:79:27:
|
||||||
|
a8:1b:31:0d:5d:50:21:ff:42:f2:da:74:17:5e:53:
|
||||||
|
b2:65:41:c1:fc:84:de:4a:11:b9:8c:f4:19:d9:c4:
|
||||||
|
ca:2b:ea:eb:2c
|
||||||
|
ASN1 OID: prime256v1
|
||||||
|
NIST CURVE: P-256
|
||||||
|
X509v3 extensions:
|
||||||
|
X509v3 Basic Constraints:
|
||||||
|
CA:TRUE
|
||||||
|
X509v3 Key Usage:
|
||||||
|
Digital Signature, Key Encipherment, Key Agreement, Certificate Sign, CRL Sign
|
||||||
|
Signature Algorithm: ecdsa-with-SHA256
|
||||||
|
30:46:02:21:00:9c:71:6c:00:8c:06:41:0c:91:2f:cd:41:d3:
|
||||||
|
87:47:e9:df:3a:22:ad:25:7c:bf:0e:2b:39:dd:7a:0c:4e:68:
|
||||||
|
1d:02:21:00:8f:c1:22:30:10:61:5d:51:10:ea:08:2d:02:63:
|
||||||
|
67:67:32:b5:06:63:96:57:bb:78:47:0a:88:d9:19:2e:f3:be
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBqjCCAU+gAwIBAgIUESoOPGqMhf9uarzblVFwzrQweMcwCgYIKoZIzj0EAwIw
|
||||||
|
RDELMAkGA1UEBhMCSUUxDzANBgNVBAcMBkR1YmxpbjEQMA4GA1UECgwHQ2VzYW50
|
||||||
|
YTESMBAGA1UEAwwJVGVzdCBSb290MCAXDTIwMDUwOTIxNTE0NFoYDzIwNTAwNTA5
|
||||||
|
MjE1MTQ0WjBEMQswCQYDVQQGEwJJRTEPMA0GA1UEBwwGRHVibGluMRAwDgYDVQQK
|
||||||
|
DAdDZXNhbnRhMRIwEAYDVQQDDAlUZXN0IFJvb3QwWTATBgcqhkjOPQIBBggqhkjO
|
||||||
|
PQMBBwNCAAQsq9ECZiSW1xI+CVBP8VDuUehVA166sR2YsnJ5J6gbMQ1dUCH/QvLa
|
||||||
|
dBdeU7JlQcH8hN5KEbmM9BnZxMor6ussox0wGzAMBgNVHRMEBTADAQH/MAsGA1Ud
|
||||||
|
DwQEAwIBrjAKBggqhkjOPQQDAgNJADBGAiEAnHFsAIwGQQyRL81B04dH6d86Iq0l
|
||||||
|
fL8OKzndegxOaB0CIQCPwSIwEGFdURDqCC0CY2dnMrUGY5ZXu3hHCojZGS7zvg==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -1,25 +1,41 @@
|
|||||||
// Copyright (c) 2020 Cesanta Software Limited
|
// Copyright (c) 2020 Cesanta Software Limited
|
||||||
// All rights reserved
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// HTTP server example. This server serves both static and dynamic content.
|
||||||
|
// It implements the following endpoints:
|
||||||
|
// /api/f1 - respond with JSON string {"result": 123}
|
||||||
|
// /api/f2/:id - wildcard example, respond with JSON string {"result": "URI"}
|
||||||
|
// any other URI serves static files from s_web_directory
|
||||||
|
//
|
||||||
|
// To enable SSL/TLS (using self-signed certificates in PEM files),
|
||||||
|
// 1. Change s_listen_on from http:// to https://
|
||||||
|
// 2. make MBEDTLS_DIR=/path/to/your/mbedtls/installation
|
||||||
|
// 3. curl -k https://127.0.0.1:8000
|
||||||
|
|
||||||
#include "mongoose.h"
|
#include "mongoose.h"
|
||||||
|
|
||||||
static const char *s_listen_on = "http://localhost:8000";
|
static const char *s_listen_on = "http://0.0.0.0:8000";
|
||||||
static const char *s_web_directory = ".";
|
static const char *s_web_directory = ".";
|
||||||
|
|
||||||
// This RESTful server implements the following endpoints:
|
|
||||||
// /api/f1 - respond with JSON string {"result": 123}
|
|
||||||
// /api/f2/:id - wildcard example, respond with JSON string {"result": "URI"}
|
|
||||||
// any other URI serves static files from s_web_directory
|
|
||||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
if (ev == MG_EV_HTTP_MSG) {
|
if (ev == MG_EV_ACCEPT && mg_url_is_ssl(s_listen_on)) {
|
||||||
|
// If s_listen_on URL is https://, tell listening connection to use TLS
|
||||||
|
struct mg_tls_opts opts = {
|
||||||
|
//.ca = "ca.pem", // Uncomment to enable two-way SSL
|
||||||
|
.cert = "server.pem", // Certificate PEM file
|
||||||
|
.certkey = "server.pem", // This pem conains both cert and key
|
||||||
|
};
|
||||||
|
mg_tls_init(c, &opts);
|
||||||
|
} else if (ev == MG_EV_HTTP_MSG) {
|
||||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
if (mg_http_match_uri(hm, "/api/f1")) {
|
if (mg_http_match_uri(hm, "/api/f1")) {
|
||||||
mg_http_reply(c, 200, "{\"result\": %d}\n", 123); // Serve REST response
|
mg_http_reply(c, 200, "", "{\"result\": %d}\n", 123); // Serve REST
|
||||||
} else if (mg_http_match_uri(hm, "/api/f2/*")) {
|
} else if (mg_http_match_uri(hm, "/api/f2/*")) {
|
||||||
mg_http_reply(c, 200, "{\"result\": \"%.*s\"}\n", (int) hm->uri.len,
|
mg_http_reply(c, 200, "", "{\"result\": \"%.*s\"}\n", (int) hm->uri.len,
|
||||||
hm->uri.ptr);
|
hm->uri.ptr);
|
||||||
} else {
|
} else {
|
||||||
mg_http_serve_dir(c, ev_data, s_web_directory); // Serve static files
|
struct mg_http_serve_opts opts = {.root_dir = s_web_directory};
|
||||||
|
mg_http_serve_dir(c, ev_data, &opts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(void) fn_data;
|
(void) fn_data;
|
||||||
@@ -27,6 +43,7 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
struct mg_mgr mgr; // Event manager
|
struct mg_mgr mgr; // Event manager
|
||||||
|
mg_log_set("2"); // Set to 3 to enable debug
|
||||||
mg_mgr_init(&mgr); // Initialise event manager
|
mg_mgr_init(&mgr); // Initialise event manager
|
||||||
mg_http_listen(&mgr, s_listen_on, fn, NULL); // Create HTTP listener
|
mg_http_listen(&mgr, s_listen_on, fn, NULL); // Create HTTP listener
|
||||||
for (;;) mg_mgr_poll(&mgr, 1000); // Infinite event loop
|
for (;;) mg_mgr_poll(&mgr, 1000); // Infinite event loop
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
Certificate:
|
||||||
|
Data:
|
||||||
|
Version: 3 (0x2)
|
||||||
|
Serial Number:
|
||||||
|
6e:73:28:55:df:13:b5:61:f5:4f:4f:5d:00:d9:0a:d8:b5:3a:21:4b
|
||||||
|
Signature Algorithm: ecdsa-with-SHA256
|
||||||
|
Issuer: C = IE, L = Dublin, O = Cesanta, CN = Test Root
|
||||||
|
Validity
|
||||||
|
Not Before: May 9 21:51:49 2020 GMT
|
||||||
|
Not After : May 9 21:51:49 2030 GMT
|
||||||
|
Subject: CN = server
|
||||||
|
Subject Public Key Info:
|
||||||
|
Public Key Algorithm: id-ecPublicKey
|
||||||
|
Public-Key: (256 bit)
|
||||||
|
pub:
|
||||||
|
04:92:e0:46:9c:89:c3:37:a9:74:eb:35:55:43:55:
|
||||||
|
5c:ac:eb:c7:e4:50:ee:f4:c0:ba:17:02:5c:d9:ed:
|
||||||
|
b4:d4:ff:21:12:9a:b4:43:f4:89:4b:69:e4:6d:2b:
|
||||||
|
96:1f:fc:01:4d:30:5a:79:73:76:ba:19:41:cc:c5:
|
||||||
|
16:2b:bf:74:28
|
||||||
|
ASN1 OID: prime256v1
|
||||||
|
NIST CURVE: P-256
|
||||||
|
X509v3 extensions:
|
||||||
|
X509v3 Basic Constraints:
|
||||||
|
CA:FALSE
|
||||||
|
X509v3 Key Usage:
|
||||||
|
Digital Signature, Key Encipherment, Key Agreement
|
||||||
|
X509v3 Extended Key Usage:
|
||||||
|
TLS Web Server Authentication
|
||||||
|
Signature Algorithm: ecdsa-with-SHA256
|
||||||
|
30:46:02:21:00:fa:3a:c7:1e:cb:8c:27:59:41:8d:77:dd:7b:
|
||||||
|
cb:8c:08:15:16:b9:6e:70:e6:47:38:d1:55:42:e0:d7:66:c8:
|
||||||
|
f0:02:21:00:cc:70:4d:96:28:00:d3:c7:39:53:74:b2:49:87:
|
||||||
|
27:92:1b:ab:1a:0e:74:06:59:42:23:47:98:43:d8:20:a7:fa
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBhzCCASygAwIBAgIUbnMoVd8TtWH1T09dANkK2LU6IUswCgYIKoZIzj0EAwIw
|
||||||
|
RDELMAkGA1UEBhMCSUUxDzANBgNVBAcMBkR1YmxpbjEQMA4GA1UECgwHQ2VzYW50
|
||||||
|
YTESMBAGA1UEAwwJVGVzdCBSb290MB4XDTIwMDUwOTIxNTE0OVoXDTMwMDUwOTIx
|
||||||
|
NTE0OVowETEPMA0GA1UEAwwGc2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD
|
||||||
|
QgAEkuBGnInDN6l06zVVQ1VcrOvH5FDu9MC6FwJc2e201P8hEpq0Q/SJS2nkbSuW
|
||||||
|
H/wBTTBaeXN2uhlBzMUWK790KKMvMC0wCQYDVR0TBAIwADALBgNVHQ8EBAMCA6gw
|
||||||
|
EwYDVR0lBAwwCgYIKwYBBQUHAwEwCgYIKoZIzj0EAwIDSQAwRgIhAPo6xx7LjCdZ
|
||||||
|
QY133XvLjAgVFrlucOZHONFVQuDXZsjwAiEAzHBNligA08c5U3SySYcnkhurGg50
|
||||||
|
BllCI0eYQ9ggp/o=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQglNni0t9Dg9icgG8w
|
||||||
|
kbfxWSS+TuNgbtNybIQXcm3NHpmhRANCAASS4EacicM3qXTrNVVDVVys68fkUO70
|
||||||
|
wLoXAlzZ7bTU/yESmrRD9IlLaeRtK5Yf/AFNMFp5c3a6GUHMxRYrv3Qo
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
PROG ?= example
|
||||||
|
CFLAGS ?= -DMG_IO_SIZE=8192
|
||||||
|
MBEDTLS_DIR ?=
|
||||||
|
|
||||||
|
ifeq "$(MBEDTLS_DIR)" ""
|
||||||
|
else
|
||||||
|
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS_DIR)/include -I/usr/include
|
||||||
|
CFLAGS += -L$(MBEDTLS_DIR)/lib -lmbedtls -lmbedcrypto -lmbedx509
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(DEBUGGER) ./$(PROG) $(ARGS)
|
||||||
|
|
||||||
|
|
||||||
|
$(PROG): main.c
|
||||||
|
$(CC) ../../mongoose.c -I../.. -W -Wall $(CFLAGS) -o $(PROG) main.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb
|
||||||
@@ -0,0 +1,507 @@
|
|||||||
|
Subject: O=Digital Signature Trust Co., CN=DST Root CA X3
|
||||||
|
Not Before: Sep 30 21:12:19 2000 GMT
|
||||||
|
Not After : Sep 30 14:01:15 2021 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
|
||||||
|
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
||||||
|
DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
|
||||||
|
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
|
||||||
|
Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||||
|
AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
|
||||||
|
rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
|
||||||
|
OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
|
||||||
|
xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
|
||||||
|
7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
|
||||||
|
aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
|
||||||
|
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
|
||||||
|
SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
|
||||||
|
ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
|
||||||
|
AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
|
||||||
|
R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
|
||||||
|
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
|
||||||
|
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root
|
||||||
|
Not Before: May 12 18:46:00 2000 GMT
|
||||||
|
Not After : May 12 23:59:00 2025 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
|
||||||
|
RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
|
||||||
|
VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
|
||||||
|
DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
|
||||||
|
ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
|
||||||
|
VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
|
||||||
|
mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
|
||||||
|
IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
|
||||||
|
mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
|
||||||
|
XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
|
||||||
|
dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
|
||||||
|
jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
|
||||||
|
BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
|
||||||
|
DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
|
||||||
|
9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
|
||||||
|
jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
|
||||||
|
Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
|
||||||
|
ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
|
||||||
|
R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA
|
||||||
|
Not Before: May 21 04:00:00 2002 GMT
|
||||||
|
Not After : May 21 04:00:00 2022 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
|
||||||
|
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
|
||||||
|
YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
|
||||||
|
EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
|
||||||
|
R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
|
||||||
|
9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
|
||||||
|
fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
|
||||||
|
iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
|
||||||
|
1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
|
||||||
|
bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
|
||||||
|
MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
|
||||||
|
ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
|
||||||
|
uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
|
||||||
|
Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
|
||||||
|
tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
|
||||||
|
PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
|
||||||
|
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
|
||||||
|
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=Symantec Corporation, OU=Symantec Trust Network, CN=Symantec Class 3 ECC 256 bit SSL CA - G2
|
||||||
|
Not Before: May 12 00:00:00 2015 GMT
|
||||||
|
Not After : May 11 23:59:59 2025 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEajCCA1KgAwIBAgIQP5KHvp0dpKN6nfYoLndaxDANBgkqhkiG9w0BAQsFADCB
|
||||||
|
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||||
|
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
|
||||||
|
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
|
||||||
|
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
|
||||||
|
aG9yaXR5IC0gRzUwHhcNMTUwNTEyMDAwMDAwWhcNMjUwNTExMjM1OTU5WjCBgDEL
|
||||||
|
MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD
|
||||||
|
VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMTEwLwYDVQQDEyhTeW1hbnRlYyBD
|
||||||
|
bGFzcyAzIEVDQyAyNTYgYml0IFNTTCBDQSAtIEcyMFkwEwYHKoZIzj0CAQYIKoZI
|
||||||
|
zj0DAQcDQgAEDxukkdfnrOfRTk63ZFvhj39uBNOrONtEt0Bcbb2WljffeYmGZ/ex
|
||||||
|
Hwie/WM7RoyfvVPoFdyXPiuBRq2Gfw4BOaOCAV0wggFZMC4GCCsGAQUFBwEBBCIw
|
||||||
|
IDAeBggrBgEFBQcwAYYSaHR0cDovL3Muc3ltY2QuY29tMBIGA1UdEwEB/wQIMAYB
|
||||||
|
Af8CAQAwZQYDVR0gBF4wXDBaBgpghkgBhvhFAQc2MEwwIwYIKwYBBQUHAgEWF2h0
|
||||||
|
dHBzOi8vZC5zeW1jYi5jb20vY3BzMCUGCCsGAQUFBwICMBkaF2h0dHBzOi8vZC5z
|
||||||
|
eW1jYi5jb20vcnBhMC8GA1UdHwQoMCYwJKAioCCGHmh0dHA6Ly9zLnN5bWNiLmNv
|
||||||
|
bS9wY2EzLWc1LmNybDAOBgNVHQ8BAf8EBAMCAQYwKwYDVR0RBCQwIqQgMB4xHDAa
|
||||||
|
BgNVBAMTE1NZTUMtRUNDLUNBLXAyNTYtMjIwHQYDVR0OBBYEFCXwiuFLetkBlQrt
|
||||||
|
xlPxjHgf2fP4MB8GA1UdIwQYMBaAFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG
|
||||||
|
SIb3DQEBCwUAA4IBAQAMMGUXBaWTdaLxsTGtcB/naqjIQrLvoV9NG+7MoHpGd/69
|
||||||
|
dZ/h2zOy7sGFUHoG/0HGRA9rxT/5w5GkEVIVkxtWyIWWq6rs4CTZt8Bej/KHYRbo
|
||||||
|
jtEDUkCTZSTLiCvguPyvinXgxy+LHT+PmdtEfXsvcdbeBSWUYpOsDYvD2hNtz9dw
|
||||||
|
Od5nBosMApmdxt+z7LQyZu8wMnfI1U6IMO+RWowxZ8uy0oswdFYd32l9xe+aAE/k
|
||||||
|
y9alLu/M9pvxiUKufqHJRgDBKA6uDjHLMPX+/nxXaNCPX3SI4KVZ1stHQ/U5oNlM
|
||||||
|
dHN9umAvlU313g0IgJrjsQ2nIdf9dsdP+6lrmP7s
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5
|
||||||
|
Not Before: Nov 8 00:00:00 2006 GMT
|
||||||
|
Not After : Jul 16 23:59:59 2036 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
|
||||||
|
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||||
|
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
|
||||||
|
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
|
||||||
|
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
|
||||||
|
aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
|
||||||
|
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
|
||||||
|
ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
|
||||||
|
biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
|
||||||
|
U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
|
||||||
|
aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
|
||||||
|
nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
|
||||||
|
t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
|
||||||
|
SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
|
||||||
|
BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
|
||||||
|
rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
|
||||||
|
NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
|
||||||
|
BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
|
||||||
|
BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
|
||||||
|
aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
|
||||||
|
MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
|
||||||
|
p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
|
||||||
|
5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
|
||||||
|
WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
|
||||||
|
4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
|
||||||
|
hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority
|
||||||
|
Not Before: Jun 29 17:06:20 2004 GMT
|
||||||
|
Not After : Jun 29 17:06:20 2034 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
|
||||||
|
MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
|
||||||
|
YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
|
||||||
|
MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
|
||||||
|
ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
|
||||||
|
MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
|
||||||
|
ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
|
||||||
|
PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
|
||||||
|
wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
|
||||||
|
EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
|
||||||
|
avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
|
||||||
|
YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
|
||||||
|
sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
|
||||||
|
/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
|
||||||
|
IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
|
||||||
|
YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
|
||||||
|
ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
|
||||||
|
OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
|
||||||
|
TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
|
||||||
|
HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
|
||||||
|
dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
|
||||||
|
ReYNnyicsbkqWletNw+vHX/bvZ8=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
# Note: Amazon ATS endpoint uses this (2018/12/18)
|
||||||
|
Subject: C=US, O=Starfield Technologies, Inc., OU=Starfield Class 2 Certification Authority
|
||||||
|
Not Before: Jun 29 17:39:16 2004 GMT
|
||||||
|
Not After : Jun 29 17:39:16 2034 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
|
||||||
|
MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
|
||||||
|
U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
|
||||||
|
NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
|
||||||
|
ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
|
||||||
|
ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
|
||||||
|
DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
|
||||||
|
8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
|
||||||
|
+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
|
||||||
|
X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
|
||||||
|
K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
|
||||||
|
1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
|
||||||
|
A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
|
||||||
|
zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
|
||||||
|
YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
|
||||||
|
bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
|
||||||
|
DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
|
||||||
|
L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
|
||||||
|
eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
|
||||||
|
xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
|
||||||
|
VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
|
||||||
|
WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Sep 1 00:00:00 2009 GMT
|
||||||
|
Not After : Dec 31 23:59:59 2037 GMT
|
||||||
|
Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Root Certificate Authority - G2
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx
|
||||||
|
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
|
||||||
|
HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs
|
||||||
|
ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw
|
||||||
|
MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
|
||||||
|
b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj
|
||||||
|
aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp
|
||||||
|
Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||||
|
ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg
|
||||||
|
nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1
|
||||||
|
HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N
|
||||||
|
Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN
|
||||||
|
dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0
|
||||||
|
HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
|
||||||
|
BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G
|
||||||
|
CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU
|
||||||
|
sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3
|
||||||
|
4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg
|
||||||
|
8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
|
||||||
|
pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1
|
||||||
|
mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Services Root Certificate Authority - G2
|
||||||
|
Not Before: Sep 1 00:00:00 2009 GMT
|
||||||
|
Not After : Dec 31 23:59:59 2037 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
|
||||||
|
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
|
||||||
|
HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs
|
||||||
|
ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
|
||||||
|
MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD
|
||||||
|
VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy
|
||||||
|
ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy
|
||||||
|
dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
|
||||||
|
hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p
|
||||||
|
OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2
|
||||||
|
8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K
|
||||||
|
Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe
|
||||||
|
hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk
|
||||||
|
6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw
|
||||||
|
DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q
|
||||||
|
AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI
|
||||||
|
bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB
|
||||||
|
ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z
|
||||||
|
qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
|
||||||
|
iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn
|
||||||
|
0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN
|
||||||
|
sSi6
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign
|
||||||
|
Not Before: Dec 15 08:00:00 2006 GMT
|
||||||
|
Not After : Dec 15 08:00:00 2021 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
|
||||||
|
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
|
||||||
|
Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
|
||||||
|
MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
|
||||||
|
A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
|
||||||
|
hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
|
||||||
|
v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
|
||||||
|
eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
|
||||||
|
tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
|
||||||
|
C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
|
||||||
|
zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
|
||||||
|
mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
|
||||||
|
V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
|
||||||
|
bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
|
||||||
|
3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
|
||||||
|
J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
|
||||||
|
291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
|
||||||
|
ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
|
||||||
|
AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
|
||||||
|
TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA
|
||||||
|
Not Before: Nov 10 00:00:00 2006 GMT
|
||||||
|
Not After : Nov 10 00:00:00 2031 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||||
|
ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
|
||||||
|
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
||||||
|
LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
|
||||||
|
RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
|
||||||
|
+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
|
||||||
|
PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
|
||||||
|
xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
|
||||||
|
Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
|
||||||
|
hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
|
||||||
|
EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
|
||||||
|
MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
|
||||||
|
FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
|
||||||
|
nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
|
||||||
|
eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
|
||||||
|
hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
|
||||||
|
Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
|
||||||
|
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
|
||||||
|
+OkuE6N36B9K
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA
|
||||||
|
Not Before: Nov 10 00:00:00 2006 GMT
|
||||||
|
Not After : Nov 10 00:00:00 2031 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||||
|
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||||
|
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||||
|
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||||
|
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||||
|
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||||
|
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||||
|
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||||
|
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||||
|
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||||
|
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||||
|
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||||
|
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||||
|
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||||
|
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||||
|
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||||
|
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||||
|
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
# *.azure-devices.de use this root.
|
||||||
|
Subject: C = DE, O = D-Trust GmbH, CN = D-TRUST Root Class 3 CA 2 2009
|
||||||
|
Not Before: Nov 5 08:35:58 2009 GMT
|
||||||
|
Not After : Nov 5 08:35:58 2029 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF
|
||||||
|
MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD
|
||||||
|
bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha
|
||||||
|
ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM
|
||||||
|
HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB
|
||||||
|
BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03
|
||||||
|
UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42
|
||||||
|
tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R
|
||||||
|
ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM
|
||||||
|
lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp
|
||||||
|
/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G
|
||||||
|
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G
|
||||||
|
A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj
|
||||||
|
dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy
|
||||||
|
MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl
|
||||||
|
cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js
|
||||||
|
L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL
|
||||||
|
BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni
|
||||||
|
acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
|
||||||
|
o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K
|
||||||
|
zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8
|
||||||
|
PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y
|
||||||
|
Johw1+qRzT65ysCQblrGXnRl11z+o+I=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
# https://www.amazontrust.com/repository/
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 1
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : Jan 17 00:00:00 2038 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
|
||||||
|
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
|
||||||
|
b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
|
||||||
|
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
|
||||||
|
b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
|
||||||
|
ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
|
||||||
|
9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
|
||||||
|
IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
|
||||||
|
VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
|
||||||
|
93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
|
||||||
|
jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
|
||||||
|
AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
|
||||||
|
A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
|
||||||
|
U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
|
||||||
|
N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
|
||||||
|
o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
|
||||||
|
5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
|
||||||
|
rqXRfboQnoZsG4q5WTP468SQvvG5
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 2
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : May 26 00:00:00 2040 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF
|
||||||
|
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
|
||||||
|
b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL
|
||||||
|
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
|
||||||
|
b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK
|
||||||
|
gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ
|
||||||
|
W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg
|
||||||
|
1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K
|
||||||
|
8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r
|
||||||
|
2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me
|
||||||
|
z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR
|
||||||
|
8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj
|
||||||
|
mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz
|
||||||
|
7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6
|
||||||
|
+XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI
|
||||||
|
0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB
|
||||||
|
Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm
|
||||||
|
UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2
|
||||||
|
LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY
|
||||||
|
+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS
|
||||||
|
k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl
|
||||||
|
7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm
|
||||||
|
btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl
|
||||||
|
urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+
|
||||||
|
fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63
|
||||||
|
n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE
|
||||||
|
76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H
|
||||||
|
9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT
|
||||||
|
4PsJYGw=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : May 26 00:00:00 2040 GMT
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 3
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5
|
||||||
|
MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
|
||||||
|
Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
|
||||||
|
A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
|
||||||
|
Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl
|
||||||
|
ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j
|
||||||
|
QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr
|
||||||
|
ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr
|
||||||
|
BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM
|
||||||
|
YyRIHN8wfdVoOw==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : May 26 00:00:00 2040 GMT
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 4
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5
|
||||||
|
MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
|
||||||
|
Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
|
||||||
|
A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
|
||||||
|
Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi
|
||||||
|
9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk
|
||||||
|
M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB
|
||||||
|
/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB
|
||||||
|
MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw
|
||||||
|
CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW
|
||||||
|
1KyLa2tJElMzrdfkviT8tQp21KW8EA==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Nov 10 00:00:00 2006 GMT
|
||||||
|
Not After : Nov 10 00:00:00 2031 GMT
|
||||||
|
Subject: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||||
|
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||||
|
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||||
|
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||||
|
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||||
|
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||||
|
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||||
|
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||||
|
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||||
|
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||||
|
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||||
|
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||||
|
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||||
|
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||||
|
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||||
|
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||||
|
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||||
|
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Nov 13 00:00:00 2012 GMT
|
||||||
|
Not After : Jan 19 03:14:07 2038 GMT
|
||||||
|
Subject: OU = GlobalSign ECC Root CA - R4, O = GlobalSign, CN = GlobalSign
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk
|
||||||
|
MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH
|
||||||
|
bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
|
||||||
|
DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
|
||||||
|
QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
|
||||||
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ
|
||||||
|
FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw
|
||||||
|
DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F
|
||||||
|
uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX
|
||||||
|
kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs
|
||||||
|
ewv4n4Q=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Nov 1 00:00:42 2018 GMT
|
||||||
|
Not After : Nov 1 00:00:42 2042 GMT
|
||||||
|
Subject: C = US, O = Google Trust Services LLC, CN = GTS LTSR
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBxTCCAWugAwIBAgINAfD3nVndblD3QnNxUDAKBggqhkjOPQQDAjBEMQswCQYD
|
||||||
|
VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzERMA8G
|
||||||
|
A1UEAxMIR1RTIExUU1IwHhcNMTgxMTAxMDAwMDQyWhcNNDIxMTAxMDAwMDQyWjBE
|
||||||
|
MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
|
||||||
|
QzERMA8GA1UEAxMIR1RTIExUU1IwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATN
|
||||||
|
8YyO2u+yCQoZdwAkUNv5c3dokfULfrA6QJgFV2XMuENtQZIG5HUOS6jFn8f0ySlV
|
||||||
|
eORCxqFyjDJyRn86d+Iko0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUw
|
||||||
|
AwEB/zAdBgNVHQ4EFgQUPv7/zFLrvzQ+PfNA0OQlsV+4u1IwCgYIKoZIzj0EAwID
|
||||||
|
SAAwRQIhAPKuf/VtBHqGw3TUwUIq7TfaExp3bH7bjCBmVXJupT9FAiBr0SmCtsuk
|
||||||
|
miGgpajjf/gFigGM34F9021bCWs1MbL0SA==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
// Copyright (c) 2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// Example HTTP reverse proxy
|
||||||
|
// 1. Run `make`. This builds and starts a proxy on port 8000
|
||||||
|
// 2. Start your browser, go to https://localhost:8000
|
||||||
|
//
|
||||||
|
// To enable SSL/TLS, build it like this:
|
||||||
|
// make MBEDTLS_DIR=/path/to/your/mbedtls/installation
|
||||||
|
|
||||||
|
static const char *s_backend_url = "https://cesanta.com";
|
||||||
|
static const char *s_listen_url = "http://localhost:8000";
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
// Forward client request to the backend connection, rewriting the Host header
|
||||||
|
static void forward_request(struct mg_http_message *hm,
|
||||||
|
struct mg_connection *c) {
|
||||||
|
size_t i, max = sizeof(hm->headers) / sizeof(hm->headers[0]);
|
||||||
|
struct mg_str host = mg_url_host(s_backend_url);
|
||||||
|
mg_printf(c, "%.*s\r\n",
|
||||||
|
(int) (hm->proto.ptr + hm->proto.len - hm->message.ptr),
|
||||||
|
hm->message.ptr);
|
||||||
|
for (i = 0; i < max && hm->headers[i].name.len > 0; i++) {
|
||||||
|
struct mg_str *k = &hm->headers[i].name, *v = &hm->headers[i].value;
|
||||||
|
if (mg_strcmp(*k, mg_str("Host")) == 0) v = &host;
|
||||||
|
mg_printf(c, "%.*s: %.*s\r\n", (int) k->len, k->ptr, (int) v->len, v->ptr);
|
||||||
|
}
|
||||||
|
mg_send(c, "\r\n", 2);
|
||||||
|
mg_send(c, hm->body.ptr, hm->body.len);
|
||||||
|
LOG(LL_DEBUG, ("FORWARDING: %.*s %.*s", (int) hm->method.len, hm->method.ptr,
|
||||||
|
(int) hm->uri.len, hm->uri.ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
struct mg_connection *c2 = fn_data;
|
||||||
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
if (c->label[0] != 'B' && c2 == NULL) {
|
||||||
|
// Client request, create backend connection Note that we're passing
|
||||||
|
// client connection `c` as fn_data for the created backend connection.
|
||||||
|
// This way, we tie together these two connections via `fn_data` pointer:
|
||||||
|
// client's c->fn_data points to the backend connection, and backend's
|
||||||
|
// c->fn_data points to the client connection
|
||||||
|
c2 = mg_connect(c->mgr, s_backend_url, fn, c);
|
||||||
|
c->fn_data = c2;
|
||||||
|
if (c2 != NULL) {
|
||||||
|
c2->is_hexdumping = 1;
|
||||||
|
c2->label[0] = 'B'; // Mark this connection as backend
|
||||||
|
} else {
|
||||||
|
c->is_closing = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c2 != NULL && c2->label[0] == 'B') forward_request(hm, c2);
|
||||||
|
} else if (ev == MG_EV_READ) {
|
||||||
|
if (c->label[0] == 'B' && c2 != NULL) {
|
||||||
|
// All incoming data from the backend, forward to the client
|
||||||
|
mg_send(c2, c->recv.buf, c->recv.len);
|
||||||
|
mg_iobuf_delete(&c->recv, c->recv.len);
|
||||||
|
}
|
||||||
|
} else if (ev == MG_EV_CONNECT) {
|
||||||
|
if (mg_url_is_ssl(s_backend_url)) {
|
||||||
|
struct mg_tls_opts opts = {.ca = "ca.pem"};
|
||||||
|
mg_tls_init(c, &opts);
|
||||||
|
}
|
||||||
|
} else if (ev == MG_EV_CLOSE) {
|
||||||
|
if (c2 != NULL) c2->is_closing = 1;
|
||||||
|
c->fn_data = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_mgr mgr;
|
||||||
|
|
||||||
|
mg_log_set("3"); // Set log level
|
||||||
|
mg_mgr_init(&mgr); // Initialise event manager
|
||||||
|
mg_http_listen(&mgr, s_listen_url, fn, NULL); // Start proxy
|
||||||
|
for (;;) mg_mgr_poll(&mgr, 1000); // Event loop
|
||||||
|
mg_mgr_free(&mgr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
PROG ?= example
|
||||||
|
ROOT ?= $(realpath $(CURDIR)/../..)
|
||||||
|
DEFS ?= -DMG_ENABLE_LINES=1 -DMG_ENABLE_DIRECTORY_LISTING=1 -DMG_ENABLE_SSI=1
|
||||||
|
CFLAGS ?= -I../.. -W -Wall -DMG_ENABLE_IPV6=1 $(DEFS) $(EXTRA)
|
||||||
|
VCFLAGS = /nologo /W3 /O2 /I../.. $(DEFS) $(EXTRA) /link /incremental:no /machine:IX86
|
||||||
|
VC98 = docker run --rm -e Tmp=. -v $(ROOT):$(ROOT) -w $(CURDIR) docker.io/mdashnet/vc98
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(DEBUGGER) ./$(PROG) $(ARGS)
|
||||||
|
|
||||||
|
$(PROG): main.c Makefile
|
||||||
|
$(CC) ../../mongoose.c main.c -I../.. $(CFLAGS) -o $@
|
||||||
|
|
||||||
|
mongoose.exe: main.c
|
||||||
|
$(VC98) wine cl ../../mongoose.c main.c $(VCFLAGS) ws2_32.lib /out:$@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb mongoose mongoose_* mongoose.*
|
||||||
@@ -4,15 +4,15 @@
|
|||||||
#include "mongoose.h"
|
#include "mongoose.h"
|
||||||
|
|
||||||
static const char *s_debug_level = "2";
|
static const char *s_debug_level = "2";
|
||||||
static const char *s_web_root_dir = ".";
|
static const char *s_root_dir = ".";
|
||||||
static const char *s_listening_address = "http://localhost:8000";
|
static const char *s_listening_address = "http://localhost:8000";
|
||||||
static const char *s_enable_hexdump = "no";
|
static const char *s_enable_hexdump = "no";
|
||||||
static const char *s_rewrites = "";
|
static const char *s_ssi_pattern = "#.shtml";
|
||||||
|
|
||||||
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
if (ev == MG_EV_HTTP_MSG) {
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
// struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
struct mg_http_serve_opts opts = {s_root_dir, s_ssi_pattern};
|
||||||
mg_http_serve_dir(c, ev_data, s_web_root_dir);
|
mg_http_serve_dir(c, ev_data, &opts);
|
||||||
}
|
}
|
||||||
(void) fn_data;
|
(void) fn_data;
|
||||||
}
|
}
|
||||||
@@ -21,13 +21,13 @@ static void usage(const char *prog) {
|
|||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Mongoose v.%s, built " __DATE__ " " __TIME__
|
"Mongoose v.%s, built " __DATE__ " " __TIME__
|
||||||
"\nUsage: %s OPTIONS\n"
|
"\nUsage: %s OPTIONS\n"
|
||||||
" -D LEVEL - debug level, from 0 to 4, default: '%s'\n"
|
|
||||||
" -H yes|no - enable traffic hexdump, default: '%s'\n"
|
" -H yes|no - enable traffic hexdump, default: '%s'\n"
|
||||||
|
" -S GLOB - glob pattern for SSI files, default: '%s'\n"
|
||||||
" -d DIR - directory to serve, default: '%s'\n"
|
" -d DIR - directory to serve, default: '%s'\n"
|
||||||
" -l ADDR - listening address, default: '%s'\n"
|
" -l ADDR - listening address, default: '%s'\n"
|
||||||
" -r LIST - list of URI=DIR,... URI rewrites, default: '%s'\n",
|
" -v LEVEL - debug level, from 0 to 4, default: '%s'\n",
|
||||||
MG_VERSION, prog, s_debug_level, s_enable_hexdump, s_web_root_dir,
|
MG_VERSION, prog, s_debug_level, s_enable_hexdump, s_ssi_pattern,
|
||||||
s_listening_address, s_rewrites);
|
s_root_dir, s_listening_address);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,15 +39,15 @@ int main(int argc, char *argv[]) {
|
|||||||
// Parse command-line flags
|
// Parse command-line flags
|
||||||
for (i = 1; i < argc; i++) {
|
for (i = 1; i < argc; i++) {
|
||||||
if (strcmp(argv[i], "-d") == 0) {
|
if (strcmp(argv[i], "-d") == 0) {
|
||||||
s_web_root_dir = argv[++i];
|
s_root_dir = argv[++i];
|
||||||
} else if (strcmp(argv[i], "-D") == 0) {
|
|
||||||
s_debug_level = argv[++i];
|
|
||||||
} else if (strcmp(argv[i], "-H") == 0) {
|
} else if (strcmp(argv[i], "-H") == 0) {
|
||||||
s_enable_hexdump = argv[++i];
|
s_enable_hexdump = argv[++i];
|
||||||
|
} else if (strcmp(argv[i], "-S") == 0) {
|
||||||
|
s_ssi_pattern = argv[++i];
|
||||||
} else if (strcmp(argv[i], "-l") == 0) {
|
} else if (strcmp(argv[i], "-l") == 0) {
|
||||||
s_listening_address = argv[++i];
|
s_listening_address = argv[++i];
|
||||||
} else if (strcmp(argv[i], "-r") == 0) {
|
} else if (strcmp(argv[i], "-v") == 0) {
|
||||||
s_rewrites = argv[++i];
|
s_debug_level = argv[++i];
|
||||||
} else {
|
} else {
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ int main(int argc, char *argv[]) {
|
|||||||
if (mg_casecmp(s_enable_hexdump, "yes") == 0) c->is_hexdumping = 1;
|
if (mg_casecmp(s_enable_hexdump, "yes") == 0) c->is_hexdumping = 1;
|
||||||
|
|
||||||
// Start infinite event loop
|
// 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);
|
for (;;) mg_mgr_poll(&mgr, 1000);
|
||||||
mg_mgr_free(&mgr);
|
mg_mgr_free(&mgr);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
PROG ?= example
|
||||||
|
CFLAGS ?= -DMG_ENABLE_LINES $(EXTRA)
|
||||||
|
|
||||||
|
ifneq ($(MBEDTLS),)
|
||||||
|
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS)/include -I/usr/include
|
||||||
|
CFLAGS += -L$(MBEDTLS)/lib -lmbedtls -lmbedcrypto -lmbedx509
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(OPENSSL),)
|
||||||
|
CFLAGS += -DMG_ENABLE_OPENSSL=1 -I$(OPENSSL)/include
|
||||||
|
CFLAGS += -L$(OPENSSL)/lib -lssl -lcrypto
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(DEBUGGER) ./$(PROG) $(ARGS)
|
||||||
|
|
||||||
|
|
||||||
|
$(PROG): main.c
|
||||||
|
$(CC) ../../mongoose.c -I../.. -W -Wall $(CFLAGS) -o $(PROG) main.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb
|
||||||
@@ -0,0 +1,507 @@
|
|||||||
|
Subject: O=Digital Signature Trust Co., CN=DST Root CA X3
|
||||||
|
Not Before: Sep 30 21:12:19 2000 GMT
|
||||||
|
Not After : Sep 30 14:01:15 2021 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
|
||||||
|
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
||||||
|
DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
|
||||||
|
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
|
||||||
|
Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||||
|
AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
|
||||||
|
rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
|
||||||
|
OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
|
||||||
|
xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
|
||||||
|
7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
|
||||||
|
aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
|
||||||
|
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
|
||||||
|
SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
|
||||||
|
ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
|
||||||
|
AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
|
||||||
|
R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
|
||||||
|
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
|
||||||
|
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root
|
||||||
|
Not Before: May 12 18:46:00 2000 GMT
|
||||||
|
Not After : May 12 23:59:00 2025 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
|
||||||
|
RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
|
||||||
|
VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
|
||||||
|
DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
|
||||||
|
ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
|
||||||
|
VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
|
||||||
|
mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
|
||||||
|
IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
|
||||||
|
mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
|
||||||
|
XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
|
||||||
|
dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
|
||||||
|
jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
|
||||||
|
BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
|
||||||
|
DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
|
||||||
|
9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
|
||||||
|
jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
|
||||||
|
Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
|
||||||
|
ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
|
||||||
|
R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA
|
||||||
|
Not Before: May 21 04:00:00 2002 GMT
|
||||||
|
Not After : May 21 04:00:00 2022 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
|
||||||
|
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
|
||||||
|
YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
|
||||||
|
EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
|
||||||
|
R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
|
||||||
|
9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
|
||||||
|
fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
|
||||||
|
iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
|
||||||
|
1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
|
||||||
|
bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
|
||||||
|
MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
|
||||||
|
ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
|
||||||
|
uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
|
||||||
|
Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
|
||||||
|
tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
|
||||||
|
PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
|
||||||
|
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
|
||||||
|
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=Symantec Corporation, OU=Symantec Trust Network, CN=Symantec Class 3 ECC 256 bit SSL CA - G2
|
||||||
|
Not Before: May 12 00:00:00 2015 GMT
|
||||||
|
Not After : May 11 23:59:59 2025 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEajCCA1KgAwIBAgIQP5KHvp0dpKN6nfYoLndaxDANBgkqhkiG9w0BAQsFADCB
|
||||||
|
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||||
|
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
|
||||||
|
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
|
||||||
|
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
|
||||||
|
aG9yaXR5IC0gRzUwHhcNMTUwNTEyMDAwMDAwWhcNMjUwNTExMjM1OTU5WjCBgDEL
|
||||||
|
MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD
|
||||||
|
VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMTEwLwYDVQQDEyhTeW1hbnRlYyBD
|
||||||
|
bGFzcyAzIEVDQyAyNTYgYml0IFNTTCBDQSAtIEcyMFkwEwYHKoZIzj0CAQYIKoZI
|
||||||
|
zj0DAQcDQgAEDxukkdfnrOfRTk63ZFvhj39uBNOrONtEt0Bcbb2WljffeYmGZ/ex
|
||||||
|
Hwie/WM7RoyfvVPoFdyXPiuBRq2Gfw4BOaOCAV0wggFZMC4GCCsGAQUFBwEBBCIw
|
||||||
|
IDAeBggrBgEFBQcwAYYSaHR0cDovL3Muc3ltY2QuY29tMBIGA1UdEwEB/wQIMAYB
|
||||||
|
Af8CAQAwZQYDVR0gBF4wXDBaBgpghkgBhvhFAQc2MEwwIwYIKwYBBQUHAgEWF2h0
|
||||||
|
dHBzOi8vZC5zeW1jYi5jb20vY3BzMCUGCCsGAQUFBwICMBkaF2h0dHBzOi8vZC5z
|
||||||
|
eW1jYi5jb20vcnBhMC8GA1UdHwQoMCYwJKAioCCGHmh0dHA6Ly9zLnN5bWNiLmNv
|
||||||
|
bS9wY2EzLWc1LmNybDAOBgNVHQ8BAf8EBAMCAQYwKwYDVR0RBCQwIqQgMB4xHDAa
|
||||||
|
BgNVBAMTE1NZTUMtRUNDLUNBLXAyNTYtMjIwHQYDVR0OBBYEFCXwiuFLetkBlQrt
|
||||||
|
xlPxjHgf2fP4MB8GA1UdIwQYMBaAFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG
|
||||||
|
SIb3DQEBCwUAA4IBAQAMMGUXBaWTdaLxsTGtcB/naqjIQrLvoV9NG+7MoHpGd/69
|
||||||
|
dZ/h2zOy7sGFUHoG/0HGRA9rxT/5w5GkEVIVkxtWyIWWq6rs4CTZt8Bej/KHYRbo
|
||||||
|
jtEDUkCTZSTLiCvguPyvinXgxy+LHT+PmdtEfXsvcdbeBSWUYpOsDYvD2hNtz9dw
|
||||||
|
Od5nBosMApmdxt+z7LQyZu8wMnfI1U6IMO+RWowxZ8uy0oswdFYd32l9xe+aAE/k
|
||||||
|
y9alLu/M9pvxiUKufqHJRgDBKA6uDjHLMPX+/nxXaNCPX3SI4KVZ1stHQ/U5oNlM
|
||||||
|
dHN9umAvlU313g0IgJrjsQ2nIdf9dsdP+6lrmP7s
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5
|
||||||
|
Not Before: Nov 8 00:00:00 2006 GMT
|
||||||
|
Not After : Jul 16 23:59:59 2036 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
|
||||||
|
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||||
|
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
|
||||||
|
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
|
||||||
|
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
|
||||||
|
aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
|
||||||
|
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
|
||||||
|
ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
|
||||||
|
biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
|
||||||
|
U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
|
||||||
|
aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
|
||||||
|
nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
|
||||||
|
t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
|
||||||
|
SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
|
||||||
|
BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
|
||||||
|
rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
|
||||||
|
NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
|
||||||
|
BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
|
||||||
|
BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
|
||||||
|
aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
|
||||||
|
MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
|
||||||
|
p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
|
||||||
|
5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
|
||||||
|
WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
|
||||||
|
4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
|
||||||
|
hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority
|
||||||
|
Not Before: Jun 29 17:06:20 2004 GMT
|
||||||
|
Not After : Jun 29 17:06:20 2034 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
|
||||||
|
MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
|
||||||
|
YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
|
||||||
|
MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
|
||||||
|
ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
|
||||||
|
MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
|
||||||
|
ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
|
||||||
|
PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
|
||||||
|
wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
|
||||||
|
EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
|
||||||
|
avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
|
||||||
|
YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
|
||||||
|
sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
|
||||||
|
/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
|
||||||
|
IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
|
||||||
|
YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
|
||||||
|
ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
|
||||||
|
OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
|
||||||
|
TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
|
||||||
|
HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
|
||||||
|
dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
|
||||||
|
ReYNnyicsbkqWletNw+vHX/bvZ8=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
# Note: Amazon ATS endpoint uses this (2018/12/18)
|
||||||
|
Subject: C=US, O=Starfield Technologies, Inc., OU=Starfield Class 2 Certification Authority
|
||||||
|
Not Before: Jun 29 17:39:16 2004 GMT
|
||||||
|
Not After : Jun 29 17:39:16 2034 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
|
||||||
|
MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
|
||||||
|
U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
|
||||||
|
NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
|
||||||
|
ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
|
||||||
|
ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
|
||||||
|
DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
|
||||||
|
8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
|
||||||
|
+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
|
||||||
|
X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
|
||||||
|
K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
|
||||||
|
1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
|
||||||
|
A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
|
||||||
|
zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
|
||||||
|
YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
|
||||||
|
bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
|
||||||
|
DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
|
||||||
|
L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
|
||||||
|
eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
|
||||||
|
xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
|
||||||
|
VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
|
||||||
|
WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Sep 1 00:00:00 2009 GMT
|
||||||
|
Not After : Dec 31 23:59:59 2037 GMT
|
||||||
|
Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Root Certificate Authority - G2
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx
|
||||||
|
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
|
||||||
|
HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs
|
||||||
|
ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw
|
||||||
|
MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
|
||||||
|
b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj
|
||||||
|
aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp
|
||||||
|
Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||||
|
ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg
|
||||||
|
nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1
|
||||||
|
HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N
|
||||||
|
Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN
|
||||||
|
dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0
|
||||||
|
HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
|
||||||
|
BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G
|
||||||
|
CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU
|
||||||
|
sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3
|
||||||
|
4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg
|
||||||
|
8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
|
||||||
|
pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1
|
||||||
|
mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Services Root Certificate Authority - G2
|
||||||
|
Not Before: Sep 1 00:00:00 2009 GMT
|
||||||
|
Not After : Dec 31 23:59:59 2037 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
|
||||||
|
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
|
||||||
|
HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs
|
||||||
|
ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
|
||||||
|
MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD
|
||||||
|
VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy
|
||||||
|
ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy
|
||||||
|
dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
|
||||||
|
hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p
|
||||||
|
OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2
|
||||||
|
8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K
|
||||||
|
Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe
|
||||||
|
hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk
|
||||||
|
6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw
|
||||||
|
DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q
|
||||||
|
AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI
|
||||||
|
bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB
|
||||||
|
ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z
|
||||||
|
qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
|
||||||
|
iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn
|
||||||
|
0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN
|
||||||
|
sSi6
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign
|
||||||
|
Not Before: Dec 15 08:00:00 2006 GMT
|
||||||
|
Not After : Dec 15 08:00:00 2021 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
|
||||||
|
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
|
||||||
|
Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
|
||||||
|
MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
|
||||||
|
A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
|
||||||
|
hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
|
||||||
|
v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
|
||||||
|
eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
|
||||||
|
tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
|
||||||
|
C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
|
||||||
|
zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
|
||||||
|
mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
|
||||||
|
V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
|
||||||
|
bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
|
||||||
|
3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
|
||||||
|
J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
|
||||||
|
291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
|
||||||
|
ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
|
||||||
|
AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
|
||||||
|
TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA
|
||||||
|
Not Before: Nov 10 00:00:00 2006 GMT
|
||||||
|
Not After : Nov 10 00:00:00 2031 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||||
|
ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
|
||||||
|
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
||||||
|
LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
|
||||||
|
RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
|
||||||
|
+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
|
||||||
|
PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
|
||||||
|
xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
|
||||||
|
Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
|
||||||
|
hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
|
||||||
|
EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
|
||||||
|
MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
|
||||||
|
FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
|
||||||
|
nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
|
||||||
|
eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
|
||||||
|
hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
|
||||||
|
Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
|
||||||
|
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
|
||||||
|
+OkuE6N36B9K
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA
|
||||||
|
Not Before: Nov 10 00:00:00 2006 GMT
|
||||||
|
Not After : Nov 10 00:00:00 2031 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||||
|
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||||
|
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||||
|
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||||
|
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||||
|
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||||
|
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||||
|
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||||
|
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||||
|
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||||
|
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||||
|
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||||
|
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||||
|
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||||
|
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||||
|
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||||
|
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||||
|
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
# *.azure-devices.de use this root.
|
||||||
|
Subject: C = DE, O = D-Trust GmbH, CN = D-TRUST Root Class 3 CA 2 2009
|
||||||
|
Not Before: Nov 5 08:35:58 2009 GMT
|
||||||
|
Not After : Nov 5 08:35:58 2029 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF
|
||||||
|
MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD
|
||||||
|
bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha
|
||||||
|
ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM
|
||||||
|
HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB
|
||||||
|
BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03
|
||||||
|
UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42
|
||||||
|
tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R
|
||||||
|
ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM
|
||||||
|
lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp
|
||||||
|
/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G
|
||||||
|
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G
|
||||||
|
A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj
|
||||||
|
dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy
|
||||||
|
MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl
|
||||||
|
cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js
|
||||||
|
L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL
|
||||||
|
BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni
|
||||||
|
acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
|
||||||
|
o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K
|
||||||
|
zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8
|
||||||
|
PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y
|
||||||
|
Johw1+qRzT65ysCQblrGXnRl11z+o+I=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
# https://www.amazontrust.com/repository/
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 1
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : Jan 17 00:00:00 2038 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
|
||||||
|
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
|
||||||
|
b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
|
||||||
|
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
|
||||||
|
b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
|
||||||
|
ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
|
||||||
|
9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
|
||||||
|
IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
|
||||||
|
VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
|
||||||
|
93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
|
||||||
|
jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
|
||||||
|
AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
|
||||||
|
A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
|
||||||
|
U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
|
||||||
|
N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
|
||||||
|
o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
|
||||||
|
5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
|
||||||
|
rqXRfboQnoZsG4q5WTP468SQvvG5
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 2
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : May 26 00:00:00 2040 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF
|
||||||
|
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
|
||||||
|
b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL
|
||||||
|
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
|
||||||
|
b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK
|
||||||
|
gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ
|
||||||
|
W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg
|
||||||
|
1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K
|
||||||
|
8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r
|
||||||
|
2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me
|
||||||
|
z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR
|
||||||
|
8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj
|
||||||
|
mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz
|
||||||
|
7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6
|
||||||
|
+XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI
|
||||||
|
0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB
|
||||||
|
Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm
|
||||||
|
UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2
|
||||||
|
LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY
|
||||||
|
+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS
|
||||||
|
k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl
|
||||||
|
7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm
|
||||||
|
btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl
|
||||||
|
urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+
|
||||||
|
fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63
|
||||||
|
n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE
|
||||||
|
76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H
|
||||||
|
9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT
|
||||||
|
4PsJYGw=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : May 26 00:00:00 2040 GMT
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 3
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5
|
||||||
|
MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
|
||||||
|
Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
|
||||||
|
A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
|
||||||
|
Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl
|
||||||
|
ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j
|
||||||
|
QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr
|
||||||
|
ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr
|
||||||
|
BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM
|
||||||
|
YyRIHN8wfdVoOw==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : May 26 00:00:00 2040 GMT
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 4
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5
|
||||||
|
MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
|
||||||
|
Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
|
||||||
|
A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
|
||||||
|
Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi
|
||||||
|
9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk
|
||||||
|
M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB
|
||||||
|
/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB
|
||||||
|
MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw
|
||||||
|
CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW
|
||||||
|
1KyLa2tJElMzrdfkviT8tQp21KW8EA==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Nov 10 00:00:00 2006 GMT
|
||||||
|
Not After : Nov 10 00:00:00 2031 GMT
|
||||||
|
Subject: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||||
|
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||||
|
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||||
|
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||||
|
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||||
|
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||||
|
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||||
|
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||||
|
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||||
|
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||||
|
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||||
|
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||||
|
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||||
|
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||||
|
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||||
|
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||||
|
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||||
|
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Nov 13 00:00:00 2012 GMT
|
||||||
|
Not After : Jan 19 03:14:07 2038 GMT
|
||||||
|
Subject: OU = GlobalSign ECC Root CA - R4, O = GlobalSign, CN = GlobalSign
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk
|
||||||
|
MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH
|
||||||
|
bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
|
||||||
|
DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
|
||||||
|
QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
|
||||||
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ
|
||||||
|
FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw
|
||||||
|
DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F
|
||||||
|
uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX
|
||||||
|
kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs
|
||||||
|
ewv4n4Q=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Nov 1 00:00:42 2018 GMT
|
||||||
|
Not After : Nov 1 00:00:42 2042 GMT
|
||||||
|
Subject: C = US, O = Google Trust Services LLC, CN = GTS LTSR
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBxTCCAWugAwIBAgINAfD3nVndblD3QnNxUDAKBggqhkjOPQQDAjBEMQswCQYD
|
||||||
|
VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzERMA8G
|
||||||
|
A1UEAxMIR1RTIExUU1IwHhcNMTgxMTAxMDAwMDQyWhcNNDIxMTAxMDAwMDQyWjBE
|
||||||
|
MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
|
||||||
|
QzERMA8GA1UEAxMIR1RTIExUU1IwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATN
|
||||||
|
8YyO2u+yCQoZdwAkUNv5c3dokfULfrA6QJgFV2XMuENtQZIG5HUOS6jFn8f0ySlV
|
||||||
|
eORCxqFyjDJyRn86d+Iko0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUw
|
||||||
|
AwEB/zAdBgNVHQ4EFgQUPv7/zFLrvzQ+PfNA0OQlsV+4u1IwCgYIKoZIzj0EAwID
|
||||||
|
SAAwRQIhAPKuf/VtBHqGw3TUwUIq7TfaExp3bH7bjCBmVXJupT9FAiBr0SmCtsuk
|
||||||
|
miGgpajjf/gFigGM34F9021bCWs1MbL0SA==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
// Copyright (c) 2021 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// Example HTTP client.
|
||||||
|
// Instead of buffering the whole HTTP response in memory and wait for the
|
||||||
|
// MG_EV_HTTP_MSG event, this client catches MG_EV_HTTP_CHUNK events and
|
||||||
|
// prints them. This is useful to download large content without spooling
|
||||||
|
// everything to memory, or catch chunked content.
|
||||||
|
//
|
||||||
|
// You can change `s_url` from the command line by executing: ./example YOUR_URL
|
||||||
|
//
|
||||||
|
// To enable SSL/TLS for this client, build it like this:
|
||||||
|
// make MBEDTLS=/path/to/your/mbedtls/installation
|
||||||
|
// make OPENSSL=/path/to/your/openssl/installation
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
// The very first web page in history. You can replace it from command line
|
||||||
|
static const char *s_url = "http://info.cern.ch";
|
||||||
|
|
||||||
|
// Print HTTP response and signal that we're done
|
||||||
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_CONNECT) {
|
||||||
|
// Connected to server. Extract host name from URL
|
||||||
|
struct mg_str host = mg_url_host(s_url);
|
||||||
|
|
||||||
|
// If s_url is https://, tell client connection to use TLS
|
||||||
|
if (mg_url_is_ssl(s_url)) {
|
||||||
|
struct mg_tls_opts opts = {.ca = "ca.pem", .srvname = host};
|
||||||
|
mg_tls_init(c, &opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send request
|
||||||
|
mg_printf(c,
|
||||||
|
"GET %s HTTP/1.0\r\n"
|
||||||
|
"Host: %.*s\r\n"
|
||||||
|
"\r\n",
|
||||||
|
mg_url_uri(s_url), (int) host.len, host.ptr);
|
||||||
|
} else if (ev == MG_EV_HTTP_CHUNK) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
LOG(LL_INFO, ("%.*s", (int) hm->chunk.len, hm->chunk.ptr));
|
||||||
|
mg_http_delete_chunk(c, hm);
|
||||||
|
if (hm->chunk.len == 0) *(bool *) fn_data = true; // Last chunk
|
||||||
|
} else if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
// Response is received. Print it
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
LOG(LL_INFO, ("%.*s", (int) hm->body.len, hm->body.ptr));
|
||||||
|
c->is_closing = 1; // Tell mongoose to close this connection
|
||||||
|
*(bool *) fn_data = true; // Tell event loop to stop
|
||||||
|
} else if (ev == MG_EV_ERROR) {
|
||||||
|
*(bool *) fn_data = true; // Error, tell event loop to stop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
struct mg_mgr mgr; // Event manager
|
||||||
|
bool done = false; // Event handler flips it to true
|
||||||
|
if (argc > 1) s_url = argv[1]; // Use URL from command line
|
||||||
|
mg_log_set("3"); // Set to 0 to disable debug
|
||||||
|
mg_mgr_init(&mgr); // Initialise event manager
|
||||||
|
mg_http_connect(&mgr, s_url, fn, &done); // Create client connection
|
||||||
|
while (!done) mg_mgr_poll(&mgr, 1000); // Infinite event loop
|
||||||
|
mg_mgr_free(&mgr); // Free resources
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -11,12 +11,13 @@ static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
if (ev == MG_EV_HTTP_MSG) {
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
if (mg_http_match_uri(hm, "/api/log/static")) {
|
if (mg_http_match_uri(hm, "/api/log/static")) {
|
||||||
mg_http_serve_file(c, hm, "log.txt", "text/plain");
|
mg_http_serve_file(c, hm, "log.txt", "text/plain", "");
|
||||||
} else if (mg_http_match_uri(hm, "/api/log/live")) {
|
} else if (mg_http_match_uri(hm, "/api/log/live")) {
|
||||||
c->label[0] = 'L'; // Mark that connection as live log listener
|
c->label[0] = 'L'; // Mark that connection as live log listener
|
||||||
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||||
} else {
|
} else {
|
||||||
mg_http_serve_dir(c, ev_data, "web_root");
|
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
|
||||||
|
mg_http_serve_dir(c, ev_data, &opts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ static const char *s_topic = "mg/test";
|
|||||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
if (ev == MG_EV_ERROR) {
|
if (ev == MG_EV_ERROR) {
|
||||||
// On error, log error message
|
// On error, log error message
|
||||||
LOG(LL_ERROR, ("%p %s", c->fd, ev_data));
|
LOG(LL_ERROR, ("%p %s", c->fd, (char *) ev_data));
|
||||||
} else if (ev == MG_EV_CONNECT) {
|
} else if (ev == MG_EV_CONNECT) {
|
||||||
// If target URL is SSL/TLS, command client connection to use TLS
|
// If target URL is SSL/TLS, command client connection to use TLS
|
||||||
if (mg_url_is_ssl(s_url)) {
|
if (mg_url_is_ssl(s_url)) {
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
PROG ?= example
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(DEBUGGER) ./$(PROG) $(ARGS)
|
||||||
|
|
||||||
|
$(PROG): main.c
|
||||||
|
$(CC) ../../mongoose.c -I../.. -W -Wall -DMG_ENABLE_LINES=1 $(CFLAGS) -o $(PROG) main.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
// Copyright (c) 2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// Example MQTT server. Usage:
|
||||||
|
// 1. Start this server, type `make`
|
||||||
|
// 2. Install mosquitto MQTT client
|
||||||
|
// 3. In one terminal, run: mosquitto_sub -h localhost -t foo -t bar
|
||||||
|
// 4. In another, run: mosquitto_pub -h localhost -t foo -m hi
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static const char *s_listen_on = "mqtt://0.0.0.0:1883";
|
||||||
|
|
||||||
|
// A list of subscription, held in memory
|
||||||
|
struct sub {
|
||||||
|
struct sub *next;
|
||||||
|
struct mg_connection *c;
|
||||||
|
struct mg_str topic;
|
||||||
|
uint8_t qos;
|
||||||
|
};
|
||||||
|
static struct sub *s_subs = NULL;
|
||||||
|
|
||||||
|
// Event handler function
|
||||||
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_MQTT_CMD) {
|
||||||
|
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
|
||||||
|
LOG(LL_DEBUG, ("cmd %d qos %d", mm->cmd, mm->qos));
|
||||||
|
switch (mm->cmd) {
|
||||||
|
case MQTT_CMD_CONNECT: {
|
||||||
|
// Client connects. Return success, do not check user/password
|
||||||
|
uint8_t response[] = {0, 0};
|
||||||
|
mg_mqtt_send_header(c, MQTT_CMD_CONNACK, 0, sizeof(response));
|
||||||
|
mg_send(c, response, sizeof(response));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MQTT_CMD_SUBSCRIBE: {
|
||||||
|
// Client subscribes
|
||||||
|
int pos = 4; // Initial topic offset, where ID ends
|
||||||
|
uint8_t qos;
|
||||||
|
struct mg_str topic;
|
||||||
|
while ((pos = mg_mqtt_next_sub(mm, &topic, &qos, pos)) > 0) {
|
||||||
|
struct sub *sub = calloc(1, sizeof(*sub));
|
||||||
|
sub->c = c;
|
||||||
|
sub->topic = mg_strdup(topic);
|
||||||
|
sub->qos = qos;
|
||||||
|
LIST_ADD_HEAD(struct sub, &s_subs, sub);
|
||||||
|
LOG(LL_INFO,
|
||||||
|
("SUB %p [%.*s]", c->fd, (int) sub->topic.len, sub->topic.ptr));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MQTT_CMD_PUBLISH: {
|
||||||
|
// Client published message. Push to all subscribed channels
|
||||||
|
LOG(LL_INFO, ("PUB %p [%.*s] -> [%.*s]", c->fd, (int) mm->data.len,
|
||||||
|
mm->data.ptr, (int) mm->topic.len, mm->topic.ptr));
|
||||||
|
for (struct sub *sub = s_subs; sub != NULL; sub = sub->next) {
|
||||||
|
if (mg_strcmp(mm->topic, sub->topic) != 0) continue;
|
||||||
|
mg_mqtt_pub(sub->c, &mm->topic, &mm->data);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ev == MG_EV_CLOSE) {
|
||||||
|
// Client disconnects. Remove from the subscription list
|
||||||
|
for (struct sub *next, *sub = s_subs; sub != NULL; sub = next) {
|
||||||
|
next = sub->next;
|
||||||
|
if (c != sub->c) continue;
|
||||||
|
LOG(LL_INFO,
|
||||||
|
("UNSUB %p [%.*s]", c->fd, (int) sub->topic.len, sub->topic.ptr));
|
||||||
|
LIST_DELETE(struct sub, &s_subs, sub);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void) fn_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_mgr mgr; // Event manager
|
||||||
|
mg_mgr_init(&mgr); // Initialise event manager
|
||||||
|
mg_mqtt_listen(&mgr, s_listen_on, fn, NULL); // Create MQTT listener
|
||||||
|
for (;;) mg_mgr_poll(&mgr, 1000); // Infinite event loop
|
||||||
|
mg_mgr_free(&mgr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -31,20 +31,11 @@ struct response {
|
|||||||
#define SLEEP_TIME 3 // Seconds to sleep to simulate calculation
|
#define SLEEP_TIME 3 // Seconds to sleep to simulate calculation
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void thread_function(void *param) {
|
|
||||||
int sock = (long) param; // Grab our blocking socket
|
|
||||||
struct response r = {strdup("hello"), 5}; // Create response
|
|
||||||
sleep(SLEEP_TIME); // Simulate long execution
|
|
||||||
send(sock, (void *) &r, sizeof(r), 0); // Send to request handler
|
|
||||||
close(sock); // Done, close socket, end thread
|
|
||||||
}
|
|
||||||
|
|
||||||
static void start_thread(void (*f)(void *), void *p) {
|
static void start_thread(void (*f)(void *), void *p) {
|
||||||
#ifdef WINCE
|
#ifdef _WIN32
|
||||||
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) f, p, 0, NULL);
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
_beginthread((void(__cdecl *)(void *)) f, 0, p);
|
_beginthread((void(__cdecl *)(void *)) f, 0, p);
|
||||||
#else
|
#else
|
||||||
|
#define closesocket(x) close(x)
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
pthread_t thread_id = (pthread_t) 0;
|
pthread_t thread_id = (pthread_t) 0;
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
@@ -55,6 +46,15 @@ static void start_thread(void (*f)(void *), void *p) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void thread_function(void *param) {
|
||||||
|
int sock = (long) param; // Grab our blocking socket
|
||||||
|
struct response r = {strdup("hello\n"), 6}; // Create response
|
||||||
|
mg_usleep(SLEEP_TIME * 1000000); // Simulate long execution
|
||||||
|
LOG(LL_INFO, ("got sock %d", sock)); // For debugging
|
||||||
|
send(sock, (void *) &r, sizeof(r), 0); // Send to request handler
|
||||||
|
closesocket(sock); // Done, close socket, end thread
|
||||||
|
}
|
||||||
|
|
||||||
// HTTP request callback
|
// HTTP request callback
|
||||||
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
if (ev == MG_EV_HTTP_MSG) {
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
@@ -70,7 +70,7 @@ static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
"Content-Length: 3\r\n\r\n" // Set to allow keep-alive
|
"Content-Length: 3\r\n\r\n" // Set to allow keep-alive
|
||||||
"hi\n");
|
"hi\n");
|
||||||
} else {
|
} else {
|
||||||
int blocking, non_blocking;
|
int blocking = -1, non_blocking = -1;
|
||||||
mg_socketpair(&blocking, &non_blocking); // Create connected pair
|
mg_socketpair(&blocking, &non_blocking); // Create connected pair
|
||||||
|
|
||||||
// Pass blocking socket to the thread_function.
|
// Pass blocking socket to the thread_function.
|
||||||
@@ -82,7 +82,7 @@ static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
}
|
}
|
||||||
} else if (ev == MG_EV_POLL && c->fn_data != NULL) {
|
} else if (ev == MG_EV_POLL && c->fn_data != NULL) {
|
||||||
// On each poll iteration, try to receive response data
|
// On each poll iteration, try to receive response data
|
||||||
int sock = (int) c->fn_data;
|
int sock = (int) (long) c->fn_data;
|
||||||
struct response response = {NULL, 0};
|
struct response response = {NULL, 0};
|
||||||
if (recv(sock, (void *) &response, sizeof(response), 0) ==
|
if (recv(sock, (void *) &response, sizeof(response), 0) ==
|
||||||
sizeof(response)) {
|
sizeof(response)) {
|
||||||
@@ -90,7 +90,7 @@ static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
mg_printf(c, "HTTP/1.0 200 OK\r\nContent-Length: %d\r\n\r\n%.*s",
|
mg_printf(c, "HTTP/1.0 200 OK\r\nContent-Length: %d\r\n\r\n%.*s",
|
||||||
response.len, response.len, response.data);
|
response.len, response.len, response.data);
|
||||||
free(response.data); // We can free produced data now
|
free(response.data); // We can free produced data now
|
||||||
close(sock); // And close our end of the socket pair
|
closesocket(sock); // And close our end of the socket pair
|
||||||
c->fn_data = NULL;
|
c->fn_data = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
u->token);
|
u->token);
|
||||||
mg_http_printf_chunk(c, "");
|
mg_http_printf_chunk(c, "");
|
||||||
} else {
|
} else {
|
||||||
mg_http_serve_dir(c, ev_data, "web_root");
|
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
|
||||||
|
mg_http_serve_dir(c, ev_data, &opts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-8
@@ -1,9 +1,3 @@
|
|||||||
/* axios v0.19.0-beta.1 | (c) 2018 by Matt Zabriskie */
|
/* axios v0.21.1 | (c) 2020 by Matt Zabriskie */
|
||||||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function r(e){var t=new i(e),n=s(i.prototype.request,t);return o.extend(n,i.prototype,t),o.extend(n,t),n}var o=n(2),s=n(3),i=n(5),a=n(22),u=n(11),c=r(u);c.Axios=i,c.create=function(e){return r(a(c.defaults,e))},c.Cancel=n(23),c.CancelToken=n(24),c.isCancel=n(10),c.all=function(e){return Promise.all(e)},c.spread=n(25),e.exports=c,e.exports.default=c},function(e,t,n){"use strict";function r(e){return"[object Array]"===j.call(e)}function o(e){return"[object ArrayBuffer]"===j.call(e)}function s(e){return"undefined"!=typeof FormData&&e instanceof FormData}function i(e){var t;return t="undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function a(e){return"string"==typeof e}function u(e){return"number"==typeof e}function c(e){return"undefined"==typeof e}function f(e){return null!==e&&"object"==typeof e}function p(e){return"[object Date]"===j.call(e)}function d(e){return"[object File]"===j.call(e)}function l(e){return"[object Blob]"===j.call(e)}function h(e){return"[object Function]"===j.call(e)}function m(e){return f(e)&&h(e.pipe)}function y(e){return"undefined"!=typeof URLSearchParams&&e instanceof URLSearchParams}function g(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function x(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product&&"NativeScript"!==navigator.product&&"NS"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)}function v(e,t){if(null!==e&&"undefined"!=typeof e)if("object"!=typeof e&&(e=[e]),r(e))for(var n=0,o=e.length;n<o;n++)t.call(null,e[n],n,e);else for(var s in e)Object.prototype.hasOwnProperty.call(e,s)&&t.call(null,e[s],s,e)}function w(){function e(e,n){"object"==typeof t[n]&&"object"==typeof e?t[n]=w(t[n],e):t[n]=e}for(var t={},n=0,r=arguments.length;n<r;n++)v(arguments[n],e);return t}function b(){function e(e,n){"object"==typeof t[n]&&"object"==typeof e?t[n]=b(t[n],e):"object"==typeof e?t[n]=b({},e):t[n]=e}for(var t={},n=0,r=arguments.length;n<r;n++)v(arguments[n],e);return t}function E(e,t,n){return v(t,function(t,r){n&&"function"==typeof t?e[r]=S(t,n):e[r]=t}),e}var S=n(3),R=n(4),j=Object.prototype.toString;e.exports={isArray:r,isArrayBuffer:o,isBuffer:R,isFormData:s,isArrayBufferView:i,isString:a,isNumber:u,isObject:f,isUndefined:c,isDate:p,isFile:d,isBlob:l,isFunction:h,isStream:m,isURLSearchParams:y,isStandardBrowserEnv:x,forEach:v,merge:w,deepMerge:b,extend:E,trim:g}},function(e,t){"use strict";e.exports=function(e,t){return function(){for(var n=new Array(arguments.length),r=0;r<n.length;r++)n[r]=arguments[r];return e.apply(t,n)}}},function(e,t){/*!
|
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function r(e){var t=new i(e),n=s(i.prototype.request,t);return o.extend(n,i.prototype,t),o.extend(n,t),n}var o=n(2),s=n(3),i=n(4),a=n(22),u=n(10),c=r(u);c.Axios=i,c.create=function(e){return r(a(c.defaults,e))},c.Cancel=n(23),c.CancelToken=n(24),c.isCancel=n(9),c.all=function(e){return Promise.all(e)},c.spread=n(25),c.isAxiosError=n(26),e.exports=c,e.exports.default=c},function(e,t,n){"use strict";function r(e){return"[object Array]"===R.call(e)}function o(e){return"undefined"==typeof e}function s(e){return null!==e&&!o(e)&&null!==e.constructor&&!o(e.constructor)&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}function i(e){return"[object ArrayBuffer]"===R.call(e)}function a(e){return"undefined"!=typeof FormData&&e instanceof FormData}function u(e){var t;return t="undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function c(e){return"string"==typeof e}function f(e){return"number"==typeof e}function p(e){return null!==e&&"object"==typeof e}function d(e){if("[object Object]"!==R.call(e))return!1;var t=Object.getPrototypeOf(e);return null===t||t===Object.prototype}function l(e){return"[object Date]"===R.call(e)}function h(e){return"[object File]"===R.call(e)}function m(e){return"[object Blob]"===R.call(e)}function y(e){return"[object Function]"===R.call(e)}function g(e){return p(e)&&y(e.pipe)}function v(e){return"undefined"!=typeof URLSearchParams&&e instanceof URLSearchParams}function x(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function w(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product&&"NativeScript"!==navigator.product&&"NS"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)}function b(e,t){if(null!==e&&"undefined"!=typeof e)if("object"!=typeof e&&(e=[e]),r(e))for(var n=0,o=e.length;n<o;n++)t.call(null,e[n],n,e);else for(var s in e)Object.prototype.hasOwnProperty.call(e,s)&&t.call(null,e[s],s,e)}function E(){function e(e,n){d(t[n])&&d(e)?t[n]=E(t[n],e):d(e)?t[n]=E({},e):r(e)?t[n]=e.slice():t[n]=e}for(var t={},n=0,o=arguments.length;n<o;n++)b(arguments[n],e);return t}function j(e,t,n){return b(t,function(t,r){n&&"function"==typeof t?e[r]=S(t,n):e[r]=t}),e}function C(e){return 65279===e.charCodeAt(0)&&(e=e.slice(1)),e}var S=n(3),R=Object.prototype.toString;e.exports={isArray:r,isArrayBuffer:i,isBuffer:s,isFormData:a,isArrayBufferView:u,isString:c,isNumber:f,isObject:p,isPlainObject:d,isUndefined:o,isDate:l,isFile:h,isBlob:m,isFunction:y,isStream:g,isURLSearchParams:v,isStandardBrowserEnv:w,forEach:b,merge:E,extend:j,trim:x,stripBOM:C}},function(e,t){"use strict";e.exports=function(e,t){return function(){for(var n=new Array(arguments.length),r=0;r<n.length;r++)n[r]=arguments[r];return e.apply(t,n)}}},function(e,t,n){"use strict";function r(e){this.defaults=e,this.interceptors={request:new i,response:new i}}var o=n(2),s=n(5),i=n(6),a=n(7),u=n(22);r.prototype.request=function(e){"string"==typeof e?(e=arguments[1]||{},e.url=arguments[0]):e=e||{},e=u(this.defaults,e),e.method?e.method=e.method.toLowerCase():this.defaults.method?e.method=this.defaults.method.toLowerCase():e.method="get";var t=[a,void 0],n=Promise.resolve(e);for(this.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),this.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)n=n.then(t.shift(),t.shift());return n},r.prototype.getUri=function(e){return e=u(this.defaults,e),s(e.url,e.params,e.paramsSerializer).replace(/^\?/,"")},o.forEach(["delete","get","head","options"],function(e){r.prototype[e]=function(t,n){return this.request(u(n||{},{method:e,url:t,data:(n||{}).data}))}}),o.forEach(["post","put","patch"],function(e){r.prototype[e]=function(t,n,r){return this.request(u(r||{},{method:e,url:t,data:n}))}}),e.exports=r},function(e,t,n){"use strict";function r(e){return encodeURIComponent(e).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var o=n(2);e.exports=function(e,t,n){if(!t)return e;var s;if(n)s=n(t);else if(o.isURLSearchParams(t))s=t.toString();else{var i=[];o.forEach(t,function(e,t){null!==e&&"undefined"!=typeof e&&(o.isArray(e)?t+="[]":e=[e],o.forEach(e,function(e){o.isDate(e)?e=e.toISOString():o.isObject(e)&&(e=JSON.stringify(e)),i.push(r(t)+"="+r(e))}))}),s=i.join("&")}if(s){var a=e.indexOf("#");a!==-1&&(e=e.slice(0,a)),e+=(e.indexOf("?")===-1?"?":"&")+s}return e}},function(e,t,n){"use stricLine truncated
|
||||||
* Determine if an object is a Buffer
|
|
||||||
*
|
|
||||||
* @author Feross Aboukhadijeh <https://feross.org>
|
|
||||||
* @license MIT
|
|
||||||
*/
|
|
||||||
e.exports=function(e){return null!=e&&null!=e.constructor&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}},function(e,t,n){"use strict";function r(e){this.defaults=e,this.interceptors={request:new i,response:new i}}var o=n(2),s=n(6),i=n(7),a=n(8),u=n(22);r.prototype.request=function(e){"string"==typeof e?(e=arguments[1]||{},e.url=arguments[0]):e=e||{},e=u(this.defaults,e),e.method=e.method?e.method.toLowerCase():"get";var t=[a,void 0],n=Promise.resolve(e);for(this.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),this.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)n=n.then(t.shift(),t.shift());return n},r.prototype.getUri=function(e){return e=u(this.defaults,e),s(e.url,e.params,e.paramsSerializer).replace(/^\?/,"")},o.forEach(["delete","get","head","options"],function(e){r.prototype[e]=function(t,n){return this.request(o.merge(n||{},{method:e,url:t}))}}),o.forEach(["post","put","patch"],function(e){r.prototype[e]=function(t,n,r){return this.request(o.merge(r||{},{method:e,url:t,data:n}))}}),e.exports=r},function(e,t,n){"use strict";function r(e){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var o=n(2);e.exports=function(e,t,n){if(!t)return e;var s;if(n)s=n(t);else if(o.isURLSearchParams(t))s=t.toString();else{var i=[];o.forEach(t,function(e,t){null!==e&&"undefined"!=typeof e&&(o.isArray(e)?t+="[]":e=[e],o.forEach(e,function(e){o.isDate(e)?e=e.toISOString():o.isObject(e)&&(e=JSON.stringify(e)),i.push(r(t)+"="+r(e))}))}),s=i.join("&")}return s&&(e+=(e.indexOf("?")===-1?"?":"&")+s),e}},function(e,t,n){"use strict";function r(){this.handlers=[]}var o=n(2);r.prototype.use=function(e,t){return this.handlers.push({fulfilled:e,rejected:t}),this.handlers.length-1},r.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)},r.prototype.forEach=function(e){o.forEach(this.handlers,function(t){null!==t&&e(t)})},e.exports=r},function(e,t,n){"use strict";function r(e){e.cancelToken&&e.cancelToken.throwIfRequested()}var o=n(2),s=n(9),i=n(10),a=n(11),u=n(20),c=n(21);e.exports=function(e){r(e),e.baseURL&&!u(e.url)&&(e.url=c(e.baseURL,e.url)),e.headers=e.headers||{},e.data=s(e.data,e.headers,e.transformRequest),e.headers=o.merge(e.headers.common||{},e.headers[e.method]||{},e.headers||{}),o.forEach(["delete","get","head","post","put","patch","common"],function(t){delete e.headers[t]});var t=e.adapter||a.adapter;return t(e).then(function(t){return r(e),t.data=s(t.data,t.headers,e.transformResponse),t},function(t){return i(t)||(r(e),t&&t.response&&(t.response.data=s(t.response.data,t.response.headers,e.transformResponse))),Promise.reject(t)})}},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t,n){return r.forEach(n,function(n){e=n(e,t)}),e}},function(e,t){"use strict";e.exports=function(e){return!(!e||!e.__CANCEL__)}},function(e,t,n){"use strict";function r(e,t){!s.isUndefined(e)&&s.isUndefined(e["Content-Type"])&&(e["Content-Type"]=t)}function o(){var e;return"undefined"!=typeof process&&"[object process]"===Object.prototype.toString.call(process)?e=n(13):"undefined"!=typeof XMLHttpRequest&&(e=n(13)),e}var s=n(2),i=n(12),a={"Content-Type":"application/x-www-form-urlencoded"},u={adapter:o(),transformRequest:[function(e,t){return i(t,"Accept"),i(t,"Content-Type"),s.isFormData(e)||s.isArrayBuffer(e)||s.isBuffer(e)||s.isStream(e)||s.isFile(e)||s.isBlob(e)?e:s.isArrayBufferView(e)?e.buffer:s.isURLSearchParams(e)?(r(t,"application/x-www-form-urlencoded;charset=utf-8"),e.toString()):s.isObject(e)?(r(t,"application/json;charset=utf-8"),JSON.stringify(e)):e}],transformResponse:[function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(e){}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,validateStatus:function(e){return e>=200&&e<300}};u.headers={common:{Accept:"application/json, text/plain, */*"}},s.forEach(["delete","get","head"],function(e){u.headers[e]={}}),s.forEach(["post","put","patch"],function(e){u.headers[e]=s.merge(a)}),e.exports=u},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t){r.forEach(e,function(n,r){r!==t&&r.toUpperCase()===t.toUpperCase()&&(e[t]=n,delete e[r])})}},function(e,t,n){"use strict";var r=n(2),o=n(14),s=n(6),i=n(17),a=n(18),u=n(15);e.exports=function(e){return new Promise(function(t,c){var f=e.data,p=e.headers;r.isFormData(f)&&delete p["Content-Type"];var d=new XMLHttpRequest;if(e.auth){var l=e.auth.username||"",h=e.auth.password||"";p.Authorization="Basic "+btoa(l+":"+h)}if(d.open(e.method.toUpperCase(),s(e.url,e.params,e.paramsSerializer),!0),d.timeout=e.timeout,d.onreadystatechange=function(){if(d&&4===d.readyState&&(0!==d.status||d.responseURL&&0===d.responseURL.indexOf("file:"))){var n="getAllResponseHeaders"in d?i(d.getAllResponseHeaders()):null,r=e.responseType&&"text"!==e.responseType?d.response:Line truncated
|
|
||||||
//# sourceMappingURL=axios.min.map
|
//# sourceMappingURL=axios.min.map
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
PROG ?= example
|
||||||
|
CFLAGS ?= -DMG_ENABLE_LINES $(CFLAGS_EXTRA)
|
||||||
|
MBEDTLS_DIR ?=
|
||||||
|
|
||||||
|
ifeq "$(MBEDTLS_DIR)" ""
|
||||||
|
else
|
||||||
|
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS_DIR)/include -I/usr/include
|
||||||
|
CFLAGS += -L$(MBEDTLS_DIR)/lib -lmbedtls -lmbedcrypto -lmbedx509
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(DEBUGGER) ./$(PROG) $(ARGS)
|
||||||
|
|
||||||
|
|
||||||
|
$(PROG): main.c
|
||||||
|
$(CC) ../../mongoose.c -I../.. -W -Wall $(CFLAGS) -o $(PROG) main.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
// Copyright (c) 2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// Example socks5 server. To test,
|
||||||
|
// 1. Run `make` to start this server on port 1080
|
||||||
|
// 2. Run `curl`
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static const char *s_lsn = "tcp://localhost:1080"; // Listening address
|
||||||
|
|
||||||
|
enum {
|
||||||
|
VERSION = 5, // Socks protocol version
|
||||||
|
STATE_HANDSHAKE = 0, // Connection state: in handshake
|
||||||
|
STATE_REQUEST = 1, // Connection state: connecting
|
||||||
|
STATE_ESTABLISHED = 2, // Connection state: established
|
||||||
|
HANDSHAKE_NOAUTH = 0, // Handshake method - no authentication
|
||||||
|
HANDSHAKE_GSSAPI = 1, // Handshake method - GSSAPI auth
|
||||||
|
HANDSHAKE_USERPASS = 2, // Handshake method - user/password auth
|
||||||
|
HANDSHAKE_FAILURE = 0xff, // Handshake method - failure
|
||||||
|
CMD_CONNECT = 1, // Command: CONNECT
|
||||||
|
CMD_BIND = 2, // Command: BIND
|
||||||
|
CMD_UDP_ASSOCIATE = 3, // Command: UDP ASSOCIATE
|
||||||
|
ADDR_TYPE_IPV4 = 1, // Address type: IPv4
|
||||||
|
ADDR_TYPE_DOMAIN = 3, // Address type: Domain name
|
||||||
|
ADDR_TYPE_IPV6 = 4, // Address type: IPv6
|
||||||
|
RESP_SUCCESS = 0, // Response: success
|
||||||
|
RESP_FAILURE = 1, // Response: failure
|
||||||
|
RESP_NOT_ALLOWED = 2, // Response status
|
||||||
|
RESP_NET_UNREACHABLE = 3, // Response status
|
||||||
|
RESP_HOST_UNREACHABLE = 4, // Response status
|
||||||
|
RESP_CONN_REFUSED = 5, // Response status
|
||||||
|
RESP_TTL_EXPIRED = 6, // Response status
|
||||||
|
RESP_CMD_NOT_SUPPORTED = 7, // Response status
|
||||||
|
RESP_ADDR_NOT_SUPPORTED = 8, // Response status
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://www.ietf.org/rfc/rfc1928.txt paragraph 3, handle client handshake
|
||||||
|
// +----+----------+----------+
|
||||||
|
// |VER | NMETHODS | METHODS |
|
||||||
|
// +----+----------+----------+
|
||||||
|
// | 1 | 1 | 1 to 255 |
|
||||||
|
// +----+----------+----------+
|
||||||
|
static void handshake(struct mg_connection *c) {
|
||||||
|
struct mg_iobuf *r = &c->recv;
|
||||||
|
if (r->buf[0] != VERSION) {
|
||||||
|
c->is_closing = 1;
|
||||||
|
} else if (r->len > 2 && (size_t) r->buf[1] + 2 <= r->len) {
|
||||||
|
/* https://www.ietf.org/rfc/rfc1928.txt paragraph 3 */
|
||||||
|
uint8_t reply[2] = {VERSION, HANDSHAKE_FAILURE};
|
||||||
|
int i;
|
||||||
|
for (i = 2; i < r->buf[1] + 2; i++) {
|
||||||
|
// TODO(lsm): support other auth methods
|
||||||
|
if (r->buf[i] == HANDSHAKE_NOAUTH) reply[1] = r->buf[i];
|
||||||
|
}
|
||||||
|
mg_iobuf_delete(r, 2 + r->buf[1]);
|
||||||
|
mg_send(c, reply, sizeof(reply));
|
||||||
|
c->label[0] = STATE_REQUEST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void disband(struct mg_connection *c) {
|
||||||
|
struct mg_connection *c2 = (struct mg_connection *) c->fn_data;
|
||||||
|
if (c2 != NULL) {
|
||||||
|
c2->is_draining = 1;
|
||||||
|
c2->fn_data = NULL;
|
||||||
|
}
|
||||||
|
c->is_draining = 1;
|
||||||
|
c->fn_data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exchange(struct mg_connection *c) {
|
||||||
|
struct mg_connection *c2 = (struct mg_connection *) c->fn_data;
|
||||||
|
if (c2 != NULL) {
|
||||||
|
mg_send(c2, c->recv.buf, c->recv.len);
|
||||||
|
mg_iobuf_delete(&c->recv, c->recv.len);
|
||||||
|
} else {
|
||||||
|
c->is_draining = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fn2(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_READ) {
|
||||||
|
exchange(c);
|
||||||
|
} else if (ev == MG_EV_CLOSE) {
|
||||||
|
disband(c);
|
||||||
|
}
|
||||||
|
(void) ev_data;
|
||||||
|
(void) fn_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request, https://www.ietf.org/rfc/rfc1928.txt paragraph 4
|
||||||
|
// +----+-----+-------+------+----------+----------+
|
||||||
|
// |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
|
||||||
|
// +----+-----+-------+------+----------+----------+
|
||||||
|
// | 1 | 1 | X'00' | 1 | Variable | 2 |
|
||||||
|
// +----+-----+-------+------+----------+----------+
|
||||||
|
static void request(struct mg_connection *c) {
|
||||||
|
struct mg_iobuf *r = &c->recv;
|
||||||
|
uint8_t *p = r->buf, addr_len = 4, reply = RESP_SUCCESS;
|
||||||
|
int ver, cmd, atyp;
|
||||||
|
char addr[1024];
|
||||||
|
|
||||||
|
if (r->len < 8) return; // return if not fully buffered. min DST.ADDR is 2
|
||||||
|
ver = p[0];
|
||||||
|
cmd = p[1];
|
||||||
|
atyp = p[3];
|
||||||
|
|
||||||
|
// TODO(lsm): support other commands
|
||||||
|
if (ver != VERSION || cmd != CMD_CONNECT) {
|
||||||
|
reply = RESP_CMD_NOT_SUPPORTED;
|
||||||
|
} else if (atyp == ADDR_TYPE_IPV4) {
|
||||||
|
addr_len = 4;
|
||||||
|
if (r->len < (size_t) addr_len + 6) return; /* return if not buffered */
|
||||||
|
snprintf(addr, sizeof(addr), "tcp://%d.%d.%d.%d:%d", p[4], p[5], p[6], p[7],
|
||||||
|
p[8] << 8 | p[9]);
|
||||||
|
c->fn_data = mg_connect(c->mgr, addr, fn2, c);
|
||||||
|
} else if (atyp == ADDR_TYPE_IPV6) {
|
||||||
|
addr_len = 16;
|
||||||
|
if (r->len < (size_t) addr_len + 6) return; /* return if not buffered */
|
||||||
|
snprintf(addr, sizeof(addr), "tcp://[%x:%x:%x:%x:%x:%x:%x:%x]:%d",
|
||||||
|
p[4] << 8 | p[5], p[6] << 8 | p[7], p[8] << 8 | p[9],
|
||||||
|
p[10] << 8 | p[11], p[12] << 8 | p[13], p[14] << 8 | p[15],
|
||||||
|
p[16] << 8 | p[17], p[18] << 8 | p[19], p[20] << 8 | p[21]);
|
||||||
|
c->fn_data = mg_connect(c->mgr, addr, fn2, c);
|
||||||
|
} else if (atyp == ADDR_TYPE_DOMAIN) {
|
||||||
|
addr_len = p[4] + 1;
|
||||||
|
if (r->len < (size_t) addr_len + 6) return; /* return if not buffered */
|
||||||
|
snprintf(addr, sizeof(addr), "tcp://%.*s:%d", p[4], p + 5,
|
||||||
|
p[4 + addr_len] << 8 | p[4 + addr_len + 1]);
|
||||||
|
c->fn_data = mg_connect(c->mgr, addr, fn2, c);
|
||||||
|
} else {
|
||||||
|
reply = RESP_ADDR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reply, https://www.ietf.org/rfc/rfc1928.txt paragraph 5
|
||||||
|
//
|
||||||
|
// +----+-----+-------+------+----------+----------+
|
||||||
|
// |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
|
||||||
|
// +----+-----+-------+------+----------+----------+
|
||||||
|
// | 1 | 1 | X'00' | 1 | Variable | 2 |
|
||||||
|
// +----+-----+-------+------+----------+----------+
|
||||||
|
{
|
||||||
|
uint8_t buf[] = {VERSION, reply, 0};
|
||||||
|
mg_send(c, buf, sizeof(buf));
|
||||||
|
}
|
||||||
|
mg_send(c, r->buf + 3, addr_len + 1 + 2);
|
||||||
|
mg_iobuf_delete(r, 6 + addr_len); // Remove request from the input stream
|
||||||
|
c->label[0] = STATE_ESTABLISHED; // Mark ourselves as connected
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_READ) {
|
||||||
|
// We use the first label byte as a state
|
||||||
|
if (c->label[0] == STATE_HANDSHAKE) handshake(c);
|
||||||
|
if (c->label[0] == STATE_REQUEST) request(c);
|
||||||
|
if (c->label[0] == STATE_ESTABLISHED) exchange(c);
|
||||||
|
} else if (ev == MG_EV_CLOSE) {
|
||||||
|
disband(c);
|
||||||
|
}
|
||||||
|
(void) fn_data;
|
||||||
|
(void) ev_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_mgr mgr; // Event manager
|
||||||
|
mg_log_set("3"); // Set to 0 to disable debug
|
||||||
|
mg_mgr_init(&mgr); // Initialise event manager
|
||||||
|
mg_listen(&mgr, s_lsn, fn, NULL); // Create client connection
|
||||||
|
while (true) mg_mgr_poll(&mgr, 1000); // Infinite event loop
|
||||||
|
mg_mgr_free(&mgr); // Free resources
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
PROG ?= example
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(DEBUGGER) ./$(PROG) $(ARGS)
|
||||||
|
|
||||||
|
$(PROG): main.c
|
||||||
|
$(CC) ../../mongoose.c -I../.. -W -Wall -DMG_ENABLE_LINES=1 -DMG_ENABLE_DIRECTORY_LISTING=1 $(CFLAGS) -o $(PROG) main.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
// Copyright (c) 2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// Example Websocket server with timers. This is a simple Websocket echo
|
||||||
|
// server, which sends a message to all connected clients periodically,
|
||||||
|
// using timer API.
|
||||||
|
//
|
||||||
|
// 1. Start this server, type `make`
|
||||||
|
// 2. Open https://www.websocket.org/echo.html in your browser
|
||||||
|
// 3. In the "Location" text field, type ws://127.0.0.1:8000/websocket
|
||||||
|
// 4. See "hi" messages appearing periodically
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static const char *s_listen_on = "http://localhost:8000";
|
||||||
|
|
||||||
|
// This RESTful server implements the following endpoints:
|
||||||
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
mg_ws_upgrade(c, hm, NULL);
|
||||||
|
} else if (ev == MG_EV_WS_MSG) {
|
||||||
|
// Got websocket frame. Received data is wm->data. Echo it back!
|
||||||
|
struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
|
||||||
|
mg_ws_send(c, wm->data.ptr, wm->data.len, WEBSOCKET_OP_TEXT);
|
||||||
|
mg_iobuf_delete(&c->recv, c->recv.len);
|
||||||
|
}
|
||||||
|
(void) fn_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void timer_fn(void *arg) {
|
||||||
|
struct mg_mgr *mgr = (struct mg_mgr *) arg;
|
||||||
|
struct mg_connection *c;
|
||||||
|
// Broadcast "hi" message to all connected websocket clients.
|
||||||
|
// Traverse over all connections
|
||||||
|
for (c = mgr->conns; c != NULL; c = c->next) {
|
||||||
|
// Send only to accepted websocket connections
|
||||||
|
if (c->is_accepted && c->is_websocket) {
|
||||||
|
mg_ws_send(c, "hi", 2, WEBSOCKET_OP_TEXT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_mgr mgr; // Event manager
|
||||||
|
struct mg_timer t1; // Timer
|
||||||
|
mg_mgr_init(&mgr); // Initialise event manager
|
||||||
|
mg_timer_init(&t1, 300, MG_TIMER_REPEAT, timer_fn, &mgr); // Init timer
|
||||||
|
mg_http_listen(&mgr, s_listen_on, fn, NULL); // Create HTTP listener
|
||||||
|
for (;;) mg_mgr_poll(&mgr, 1000); // Infinite event loop
|
||||||
|
mg_timer_free(&t1); // Free timer resources
|
||||||
|
mg_mgr_free(&mgr); // Free manager resources
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -18,7 +18,8 @@ static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
"Pragma: no-cache\r\nExpires: Thu, 01 Dec 1994 16:00:00 GMT\r\n"
|
"Pragma: no-cache\r\nExpires: Thu, 01 Dec 1994 16:00:00 GMT\r\n"
|
||||||
"Content-Type: multipart/x-mixed-replace; boundary=--foo\r\n\r\n");
|
"Content-Type: multipart/x-mixed-replace; boundary=--foo\r\n\r\n");
|
||||||
} else {
|
} else {
|
||||||
mg_http_serve_dir(c, ev_data, "web_root");
|
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
|
||||||
|
mg_http_serve_dir(c, ev_data, &opts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,7 +36,7 @@ static void broadcast_mjpeg_frame(struct mg_mgr *mgr) {
|
|||||||
char *data = mg_file_read(path); // Read next file
|
char *data = mg_file_read(path); // Read next file
|
||||||
struct mg_connection *c;
|
struct mg_connection *c;
|
||||||
for (c = mgr->conns; c != NULL; c = c->next) {
|
for (c = mgr->conns; c != NULL; c = c->next) {
|
||||||
if (c->label[0] != 'S') continue; // Skip non-stream connections
|
if (c->label[0] != 'S') continue; // Skip non-stream connections
|
||||||
if (data == NULL || size == 0) continue; // Skip on file read error
|
if (data == NULL || size == 0) continue; // Skip on file read error
|
||||||
mg_printf(c,
|
mg_printf(c,
|
||||||
"--foo\r\nContent-Type: image/jpeg\r\n"
|
"--foo\r\nContent-Type: image/jpeg\r\n"
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ static const char *s_url = "ws://localhost:8000/websocket";
|
|||||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
if (ev == MG_EV_ERROR) {
|
if (ev == MG_EV_ERROR) {
|
||||||
// On error, log error message
|
// On error, log error message
|
||||||
LOG(LL_ERROR, ("%p %s", c->fd, ev_data));
|
LOG(LL_ERROR, ("%p %s", c->fd, (char *) ev_data));
|
||||||
} else if (ev == MG_EV_WS_OPEN) {
|
} else if (ev == MG_EV_WS_OPEN) {
|
||||||
// When websocket handshake is successful, send message
|
// When websocket handshake is successful, send message
|
||||||
mg_ws_send(c, "hello", 5, WEBSOCKET_OP_TEXT);
|
mg_ws_send(c, "hello", 5, WEBSOCKET_OP_TEXT);
|
||||||
|
|||||||
@@ -21,13 +21,14 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
if (mg_http_match_uri(hm, "/websocket")) {
|
if (mg_http_match_uri(hm, "/websocket")) {
|
||||||
// Upgrade to websocket. From now on, a connection is a full-duplex
|
// Upgrade to websocket. From now on, a connection is a full-duplex
|
||||||
// Websocket connection, which will receive MG_EV_WS_MSG events.
|
// Websocket connection, which will receive MG_EV_WS_MSG events.
|
||||||
mg_ws_upgrade(c, hm);
|
mg_ws_upgrade(c, hm, NULL);
|
||||||
} else if (mg_http_match_uri(hm, "/rest")) {
|
} else if (mg_http_match_uri(hm, "/rest")) {
|
||||||
// Serve REST response
|
// Serve REST response
|
||||||
mg_http_reply(c, 200, "{\"result\": %d}\n", 123);
|
mg_http_reply(c, 200, "", "{\"result\": %d}\n", 123);
|
||||||
} else {
|
} else {
|
||||||
// Serve static files
|
// Serve static files
|
||||||
mg_http_serve_dir(c, ev_data, s_web_directory);
|
struct mg_http_serve_opts opts = {.root_dir = s_web_directory};
|
||||||
|
mg_http_serve_dir(c, ev_data, &opts);
|
||||||
}
|
}
|
||||||
} else if (ev == MG_EV_WS_MSG) {
|
} else if (ev == MG_EV_WS_MSG) {
|
||||||
// Got websocket frame. Received data is wm->data. Echo it back!
|
// Got websocket frame. Received data is wm->data. Echo it back!
|
||||||
|
|||||||
+1142
-573
File diff suppressed because it is too large.
Load diff
+198
-102
@@ -1,5 +1,5 @@
|
|||||||
// Copyright (c) 2004-2013 Sergey Lyubka
|
// Copyright (c) 2004-2013 Sergey Lyubka
|
||||||
// Copyright (c) 2013-2020 Cesanta Software Limited
|
// Copyright (c) 2013-2021 Cesanta Software Limited
|
||||||
// All rights reserved
|
// All rights reserved
|
||||||
//
|
//
|
||||||
// This software is dual-licensed: you can redistribute it and/or modify
|
// 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
|
// Alternatively, you can license this software under a commercial
|
||||||
// license, as set out in <https://www.cesanta.com/license>.
|
// license, as set out in <https://www.cesanta.com/license>.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#define MG_VERSION "7.0"
|
#define MG_VERSION "7.2"
|
||||||
|
|
||||||
|
|
||||||
#define MG_ARCH_CUSTOM 0
|
#define MG_ARCH_CUSTOM 0
|
||||||
@@ -61,10 +60,10 @@
|
|||||||
#define MG_ARCH MG_ARCH_NXP_KINETIS
|
#define MG_ARCH MG_ARCH_NXP_KINETIS
|
||||||
#elif defined(PIC32)
|
#elif defined(PIC32)
|
||||||
#define MG_ARCH MG_ARCH_PIC32
|
#define MG_ARCH MG_ARCH_PIC32
|
||||||
#elif defined(ESP_PLATFORM)
|
|
||||||
#define MG_ARCH MG_ARCH_ESP32
|
|
||||||
#elif defined(ICACHE_FLASH) || defined(ICACHE_RAM_ATTR)
|
#elif defined(ICACHE_FLASH) || defined(ICACHE_RAM_ATTR)
|
||||||
#define MG_ARCH MG_ARCH_ESP8266
|
#define MG_ARCH MG_ARCH_ESP8266
|
||||||
|
#elif defined(ESP_PLATFORM)
|
||||||
|
#define MG_ARCH MG_ARCH_ESP32
|
||||||
#elif defined(TARGET_IS_TM4C129_RA0) || defined(TARGET_IS_TM4C129_RA1) || \
|
#elif defined(TARGET_IS_TM4C129_RA0) || defined(TARGET_IS_TM4C129_RA1) || \
|
||||||
defined(TARGET_IS_TM4C129_RA2)
|
defined(TARGET_IS_TM4C129_RA2)
|
||||||
#define MG_ARCH MG_ARCH_TM4C129
|
#define MG_ARCH MG_ARCH_TM4C129
|
||||||
@@ -120,7 +119,12 @@
|
|||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#define MG_DIRSEP '/'
|
#define MG_DIRSEP '/'
|
||||||
|
#define MG_INT64_FMT "%lld"
|
||||||
|
#ifndef MG_PATH_MAX
|
||||||
|
#define MG_PATH_MAX 128
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -128,26 +132,12 @@
|
|||||||
#if MG_ARCH == MG_ARCH_ESP8266
|
#if MG_ARCH == MG_ARCH_ESP8266
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <esp_system.h>
|
||||||
|
#include <netdb.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <user_interface.h>
|
|
||||||
|
|
||||||
#define MG_DIRSEP '/'
|
#define MG_DIRSEP '/'
|
||||||
#ifndef PATH_MAX
|
#define MG_INT64_FMT "%lld"
|
||||||
#define PATH_MAX 128
|
|
||||||
#endif
|
|
||||||
#define MG_ENABLE_LWIP 1
|
|
||||||
#define LWIP_TIMEVAL_PRIVATE 0 // struct timeval is defined in sys/time.h
|
|
||||||
|
|
||||||
#if LWIP_SOCKET
|
|
||||||
#include <lwip/sockets.h>
|
|
||||||
#else
|
|
||||||
#undef LWIP_SOCKET
|
|
||||||
#define LWIP_SOCKET 1
|
|
||||||
#include <lwip/sockets.h> // Source sockaddr_in anyway
|
|
||||||
#undef LWIP_SOCKET
|
|
||||||
#define LWIP_SOCKET 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -161,6 +151,7 @@
|
|||||||
#include <FreeRTOS_Sockets.h>
|
#include <FreeRTOS_Sockets.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define MG_INT64_FMT "%lld"
|
||||||
#define MG_DIRSEP '/'
|
#define MG_DIRSEP '/'
|
||||||
#define IPPROTO_TCP FREERTOS_IPPROTO_TCP
|
#define IPPROTO_TCP FREERTOS_IPPROTO_TCP
|
||||||
#define IPPROTO_UDP FREERTOS_IPPROTO_UDP
|
#define IPPROTO_UDP FREERTOS_IPPROTO_UDP
|
||||||
@@ -221,6 +212,7 @@ static inline int ff_vfprintf(FF_FILE *fp, const char *fmt, va_list ap) {
|
|||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <inttypes.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
@@ -232,6 +224,7 @@ static inline int ff_vfprintf(FF_FILE *fp, const char *fmt, va_list ap) {
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#define MG_DIRSEP '/'
|
#define MG_DIRSEP '/'
|
||||||
#define MG_ENABLE_POSIX 1
|
#define MG_ENABLE_POSIX 1
|
||||||
|
#define MG_INT64_FMT "%" PRId64
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -243,31 +236,40 @@ static inline int ff_vfprintf(FF_FILE *fp, const char *fmt, va_list ap) {
|
|||||||
typedef __int64 int64_t;
|
typedef __int64 int64_t;
|
||||||
typedef unsigned __int64 uint64_t;
|
typedef unsigned __int64 uint64_t;
|
||||||
typedef unsigned char uint8_t;
|
typedef unsigned char uint8_t;
|
||||||
|
typedef char int8_t;
|
||||||
typedef unsigned short uint16_t;
|
typedef unsigned short uint16_t;
|
||||||
|
typedef short int16_t;
|
||||||
typedef unsigned int uint32_t;
|
typedef unsigned int uint32_t;
|
||||||
typedef int bool;
|
typedef int int32_t;
|
||||||
enum { false = 0, true = 1 };
|
typedef enum { false = 0, true = 1 } bool;
|
||||||
#else
|
#else
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
|
||||||
|
// Protect from calls like std::snprintf in app code
|
||||||
|
// See https://github.com/cesanta/mongoose/issues/1047
|
||||||
|
#ifndef __cplusplus
|
||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
#define vsnprintf _vsnprintf
|
#define vsnprintf _vsnprintf
|
||||||
#define strdup(x) _strdup(x)
|
#define strdup(x) _strdup(x)
|
||||||
#define sleep(x) Sleep((x) *1000)
|
#endif
|
||||||
|
|
||||||
typedef int socklen_t;
|
typedef int socklen_t;
|
||||||
#define PATH_MAX MAX_PATH
|
|
||||||
#define MG_DIRSEP '\\'
|
#define MG_DIRSEP '\\'
|
||||||
#define inline __inline
|
#ifndef PATH_MAX
|
||||||
|
#define PATH_MAX MAX_PATH
|
||||||
|
#endif
|
||||||
#ifndef EINPROGRESS
|
#ifndef EINPROGRESS
|
||||||
#define EINPROGRESS WSAEINPROGRESS
|
#define EINPROGRESS WSAEINPROGRESS
|
||||||
#endif
|
#endif
|
||||||
#ifndef EWOULDBLOCK
|
#ifndef EWOULDBLOCK
|
||||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||||
#endif
|
#endif
|
||||||
#define realpath(a, b) _fullpath((b), (a), 512)
|
#define realpath(a, b) _fullpath((b), (a), MG_PATH_MAX)
|
||||||
#ifndef va_copy
|
#ifndef va_copy
|
||||||
#ifdef __va_copy
|
#ifdef __va_copy
|
||||||
#define va_copy __va_copy
|
#define va_copy __va_copy
|
||||||
@@ -275,11 +277,12 @@ typedef int socklen_t;
|
|||||||
#define va_copy(x, y) (x) = (y)
|
#define va_copy(x, y) (x) = (y)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef S_ISDIR
|
#ifndef S_ISDIR
|
||||||
#define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR)
|
#define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MG_INT64_FMT "%I64d"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -289,7 +292,7 @@ typedef int socklen_t;
|
|||||||
|
|
||||||
#if MG_ENABLE_LWIP
|
#if MG_ENABLE_LWIP
|
||||||
#define MG_ENABLE_SOCKET 0
|
#define MG_ENABLE_SOCKET 0
|
||||||
#else
|
#elif !defined(MG_ENABLE_SOCKET)
|
||||||
#define MG_ENABLE_SOCKET 1
|
#define MG_ENABLE_SOCKET 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -305,6 +308,10 @@ typedef int socklen_t;
|
|||||||
#define MG_ENABLE_FS 1
|
#define MG_ENABLE_FS 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef MG_ENABLE_SSI
|
||||||
|
#define MG_ENABLE_SSI 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef MG_ENABLE_IPV6
|
#ifndef MG_ENABLE_IPV6
|
||||||
#define MG_ENABLE_IPV6 0
|
#define MG_ENABLE_IPV6 0
|
||||||
#endif
|
#endif
|
||||||
@@ -325,10 +332,6 @@ typedef int socklen_t;
|
|||||||
#define MG_ENABLE_DIRECTORY_LISTING 0
|
#define MG_ENABLE_DIRECTORY_LISTING 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MG_ENABLE_HTTP_DEBUG_ENDPOINT
|
|
||||||
#define MG_ENABLE_HTTP_DEBUG_ENDPOINT 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MG_ENABLE_SOCKETPAIR
|
#ifndef MG_ENABLE_SOCKETPAIR
|
||||||
#define MG_ENABLE_SOCKETPAIR 0
|
#define MG_ENABLE_SOCKETPAIR 0
|
||||||
#endif
|
#endif
|
||||||
@@ -347,6 +350,10 @@ typedef int socklen_t;
|
|||||||
#define MG_MAX_HTTP_HEADERS 40
|
#define MG_MAX_HTTP_HEADERS 40
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef MG_PATH_MAX
|
||||||
|
#define MG_PATH_MAX PATH_MAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -416,26 +423,36 @@ void mg_timer_poll(unsigned long uptime_ms);
|
|||||||
|
|
||||||
|
|
||||||
char *mg_file_read(const char *path);
|
char *mg_file_read(const char *path);
|
||||||
size_t mg_file_size(const char *path);
|
int64_t mg_file_size(const char *path);
|
||||||
int mg_file_write(const char *path, const char *fmt, ...);
|
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);
|
void mg_random(void *buf, size_t len);
|
||||||
bool mg_globmatch(const char *pattern, int plen, const char *s, int n);
|
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);
|
bool mg_next_comma_entry(struct mg_str *s, struct mg_str *k, struct mg_str *v);
|
||||||
uint16_t mg_ntohs(uint16_t net);
|
uint16_t mg_ntohs(uint16_t net);
|
||||||
uint32_t mg_ntohl(uint32_t net);
|
uint32_t mg_ntohl(uint32_t net);
|
||||||
char *mg_hexdump(const void *buf, int len);
|
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);
|
char *mg_hex(const void *buf, int len, char *dst);
|
||||||
void mg_unhex(const char *buf, int len, unsigned char *to);
|
void mg_unhex(const char *buf, int len, unsigned char *to);
|
||||||
unsigned long mg_unhexn(const char *s, int len);
|
unsigned long mg_unhexn(const char *s, int len);
|
||||||
int mg_asprintf(char **buf, size_t size, const char *fmt, ...);
|
int mg_asprintf(char **buf, size_t size, const char *fmt, ...);
|
||||||
int mg_vasprintf(char **buf, size_t size, const char *fmt, va_list ap);
|
int mg_vasprintf(char **buf, size_t size, const char *fmt, va_list ap);
|
||||||
int64_t mg_to64(const char *s);
|
int64_t mg_to64(struct mg_str str);
|
||||||
bool mg_aton(const char *s, uint32_t *ipaddr);
|
|
||||||
char *mg_ntoa(uint32_t ipaddr, char *buf, size_t len);
|
|
||||||
double mg_time(void);
|
double mg_time(void);
|
||||||
unsigned long mg_millis(void);
|
unsigned long mg_millis(void);
|
||||||
void mg_usleep(unsigned long usecs);
|
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_htons(x) mg_ntohs(x)
|
||||||
#define mg_htonl(x) mg_ntohl(x)
|
#define mg_htonl(x) mg_ntohl(x)
|
||||||
|
|
||||||
@@ -446,7 +463,7 @@ void mg_usleep(unsigned long usecs);
|
|||||||
#if !defined(WEAK)
|
#if !defined(WEAK)
|
||||||
#if (defined(__GNUC__) || defined(__clang__) || \
|
#if (defined(__GNUC__) || defined(__clang__) || \
|
||||||
defined(__TI_COMPILER_VERSION__)) && \
|
defined(__TI_COMPILER_VERSION__)) && \
|
||||||
!defined(_WIN32)
|
!defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
#define WEAK __attribute__((weak))
|
#define WEAK __attribute__((weak))
|
||||||
#else
|
#else
|
||||||
#define WEAK
|
#define WEAK
|
||||||
@@ -503,8 +520,8 @@ struct mg_iobuf {
|
|||||||
size_t size, len;
|
size_t size, len;
|
||||||
};
|
};
|
||||||
|
|
||||||
void mg_iobuf_init(struct mg_iobuf *, size_t);
|
int mg_iobuf_init(struct mg_iobuf *, size_t);
|
||||||
void mg_iobuf_resize(struct mg_iobuf *, size_t);
|
int mg_iobuf_resize(struct mg_iobuf *, size_t);
|
||||||
void mg_iobuf_free(struct mg_iobuf *);
|
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_append(struct mg_iobuf *, const void *, size_t, size_t);
|
||||||
size_t mg_iobuf_delete(struct mg_iobuf *, size_t);
|
size_t mg_iobuf_delete(struct mg_iobuf *, size_t);
|
||||||
@@ -547,36 +564,28 @@ void mg_hmac_sha1(const unsigned char *key, size_t key_len,
|
|||||||
struct mg_connection;
|
struct mg_connection;
|
||||||
typedef void (*mg_event_handler_t)(struct mg_connection *, int ev,
|
typedef void (*mg_event_handler_t)(struct mg_connection *, int ev,
|
||||||
void *ev_data, void *fn_data);
|
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_call(struct mg_connection *c, int ev, void *ev_data);
|
||||||
void mg_error(struct mg_connection *c, const char *fmt, ...);
|
void mg_error(struct mg_connection *c, const char *fmt, ...);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MG_EV_ERROR, // Error char *error_message
|
MG_EV_ERROR, // Error char *error_message
|
||||||
MG_EV_POLL, // mg_mgr_poll iteration unsigned long *millis
|
MG_EV_POLL, // mg_mgr_poll iteration unsigned long *millis
|
||||||
MG_EV_RESOLVE, // Host name is resolved NULL
|
MG_EV_RESOLVE, // Host name is resolved NULL
|
||||||
MG_EV_CONNECT, // Connection established NULL
|
MG_EV_CONNECT, // Connection established NULL
|
||||||
MG_EV_ACCEPT, // Connection accepted NULL
|
MG_EV_ACCEPT, // Connection accepted NULL
|
||||||
MG_EV_READ, // Data received from socket struct mg_str *
|
MG_EV_READ, // Data received from socket struct mg_str *
|
||||||
MG_EV_WRITE, // Data written to socket int *num_bytes_written
|
MG_EV_WRITE, // Data written to socket int *num_bytes_written
|
||||||
MG_EV_CLOSE, // Connection closed NULL
|
MG_EV_CLOSE, // Connection closed NULL
|
||||||
MG_EV_HTTP_MSG, // HTTP request/response struct mg_http_message *
|
MG_EV_HTTP_MSG, // HTTP request/response struct mg_http_message *
|
||||||
MG_EV_WS_OPEN, // Websocket handshake done NULL
|
MG_EV_HTTP_CHUNK, // HTTP chunk (partial msg) struct mg_http_message *
|
||||||
MG_EV_WS_MSG, // Websocket message received struct mg_ws_message *
|
MG_EV_WS_OPEN, // Websocket handshake done struct mg_http_message *
|
||||||
MG_EV_MQTT_MSG, // MQTT message struct mg_mqtt_message *
|
MG_EV_WS_MSG, // Websocket msg, text or bin struct mg_ws_message *
|
||||||
MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code
|
MG_EV_WS_CTL, // Websocket control msg struct mg_ws_message *
|
||||||
MG_EV_SNTP_TIME, // SNTP time received struct timeval *
|
MG_EV_MQTT_CMD, // MQTT low-level command struct mg_mqtt_message *
|
||||||
MG_EV_USER, // Starting ID for user events
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -585,19 +594,28 @@ enum {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct mg_mgr {
|
struct mg_dns {
|
||||||
struct mg_connection *conns; // List of active connections
|
const char *url; // DNS server URL
|
||||||
struct mg_connection *dnsc; // DNS resolver connection
|
struct mg_connection *c; // DNS server connection
|
||||||
const char *dnsserver; // DNS server URL
|
|
||||||
int dnstimeout; // DNS resolve timeout in milliseconds
|
|
||||||
#if MG_ARCH == MG_ARCH_FREERTOS
|
|
||||||
SocketSet_t ss; // NOTE(lsm): referenced from socket struct
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mg_addr {
|
struct mg_addr {
|
||||||
uint16_t port; // TCP or UDP port in network byte order
|
uint16_t port; // TCP or UDP port in network byte order
|
||||||
uint32_t ip; // IP address in network byte order
|
uint32_t ip; // IP address in network byte order
|
||||||
|
uint8_t ip6[16]; // IPv6 address
|
||||||
|
bool is_ip6; // True when address is IPv6 address
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mg_mgr {
|
||||||
|
struct mg_connection *conns; // List of active connections
|
||||||
|
struct mg_dns dns4; // DNS for IPv4
|
||||||
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mg_connection {
|
struct mg_connection {
|
||||||
@@ -605,13 +623,14 @@ struct mg_connection {
|
|||||||
struct mg_mgr *mgr; // Our container
|
struct mg_mgr *mgr; // Our container
|
||||||
struct mg_addr peer; // Remote peer address
|
struct mg_addr peer; // Remote peer address
|
||||||
void *fd; // Connected socket, or LWIP data
|
void *fd; // Connected socket, or LWIP data
|
||||||
|
unsigned long id; // Auto-incrementing unique connection ID
|
||||||
struct mg_iobuf recv; // Incoming data
|
struct mg_iobuf recv; // Incoming data
|
||||||
struct mg_iobuf send; // Outgoing data
|
struct mg_iobuf send; // Outgoing data
|
||||||
mg_event_handler_t fn; // User-specified event handler function
|
mg_event_handler_t fn; // User-specified event handler function
|
||||||
void *fn_data; // User-speficied function parameter
|
void *fn_data; // User-speficied function parameter
|
||||||
mg_event_handler_t pfn; // Protocol-specific handler function
|
mg_event_handler_t pfn; // Protocol-specific handler function
|
||||||
void *pfn_data; // Protocol-specific function parameter
|
void *pfn_data; // Protocol-specific function parameter
|
||||||
char label[32]; // Arbitrary label
|
char label[50]; // Arbitrary label
|
||||||
void *tls; // TLS specific data
|
void *tls; // TLS specific data
|
||||||
unsigned is_listening : 1; // Listening connection
|
unsigned is_listening : 1; // Listening connection
|
||||||
unsigned is_client : 1; // Outbound (client) connection
|
unsigned is_client : 1; // Outbound (client) connection
|
||||||
@@ -642,6 +661,8 @@ int mg_printf(struct mg_connection *, const char *fmt, ...);
|
|||||||
int mg_vprintf(struct mg_connection *, const char *fmt, va_list ap);
|
int mg_vprintf(struct mg_connection *, const char *fmt, va_list ap);
|
||||||
char *mg_straddr(struct mg_connection *, char *, size_t);
|
char *mg_straddr(struct mg_connection *, char *, size_t);
|
||||||
bool mg_socketpair(int *s1, int *s2);
|
bool mg_socketpair(int *s1, int *s2);
|
||||||
|
bool mg_aton(struct mg_str str, struct mg_addr *addr);
|
||||||
|
char *mg_ntoa(const struct mg_addr *addr, char *buf, size_t len);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -657,30 +678,40 @@ struct mg_http_message {
|
|||||||
// GET /foo/bar/baz?aa=b&cc=ddd HTTP/1.1
|
// GET /foo/bar/baz?aa=b&cc=ddd HTTP/1.1
|
||||||
// method |-| |----uri---| |--query--| |proto-|
|
// method |-| |----uri---| |--query--| |proto-|
|
||||||
|
|
||||||
struct mg_str method, uri, query, proto; // Request/response line
|
struct mg_str method, uri, query, proto; // Request/response line
|
||||||
struct mg_http_header headers[MG_MAX_HTTP_HEADERS]; // Headers
|
struct mg_http_header headers[MG_MAX_HTTP_HEADERS]; // Headers
|
||||||
struct mg_str body; // Body
|
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()
|
||||||
|
struct mg_http_serve_opts {
|
||||||
|
const char *root_dir; // Web root directory, must be non-NULL
|
||||||
|
const char *ssi_pattern; // SSI filename pattern, e.g. #.shtml
|
||||||
};
|
};
|
||||||
|
|
||||||
int mg_http_parse(const char *s, size_t len, struct mg_http_message *);
|
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);
|
int mg_http_get_request_len(const unsigned char *buf, size_t buf_len);
|
||||||
void mg_http_write_head(struct mg_connection *, int code, const char *fmt, ...);
|
|
||||||
void mg_http_printf_chunk(struct mg_connection *cnn, const char *fmt, ...);
|
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_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,
|
struct mg_connection *mg_http_listen(struct mg_mgr *, const char *url,
|
||||||
mg_event_handler_t fn, void *fn_data);
|
mg_event_handler_t fn, void *fn_data);
|
||||||
struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url,
|
struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url,
|
||||||
mg_event_handler_t fn, void *fn_data);
|
mg_event_handler_t fn, void *fn_data);
|
||||||
void mg_http_serve_dir(struct mg_connection *, struct mg_http_message *hm,
|
void mg_http_serve_dir(struct mg_connection *, struct mg_http_message *hm,
|
||||||
const char *path);
|
struct mg_http_serve_opts *);
|
||||||
void mg_http_serve_file(struct mg_connection *, struct mg_http_message *,
|
void mg_http_serve_file(struct mg_connection *, struct mg_http_message *,
|
||||||
const char *, const char *mime);
|
const char *, const char *mime, const char *headers);
|
||||||
void mg_http_reply(struct mg_connection *c, int code, const char *fmt, ...);
|
void mg_http_reply(struct mg_connection *, int status_code, const char *headers,
|
||||||
|
const char *body_fmt, ...);
|
||||||
struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name);
|
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);
|
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_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_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);
|
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);
|
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,
|
int mg_http_upload(struct mg_connection *, struct mg_http_message *hm,
|
||||||
@@ -688,13 +719,17 @@ int mg_http_upload(struct mg_connection *, struct mg_http_message *hm,
|
|||||||
void mg_http_bauth(struct mg_connection *, const char *user, const char *pass);
|
void mg_http_bauth(struct mg_connection *, const char *user, const char *pass);
|
||||||
|
|
||||||
|
|
||||||
|
void mg_http_serve_ssi(struct mg_connection *c, const char *root,
|
||||||
|
const char *fullpath);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct mg_tls_opts {
|
struct mg_tls_opts {
|
||||||
const char *ca; // CA certificate file. For both listeners and clients
|
const char *ca; // CA certificate file. For both listeners and clients
|
||||||
const char *cert; // Certificate
|
const char *cert; // Certificate
|
||||||
const char *certkey; // Certificate key
|
const char *certkey; // Certificate key
|
||||||
const char *ciphers; // Cipher list
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
int mg_tls_init(struct mg_connection *, struct mg_tls_opts *);
|
int mg_tls_init(struct mg_connection *, struct mg_tls_opts *);
|
||||||
@@ -724,7 +759,8 @@ struct mg_ws_message {
|
|||||||
struct mg_connection *mg_ws_connect(struct mg_mgr *, const char *url,
|
struct mg_connection *mg_ws_connect(struct mg_mgr *, const char *url,
|
||||||
mg_event_handler_t fn, void *fn_data,
|
mg_event_handler_t fn, void *fn_data,
|
||||||
const char *fmt, ...);
|
const char *fmt, ...);
|
||||||
void mg_ws_upgrade(struct mg_connection *, struct mg_http_message *);
|
void mg_ws_upgrade(struct mg_connection *, struct mg_http_message *,
|
||||||
|
const char *fmt, ...);
|
||||||
size_t mg_ws_send(struct mg_connection *, const char *buf, size_t len, int op);
|
size_t mg_ws_send(struct mg_connection *, const char *buf, size_t len, int op);
|
||||||
|
|
||||||
|
|
||||||
@@ -739,6 +775,25 @@ int mg_sntp_parse(const unsigned char *buf, size_t len, struct timeval *tv);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define MQTT_CMD_CONNECT 1
|
||||||
|
#define MQTT_CMD_CONNACK 2
|
||||||
|
#define MQTT_CMD_PUBLISH 3
|
||||||
|
#define MQTT_CMD_PUBACK 4
|
||||||
|
#define MQTT_CMD_PUBREC 5
|
||||||
|
#define MQTT_CMD_PUBREL 6
|
||||||
|
#define MQTT_CMD_PUBCOMP 7
|
||||||
|
#define MQTT_CMD_SUBSCRIBE 8
|
||||||
|
#define MQTT_CMD_SUBACK 9
|
||||||
|
#define MQTT_CMD_UNSUBSCRIBE 10
|
||||||
|
#define MQTT_CMD_UNSUBACK 11
|
||||||
|
#define MQTT_CMD_PINGREQ 12
|
||||||
|
#define MQTT_CMD_PINGRESP 13
|
||||||
|
#define MQTT_CMD_DISCONNECT 14
|
||||||
|
|
||||||
|
#define MQTT_QOS(qos) ((qos) << 1)
|
||||||
|
#define MQTT_GET_QOS(flags) (((flags) &0x6) >> 1)
|
||||||
|
#define MQTT_SET_QOS(flags, qos) (flags) = ((flags) & ~0x6) | ((qos) << 1)
|
||||||
|
|
||||||
struct mg_mqtt_opts {
|
struct mg_mqtt_opts {
|
||||||
struct mg_str client_id;
|
struct mg_str client_id;
|
||||||
struct mg_str will_topic;
|
struct mg_str will_topic;
|
||||||
@@ -750,28 +805,69 @@ struct mg_mqtt_opts {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct mg_mqtt_message {
|
struct mg_mqtt_message {
|
||||||
struct mg_str topic;
|
struct mg_str topic; // Parsed topic
|
||||||
struct mg_str data;
|
struct mg_str data; // Parsed message
|
||||||
|
struct mg_str dgram; // Whole MQTT datagram, including headers
|
||||||
|
uint16_t id; // Set for PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, PUBLISH
|
||||||
|
uint8_t cmd; // MQTT command, one of MQTT_CMD_*
|
||||||
|
uint8_t qos; // Quality of service
|
||||||
|
uint8_t ack; // Connack return code. 0 - success
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mg_connection *mg_mqtt_connect(struct mg_mgr *, const char *url,
|
struct mg_connection *mg_mqtt_connect(struct mg_mgr *, const char *url,
|
||||||
struct mg_mqtt_opts *opts,
|
struct mg_mqtt_opts *opts,
|
||||||
mg_event_handler_t fn, void *fn_data);
|
mg_event_handler_t fn, void *fn_data);
|
||||||
|
struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url,
|
||||||
|
mg_event_handler_t fn, void *fn_data);
|
||||||
void mg_mqtt_pub(struct mg_connection *, struct mg_str *topic,
|
void mg_mqtt_pub(struct mg_connection *, struct mg_str *topic,
|
||||||
struct mg_str *data);
|
struct mg_str *data);
|
||||||
void mg_mqtt_sub(struct mg_connection *, struct mg_str *topic);
|
void mg_mqtt_sub(struct mg_connection *, struct mg_str *topic);
|
||||||
int mg_mqtt_parse(const unsigned char *buf, int len, struct mg_mqtt_message *m);
|
int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m);
|
||||||
|
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 *);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Mongoose sends DNS queries that contain only one question:
|
||||||
|
// either A (IPv4) or AAAA (IPv6) address lookup.
|
||||||
|
// Therefore, we expect zero or one answer.
|
||||||
|
// If `resolved` is true, then `addr` contains resolved IPv4 or IPV6 address.
|
||||||
struct mg_dns_message {
|
struct mg_dns_message {
|
||||||
uint16_t txnid; // Transaction ID
|
uint16_t txnid; // Transaction ID
|
||||||
uint32_t ipaddr; // Resolved IPv4 address
|
bool resolved; // Resolve successful, addr is set
|
||||||
char name[256]; // Host name
|
struct mg_addr addr; // Resolved address
|
||||||
|
char name[256]; // Host name
|
||||||
};
|
};
|
||||||
|
|
||||||
void mg_resolve(struct mg_mgr *, struct mg_connection *, struct mg_str *, int);
|
struct mg_dns_header {
|
||||||
void mg_resolve_cancel(struct mg_mgr *, struct mg_connection *);
|
uint16_t txnid; // Transaction ID
|
||||||
int mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *);
|
uint16_t flags;
|
||||||
|
uint16_t num_questions;
|
||||||
|
uint16_t num_answers;
|
||||||
|
uint16_t num_authority_prs;
|
||||||
|
uint16_t num_other_prs;
|
||||||
|
};
|
||||||
|
|
||||||
|
// DNS resource record
|
||||||
|
struct mg_dns_rr {
|
||||||
|
uint16_t nlen; // Name or pointer length
|
||||||
|
uint16_t atype; // Address type
|
||||||
|
uint16_t aclass; // Address class
|
||||||
|
uint16_t alen; // Address length
|
||||||
|
};
|
||||||
|
|
||||||
|
void mg_resolve(struct mg_connection *, struct mg_str *, int);
|
||||||
|
void mg_resolve_cancel(struct mg_connection *);
|
||||||
|
bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *);
|
||||||
|
size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
|
||||||
|
bool is_question, struct mg_dns_rr *);
|
||||||
|
size_t mg_dns_decode_name(const uint8_t *, size_t, size_t, char *, size_t);
|
||||||
+2
-2
@@ -42,10 +42,10 @@
|
|||||||
#define MG_ARCH MG_ARCH_NXP_KINETIS
|
#define MG_ARCH MG_ARCH_NXP_KINETIS
|
||||||
#elif defined(PIC32)
|
#elif defined(PIC32)
|
||||||
#define MG_ARCH MG_ARCH_PIC32
|
#define MG_ARCH MG_ARCH_PIC32
|
||||||
#elif defined(ESP_PLATFORM)
|
|
||||||
#define MG_ARCH MG_ARCH_ESP32
|
|
||||||
#elif defined(ICACHE_FLASH) || defined(ICACHE_RAM_ATTR)
|
#elif defined(ICACHE_FLASH) || defined(ICACHE_RAM_ATTR)
|
||||||
#define MG_ARCH MG_ARCH_ESP8266
|
#define MG_ARCH MG_ARCH_ESP8266
|
||||||
|
#elif defined(ESP_PLATFORM)
|
||||||
|
#define MG_ARCH MG_ARCH_ESP32
|
||||||
#elif defined(TARGET_IS_TM4C129_RA0) || defined(TARGET_IS_TM4C129_RA1) || \
|
#elif defined(TARGET_IS_TM4C129_RA0) || defined(TARGET_IS_TM4C129_RA1) || \
|
||||||
defined(TARGET_IS_TM4C129_RA2)
|
defined(TARGET_IS_TM4C129_RA2)
|
||||||
#define MG_ARCH MG_ARCH_TM4C129
|
#define MG_ARCH MG_ARCH_TM4C129
|
||||||
|
|||||||
@@ -4,6 +4,11 @@
|
|||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#define MG_DIRSEP '/'
|
#define MG_DIRSEP '/'
|
||||||
|
#define MG_INT64_FMT "%lld"
|
||||||
|
#ifndef MG_PATH_MAX
|
||||||
|
#define MG_PATH_MAX 128
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+3
-17
@@ -3,25 +3,11 @@
|
|||||||
#if MG_ARCH == MG_ARCH_ESP8266
|
#if MG_ARCH == MG_ARCH_ESP8266
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <esp_system.h>
|
||||||
|
#include <netdb.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <user_interface.h>
|
|
||||||
|
|
||||||
#define MG_DIRSEP '/'
|
#define MG_DIRSEP '/'
|
||||||
#ifndef PATH_MAX
|
#define MG_INT64_FMT "%lld"
|
||||||
#define PATH_MAX 128
|
|
||||||
#endif
|
|
||||||
#define MG_ENABLE_LWIP 1
|
|
||||||
#define LWIP_TIMEVAL_PRIVATE 0 // struct timeval is defined in sys/time.h
|
|
||||||
|
|
||||||
#if LWIP_SOCKET
|
|
||||||
#include <lwip/sockets.h>
|
|
||||||
#else
|
|
||||||
#undef LWIP_SOCKET
|
|
||||||
#define LWIP_SOCKET 1
|
|
||||||
#include <lwip/sockets.h> // Source sockaddr_in anyway
|
|
||||||
#undef LWIP_SOCKET
|
|
||||||
#define LWIP_SOCKET 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <FreeRTOS_Sockets.h>
|
#include <FreeRTOS_Sockets.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define MG_INT64_FMT "%lld"
|
||||||
#define MG_DIRSEP '/'
|
#define MG_DIRSEP '/'
|
||||||
#define IPPROTO_TCP FREERTOS_IPPROTO_TCP
|
#define IPPROTO_TCP FREERTOS_IPPROTO_TCP
|
||||||
#define IPPROTO_UDP FREERTOS_IPPROTO_UDP
|
#define IPPROTO_UDP FREERTOS_IPPROTO_UDP
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <inttypes.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
@@ -17,5 +18,6 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#define MG_DIRSEP '/'
|
#define MG_DIRSEP '/'
|
||||||
#define MG_ENABLE_POSIX 1
|
#define MG_ENABLE_POSIX 1
|
||||||
|
#define MG_INT64_FMT "%" PRId64
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+17
-7
@@ -7,31 +7,40 @@
|
|||||||
typedef __int64 int64_t;
|
typedef __int64 int64_t;
|
||||||
typedef unsigned __int64 uint64_t;
|
typedef unsigned __int64 uint64_t;
|
||||||
typedef unsigned char uint8_t;
|
typedef unsigned char uint8_t;
|
||||||
|
typedef char int8_t;
|
||||||
typedef unsigned short uint16_t;
|
typedef unsigned short uint16_t;
|
||||||
|
typedef short int16_t;
|
||||||
typedef unsigned int uint32_t;
|
typedef unsigned int uint32_t;
|
||||||
typedef int bool;
|
typedef int int32_t;
|
||||||
enum { false = 0, true = 1 };
|
typedef enum { false = 0, true = 1 } bool;
|
||||||
#else
|
#else
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
|
||||||
|
// Protect from calls like std::snprintf in app code
|
||||||
|
// See https://github.com/cesanta/mongoose/issues/1047
|
||||||
|
#ifndef __cplusplus
|
||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
#define vsnprintf _vsnprintf
|
#define vsnprintf _vsnprintf
|
||||||
#define strdup(x) _strdup(x)
|
#define strdup(x) _strdup(x)
|
||||||
#define sleep(x) Sleep((x) *1000)
|
#endif
|
||||||
|
|
||||||
typedef int socklen_t;
|
typedef int socklen_t;
|
||||||
#define PATH_MAX MAX_PATH
|
|
||||||
#define MG_DIRSEP '\\'
|
#define MG_DIRSEP '\\'
|
||||||
#define inline __inline
|
#ifndef PATH_MAX
|
||||||
|
#define PATH_MAX MAX_PATH
|
||||||
|
#endif
|
||||||
#ifndef EINPROGRESS
|
#ifndef EINPROGRESS
|
||||||
#define EINPROGRESS WSAEINPROGRESS
|
#define EINPROGRESS WSAEINPROGRESS
|
||||||
#endif
|
#endif
|
||||||
#ifndef EWOULDBLOCK
|
#ifndef EWOULDBLOCK
|
||||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||||
#endif
|
#endif
|
||||||
#define realpath(a, b) _fullpath((b), (a), 512)
|
#define realpath(a, b) _fullpath((b), (a), MG_PATH_MAX)
|
||||||
#ifndef va_copy
|
#ifndef va_copy
|
||||||
#ifdef __va_copy
|
#ifdef __va_copy
|
||||||
#define va_copy __va_copy
|
#define va_copy __va_copy
|
||||||
@@ -39,9 +48,10 @@ typedef int socklen_t;
|
|||||||
#define va_copy(x, y) (x) = (y)
|
#define va_copy(x, y) (x) = (y)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef S_ISDIR
|
#ifndef S_ISDIR
|
||||||
#define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR)
|
#define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MG_INT64_FMT "%I64d"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+9
-5
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#if MG_ENABLE_LWIP
|
#if MG_ENABLE_LWIP
|
||||||
#define MG_ENABLE_SOCKET 0
|
#define MG_ENABLE_SOCKET 0
|
||||||
#else
|
#elif !defined(MG_ENABLE_SOCKET)
|
||||||
#define MG_ENABLE_SOCKET 1
|
#define MG_ENABLE_SOCKET 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -22,6 +22,10 @@
|
|||||||
#define MG_ENABLE_FS 1
|
#define MG_ENABLE_FS 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef MG_ENABLE_SSI
|
||||||
|
#define MG_ENABLE_SSI 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef MG_ENABLE_IPV6
|
#ifndef MG_ENABLE_IPV6
|
||||||
#define MG_ENABLE_IPV6 0
|
#define MG_ENABLE_IPV6 0
|
||||||
#endif
|
#endif
|
||||||
@@ -42,10 +46,6 @@
|
|||||||
#define MG_ENABLE_DIRECTORY_LISTING 0
|
#define MG_ENABLE_DIRECTORY_LISTING 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MG_ENABLE_HTTP_DEBUG_ENDPOINT
|
|
||||||
#define MG_ENABLE_HTTP_DEBUG_ENDPOINT 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MG_ENABLE_SOCKETPAIR
|
#ifndef MG_ENABLE_SOCKETPAIR
|
||||||
#define MG_ENABLE_SOCKETPAIR 0
|
#define MG_ENABLE_SOCKETPAIR 0
|
||||||
#endif
|
#endif
|
||||||
@@ -63,3 +63,7 @@
|
|||||||
#ifndef MG_MAX_HTTP_HEADERS
|
#ifndef MG_MAX_HTTP_HEADERS
|
||||||
#define MG_MAX_HTTP_HEADERS 40
|
#define MG_MAX_HTTP_HEADERS 40
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef MG_PATH_MAX
|
||||||
|
#define MG_PATH_MAX PATH_MAX
|
||||||
|
#endif
|
||||||
@@ -5,15 +5,6 @@
|
|||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
struct mg_dns_header {
|
|
||||||
uint16_t transaction_id;
|
|
||||||
uint16_t flags;
|
|
||||||
uint16_t num_questions;
|
|
||||||
uint16_t num_answers;
|
|
||||||
uint16_t num_authority_prs;
|
|
||||||
uint16_t num_other_prs;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dns_data {
|
struct dns_data {
|
||||||
struct dns_data *next;
|
struct dns_data *next;
|
||||||
struct mg_connection *c;
|
struct mg_connection *c;
|
||||||
@@ -21,82 +12,130 @@ struct dns_data {
|
|||||||
uint16_t txnid;
|
uint16_t txnid;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void mg_dns_free(struct dns_data **head, struct dns_data *d) {
|
static struct dns_data *s_reqs; // Active DNS requests
|
||||||
LIST_DELETE(struct dns_data, head, d);
|
|
||||||
// LOG(LL_INFO, ("--> %p %p %d", d, d->c, d->c->fd));
|
static void mg_sendnsreq(struct mg_connection *, struct mg_str *, int,
|
||||||
|
struct mg_dns *, bool);
|
||||||
|
|
||||||
|
static void mg_dns_free(struct dns_data *d) {
|
||||||
|
LIST_DELETE(struct dns_data, &s_reqs, d);
|
||||||
free(d);
|
free(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_resolve_cancel(struct mg_mgr *mgr, struct mg_connection *c) {
|
void mg_resolve_cancel(struct mg_connection *c) {
|
||||||
struct dns_data *tmp, *d, **head;
|
struct dns_data *tmp, *d;
|
||||||
head = mgr->dnsc == NULL ? NULL : (struct dns_data **) &mgr->dnsc->pfn_data;
|
for (d = s_reqs; d != NULL; d = tmp) {
|
||||||
for (d = head == NULL ? NULL : *head; d != NULL; d = tmp) {
|
|
||||||
tmp = d->next;
|
tmp = d->next;
|
||||||
if (d->c == c) mg_dns_free(head, d);
|
if (d->c == c) mg_dns_free(d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t mg_dns_parse_name(const uint8_t *s, const uint8_t *e, size_t off,
|
static size_t mg_dns_parse_name_depth(const uint8_t *s, size_t len, size_t ofs,
|
||||||
char *to, size_t tolen, int depth) {
|
char *to, size_t tolen, int depth) {
|
||||||
size_t i = 0, j = 0;
|
size_t i = 0, j = 0;
|
||||||
|
if (tolen > 0) to[0] = '\0';
|
||||||
if (depth > 5) return 0;
|
if (depth > 5) return 0;
|
||||||
while (&s[off + i + 1] < e && s[off + i] > 0) {
|
while (ofs + i + 1 < len) {
|
||||||
size_t n = s[off + i];
|
size_t n = s[ofs + i];
|
||||||
if (n & 0xc0) {
|
if (n == 0) {
|
||||||
size_t ptr = (((n & 0x3f) << 8) | s[off + i + 1]) - 12; // 12 is hdr len
|
|
||||||
if (&s[ptr + 1] < e && (s[ptr] & 0xc0) == 0) {
|
|
||||||
j = mg_dns_parse_name(s, e, ptr, to, tolen, depth + 1);
|
|
||||||
}
|
|
||||||
i++;
|
i++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (&s[off + i + n + 1] >= e) break;
|
if (n & 0xc0) {
|
||||||
if (j > 0 && j < tolen) to[j++] = '.';
|
size_t ptr = (((n & 0x3f) << 8) | s[ofs + i + 1]); // 12 is hdr len
|
||||||
if (j + n < tolen) memcpy(&to[j], &s[off + i + 1], n);
|
if (ptr + 1 < len && (s[ptr] & 0xc0) == 0 &&
|
||||||
|
mg_dns_parse_name_depth(s, len, ptr, to, tolen, depth + 1) == 0)
|
||||||
|
return 0;
|
||||||
|
i += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ofs + i + n + 1 >= len) return 0;
|
||||||
|
if (j > 0) {
|
||||||
|
if (j < tolen) to[j] = '.';
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if (j + n < tolen) memcpy(&to[j], &s[ofs + i + 1], n);
|
||||||
j += n;
|
j += n;
|
||||||
i += n + 1;
|
i += n + 1;
|
||||||
|
if (j < tolen) to[j] = '\0'; // Zero-terminate this chunk
|
||||||
}
|
}
|
||||||
if (j < tolen) to[j] = '\0'; // Zero-terminate the name
|
if (tolen > 0) to[tolen - 1] = '\0'; // Make sure make sure it is nul-term
|
||||||
to[tolen - 1] = '\0'; // Just in case
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
// txid flags numQ numA numAP numOP
|
size_t mg_dns_parse_name(const uint8_t *s, size_t n, size_t ofs, char *dst,
|
||||||
// 0000 00 01 81 80 00 01 00 01 00 00 00 00 07 63 65 73 .............ces
|
size_t dstlen) {
|
||||||
// 0010 61 6e 74 61 03 63 6f 6d 00 00 01 00 01 c0 0c 00 anta.com........
|
return mg_dns_parse_name_depth(s, n, ofs, dst, dstlen, 0);
|
||||||
// 0020 01 00 01 00 00 02 57 00 04 94 fb 36 ec ......W....6.
|
}
|
||||||
int mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) {
|
|
||||||
struct mg_dns_header *h = (struct mg_dns_header *) buf;
|
size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
|
||||||
const uint8_t *s = buf + sizeof(*h), *e = &buf[len];
|
bool is_question, struct mg_dns_rr *rr) {
|
||||||
size_t i, j = 0, n, ok = 0;
|
const struct mg_dns_header *h = (struct mg_dns_header *) buf;
|
||||||
if (len < sizeof(*h)) return ok;
|
const uint8_t *s = buf + ofs, *e = &buf[len];
|
||||||
|
|
||||||
|
memset(rr, 0, sizeof(*rr));
|
||||||
|
if (len < sizeof(*h)) return 0; // Too small, headers dont fit
|
||||||
|
if (len > 512) return 0; // Too large, we don't expect that
|
||||||
|
if (s >= e) return 0; // Overflow
|
||||||
|
|
||||||
|
if ((rr->nlen = (uint16_t) mg_dns_parse_name(buf, len, ofs, NULL, 0)) == 0)
|
||||||
|
return 0;
|
||||||
|
s += rr->nlen + 4;
|
||||||
|
if (s > e) return 0;
|
||||||
|
rr->atype = ((uint16_t) s[-4] << 8) | s[-3];
|
||||||
|
rr->aclass = ((uint16_t) s[-2] << 8) | s[-1];
|
||||||
|
if (is_question) return rr->nlen + 4;
|
||||||
|
|
||||||
|
s += 6;
|
||||||
|
if (s > e) return 0;
|
||||||
|
rr->alen = ((uint16_t) s[-2] << 8) | s[-1];
|
||||||
|
if (s + rr->alen > e) return 0;
|
||||||
|
return rr->nlen + rr->alen + 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) {
|
||||||
|
const struct mg_dns_header *h = (struct mg_dns_header *) buf;
|
||||||
|
struct mg_dns_rr rr;
|
||||||
|
size_t i, n, ofs = sizeof(*h);
|
||||||
|
memset(dm, 0, sizeof(*dm));
|
||||||
|
|
||||||
|
if (len < sizeof(*h)) return 0; // Too small, headers dont fit
|
||||||
|
if (mg_ntohs(h->num_questions) > 1) return 0; // Sanity
|
||||||
|
if (mg_ntohs(h->num_answers) > 10) return 0; // Sanity
|
||||||
|
dm->txnid = mg_ntohs(h->txnid);
|
||||||
|
|
||||||
for (i = 0; i < mg_ntohs(h->num_questions); i++) {
|
for (i = 0; i < mg_ntohs(h->num_questions); i++) {
|
||||||
j += mg_dns_parse_name(s, e, j, dm->name, sizeof(dm->name), 0) + 5;
|
if ((n = mg_dns_parse_rr(buf, len, ofs, true, &rr)) == 0) return false;
|
||||||
// LOG(LL_INFO, ("QUE [%s]", name));
|
// LOG(LL_INFO, ("Q %zu %zu", ofs, n));
|
||||||
|
ofs += n;
|
||||||
}
|
}
|
||||||
for (i = 0; i < mg_ntohs(h->num_answers); i++) {
|
for (i = 0; i < mg_ntohs(h->num_answers); i++) {
|
||||||
j += mg_dns_parse_name(s, e, j, dm->name, sizeof(dm->name), 0) + 9;
|
// LOG(LL_INFO, ("A -- %zu %zu %s", ofs, n, dm->name));
|
||||||
// LOG(LL_DEBUG, ("NAME %s", name));
|
if ((n = mg_dns_parse_rr(buf, len, ofs, false, &rr)) == 0) return false;
|
||||||
if (&s[j] + 2 > e) break;
|
mg_dns_parse_name(buf, len, ofs, dm->name, sizeof(dm->name));
|
||||||
n = ((int) s[j] << 8) | s[j + 1];
|
ofs += n;
|
||||||
if (&s[j] + 2 + n > e) break;
|
|
||||||
if (n == 4) {
|
if (rr.alen == 4 && rr.atype == 1 && rr.aclass == 1) {
|
||||||
dm->txnid = mg_ntohs(h->transaction_id);
|
dm->addr.is_ip6 = false;
|
||||||
memcpy(&dm->ipaddr, &s[j + 2], 4);
|
memcpy(&dm->addr.ip, &buf[ofs - 4], 4);
|
||||||
ok = 1;
|
dm->resolved = true;
|
||||||
break;
|
break; // Return success
|
||||||
|
} else if (rr.alen == 16 && rr.atype == 28 && rr.aclass == 1) {
|
||||||
|
dm->addr.is_ip6 = true;
|
||||||
|
memcpy(&dm->addr.ip6, &buf[ofs - 16], 16);
|
||||||
|
dm->resolved = true;
|
||||||
|
break; // Return success
|
||||||
}
|
}
|
||||||
j += 2 + n;
|
|
||||||
}
|
}
|
||||||
return ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dns_cb(struct mg_connection *c, int ev, void *ev_data,
|
static void dns_cb(struct mg_connection *c, int ev, void *ev_data,
|
||||||
void *fn_data) {
|
void *fn_data) {
|
||||||
struct dns_data *d, *tmp, **head = (struct dns_data **) &c->pfn_data;
|
struct dns_data *d, *tmp;
|
||||||
if (ev == MG_EV_POLL) {
|
if (ev == MG_EV_POLL) {
|
||||||
unsigned long now = *(unsigned long *) ev_data;
|
unsigned long now = *(unsigned long *) ev_data;
|
||||||
for (d = (struct dns_data *) fn_data; d != NULL; d = tmp) {
|
for (d = s_reqs; d != NULL; d = tmp) {
|
||||||
tmp = d->next;
|
tmp = d->next;
|
||||||
// LOG(LL_DEBUG, ("%lu %lu dns poll", d->expire, now));
|
// LOG(LL_DEBUG, ("%lu %lu dns poll", d->expire, now));
|
||||||
if (now > d->expire) mg_error(d->c, "DNS timeout");
|
if (now > d->expire) mg_error(d->c, "DNS timeout");
|
||||||
@@ -104,41 +143,62 @@ static void dns_cb(struct mg_connection *c, int ev, void *ev_data,
|
|||||||
} else if (ev == MG_EV_READ) {
|
} else if (ev == MG_EV_READ) {
|
||||||
struct mg_dns_message dm;
|
struct mg_dns_message dm;
|
||||||
int resolved = 0;
|
int resolved = 0;
|
||||||
if (mg_dns_parse(c->recv.buf, c->recv.len, &dm)) {
|
if (mg_dns_parse(c->recv.buf, c->recv.len, &dm) == false) {
|
||||||
for (d = (struct dns_data *) c->pfn_data; d != NULL; d = tmp) {
|
char *s = mg_hexdump(c->recv.buf, c->recv.len);
|
||||||
|
LOG(LL_ERROR, ("Unexpected DNS response:\n%s\n", s));
|
||||||
|
free(s);
|
||||||
|
} else {
|
||||||
|
LOG(LL_VERBOSE_DEBUG, ("%s %d", dm.name, dm.resolved));
|
||||||
|
for (d = s_reqs; d != NULL; d = tmp) {
|
||||||
tmp = d->next;
|
tmp = d->next;
|
||||||
// LOG(LL_INFO, ("d %p %p", d, tmp));
|
// LOG(LL_INFO, ("d %p %hu %hu", d, d->txnid, dm.txnid));
|
||||||
if (dm.txnid != d->txnid) continue;
|
if (dm.txnid != d->txnid) continue;
|
||||||
if (d->c->is_resolving) {
|
if (d->c->is_resolving) {
|
||||||
d->c->is_resolving = 0;
|
d->c->is_resolving = 0;
|
||||||
d->c->peer.ip = dm.ipaddr;
|
if (dm.resolved) {
|
||||||
mg_connect_resolved(d->c);
|
#if MG_ENABLE_LOG
|
||||||
mg_dns_free(head, d);
|
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,
|
||||||
|
mg_ntoa(&d->c->peer, buf, sizeof(buf))));
|
||||||
|
mg_connect_resolved(d->c);
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
} else if (dm.addr.is_ip6 == false && dm.name[0] != '\0') {
|
||||||
|
struct mg_str x = mg_str(dm.name);
|
||||||
|
mg_sendnsreq(d->c, &x, c->mgr->dnstimeout, &c->mgr->dns6, true);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
mg_error(d->c, "%s DNS lookup failed", dm.name);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG(LL_ERROR, ("%p already resolved", d->c->fd));
|
LOG(LL_ERROR, ("%lu already resolved", d->c->id));
|
||||||
}
|
}
|
||||||
|
mg_dns_free(d);
|
||||||
resolved = 1;
|
resolved = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!resolved) LOG(LL_ERROR, ("stray DNS reply"));
|
if (!resolved) LOG(LL_ERROR, ("stray DNS reply"));
|
||||||
c->recv.len = 0;
|
c->recv.len = 0;
|
||||||
} else if (ev == MG_EV_CLOSE) {
|
} else if (ev == MG_EV_CLOSE) {
|
||||||
for (d = *head; d != NULL; d = tmp) {
|
for (d = s_reqs; d != NULL; d = tmp) {
|
||||||
tmp = d->next;
|
tmp = d->next;
|
||||||
mg_dns_free(head, d);
|
mg_dns_free(d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(void) fn_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_dns_send(struct mg_connection *c, const struct mg_str *name,
|
void mg_dns_send(struct mg_connection *c, const struct mg_str *name,
|
||||||
uint16_t txnid) {
|
uint16_t txnid, bool ipv6) {
|
||||||
struct {
|
struct {
|
||||||
struct mg_dns_header header;
|
struct mg_dns_header header;
|
||||||
uint8_t data[256];
|
uint8_t data[256];
|
||||||
} pkt;
|
} pkt;
|
||||||
size_t i, n;
|
size_t i, n;
|
||||||
memset(&pkt, 0, sizeof(pkt));
|
memset(&pkt, 0, sizeof(pkt));
|
||||||
pkt.header.transaction_id = mg_htons(txnid);
|
pkt.header.txnid = mg_htons(txnid);
|
||||||
pkt.header.flags = mg_htons(0x100);
|
pkt.header.flags = mg_htons(0x100);
|
||||||
pkt.header.num_questions = mg_htons(1);
|
pkt.header.num_questions = mg_htons(1);
|
||||||
for (i = n = 0; i < sizeof(pkt.data) - 5; i++) {
|
for (i = n = 0; i < sizeof(pkt.data) - 5; i++) {
|
||||||
@@ -151,6 +211,9 @@ void mg_dns_send(struct mg_connection *c, const struct mg_str *name,
|
|||||||
}
|
}
|
||||||
memcpy(&pkt.data[n], "\x00\x00\x01\x00\x01", 5); // A query
|
memcpy(&pkt.data[n], "\x00\x00\x01\x00\x01", 5); // A query
|
||||||
n += 5;
|
n += 5;
|
||||||
|
if (ipv6) pkt.data[n - 3] = 0x1c; // AAAA query
|
||||||
|
// memcpy(&pkt.data[n], "\xc0\x0c\x00\x1c\x00\x01", 6); // AAAA query
|
||||||
|
// n += 6;
|
||||||
mg_send(c, &pkt, sizeof(pkt.header) + n);
|
mg_send(c, &pkt, sizeof(pkt.header) + n);
|
||||||
#if 0
|
#if 0
|
||||||
// Immediately after A query, send AAAA query. Whatever reply comes first,
|
// Immediately after A query, send AAAA query. Whatever reply comes first,
|
||||||
@@ -161,46 +224,42 @@ void mg_dns_send(struct mg_connection *c, const struct mg_str *name,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_resolve(struct mg_mgr *mgr, struct mg_connection *c,
|
static void mg_sendnsreq(struct mg_connection *c, struct mg_str *name, int ms,
|
||||||
struct mg_str *name, int ms) {
|
struct mg_dns *dnsc, bool ipv6) {
|
||||||
struct dns_data *d = NULL;
|
struct dns_data *d = NULL;
|
||||||
int resolved = mg_aton(name->ptr, &c->peer.ip);
|
if (dnsc->url == NULL) {
|
||||||
|
mg_error(c, "DNS server URL is NULL. Call mg_mgr_init()");
|
||||||
// Try to parse name as IP address
|
} else if (dnsc->c == NULL) {
|
||||||
if (mg_vcmp(name, "localhost") == 0) {
|
dnsc->c = mg_connect(c->mgr, dnsc->url, NULL, NULL);
|
||||||
resolved = 1;
|
if (dnsc->c != NULL) {
|
||||||
c->peer.ip = mg_htonl(0x7f000001);
|
dnsc->c->pfn = dns_cb;
|
||||||
|
snprintf(dnsc->c->label, sizeof(dnsc->c->label), "%s", "DNS");
|
||||||
|
// dnsc->c->is_hexdumping = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (dnsc->c == NULL) {
|
||||||
|
mg_error(c, "resolver");
|
||||||
|
} else if ((d = (struct dns_data *) calloc(1, sizeof(*d))) == NULL) {
|
||||||
|
mg_error(c, "resolve OOM");
|
||||||
|
} else {
|
||||||
|
d->txnid = s_reqs ? s_reqs->txnid + 1 : 1;
|
||||||
|
d->next = s_reqs;
|
||||||
|
s_reqs = d;
|
||||||
|
d->expire = mg_millis() + ms;
|
||||||
|
d->c = c;
|
||||||
|
c->is_resolving = 1;
|
||||||
|
LOG(LL_VERBOSE_DEBUG, ("%lu resolving %.*s, txnid %hu", c->id,
|
||||||
|
(int) name->len, name->ptr, d->txnid));
|
||||||
|
mg_dns_send(dnsc->c, name, d->txnid, ipv6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (resolved) {
|
void mg_resolve(struct mg_connection *c, struct mg_str *name, int ms) {
|
||||||
|
if (mg_aton(*name, &c->peer)) {
|
||||||
// name is an IP address, do not fire name resolution
|
// name is an IP address, do not fire name resolution
|
||||||
mg_connect_resolved(c);
|
mg_connect_resolved(c);
|
||||||
} else {
|
} else {
|
||||||
// name is not an IP, send DNS resolution request
|
// name is not an IP, send DNS resolution request
|
||||||
if (mgr->dnsc == NULL) {
|
mg_sendnsreq(c, name, ms, &c->mgr->dns4, false);
|
||||||
const char *srv = mgr->dnsserver ? mgr->dnsserver : "udp://8.8.8.8:53";
|
|
||||||
mgr->dnsc = mg_connect(mgr, srv, NULL, NULL);
|
|
||||||
if (mgr->dnsc != NULL) {
|
|
||||||
mgr->dnsc->pfn = dns_cb;
|
|
||||||
// mgr->dnsc->is_hexdumping = 1;
|
|
||||||
snprintf(mgr->dnsc->label, sizeof(mgr->dnsc->label), "%s", "RESOLVER");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mgr->dnsc == NULL) {
|
|
||||||
mg_error(c, "resolver");
|
|
||||||
} else if ((d = (struct dns_data *) calloc(1, sizeof(*d))) == NULL) {
|
|
||||||
mg_error(c, "resolve OOM");
|
|
||||||
} else {
|
|
||||||
struct dns_data **head = (struct dns_data **) &mgr->dnsc->pfn_data;
|
|
||||||
d->txnid = *head ? (*head)->txnid + 1 : 1;
|
|
||||||
d->next = *head;
|
|
||||||
*head = d;
|
|
||||||
d->expire = mg_millis() + ms;
|
|
||||||
d->c = c;
|
|
||||||
c->is_resolving = 1;
|
|
||||||
LOG(LL_DEBUG, ("%p resolving %.*s, txnid %hu", c->fd, (int) name->len,
|
|
||||||
name->ptr, d->txnid));
|
|
||||||
mg_dns_send(mgr->dnsc, name, d->txnid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,12 +3,37 @@
|
|||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
|
|
||||||
|
// Mongoose sends DNS queries that contain only one question:
|
||||||
|
// either A (IPv4) or AAAA (IPv6) address lookup.
|
||||||
|
// Therefore, we expect zero or one answer.
|
||||||
|
// If `resolved` is true, then `addr` contains resolved IPv4 or IPV6 address.
|
||||||
struct mg_dns_message {
|
struct mg_dns_message {
|
||||||
uint16_t txnid; // Transaction ID
|
uint16_t txnid; // Transaction ID
|
||||||
uint32_t ipaddr; // Resolved IPv4 address
|
bool resolved; // Resolve successful, addr is set
|
||||||
char name[256]; // Host name
|
struct mg_addr addr; // Resolved address
|
||||||
|
char name[256]; // Host name
|
||||||
};
|
};
|
||||||
|
|
||||||
void mg_resolve(struct mg_mgr *, struct mg_connection *, struct mg_str *, int);
|
struct mg_dns_header {
|
||||||
void mg_resolve_cancel(struct mg_mgr *, struct mg_connection *);
|
uint16_t txnid; // Transaction ID
|
||||||
int mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *);
|
uint16_t flags;
|
||||||
|
uint16_t num_questions;
|
||||||
|
uint16_t num_answers;
|
||||||
|
uint16_t num_authority_prs;
|
||||||
|
uint16_t num_other_prs;
|
||||||
|
};
|
||||||
|
|
||||||
|
// DNS resource record
|
||||||
|
struct mg_dns_rr {
|
||||||
|
uint16_t nlen; // Name or pointer length
|
||||||
|
uint16_t atype; // Address type
|
||||||
|
uint16_t aclass; // Address class
|
||||||
|
uint16_t alen; // Address length
|
||||||
|
};
|
||||||
|
|
||||||
|
void mg_resolve(struct mg_connection *, struct mg_str *, int);
|
||||||
|
void mg_resolve_cancel(struct mg_connection *);
|
||||||
|
bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *);
|
||||||
|
size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
|
||||||
|
bool is_question, struct mg_dns_rr *);
|
||||||
|
size_t mg_dns_decode_name(const uint8_t *, size_t, size_t, char *, size_t);
|
||||||
+1
-1
@@ -14,7 +14,7 @@ void mg_error(struct mg_connection *c, const char *fmt, ...) {
|
|||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
mg_vasprintf(&buf, sizeof(mem), fmt, ap);
|
mg_vasprintf(&buf, sizeof(mem), fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
LOG(LL_ERROR, ("%p %s", c->fd, buf));
|
LOG(LL_ERROR, ("%lu %s", c->id, buf));
|
||||||
mg_call(c, MG_EV_ERROR, buf);
|
mg_call(c, MG_EV_ERROR, buf);
|
||||||
if (buf != mem) free(buf);
|
if (buf != mem) free(buf);
|
||||||
c->is_closing = 1;
|
c->is_closing = 1;
|
||||||
|
|||||||
+18
-27
@@ -3,35 +3,26 @@
|
|||||||
struct mg_connection;
|
struct mg_connection;
|
||||||
typedef void (*mg_event_handler_t)(struct mg_connection *, int ev,
|
typedef void (*mg_event_handler_t)(struct mg_connection *, int ev,
|
||||||
void *ev_data, void *fn_data);
|
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_call(struct mg_connection *c, int ev, void *ev_data);
|
||||||
void mg_error(struct mg_connection *c, const char *fmt, ...);
|
void mg_error(struct mg_connection *c, const char *fmt, ...);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MG_EV_ERROR, // Error char *error_message
|
MG_EV_ERROR, // Error char *error_message
|
||||||
MG_EV_POLL, // mg_mgr_poll iteration unsigned long *millis
|
MG_EV_POLL, // mg_mgr_poll iteration unsigned long *millis
|
||||||
MG_EV_RESOLVE, // Host name is resolved NULL
|
MG_EV_RESOLVE, // Host name is resolved NULL
|
||||||
MG_EV_CONNECT, // Connection established NULL
|
MG_EV_CONNECT, // Connection established NULL
|
||||||
MG_EV_ACCEPT, // Connection accepted NULL
|
MG_EV_ACCEPT, // Connection accepted NULL
|
||||||
MG_EV_READ, // Data received from socket struct mg_str *
|
MG_EV_READ, // Data received from socket struct mg_str *
|
||||||
MG_EV_WRITE, // Data written to socket int *num_bytes_written
|
MG_EV_WRITE, // Data written to socket int *num_bytes_written
|
||||||
MG_EV_CLOSE, // Connection closed NULL
|
MG_EV_CLOSE, // Connection closed NULL
|
||||||
MG_EV_HTTP_MSG, // HTTP request/response struct mg_http_message *
|
MG_EV_HTTP_MSG, // HTTP request/response struct mg_http_message *
|
||||||
MG_EV_WS_OPEN, // Websocket handshake done NULL
|
MG_EV_HTTP_CHUNK, // HTTP chunk (partial msg) struct mg_http_message *
|
||||||
MG_EV_WS_MSG, // Websocket message received struct mg_ws_message *
|
MG_EV_WS_OPEN, // Websocket handshake done struct mg_http_message *
|
||||||
MG_EV_MQTT_MSG, // MQTT message struct mg_mqtt_message *
|
MG_EV_WS_MSG, // Websocket msg, text or bin struct mg_ws_message *
|
||||||
MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code
|
MG_EV_WS_CTL, // Websocket control msg struct mg_ws_message *
|
||||||
MG_EV_SNTP_TIME, // SNTP time received struct timeval *
|
MG_EV_MQTT_CMD, // MQTT low-level command struct mg_mqtt_message *
|
||||||
MG_EV_USER, // Starting ID for user events
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
+346
-156
@@ -1,18 +1,14 @@
|
|||||||
#include "http.h"
|
|
||||||
#include "arch.h"
|
#include "arch.h"
|
||||||
#include "base64.h"
|
#include "base64.h"
|
||||||
|
#include "http.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
|
#include "ssi.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "ws.h"
|
#include "ws.h"
|
||||||
|
|
||||||
struct http_data {
|
|
||||||
void *old_pfn_data; // Previous pfn_data
|
|
||||||
FILE *fp; // For static file serving
|
|
||||||
};
|
|
||||||
|
|
||||||
// Multipart POST example:
|
// Multipart POST example:
|
||||||
// https://gist.github.com/cpq/b8dd247571e6ee9c54ef7e8dfcfecf48
|
// https://gist.github.com/cpq/b8dd247571e6ee9c54ef7e8dfcfecf48
|
||||||
|
|
||||||
@@ -34,7 +30,7 @@ void mg_http_bauth(struct mg_connection *c, const char *user,
|
|||||||
c->send.len += 21 + n + 2;
|
c->send.len += 21 + n + 2;
|
||||||
memcpy(&c->send.buf[c->send.len - 2], "\r\n", 2);
|
memcpy(&c->send.buf[c->send.len - 2], "\r\n", 2);
|
||||||
} else {
|
} else {
|
||||||
LOG(LL_ERROR, ("%p %s cannot resize iobuf %d->%d ", c->fd, c->label,
|
LOG(LL_ERROR, ("%lu %s cannot resize iobuf %d->%d ", c->id, c->label,
|
||||||
(int) c->send.size, (int) need));
|
(int) c->send.size, (int) need));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,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));
|
s = (const char *) memchr(p, '&', (size_t)(e - p));
|
||||||
if (s == NULL) s = e;
|
if (s == NULL) s = e;
|
||||||
len = mg_url_decode(p, (size_t)(s - p), dst, dst_len, 1);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,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
|
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) {
|
int mg_http_get_request_len(const unsigned char *buf, size_t buf_len) {
|
||||||
@@ -105,12 +101,12 @@ int mg_http_get_request_len(const unsigned char *buf, size_t buf_len) {
|
|||||||
return 0;
|
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) {
|
struct mg_str *v) {
|
||||||
v->ptr = s;
|
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;
|
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;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,15 +145,19 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
|
|||||||
memset(hm, 0, sizeof(*hm));
|
memset(hm, 0, sizeof(*hm));
|
||||||
if (req_len <= 0) return req_len;
|
if (req_len <= 0) return req_len;
|
||||||
|
|
||||||
hm->message.ptr = s;
|
hm->message.ptr = hm->head.ptr = s;
|
||||||
hm->body.ptr = s + req_len;
|
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
|
hm->message.len = hm->body.len = (size_t) ~0; // Set body length to infinite
|
||||||
|
|
||||||
// Parse request line
|
// Parse request line
|
||||||
s = skip(s, end, " ", &hm->method);
|
s = skip(s, end, " ", &hm->method);
|
||||||
s = skip(s, end, " ", &hm->uri);
|
s = skip(s, end, " ", &hm->uri);
|
||||||
s = skip(s, end, "\r\n", &hm->proto);
|
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 URI contains '?' character, setup query string
|
||||||
if ((qs = (const char *) memchr(hm->uri.ptr, '?', hm->uri.len)) != NULL) {
|
if ((qs = (const char *) memchr(hm->uri.ptr, '?', hm->uri.len)) != NULL) {
|
||||||
@@ -169,7 +169,7 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
|
|||||||
mg_http_parse_headers(s, end, hm->headers,
|
mg_http_parse_headers(s, end, hm->headers,
|
||||||
sizeof(hm->headers) / sizeof(hm->headers[0]));
|
sizeof(hm->headers) / sizeof(hm->headers[0]));
|
||||||
if ((cl = mg_http_get_header(hm, "Content-Length")) != NULL) {
|
if ((cl = mg_http_get_header(hm, "Content-Length")) != NULL) {
|
||||||
hm->body.len = (size_t) mg_to64(cl->ptr);
|
hm->body.len = (size_t) mg_to64(*cl);
|
||||||
hm->message.len = req_len + hm->body.len;
|
hm->message.len = req_len + hm->body.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,6 +193,13 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
|
|||||||
hm->message.len = req_len;
|
hm->message.len = req_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The 204 (No content) responses also have 0 body length
|
||||||
|
if (hm->body.len == (size_t) ~0 && is_response &&
|
||||||
|
mg_vcasecmp(&hm->uri, "204") == 0) {
|
||||||
|
hm->body.len = 0;
|
||||||
|
hm->message.len = req_len;
|
||||||
|
}
|
||||||
|
|
||||||
return req_len;
|
return req_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,34 +226,31 @@ void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len) {
|
|||||||
mg_send(c, "\r\n", 2);
|
mg_send(c, "\r\n", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_http_reply(struct mg_connection *c, int code, const char *fmt, ...) {
|
void mg_http_reply(struct mg_connection *c, int code, const char *headers,
|
||||||
|
const char *fmt, ...) {
|
||||||
char mem[100], *buf = mem;
|
char mem[100], *buf = mem;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int len;
|
int len;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
len = mg_vasprintf(&buf, sizeof(mem), fmt, ap);
|
len = mg_vasprintf(&buf, sizeof(mem), fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
mg_printf(c,
|
mg_printf(c, "HTTP/1.1 %d OK\r\n%sContent-Length: %d\r\n\r\n", code,
|
||||||
"HTTP/1.1 %d OK\r\nContent-Type: text/plain\r\n"
|
headers == NULL ? "" : headers, len);
|
||||||
"Content-Length: %d\r\n\r\n",
|
|
||||||
code, len);
|
|
||||||
mg_send(c, buf, len);
|
mg_send(c, buf, len);
|
||||||
if (buf != mem) free(buf);
|
if (buf != mem) free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MG_ENABLE_FS
|
||||||
static void http_cb(struct mg_connection *, int, void *, void *);
|
static void http_cb(struct mg_connection *, int, void *, void *);
|
||||||
static void restore_http_cb(struct mg_connection *c) {
|
static void restore_http_cb(struct mg_connection *c) {
|
||||||
struct http_data *d = (struct http_data *) c->pfn_data;
|
if (c->pfn_data != NULL) fclose((FILE *) c->pfn_data);
|
||||||
if (d->fp != NULL) fclose(d->fp);
|
c->pfn_data = NULL;
|
||||||
c->pfn_data = d->old_pfn_data;
|
|
||||||
c->pfn = http_cb;
|
c->pfn = http_cb;
|
||||||
free(d);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MG_ENABLE_FS
|
char *mg_http_etag(char *buf, size_t len, mg_stat_t *st) {
|
||||||
char *mg_http_etag(char *buf, size_t len, struct stat *st) {
|
snprintf(buf, len, "\"%lx." MG_INT64_FMT "\"", (unsigned long) st->st_mtime,
|
||||||
snprintf(buf, len, "\"%lx.%lu\"", (unsigned long) st->st_mtime,
|
(int64_t) st->st_size);
|
||||||
(unsigned long) st->st_size);
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,7 +260,7 @@ int mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
|
|||||||
mg_http_get_var(&hm->query, "offset", offset, sizeof(offset));
|
mg_http_get_var(&hm->query, "offset", offset, sizeof(offset));
|
||||||
mg_http_get_var(&hm->query, "name", name, sizeof(name));
|
mg_http_get_var(&hm->query, "name", name, sizeof(name));
|
||||||
if (name[0] == '\0') {
|
if (name[0] == '\0') {
|
||||||
mg_http_reply(c, 400, "%s", "name required");
|
mg_http_reply(c, 400, "", "%s", "name required");
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
@@ -264,13 +268,13 @@ int mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
|
|||||||
snprintf(path, sizeof(path), "%s%c%s", dir, MG_DIRSEP, name);
|
snprintf(path, sizeof(path), "%s%c%s", dir, MG_DIRSEP, name);
|
||||||
LOG(LL_DEBUG,
|
LOG(LL_DEBUG,
|
||||||
("%p %d bytes @ %d [%s]", c->fd, (int) hm->body.len, (int) oft, name));
|
("%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);
|
mg_http_reply(c, 400, "", "fopen(%s): %d", name, errno);
|
||||||
return -2;
|
return -2;
|
||||||
} else {
|
} else {
|
||||||
fwrite(hm->body.ptr, 1, hm->body.len, fp);
|
fwrite(hm->body.ptr, 1, hm->body.len, fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
mg_http_reply(c, 200, "");
|
mg_http_reply(c, 200, "", "");
|
||||||
return hm->body.len;
|
return hm->body.len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -279,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,
|
static void static_cb(struct mg_connection *c, int ev, void *ev_data,
|
||||||
void *fn_data) {
|
void *fn_data) {
|
||||||
if (ev == MG_EV_WRITE || ev == MG_EV_POLL) {
|
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
|
// Read to send IO buffer directly, avoid extra on-stack buffer
|
||||||
size_t n, max = 2 * MG_IO_SIZE;
|
size_t n, max = 2 * MG_IO_SIZE;
|
||||||
if (c->send.size < max) mg_iobuf_resize(&c->send, max);
|
if (c->send.size < max) mg_iobuf_resize(&c->send, max);
|
||||||
if (c->send.len >= c->send.size) return; // Rate limit
|
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 (n > 0) c->send.len += n;
|
||||||
if (c->send.len < c->send.size) restore_http_cb(c);
|
if (c->send.len < c->send.size) restore_http_cb(c);
|
||||||
} else if (ev == MG_EV_CLOSE) {
|
} else if (ev == MG_EV_CLOSE) {
|
||||||
@@ -294,37 +298,92 @@ static void static_cb(struct mg_connection *c, int ev, void *ev_data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char *guess_content_type(const char *filename) {
|
static const char *guess_content_type(const char *filename) {
|
||||||
int n = (int) strlen(filename);
|
size_t n = strlen(filename);
|
||||||
if (mg_globmatch("#.html", 6, filename, n)) return "text/html";
|
#define MIME_ENTRY(_ext, _type) \
|
||||||
if (mg_globmatch("#.css", 5, filename, n)) return "text/css";
|
{ _ext, sizeof(_ext) - 1, _type }
|
||||||
if (mg_globmatch("#.js", 4, filename, n)) return "text/javascript";
|
const struct {
|
||||||
return "text/plain";
|
const char *ext;
|
||||||
|
size_t ext_len;
|
||||||
|
const char *type;
|
||||||
|
} * t, types[] = {
|
||||||
|
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"),
|
||||||
|
MIME_ENTRY("json", "application/json"),
|
||||||
|
MIME_ENTRY("ico", "image/x-icon"),
|
||||||
|
MIME_ENTRY("gif", "image/gif"),
|
||||||
|
MIME_ENTRY("jpg", "image/jpeg"),
|
||||||
|
MIME_ENTRY("jpeg", "image/jpeg"),
|
||||||
|
MIME_ENTRY("png", "image/png"),
|
||||||
|
MIME_ENTRY("svg", "image/svg+xml"),
|
||||||
|
MIME_ENTRY("txt", "text/plain; charset=utf-8"),
|
||||||
|
MIME_ENTRY("wav", "audio/wav"),
|
||||||
|
MIME_ENTRY("mp3", "audio/mpeg"),
|
||||||
|
MIME_ENTRY("mid", "audio/mid"),
|
||||||
|
MIME_ENTRY("ogg", "application/ogg"),
|
||||||
|
MIME_ENTRY("xml", "application/xml"),
|
||||||
|
MIME_ENTRY("ttf", "font/ttf"),
|
||||||
|
MIME_ENTRY("json", "application/json"),
|
||||||
|
MIME_ENTRY("xsl", "application/xml"),
|
||||||
|
MIME_ENTRY("doc", "application/msword"),
|
||||||
|
MIME_ENTRY("exe", "application/octet-stream"),
|
||||||
|
MIME_ENTRY("zip", "application/zip"),
|
||||||
|
MIME_ENTRY("xls", "application/excel"),
|
||||||
|
MIME_ENTRY("tgz", "application/tar-gz"),
|
||||||
|
MIME_ENTRY("tar", "application/tar"),
|
||||||
|
MIME_ENTRY("gz", "application/gzip"),
|
||||||
|
MIME_ENTRY("rar", "application/rar"),
|
||||||
|
MIME_ENTRY("rtf", "application/rtf"),
|
||||||
|
MIME_ENTRY("pdf", "application/pdf"),
|
||||||
|
MIME_ENTRY("mpg", "video/mpeg"),
|
||||||
|
MIME_ENTRY("webm", "video/webm"),
|
||||||
|
MIME_ENTRY("mpeg", "video/mpeg"),
|
||||||
|
MIME_ENTRY("mov", "video/quicktime"),
|
||||||
|
MIME_ENTRY("mp4", "video/mp4"),
|
||||||
|
MIME_ENTRY("avi", "video/x-msvideo"),
|
||||||
|
MIME_ENTRY("csv", "text/csv"),
|
||||||
|
MIME_ENTRY("bmp", "image/bmp"),
|
||||||
|
MIME_ENTRY("bin", "application/octet-stream"),
|
||||||
|
MIME_ENTRY("wasm", "application/wasm"),
|
||||||
|
{NULL, 0, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (t = types; t->ext != NULL; t++) {
|
||||||
|
if (n < t->ext_len + 2) continue;
|
||||||
|
if (mg_ncasecmp(t->ext, &filename[n - t->ext_len], t->ext_len)) continue;
|
||||||
|
return t->type;
|
||||||
|
}
|
||||||
|
return "text/plain; charset=utf-8";
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
|
void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
|
||||||
const char *path, const char *mime) {
|
const char *path, const char *mime, const char *hdrs) {
|
||||||
struct mg_str *inm = mg_http_get_header(hm, "If-None-Match");
|
struct mg_str *inm = mg_http_get_header(hm, "If-None-Match");
|
||||||
struct stat st;
|
mg_stat_t st;
|
||||||
FILE *fp = fopen(path, "rb");
|
|
||||||
char etag[64];
|
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) {
|
mg_http_etag(etag, sizeof(etag), &st) != etag) {
|
||||||
mg_http_reply(c, 404, "%s", "Not found\n");
|
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) {
|
} 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");
|
mg_printf(c, "HTTP/1.1 304 Not Modified\r\nContent-Length: 0\r\n\r\n");
|
||||||
} else {
|
} else {
|
||||||
mg_printf(c,
|
mg_printf(c,
|
||||||
"HTTP/1.1 200 OK\r\nContent-Type: %s\r\n"
|
"HTTP/1.1 200 OK\r\nContent-Type: %s\r\n"
|
||||||
"Etag: %s\r\nContent-Length: %lu\r\n\r\n",
|
"Etag: %s\r\nContent-Length: " MG_INT64_FMT "\r\n%s\r\n",
|
||||||
mime, etag, (unsigned long) st.st_size);
|
mime, etag, (int64_t) st.st_size, hdrs ? hdrs : "");
|
||||||
if (mg_vcasecmp(&hm->method, "HEAD") == 0) {
|
if (mg_vcasecmp(&hm->method, "HEAD") == 0) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
} else {
|
} else {
|
||||||
struct http_data *d = (struct http_data *) calloc(1, sizeof(*d));
|
|
||||||
d->fp = fp;
|
|
||||||
d->old_pfn_data = c->pfn_data;
|
|
||||||
c->pfn = static_cb;
|
c->pfn = static_cb;
|
||||||
c->pfn_data = d;
|
c->pfn_data = fp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -333,21 +392,23 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
|
|||||||
MG_ARCH == MG_ARCH_FREERTOS
|
MG_ARCH == MG_ARCH_FREERTOS
|
||||||
char *realpath(const char *src, char *dst) {
|
char *realpath(const char *src, char *dst) {
|
||||||
int len = strlen(src);
|
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);
|
strncpy(dst, src, len);
|
||||||
dst[len] = '\0';
|
dst[len] = '\0';
|
||||||
|
LOG(LL_DEBUG, ("[%s] -> [%s]", src, dst));
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Try to avoid dirent API
|
// Allow user to override this function
|
||||||
static int mg_is_dir(const char *path) {
|
bool mg_is_dir(const char *path) WEAK;
|
||||||
|
bool mg_is_dir(const char *path) {
|
||||||
#if MG_ARCH == MG_ARCH_FREERTOS
|
#if MG_ARCH == MG_ARCH_FREERTOS
|
||||||
struct FF_STAT st;
|
struct FF_STAT st;
|
||||||
return (ff_stat(path, &st) == 0) && (st.st_mode & FF_IFDIR);
|
return (ff_stat(path, &st) == 0) && (st.st_mode & FF_IFDIR);
|
||||||
#else
|
#else
|
||||||
struct stat st;
|
mg_stat_t st;
|
||||||
return (stat(path, &st) == 0) && (st.st_mode & S_IFDIR);
|
return mg_stat(path, &st) == 0 && S_ISDIR(st.st_mode);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,7 +428,6 @@ typedef struct win32_dir {
|
|||||||
int gettimeofday(struct timeval *tv, void *tz) {
|
int gettimeofday(struct timeval *tv, void *tz) {
|
||||||
FILETIME ft;
|
FILETIME ft;
|
||||||
unsigned __int64 tmpres = 0;
|
unsigned __int64 tmpres = 0;
|
||||||
static int tzflag = 0;
|
|
||||||
|
|
||||||
if (tv != NULL) {
|
if (tv != NULL) {
|
||||||
GetSystemTimeAsFileTime(&ft);
|
GetSystemTimeAsFileTime(&ft);
|
||||||
@@ -379,6 +439,7 @@ int gettimeofday(struct timeval *tv, void *tz) {
|
|||||||
tv->tv_sec = (long) (tmpres / 1000000UL);
|
tv->tv_sec = (long) (tmpres / 1000000UL);
|
||||||
tv->tv_usec = (long) (tmpres % 1000000UL);
|
tv->tv_usec = (long) (tmpres % 1000000UL);
|
||||||
}
|
}
|
||||||
|
(void) tz;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,7 +471,7 @@ DIR *opendir(const char *name) {
|
|||||||
|
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
SetLastError(ERROR_BAD_ARGUMENTS);
|
SetLastError(ERROR_BAD_ARGUMENTS);
|
||||||
} else if ((d = malloc(sizeof(*d))) == NULL) {
|
} else if ((d = (DIR *) malloc(sizeof(*d))) == NULL) {
|
||||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
} else {
|
} else {
|
||||||
to_wchar(name, wpath, sizeof(wpath) / sizeof(wpath[0]));
|
to_wchar(name, wpath, sizeof(wpath) / sizeof(wpath[0]));
|
||||||
@@ -462,10 +523,10 @@ struct dirent *readdir(DIR *d) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void printdirentry(struct mg_connection *c, struct mg_http_message *hm,
|
static void printdirentry(struct mg_connection *c, const char *name,
|
||||||
const char *name, struct stat *stp) {
|
mg_stat_t *stp) {
|
||||||
char size[64], mod[64]; //, path[PATH_MAX];
|
char size[64], mod[64], path[MG_PATH_MAX];
|
||||||
int is_dir = S_ISDIR(stp->st_mode);
|
int is_dir = S_ISDIR(stp->st_mode), n = 0;
|
||||||
const char *slash = is_dir ? "/" : "";
|
const char *slash = is_dir ? "/" : "";
|
||||||
|
|
||||||
if (is_dir) {
|
if (is_dir) {
|
||||||
@@ -482,96 +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));
|
strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&stp->st_mtime));
|
||||||
// mg_escape(file_name, path, sizeof(path));
|
n = mg_url_encode(name, strlen(name), path, sizeof(path));
|
||||||
// href = mg_url_encode(mg_mk_str(file_name));
|
mg_printf(c,
|
||||||
mg_http_printf_chunk(
|
" <tr><td><a href=\"%.*s%s\">%s%s</a></td>"
|
||||||
c,
|
"<td>%s</td><td>%s</td></tr>\n",
|
||||||
"<tr><td><a href=\"%.*s%s%s\">%s%s</a></td><td>%s</td><td>%s</td></tr>",
|
n, path, slash, name, slash, mod, size);
|
||||||
(int) hm->uri.len, hm->uri.ptr, name, slash, name, slash, mod, size);
|
|
||||||
// free((void *) href.p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void listdir(struct mg_connection *c, struct mg_http_message *hm,
|
static void listdir(struct mg_connection *c, struct mg_http_message *hm,
|
||||||
char *dir) {
|
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;
|
struct dirent *dp;
|
||||||
DIR *dirp;
|
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';
|
while (p > dir && *p != '/') *p-- = '\0';
|
||||||
// LOG(LL_DEBUG, ("%p [%s]", c->fd, dir));
|
|
||||||
if ((dirp = (opendir(dir))) != NULL) {
|
if ((dirp = (opendir(dir))) != NULL) {
|
||||||
mg_printf(c, "%s\r\n", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n");
|
size_t off, n;
|
||||||
mg_http_printf_chunk(
|
mg_printf(c, "%s\r\n",
|
||||||
c,
|
"HTTP/1.1 200 OK\r\n"
|
||||||
"<!DOCTYPE html><html><head><title>Index of %.*s</title>"
|
"Content-Type: text/html; charset=utf-8\r\n"
|
||||||
"<style>th,td {text-align: left; padding-right: 1em; "
|
"Content-Length: \r\n");
|
||||||
"font-family: monospace; }</style></head>"
|
off = c->send.len; // Start of body
|
||||||
"<body><h1>Index of %.*s</h1><table cellpadding=\"0\"><thead>"
|
mg_printf(c,
|
||||||
"<tr><th>Name</th><th>Modified</th><th>Size</th></tr>"
|
"<!DOCTYPE html><html><head><title>Index of %.*s</title>%s%s"
|
||||||
"<tr><td colspan=\"3\"><hr></td></tr></thead><tbody>",
|
"<style>th,td {text-align: left; padding-right: 1em; "
|
||||||
(int) hm->uri.len, hm->uri.ptr, (int) hm->uri.len, hm->uri.ptr);
|
"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) {
|
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
|
// Do not show current dir and hidden files
|
||||||
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue;
|
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue;
|
||||||
snprintf(path, sizeof(path), "%s/%s", dir, dp->d_name);
|
// SPIFFS can report "/foo.txt" in the dp->d_name
|
||||||
if (stat(path, &st) != 0) {
|
if (snprintf(path, sizeof(path), "%s%s%s", dir, sep, dp->d_name) < 0) {
|
||||||
LOG(LL_ERROR, ("%p stat(%s): %d", c->fd, path, errno));
|
LOG(LL_ERROR, ("%s truncated", dp->d_name));
|
||||||
continue;
|
} else if (mg_stat(path, &st) != 0) {
|
||||||
|
LOG(LL_ERROR, ("%lu stat(%s): %d", c->id, path, errno));
|
||||||
|
} else {
|
||||||
|
printdirentry(c, dp->d_name, &st);
|
||||||
}
|
}
|
||||||
printdirentry(c, hm, dp->d_name, &st);
|
|
||||||
}
|
}
|
||||||
closedir(dirp);
|
closedir(dirp);
|
||||||
mg_http_printf_chunk(
|
mg_printf(c,
|
||||||
c,
|
"</tbody><tfoot><tr><td colspan=\"3\"><hr></td></tr></tfoot>"
|
||||||
"</tbody><tfoot><tr><td colspan=\"3\"><hr></td></tr></tfoot>"
|
"</table><address>Mongoose v.%s</address></body></html>\n",
|
||||||
"</table><address>Mongoose v.%s</address></body></html>",
|
MG_VERSION);
|
||||||
MG_VERSION);
|
n = snprintf(tmp, sizeof(tmp), "%lu", (unsigned long) (c->send.len - off));
|
||||||
mg_http_write_chunk(c, "", 0);
|
memcpy(c->send.buf + off - 10, tmp, n); // Set content length
|
||||||
} else {
|
} else {
|
||||||
mg_http_reply(c, 400, "Cannot open dir");
|
mg_http_reply(c, 400, "", "Cannot open dir");
|
||||||
LOG(LL_DEBUG, ("%p opendir(%s) -> %d", c->fd, dir, errno));
|
LOG(LL_ERROR, ("%lu opendir(%s) -> %d", c->id, dir, errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
|
void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
|
||||||
const char *dir) {
|
struct mg_http_serve_opts *opts) {
|
||||||
char path[PATH_MAX + 2], root[sizeof(path) - 2], real[sizeof(path) - 2];
|
char t1[MG_PATH_MAX], t2[sizeof(t1)];
|
||||||
path[0] = root[0] = real[0] = '\0';
|
t1[0] = t2[0] = '\0';
|
||||||
if (realpath(dir, root) == NULL)
|
|
||||||
LOG(LL_DEBUG, ("realpath(%s): %d", dir, errno));
|
if (realpath(opts->root_dir, t1) == NULL) {
|
||||||
if (!mg_is_dir(root)) {
|
LOG(LL_ERROR, ("realpath(%s): %d", opts->root_dir, errno));
|
||||||
mg_http_reply(c, 400, "Bad web root [%s]\n", root);
|
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 {
|
} else {
|
||||||
// NOTE(lsm): Xilinx snprintf does not 0-terminate the detination for
|
// 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
|
// the %.*s specifier, if the length is zero. Make sure hm->uri.len > 0
|
||||||
bool is_index = false;
|
bool is_index = false;
|
||||||
size_t n = snprintf(path, sizeof(path), "%s%.*s", root, (int) hm->uri.len,
|
size_t n1 = strlen(t1), n2;
|
||||||
hm->uri.ptr);
|
|
||||||
while (n > 0 && n < sizeof(path) && path[n - 1] == MG_DIRSEP) path[--n] = 0;
|
mg_url_decode(hm->uri.ptr, hm->uri.len, t1 + n1, sizeof(t1) - n1, 0);
|
||||||
if (realpath(path, real) == NULL)
|
t1[sizeof(t1) - 1] = '\0';
|
||||||
LOG(LL_DEBUG, ("realpath(%s): %d", dir, errno));
|
n2 = strlen(t1);
|
||||||
// LOG(LL_INFO, ("PATH: [%s] REAL: [%s]", path, real));
|
while (n2 > 0 && t1[n2 - 1] == '/') t1[--n2] = 0;
|
||||||
if (mg_is_dir(real)) {
|
|
||||||
strncat(real, "/index.html", sizeof(real) - strlen(real) - 1);
|
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;
|
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 {
|
} else {
|
||||||
FILE *fp = fopen(real, "r");
|
FILE *fp = mg_fopen(t2, "r");
|
||||||
#if MG_ENABLE_HTTP_DEBUG_ENDPOINT
|
#if MG_ENABLE_SSI
|
||||||
snprintf(c->label, sizeof(c->label) - 1, "<-F %s", real);
|
if (is_index && fp == NULL) {
|
||||||
|
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
|
#endif
|
||||||
if (is_index && fp == NULL) {
|
if (is_index && fp == NULL) {
|
||||||
#if MG_ENABLE_DIRECTORY_LISTING
|
#if MG_ENABLE_DIRECTORY_LISTING
|
||||||
listdir(c, hm, real);
|
listdir(c, hm, t2);
|
||||||
#else
|
#else
|
||||||
mg_http_reply(c, 403, "%s", "Directory listing not supported");
|
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), t2,
|
||||||
|
strlen(t2))) {
|
||||||
|
t1[n1] = '\0';
|
||||||
|
mg_http_serve_ssi(c, t1, t2);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
mg_http_serve_file(c, hm, real, guess_content_type(real));
|
mg_http_serve_file(c, hm, t2, guess_content_type(t2), NULL);
|
||||||
}
|
}
|
||||||
if (fp != NULL) fclose(fp);
|
if (fp != NULL) fclose(fp);
|
||||||
}
|
}
|
||||||
@@ -579,6 +700,27 @@ void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
|
|||||||
}
|
}
|
||||||
#endif
|
#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,
|
void mg_http_creds(struct mg_http_message *hm, char *user, int userlen,
|
||||||
char *pass, int passlen) {
|
char *pass, int passlen) {
|
||||||
struct mg_str *v = mg_http_get_header(hm, "Authorization");
|
struct mg_str *v = mg_http_get_header(hm, "Authorization");
|
||||||
@@ -612,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);
|
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,
|
static size_t get_chunk_length(const char *buf, size_t len, size_t *ll) {
|
||||||
void *fn_data) {
|
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) {
|
if (ev == MG_EV_READ || ev == MG_EV_CLOSE) {
|
||||||
struct mg_http_message hm;
|
struct mg_http_message hm;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int n = mg_http_parse((char *) c->recv.buf, c->recv.len, &hm);
|
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) {
|
if (ev == MG_EV_CLOSE) {
|
||||||
hm.message.len = c->recv.len;
|
hm.message.len = c->recv.len;
|
||||||
hm.body.len = hm.message.len - (hm.body.ptr - hm.message.ptr);
|
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) {
|
if (n < 0 && ev == MG_EV_READ) {
|
||||||
LOG(LL_ERROR, ("%p HTTP parse error", c->fd));
|
LOG(LL_ERROR, ("%lu HTTP parse error", c->id));
|
||||||
c->is_closing = 1;
|
c->is_closing = 1;
|
||||||
break;
|
break;
|
||||||
} else if (n > 0 && (size_t) c->recv.len >= hm.message.len) {
|
} 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_call(c, MG_EV_HTTP_MSG, &hm);
|
||||||
mg_iobuf_delete(&c->recv, hm.message.len);
|
mg_iobuf_delete(&c->recv, hm.message.len);
|
||||||
} else {
|
} 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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(void) fn_data;
|
(void) fnd;
|
||||||
(void) ev_data;
|
(void) evd;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mg_connection *mg_http_connect(struct mg_mgr *mgr, const char *url,
|
struct mg_connection *mg_http_connect(struct mg_mgr *mgr, const char *url,
|
||||||
mg_event_handler_t fn, void *fn_data) {
|
mg_event_handler_t fn, void *fn_data) {
|
||||||
struct mg_connection *c = mg_connect(mgr, url, fn, 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 (c != NULL) c->pfn = http_cb;
|
||||||
#if MG_ENABLE_HTTP_DEBUG_ENDPOINT
|
|
||||||
snprintf(c->label, sizeof(c->label) - 1, "->%s", url);
|
|
||||||
#endif
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url,
|
struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url,
|
||||||
mg_event_handler_t fn, void *fn_data) {
|
mg_event_handler_t fn, void *fn_data) {
|
||||||
struct mg_connection *c = mg_listen(mgr, url, fn, 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 (c != NULL) c->pfn = http_cb;
|
||||||
#if MG_ENABLE_HTTP_DEBUG_ENDPOINT
|
|
||||||
snprintf(c->label, sizeof(c->label) - 1, "<-LSN");
|
|
||||||
#endif
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
+17
-7
@@ -13,30 +13,40 @@ struct mg_http_message {
|
|||||||
// GET /foo/bar/baz?aa=b&cc=ddd HTTP/1.1
|
// GET /foo/bar/baz?aa=b&cc=ddd HTTP/1.1
|
||||||
// method |-| |----uri---| |--query--| |proto-|
|
// method |-| |----uri---| |--query--| |proto-|
|
||||||
|
|
||||||
struct mg_str method, uri, query, proto; // Request/response line
|
struct mg_str method, uri, query, proto; // Request/response line
|
||||||
struct mg_http_header headers[MG_MAX_HTTP_HEADERS]; // Headers
|
struct mg_http_header headers[MG_MAX_HTTP_HEADERS]; // Headers
|
||||||
struct mg_str body; // Body
|
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()
|
||||||
|
struct mg_http_serve_opts {
|
||||||
|
const char *root_dir; // Web root directory, must be non-NULL
|
||||||
|
const char *ssi_pattern; // SSI filename pattern, e.g. #.shtml
|
||||||
};
|
};
|
||||||
|
|
||||||
int mg_http_parse(const char *s, size_t len, struct mg_http_message *);
|
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);
|
int mg_http_get_request_len(const unsigned char *buf, size_t buf_len);
|
||||||
void mg_http_write_head(struct mg_connection *, int code, const char *fmt, ...);
|
|
||||||
void mg_http_printf_chunk(struct mg_connection *cnn, const char *fmt, ...);
|
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_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,
|
struct mg_connection *mg_http_listen(struct mg_mgr *, const char *url,
|
||||||
mg_event_handler_t fn, void *fn_data);
|
mg_event_handler_t fn, void *fn_data);
|
||||||
struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url,
|
struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url,
|
||||||
mg_event_handler_t fn, void *fn_data);
|
mg_event_handler_t fn, void *fn_data);
|
||||||
void mg_http_serve_dir(struct mg_connection *, struct mg_http_message *hm,
|
void mg_http_serve_dir(struct mg_connection *, struct mg_http_message *hm,
|
||||||
const char *path);
|
struct mg_http_serve_opts *);
|
||||||
void mg_http_serve_file(struct mg_connection *, struct mg_http_message *,
|
void mg_http_serve_file(struct mg_connection *, struct mg_http_message *,
|
||||||
const char *, const char *mime);
|
const char *, const char *mime, const char *headers);
|
||||||
void mg_http_reply(struct mg_connection *c, int code, const char *fmt, ...);
|
void mg_http_reply(struct mg_connection *, int status_code, const char *headers,
|
||||||
|
const char *body_fmt, ...);
|
||||||
struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name);
|
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);
|
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_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_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);
|
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);
|
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,
|
int mg_http_upload(struct mg_connection *, struct mg_http_message *hm,
|
||||||
|
|||||||
+7
-7
@@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#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) {
|
if (new_size == 0) {
|
||||||
free(io->buf);
|
free(io->buf);
|
||||||
io->buf = NULL;
|
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->buf = (unsigned char *) p;
|
||||||
io->size = new_size;
|
io->size = new_size;
|
||||||
} else {
|
} else {
|
||||||
|
ok = 0;
|
||||||
LOG(LL_ERROR,
|
LOG(LL_ERROR,
|
||||||
("%lu->%lu", (unsigned long) io->size, (unsigned long) new_size));
|
("%lu->%lu", (unsigned long) io->size, (unsigned long) new_size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_iobuf_init(struct mg_iobuf *io, size_t size) {
|
int mg_iobuf_init(struct mg_iobuf *io, size_t size) {
|
||||||
io->buf = NULL;
|
return mg_iobuf_resize(io, size);
|
||||||
io->len = io->size = 0;
|
|
||||||
if (size > 0) mg_iobuf_resize(io, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t mg_iobuf_append(struct mg_iobuf *io, const void *buf, size_t len,
|
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) {
|
void mg_iobuf_free(struct mg_iobuf *io) {
|
||||||
free(io->buf);
|
mg_iobuf_resize(io, 0);
|
||||||
mg_iobuf_init(io, 0);
|
|
||||||
}
|
}
|
||||||
+2
-2
@@ -7,8 +7,8 @@ struct mg_iobuf {
|
|||||||
size_t size, len;
|
size_t size, len;
|
||||||
};
|
};
|
||||||
|
|
||||||
void mg_iobuf_init(struct mg_iobuf *, size_t);
|
int mg_iobuf_init(struct mg_iobuf *, size_t);
|
||||||
void mg_iobuf_resize(struct mg_iobuf *, size_t);
|
int mg_iobuf_resize(struct mg_iobuf *, size_t);
|
||||||
void mg_iobuf_free(struct mg_iobuf *);
|
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_append(struct mg_iobuf *, const void *, size_t, size_t);
|
||||||
size_t mg_iobuf_delete(struct mg_iobuf *, size_t);
|
size_t mg_iobuf_delete(struct mg_iobuf *, size_t);
|
||||||
+1
-2
@@ -1,5 +1,5 @@
|
|||||||
// Copyright (c) 2004-2013 Sergey Lyubka
|
// Copyright (c) 2004-2013 Sergey Lyubka
|
||||||
// Copyright (c) 2013-2020 Cesanta Software Limited
|
// Copyright (c) 2013-2021 Cesanta Software Limited
|
||||||
// All rights reserved
|
// All rights reserved
|
||||||
//
|
//
|
||||||
// This software is dual-licensed: you can redistribute it and/or modify
|
// 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
|
// Alternatively, you can license this software under a commercial
|
||||||
// license, as set out in <https://www.cesanta.com/license>.
|
// license, as set out in <https://www.cesanta.com/license>.
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ static void (*s_fn)(const void *, int, void *) = mg_log_stdout;
|
|||||||
static void *s_fn_param = NULL;
|
static void *s_fn_param = NULL;
|
||||||
|
|
||||||
void mg_log_set(const char *spec) {
|
void mg_log_set(const char *spec) {
|
||||||
LOG(LL_INFO, ("Setting log level to %s", spec));
|
LOG(LL_DEBUG, ("Setting log level to %s", spec));
|
||||||
s_spec = spec;
|
s_spec = spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-7
@@ -87,7 +87,7 @@ int mg_send(struct mg_connection *c, const void *buf, size_t len) {
|
|||||||
err_t err = udp_send(pcb, p);
|
err_t err = udp_send(pcb, p);
|
||||||
pbuf_free(p);
|
pbuf_free(p);
|
||||||
LOG(LL_DEBUG,
|
LOG(LL_DEBUG,
|
||||||
("%p UDP %d bytes -> %x:%hu, err %ld", c->fd, (int) len,
|
("%lu UDP %d bytes -> %x:%hu, err %ld", c->id, (int) len,
|
||||||
(unsigned) *(uint32_t *) &pcb->remote_ip, pcb->remote_port, err));
|
(unsigned) *(uint32_t *) &pcb->remote_ip, pcb->remote_port, err));
|
||||||
if (err != ERR_OK) mg_error(c, "%p err %d", c->fd, err);
|
if (err != ERR_OK) mg_error(c, "%p err %d", c->fd, err);
|
||||||
} else {
|
} else {
|
||||||
@@ -146,7 +146,7 @@ struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
|
|||||||
tcp_bind(c->fd, IP_ADDR_ANY, 0);
|
tcp_bind(c->fd, IP_ADDR_ANY, 0);
|
||||||
tcp_nagle_disable((struct tcp_pcb *) c->fd);
|
tcp_nagle_disable((struct tcp_pcb *) c->fd);
|
||||||
}
|
}
|
||||||
LOG(LL_DEBUG, ("%p -> %s %s", c->fd, url, c->is_udp ? "UDP" : "TCP"));
|
LOG(LL_DEBUG, ("%lu -> %s %s", c->id, url, c->is_udp ? "UDP" : "TCP"));
|
||||||
mg_resolve(mgr, c, &host, mgr->dnstimeout);
|
mg_resolve(mgr, c, &host, mgr->dnstimeout);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@@ -156,7 +156,7 @@ void mg_connect_resolved(struct mg_connection *c) {
|
|||||||
ip_addr_t ipaddr;
|
ip_addr_t ipaddr;
|
||||||
memcpy(&ipaddr, &c->peer.ip, sizeof(ipaddr));
|
memcpy(&ipaddr, &c->peer.ip, sizeof(ipaddr));
|
||||||
mg_call(c, MG_EV_RESOLVE, NULL);
|
mg_call(c, MG_EV_RESOLVE, NULL);
|
||||||
LOG(LL_DEBUG, ("%p resolved to %s", c->fd, mg_straddr(c, buf, sizeof(buf))));
|
LOG(LL_DEBUG, ("%lu resolved to %s", c->id, mg_straddr(c, buf, sizeof(buf))));
|
||||||
err_t err = c->is_udp ? udp_connect((struct udp_pcb *) c->fd, &ipaddr,
|
err_t err = c->is_udp ? udp_connect((struct udp_pcb *) c->fd, &ipaddr,
|
||||||
mg_ntohs(c->peer.port))
|
mg_ntohs(c->peer.port))
|
||||||
: tcp_connect((struct tcp_pcb *) c->fd, &ipaddr,
|
: tcp_connect((struct tcp_pcb *) c->fd, &ipaddr,
|
||||||
@@ -194,8 +194,4 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
|
|||||||
mg_usleep(200 * 1000);
|
mg_usleep(200 * 1000);
|
||||||
mg_timer_poll(mg_millis());
|
mg_timer_poll(mg_millis());
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_mgr_init(struct mg_mgr *mgr) {
|
|
||||||
(void) mgr;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "md5.h"
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "md5.h"
|
||||||
|
|
||||||
#if MG_ENABLE_MD5
|
#if MG_ENABLE_MD5
|
||||||
#if !defined(BYTE_ORDER) && defined(__BYTE_ORDER)
|
#if !defined(BYTE_ORDER) && defined(__BYTE_ORDER)
|
||||||
@@ -50,7 +50,7 @@ void mg_md5_init(mg_md5_ctx *ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void mg_md5_transform(uint32_t buf[4], uint32_t const in[16]) {
|
static void mg_md5_transform(uint32_t buf[4], uint32_t const in[16]) {
|
||||||
register uint32_t a, b, c, d;
|
uint32_t a, b, c, d;
|
||||||
|
|
||||||
a = buf[0];
|
a = buf[0];
|
||||||
b = buf[1];
|
b = buf[1];
|
||||||
|
|||||||
+92
-79
@@ -1,27 +1,12 @@
|
|||||||
#include "mqtt.h"
|
|
||||||
#include "arch.h"
|
#include "arch.h"
|
||||||
#include "base64.h"
|
#include "base64.h"
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "mqtt.h"
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
#include "url.h"
|
#include "url.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define MQTT_CMD_CONNECT 1
|
|
||||||
#define MQTT_CMD_CONNACK 2
|
|
||||||
#define MQTT_CMD_PUBLISH 3
|
|
||||||
#define MQTT_CMD_PUBACK 4
|
|
||||||
#define MQTT_CMD_PUBREC 5
|
|
||||||
#define MQTT_CMD_PUBREL 6
|
|
||||||
#define MQTT_CMD_PUBCOMP 7
|
|
||||||
#define MQTT_CMD_SUBSCRIBE 8
|
|
||||||
#define MQTT_CMD_SUBACK 9
|
|
||||||
#define MQTT_CMD_UNSUBSCRIBE 10
|
|
||||||
#define MQTT_CMD_UNSUBACK 11
|
|
||||||
#define MQTT_CMD_PINGREQ 12
|
|
||||||
#define MQTT_CMD_PINGRESP 13
|
|
||||||
#define MQTT_CMD_DISCONNECT 14
|
|
||||||
|
|
||||||
#define MQTT_CLEAN_SESSION 0x02
|
#define MQTT_CLEAN_SESSION 0x02
|
||||||
#define MQTT_HAS_WILL 0x04
|
#define MQTT_HAS_WILL 0x04
|
||||||
#define MQTT_WILL_RETAIN 0x20
|
#define MQTT_WILL_RETAIN 0x20
|
||||||
@@ -29,20 +14,11 @@
|
|||||||
#define MQTT_HAS_USER_NAME 0x80
|
#define MQTT_HAS_USER_NAME 0x80
|
||||||
#define MQTT_GET_WILL_QOS(flags) (((flags) &0x18) >> 3)
|
#define MQTT_GET_WILL_QOS(flags) (((flags) &0x18) >> 3)
|
||||||
#define MQTT_SET_WILL_QOS(flags, qos) (flags) = ((flags) & ~0x18) | ((qos) << 3)
|
#define MQTT_SET_WILL_QOS(flags, qos) (flags) = ((flags) & ~0x18) | ((qos) << 3)
|
||||||
#define MQTT_QOS(qos) ((qos) << 1)
|
|
||||||
#define MQTT_GET_QOS(flags) (((flags) &0x6) >> 1)
|
|
||||||
#define MQTT_SET_QOS(flags, qos) (flags) = ((flags) & ~0x6) | ((qos) << 1)
|
|
||||||
|
|
||||||
enum { MQTT_OK, MQTT_INCOMPLETE, MQTT_MALFORMED };
|
enum { MQTT_OK, MQTT_INCOMPLETE, MQTT_MALFORMED };
|
||||||
|
|
||||||
struct mqtt_message {
|
void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags,
|
||||||
size_t len, topic_offset, topic_len, data_offset, data_len;
|
uint32_t len) {
|
||||||
uint16_t id;
|
|
||||||
uint8_t cmd, qos, connack_ret_code;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void mqtt_send_header(struct mg_connection *c, uint8_t cmd,
|
|
||||||
uint8_t flags, uint32_t len) {
|
|
||||||
uint8_t buf[1 + sizeof(len)], *vlen = &buf[1];
|
uint8_t buf[1 + sizeof(len)], *vlen = &buf[1];
|
||||||
buf[0] = (cmd << 4) | flags;
|
buf[0] = (cmd << 4) | flags;
|
||||||
do {
|
do {
|
||||||
@@ -82,7 +58,7 @@ static void mqtt_login(struct mg_connection *c, const char *url,
|
|||||||
if (opts->will_retain) flags |= MQTT_WILL_RETAIN;
|
if (opts->will_retain) flags |= MQTT_WILL_RETAIN;
|
||||||
total_len += (uint32_t) opts->client_id.len;
|
total_len += (uint32_t) opts->client_id.len;
|
||||||
|
|
||||||
mqtt_send_header(c, MQTT_CMD_CONNECT, 0, total_len);
|
mg_mqtt_send_header(c, MQTT_CMD_CONNECT, 0, total_len);
|
||||||
mg_send(c, "\00\04MQTT\04", 7);
|
mg_send(c, "\00\04MQTT\04", 7);
|
||||||
mg_send(c, &flags, 1);
|
mg_send(c, &flags, 1);
|
||||||
// keepalive == 0 means "do not disconnect us!"
|
// keepalive == 0 means "do not disconnect us!"
|
||||||
@@ -109,10 +85,10 @@ void mg_mqtt_pub(struct mg_connection *c, struct mg_str *topic,
|
|||||||
struct mg_str *data) {
|
struct mg_str *data) {
|
||||||
uint8_t flags = MQTT_QOS(1);
|
uint8_t flags = MQTT_QOS(1);
|
||||||
uint32_t total_len = 2 + (uint32_t) topic->len + (uint32_t) data->len;
|
uint32_t total_len = 2 + (uint32_t) topic->len + (uint32_t) data->len;
|
||||||
LOG(LL_DEBUG, ("%p [%.*s] -> [%.*s]", c->fd, (int) topic->len,
|
LOG(LL_DEBUG, ("%lu [%.*s] -> [%.*s]", c->id, (int) topic->len,
|
||||||
(char *) topic->ptr, (int) data->len, (char *) data->ptr));
|
(char *) topic->ptr, (int) data->len, (char *) data->ptr));
|
||||||
if (MQTT_GET_QOS(flags) > 0) total_len += 2;
|
if (MQTT_GET_QOS(flags) > 0) total_len += 2;
|
||||||
mqtt_send_header(c, MQTT_CMD_PUBLISH, flags, total_len);
|
mg_mqtt_send_header(c, MQTT_CMD_PUBLISH, flags, total_len);
|
||||||
mg_send_u16(c, mg_htons((uint16_t) topic->len));
|
mg_send_u16(c, mg_htons((uint16_t) topic->len));
|
||||||
mg_send(c, topic->ptr, topic->len);
|
mg_send(c, topic->ptr, topic->len);
|
||||||
if (MQTT_GET_QOS(flags) > 0) {
|
if (MQTT_GET_QOS(flags) > 0) {
|
||||||
@@ -127,7 +103,8 @@ void mg_mqtt_sub(struct mg_connection *c, struct mg_str *topic) {
|
|||||||
static uint16_t s_id;
|
static uint16_t s_id;
|
||||||
uint8_t qos = 1;
|
uint8_t qos = 1;
|
||||||
uint32_t total_len = 2 + (uint32_t) topic->len + 2 + 1;
|
uint32_t total_len = 2 + (uint32_t) topic->len + 2 + 1;
|
||||||
mqtt_send_header(c, MQTT_CMD_SUBSCRIBE, (uint8_t) MQTT_QOS(qos), total_len);
|
mg_mqtt_send_header(c, MQTT_CMD_SUBSCRIBE, (uint8_t) MQTT_QOS(qos),
|
||||||
|
total_len);
|
||||||
if (++s_id == 0) ++s_id;
|
if (++s_id == 0) ++s_id;
|
||||||
mg_send_u16(c, mg_htons(s_id));
|
mg_send_u16(c, mg_htons(s_id));
|
||||||
mg_send_u16(c, mg_htons((uint16_t) topic->len));
|
mg_send_u16(c, mg_htons((uint16_t) topic->len));
|
||||||
@@ -135,32 +112,33 @@ void mg_mqtt_sub(struct mg_connection *c, struct mg_str *topic) {
|
|||||||
mg_send(c, &qos, sizeof(qos));
|
mg_send(c, &qos, sizeof(qos));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse(const uint8_t *in, size_t inlen, struct mqtt_message *m) {
|
int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m) {
|
||||||
uint8_t lc = 0, *p, *end;
|
uint8_t lc = 0, *p, *end;
|
||||||
uint32_t len = 0, len_len = 0;
|
uint32_t n = 0, len_len = 0;
|
||||||
|
|
||||||
if (inlen < 2) return MQTT_INCOMPLETE;
|
memset(m, 0, sizeof(*m));
|
||||||
m->cmd = in[0] >> 4;
|
m->dgram.ptr = (char *) buf;
|
||||||
m->qos = (in[0] >> 1) & 3;
|
if (len < 2) return MQTT_INCOMPLETE;
|
||||||
|
m->cmd = buf[0] >> 4;
|
||||||
|
m->qos = (buf[0] >> 1) & 3;
|
||||||
|
|
||||||
len = len_len = 0;
|
n = len_len = 0;
|
||||||
p = (uint8_t *) in + 1;
|
p = (uint8_t *) buf + 1;
|
||||||
while ((size_t)(p - in) < inlen) {
|
while ((size_t)(p - buf) < len) {
|
||||||
lc = *((uint8_t *) p++);
|
lc = *((uint8_t *) p++);
|
||||||
len += (lc & 0x7f) << 7 * len_len;
|
n += (lc & 0x7f) << 7 * len_len;
|
||||||
len_len++;
|
len_len++;
|
||||||
if (!(lc & 0x80)) break;
|
if (!(lc & 0x80)) break;
|
||||||
if (len_len >= 4) return MQTT_MALFORMED;
|
if (len_len >= 4) return MQTT_MALFORMED;
|
||||||
}
|
}
|
||||||
|
end = p + n;
|
||||||
end = p + len;
|
if (lc & 0x80 || end > buf + len) return MQTT_INCOMPLETE;
|
||||||
if (lc & 0x80 || end > in + inlen) return MQTT_INCOMPLETE;
|
m->dgram.len = end - buf;
|
||||||
m->len = (int) (end - in);
|
|
||||||
|
|
||||||
switch (m->cmd) {
|
switch (m->cmd) {
|
||||||
case MQTT_CMD_CONNACK:
|
case MQTT_CMD_CONNACK:
|
||||||
if (end - p < 2) return MQTT_MALFORMED;
|
if (end - p < 2) return MQTT_MALFORMED;
|
||||||
m->connack_ret_code = p[1];
|
m->ack = p[1];
|
||||||
break;
|
break;
|
||||||
case MQTT_CMD_PUBACK:
|
case MQTT_CMD_PUBACK:
|
||||||
case MQTT_CMD_PUBREC:
|
case MQTT_CMD_PUBREC:
|
||||||
@@ -170,11 +148,17 @@ static int parse(const uint8_t *in, size_t inlen, struct mqtt_message *m) {
|
|||||||
if (p + 2 > end) return MQTT_MALFORMED;
|
if (p + 2 > end) return MQTT_MALFORMED;
|
||||||
m->id = (p[0] << 8) | p[1];
|
m->id = (p[0] << 8) | p[1];
|
||||||
break;
|
break;
|
||||||
|
case MQTT_CMD_SUBSCRIBE: {
|
||||||
|
if (p + 2 > end) return MQTT_MALFORMED;
|
||||||
|
m->id = (p[0] << 8) | p[1];
|
||||||
|
p += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case MQTT_CMD_PUBLISH: {
|
case MQTT_CMD_PUBLISH: {
|
||||||
if (p + 2 > end) return MQTT_MALFORMED;
|
if (p + 2 > end) return MQTT_MALFORMED;
|
||||||
m->topic_len = (p[0] << 8) | p[1];
|
m->topic.len = (p[0] << 8) | p[1];
|
||||||
m->topic_offset = p + 2 - in;
|
m->topic.ptr = (char *) p + 2;
|
||||||
p += 2 + m->topic_len;
|
p += 2 + m->topic.len;
|
||||||
if (p > end) return MQTT_MALFORMED;
|
if (p > end) return MQTT_MALFORMED;
|
||||||
if (m->qos > 0) {
|
if (m->qos > 0) {
|
||||||
if (p + 2 > end) return MQTT_MALFORMED;
|
if (p + 2 > end) return MQTT_MALFORMED;
|
||||||
@@ -182,8 +166,9 @@ static int parse(const uint8_t *in, size_t inlen, struct mqtt_message *m) {
|
|||||||
p += 2;
|
p += 2;
|
||||||
}
|
}
|
||||||
if (p > end) return MQTT_MALFORMED;
|
if (p > end) return MQTT_MALFORMED;
|
||||||
m->data_offset = p - in;
|
m->data.ptr = (char *) p;
|
||||||
m->data_len = end - p;
|
m->data.len = end - p;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -191,55 +176,64 @@ static int parse(const uint8_t *in, size_t inlen, struct mqtt_message *m) {
|
|||||||
return MQTT_OK;
|
return MQTT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mg_mqtt_parse(const unsigned char *s, int n, struct mg_mqtt_message *mm) {
|
static int mg_mqtt_next_topic(struct mg_mqtt_message *msg, struct mg_str *topic,
|
||||||
struct mqtt_message m;
|
uint8_t *qos, int pos) {
|
||||||
int rc = parse(s, n, &m);
|
unsigned char *buf = (unsigned char *) msg->dgram.ptr + pos;
|
||||||
if (rc == MQTT_OK) {
|
int new_pos;
|
||||||
mm->topic.ptr = (char *) s + m.topic_offset;
|
if ((size_t) pos >= msg->dgram.len) return -1;
|
||||||
mm->topic.len = m.topic_len;
|
|
||||||
mm->data.ptr = (char *) s + m.data_offset;
|
topic->len = buf[0] << 8 | buf[1];
|
||||||
mm->data.len = m.data_len;
|
topic->ptr = (char *) buf + 2;
|
||||||
}
|
new_pos = pos + 2 + topic->len + (qos == NULL ? 0 : 1);
|
||||||
return rc;
|
if ((size_t) new_pos > msg->dgram.len) return -1;
|
||||||
|
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,
|
static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data,
|
||||||
void *fn_data) {
|
void *fn_data) {
|
||||||
if (ev == MG_EV_READ) {
|
if (ev == MG_EV_READ) {
|
||||||
struct mqtt_message m;
|
|
||||||
memset(&m, 0, sizeof(m));
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int rc = parse(c->recv.buf, c->recv.len, &m);
|
struct mg_mqtt_message mm;
|
||||||
|
int rc = mg_mqtt_parse(c->recv.buf, c->recv.len, &mm);
|
||||||
if (rc == MQTT_MALFORMED) {
|
if (rc == MQTT_MALFORMED) {
|
||||||
LOG(LL_ERROR, ("%p MQTT malformed message", c->fd));
|
LOG(LL_ERROR, ("%lu MQTT malformed message", c->id));
|
||||||
c->is_closing = 1;
|
c->is_closing = 1;
|
||||||
break;
|
break;
|
||||||
} else if (rc == MQTT_OK) {
|
} else if (rc == MQTT_OK) {
|
||||||
LOG(LL_VERBOSE_DEBUG,
|
LOG(LL_VERBOSE_DEBUG,
|
||||||
("%p MQTT CMD %d len %d [%.*s]", c->fd, m.cmd, (int) m.len,
|
("%p MQTT CMD %d len %d [%.*s]", c->fd, mm.cmd, (int) mm.dgram.len,
|
||||||
(int) m.data_len, (char *) c->recv.buf + m.data_offset));
|
(int) mm.data.len, mm.data.ptr));
|
||||||
switch (m.cmd) {
|
switch (mm.cmd) {
|
||||||
case MQTT_CMD_CONNACK:
|
case MQTT_CMD_CONNACK:
|
||||||
mg_call(c, MG_EV_MQTT_OPEN, &m.connack_ret_code);
|
mg_call(c, MG_EV_MQTT_OPEN, &mm.ack);
|
||||||
if (m.connack_ret_code == 0) {
|
if (mm.ack == 0) {
|
||||||
LOG(LL_INFO, ("%p Connected", c->fd));
|
LOG(LL_INFO, ("%lu Connected", c->id));
|
||||||
} else {
|
} else {
|
||||||
LOG(LL_ERROR,
|
LOG(LL_ERROR, ("%lu MQTT auth failed, code %d", c->id, mm.ack));
|
||||||
("%p MQTT auth failed, code %d", c->fd, m.connack_ret_code));
|
|
||||||
c->is_closing = 1;
|
c->is_closing = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MQTT_CMD_PUBLISH: {
|
case MQTT_CMD_PUBLISH: {
|
||||||
struct mg_mqtt_message evd = {
|
LOG(LL_DEBUG, ("%lu [%.*s] -> [%.*s]", c->id, (int) mm.topic.len,
|
||||||
{(char *) c->recv.buf + m.topic_offset, m.topic_len},
|
mm.topic.ptr, (int) mm.data.len, mm.data.ptr));
|
||||||
{(char *) c->recv.buf + m.data_offset, m.data_len}};
|
mg_call(c, MG_EV_MQTT_MSG, &mm);
|
||||||
LOG(LL_DEBUG, ("%p [%.*s] -> [%.*s]", c->fd, (int) evd.topic.len,
|
|
||||||
evd.topic.ptr, (int) evd.data.len, evd.data.ptr));
|
|
||||||
mg_call(c, MG_EV_MQTT_MSG, &evd);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mg_iobuf_delete(&c->recv, m.len);
|
mg_call(c, MG_EV_MQTT_CMD, &mm);
|
||||||
|
mg_iobuf_delete(&c->recv, mm.dgram.len);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -249,6 +243,18 @@ static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data,
|
|||||||
(void) fn_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_connection *mg_mqtt_connect(struct mg_mgr *mgr, const char *url,
|
||||||
struct mg_mqtt_opts *opts,
|
struct mg_mqtt_opts *opts,
|
||||||
mg_event_handler_t fn, void *fn_data) {
|
mg_event_handler_t fn, void *fn_data) {
|
||||||
@@ -261,3 +267,10 @@ struct mg_connection *mg_mqtt_connect(struct mg_mgr *mgr, const char *url,
|
|||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct mg_connection *mg_mqtt_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 = mqtt_cb, c->pfn_data = mgr;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
+38
-3
@@ -3,6 +3,25 @@
|
|||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
|
|
||||||
|
#define MQTT_CMD_CONNECT 1
|
||||||
|
#define MQTT_CMD_CONNACK 2
|
||||||
|
#define MQTT_CMD_PUBLISH 3
|
||||||
|
#define MQTT_CMD_PUBACK 4
|
||||||
|
#define MQTT_CMD_PUBREC 5
|
||||||
|
#define MQTT_CMD_PUBREL 6
|
||||||
|
#define MQTT_CMD_PUBCOMP 7
|
||||||
|
#define MQTT_CMD_SUBSCRIBE 8
|
||||||
|
#define MQTT_CMD_SUBACK 9
|
||||||
|
#define MQTT_CMD_UNSUBSCRIBE 10
|
||||||
|
#define MQTT_CMD_UNSUBACK 11
|
||||||
|
#define MQTT_CMD_PINGREQ 12
|
||||||
|
#define MQTT_CMD_PINGRESP 13
|
||||||
|
#define MQTT_CMD_DISCONNECT 14
|
||||||
|
|
||||||
|
#define MQTT_QOS(qos) ((qos) << 1)
|
||||||
|
#define MQTT_GET_QOS(flags) (((flags) &0x6) >> 1)
|
||||||
|
#define MQTT_SET_QOS(flags, qos) (flags) = ((flags) & ~0x6) | ((qos) << 1)
|
||||||
|
|
||||||
struct mg_mqtt_opts {
|
struct mg_mqtt_opts {
|
||||||
struct mg_str client_id;
|
struct mg_str client_id;
|
||||||
struct mg_str will_topic;
|
struct mg_str will_topic;
|
||||||
@@ -14,14 +33,30 @@ struct mg_mqtt_opts {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct mg_mqtt_message {
|
struct mg_mqtt_message {
|
||||||
struct mg_str topic;
|
struct mg_str topic; // Parsed topic
|
||||||
struct mg_str data;
|
struct mg_str data; // Parsed message
|
||||||
|
struct mg_str dgram; // Whole MQTT datagram, including headers
|
||||||
|
uint16_t id; // Set for PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, PUBLISH
|
||||||
|
uint8_t cmd; // MQTT command, one of MQTT_CMD_*
|
||||||
|
uint8_t qos; // Quality of service
|
||||||
|
uint8_t ack; // Connack return code. 0 - success
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mg_connection *mg_mqtt_connect(struct mg_mgr *, const char *url,
|
struct mg_connection *mg_mqtt_connect(struct mg_mgr *, const char *url,
|
||||||
struct mg_mqtt_opts *opts,
|
struct mg_mqtt_opts *opts,
|
||||||
mg_event_handler_t fn, void *fn_data);
|
mg_event_handler_t fn, void *fn_data);
|
||||||
|
struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url,
|
||||||
|
mg_event_handler_t fn, void *fn_data);
|
||||||
void mg_mqtt_pub(struct mg_connection *, struct mg_str *topic,
|
void mg_mqtt_pub(struct mg_connection *, struct mg_str *topic,
|
||||||
struct mg_str *data);
|
struct mg_str *data);
|
||||||
void mg_mqtt_sub(struct mg_connection *, struct mg_str *topic);
|
void mg_mqtt_sub(struct mg_connection *, struct mg_str *topic);
|
||||||
int mg_mqtt_parse(const unsigned char *buf, int len, struct mg_mqtt_message *m);
|
int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m);
|
||||||
|
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 *);
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "net.h"
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "net.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
int mg_vprintf(struct mg_connection *c, const char *fmt, va_list ap) {
|
int mg_vprintf(struct mg_connection *c, const char *fmt, va_list ap) {
|
||||||
@@ -20,8 +20,120 @@ int mg_printf(struct mg_connection *c, const char *fmt, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char *mg_straddr(struct mg_connection *c, char *buf, size_t len) {
|
char *mg_straddr(struct mg_connection *c, char *buf, size_t len) {
|
||||||
unsigned char *p = (unsigned char *) &c->peer.ip;
|
char tmp[100];
|
||||||
snprintf(buf, len, "%d.%d.%d.%d:%hu", p[0], p[1], p[2], p[3],
|
const char *fmt = c->peer.is_ip6 ? "[%s]:%d" : "%s:%d";
|
||||||
mg_ntohs(c->peer.port));
|
mg_ntoa(&c->peer, tmp, sizeof(tmp));
|
||||||
|
snprintf(buf, len, fmt, tmp, (int) mg_ntohs(c->peer.port));
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *mg_ntoa(const struct mg_addr *addr, char *buf, size_t len) {
|
||||||
|
if (addr->is_ip6) {
|
||||||
|
uint16_t *p = (uint16_t *) addr->ip6;
|
||||||
|
snprintf(buf, len, "%x:%x:%x:%x:%x:%x:%x:%x", mg_htons(p[0]),
|
||||||
|
mg_htons(p[1]), mg_htons(p[2]), mg_htons(p[3]), mg_htons(p[4]),
|
||||||
|
mg_htons(p[5]), mg_htons(p[6]), mg_htons(p[7]));
|
||||||
|
} else {
|
||||||
|
uint8_t p[4];
|
||||||
|
memcpy(p, &addr->ip, sizeof(p));
|
||||||
|
snprintf(buf, len, "%d.%d.%d.%d", (int) p[0], (int) p[1], (int) p[2],
|
||||||
|
(int) p[3]);
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mg_atonl(struct mg_str str, struct mg_addr *addr) {
|
||||||
|
if (mg_vcasecmp(&str, "localhost") != 0) return false;
|
||||||
|
addr->ip = mg_htonl(0x7f000001);
|
||||||
|
addr->is_ip6 = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mg_aton4(struct mg_str str, struct mg_addr *addr) {
|
||||||
|
uint8_t data[4] = {0, 0, 0, 0};
|
||||||
|
size_t i, num_dots = 0;
|
||||||
|
for (i = 0; i < str.len; i++) {
|
||||||
|
if (str.ptr[i] >= '0' && str.ptr[i] <= '9') {
|
||||||
|
int octet = data[num_dots] * 10 + (str.ptr[i] - '0');
|
||||||
|
if (octet > 255) return false;
|
||||||
|
data[num_dots] = octet;
|
||||||
|
} else if (str.ptr[i] == '.') {
|
||||||
|
if (num_dots >= 3 || i == 0 || str.ptr[i - 1] == '.') return false;
|
||||||
|
num_dots++;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (num_dots != 3 || str.ptr[i - 1] == '.') return false;
|
||||||
|
memcpy(&addr->ip, data, sizeof(data));
|
||||||
|
addr->is_ip6 = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
|
||||||
|
size_t i, j = 0, n = 0, dc = 42;
|
||||||
|
for (i = 0; i < str.len; i++) {
|
||||||
|
if ((str.ptr[i] >= '0' && str.ptr[i] <= '9') ||
|
||||||
|
(str.ptr[i] >= 'a' && str.ptr[i] <= 'f') ||
|
||||||
|
(str.ptr[i] >= 'A' && str.ptr[i] <= 'F')) {
|
||||||
|
unsigned long val;
|
||||||
|
if (i > j + 3) return false;
|
||||||
|
// LOG(LL_DEBUG, ("%zu %zu [%.*s]", i, j, (int) (i - j + 1),
|
||||||
|
// &str.ptr[j]));
|
||||||
|
val = mg_unhexn(&str.ptr[j], i - j + 1);
|
||||||
|
addr->ip6[n] = (uint8_t)((val >> 8) & 255);
|
||||||
|
addr->ip6[n + 1] = (uint8_t)(val & 255);
|
||||||
|
} else if (str.ptr[i] == ':') {
|
||||||
|
j = i + 1;
|
||||||
|
if (i > 0 && str.ptr[i - 1] == ':') {
|
||||||
|
dc = n; // Double colon
|
||||||
|
if (i > 1 && str.ptr[i - 2] == ':') return false;
|
||||||
|
} else if (i > 0) {
|
||||||
|
n += 2;
|
||||||
|
}
|
||||||
|
if (n > 14) return false;
|
||||||
|
addr->ip6[n] = addr->ip6[n + 1] = 0; // For trailing ::
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (n < 14 && dc == 42) return false;
|
||||||
|
if (n < 14) {
|
||||||
|
memmove(&addr->ip6[dc + (14 - n)], &addr->ip6[dc], n - dc + 2);
|
||||||
|
memset(&addr->ip6[dc], 0, 14 - n);
|
||||||
|
}
|
||||||
|
addr->is_ip6 = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_aton(struct mg_str str, struct mg_addr *addr) {
|
||||||
|
// LOG(LL_INFO, ("[%.*s]", (int) str.len, str.ptr));
|
||||||
|
return mg_atonl(str, addr) || mg_aton4(str, addr) || mg_aton6(str, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mg_mgr_free(struct mg_mgr *mgr) {
|
||||||
|
struct mg_connection *c;
|
||||||
|
for (c = mgr->conns; c != NULL; c = c->next) c->is_closing = 1;
|
||||||
|
mg_mgr_poll(mgr, 0);
|
||||||
|
#if MG_ARCH == MG_ARCH_FREERTOS
|
||||||
|
FreeRTOS_DeleteSocketSet(mgr->ss);
|
||||||
|
#endif
|
||||||
|
LOG(LL_INFO, ("All connections closed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mg_mgr_init(struct mg_mgr *mgr) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
WSADATA data;
|
||||||
|
WSAStartup(MAKEWORD(2, 2), &data);
|
||||||
|
#elif MG_ARCH == MG_ARCH_FREERTOS
|
||||||
|
mgr->ss = FreeRTOS_CreateSocketSet();
|
||||||
|
#elif defined(__unix) || defined(__unix__) || defined(__APPLE__)
|
||||||
|
// Ignore SIGPIPE signal, so if client cancels the request, it
|
||||||
|
// won't kill the whole process.
|
||||||
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
#endif
|
||||||
|
memset(mgr, 0, sizeof(*mgr));
|
||||||
|
mgr->dnstimeout = 3000;
|
||||||
|
mgr->dns4.url = "udp://8.8.8.8:53";
|
||||||
|
mgr->dns6.url = "udp://[2001:4860:4860::8888]:53";
|
||||||
|
}
|
||||||
@@ -3,20 +3,30 @@
|
|||||||
#include "arch.h"
|
#include "arch.h"
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "iobuf.h"
|
#include "iobuf.h"
|
||||||
|
#include "str.h"
|
||||||
|
|
||||||
struct mg_mgr {
|
struct mg_dns {
|
||||||
struct mg_connection *conns; // List of active connections
|
const char *url; // DNS server URL
|
||||||
struct mg_connection *dnsc; // DNS resolver connection
|
struct mg_connection *c; // DNS server connection
|
||||||
const char *dnsserver; // DNS server URL
|
|
||||||
int dnstimeout; // DNS resolve timeout in milliseconds
|
|
||||||
#if MG_ARCH == MG_ARCH_FREERTOS
|
|
||||||
SocketSet_t ss; // NOTE(lsm): referenced from socket struct
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mg_addr {
|
struct mg_addr {
|
||||||
uint16_t port; // TCP or UDP port in network byte order
|
uint16_t port; // TCP or UDP port in network byte order
|
||||||
uint32_t ip; // IP address in network byte order
|
uint32_t ip; // IP address in network byte order
|
||||||
|
uint8_t ip6[16]; // IPv6 address
|
||||||
|
bool is_ip6; // True when address is IPv6 address
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mg_mgr {
|
||||||
|
struct mg_connection *conns; // List of active connections
|
||||||
|
struct mg_dns dns4; // DNS for IPv4
|
||||||
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mg_connection {
|
struct mg_connection {
|
||||||
@@ -24,13 +34,14 @@ struct mg_connection {
|
|||||||
struct mg_mgr *mgr; // Our container
|
struct mg_mgr *mgr; // Our container
|
||||||
struct mg_addr peer; // Remote peer address
|
struct mg_addr peer; // Remote peer address
|
||||||
void *fd; // Connected socket, or LWIP data
|
void *fd; // Connected socket, or LWIP data
|
||||||
|
unsigned long id; // Auto-incrementing unique connection ID
|
||||||
struct mg_iobuf recv; // Incoming data
|
struct mg_iobuf recv; // Incoming data
|
||||||
struct mg_iobuf send; // Outgoing data
|
struct mg_iobuf send; // Outgoing data
|
||||||
mg_event_handler_t fn; // User-specified event handler function
|
mg_event_handler_t fn; // User-specified event handler function
|
||||||
void *fn_data; // User-speficied function parameter
|
void *fn_data; // User-speficied function parameter
|
||||||
mg_event_handler_t pfn; // Protocol-specific handler function
|
mg_event_handler_t pfn; // Protocol-specific handler function
|
||||||
void *pfn_data; // Protocol-specific function parameter
|
void *pfn_data; // Protocol-specific function parameter
|
||||||
char label[32]; // Arbitrary label
|
char label[50]; // Arbitrary label
|
||||||
void *tls; // TLS specific data
|
void *tls; // TLS specific data
|
||||||
unsigned is_listening : 1; // Listening connection
|
unsigned is_listening : 1; // Listening connection
|
||||||
unsigned is_client : 1; // Outbound (client) connection
|
unsigned is_client : 1; // Outbound (client) connection
|
||||||
@@ -61,3 +72,5 @@ int mg_printf(struct mg_connection *, const char *fmt, ...);
|
|||||||
int mg_vprintf(struct mg_connection *, const char *fmt, va_list ap);
|
int mg_vprintf(struct mg_connection *, const char *fmt, va_list ap);
|
||||||
char *mg_straddr(struct mg_connection *, char *, size_t);
|
char *mg_straddr(struct mg_connection *, char *, size_t);
|
||||||
bool mg_socketpair(int *s1, int *s2);
|
bool mg_socketpair(int *s1, int *s2);
|
||||||
|
bool mg_aton(struct mg_str str, struct mg_addr *addr);
|
||||||
|
char *mg_ntoa(const struct mg_addr *addr, char *buf, size_t len);
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
#include "sntp.h"
|
|
||||||
#include "arch.h"
|
#include "arch.h"
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "sntp.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define SNTP_INTERVAL_SEC (3600)
|
#define SNTP_INTERVAL_SEC (3600)
|
||||||
@@ -49,7 +49,7 @@ static void sntp_cb(struct mg_connection *c, int ev, void *evd, void *fnd) {
|
|||||||
|
|
||||||
void mg_sntp_send(struct mg_connection *c, unsigned long utc) {
|
void mg_sntp_send(struct mg_connection *c, unsigned long utc) {
|
||||||
if (c->is_resolving) {
|
if (c->is_resolving) {
|
||||||
LOG(LL_ERROR, ("%p wait until resolved", c->fd));
|
LOG(LL_ERROR, ("%lu wait until resolved", c->id));
|
||||||
} else if (utc > s_sntmp_next) {
|
} else if (utc > s_sntmp_next) {
|
||||||
uint8_t buf[48] = {0};
|
uint8_t buf[48] = {0};
|
||||||
s_sntmp_next = utc + SNTP_INTERVAL_SEC;
|
s_sntmp_next = utc + SNTP_INTERVAL_SEC;
|
||||||
|
|||||||
+149
-133
@@ -13,6 +13,9 @@
|
|||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#define MG_SOCK_ERRNO WSAGetLastError()
|
#define MG_SOCK_ERRNO WSAGetLastError()
|
||||||
#define FD(C_) ((SOCKET)(C_)->fd)
|
#define FD(C_) ((SOCKET)(C_)->fd)
|
||||||
|
#ifndef SO_EXCLUSIVEADDRUSE
|
||||||
|
#define SO_EXCLUSIVEADDRUSE ((int) (~SO_REUSEADDR))
|
||||||
|
#endif
|
||||||
#elif MG_ARCH == MG_ARCH_FREERTOS
|
#elif MG_ARCH == MG_ARCH_FREERTOS
|
||||||
#define MG_SOCK_ERRNO errno
|
#define MG_SOCK_ERRNO errno
|
||||||
typedef Socket_t SOCKET;
|
typedef Socket_t SOCKET;
|
||||||
@@ -26,6 +29,10 @@ typedef int SOCKET;
|
|||||||
#define FD(C_) ((SOCKET)(long) (C_)->fd)
|
#define FD(C_) ((SOCKET)(long) (C_)->fd)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef MSG_NONBLOCKING
|
||||||
|
#define MSG_NONBLOCKING 0
|
||||||
|
#endif
|
||||||
|
|
||||||
union usa {
|
union usa {
|
||||||
struct sockaddr sa;
|
struct sockaddr sa;
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
@@ -40,6 +47,13 @@ static union usa tousa(struct mg_addr *a) {
|
|||||||
usa.sin.sin_family = AF_INET;
|
usa.sin.sin_family = AF_INET;
|
||||||
usa.sin.sin_port = a->port;
|
usa.sin.sin_port = a->port;
|
||||||
*(uint32_t *) &usa.sin.sin_addr = a->ip;
|
*(uint32_t *) &usa.sin.sin_addr = a->ip;
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
if (a->is_ip6) {
|
||||||
|
usa.sin.sin_family = AF_INET6;
|
||||||
|
usa.sin6.sin6_port = a->port;
|
||||||
|
memcpy(&usa.sin6.sin6_addr, a->ip6, sizeof(a->ip6));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return usa;
|
return usa;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +76,7 @@ static struct mg_connection *alloc_conn(struct mg_mgr *mgr, int is_client,
|
|||||||
c->is_client = is_client;
|
c->is_client = is_client;
|
||||||
c->fd = (void *) (long) fd;
|
c->fd = (void *) (long) fd;
|
||||||
c->mgr = mgr;
|
c->mgr = mgr;
|
||||||
|
c->id = ++mgr->nextid;
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@@ -72,13 +87,23 @@ static int mg_sock_recv(struct mg_connection *c, void *buf, int len,
|
|||||||
if (c->is_udp) {
|
if (c->is_udp) {
|
||||||
union usa usa;
|
union usa usa;
|
||||||
socklen_t slen = sizeof(usa.sin);
|
socklen_t slen = sizeof(usa.sin);
|
||||||
n = recvfrom(FD(c), buf, len, 0, &usa.sa, &slen);
|
#if MG_ENABLE_IPV6
|
||||||
|
if (c->peer.is_ip6) slen = sizeof(usa.sin6);
|
||||||
|
#endif
|
||||||
|
n = recvfrom(FD(c), (char *) buf, len, 0, &usa.sa, &slen);
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
c->peer.ip = *(uint32_t *) &usa.sin.sin_addr;
|
if (c->peer.is_ip6) {
|
||||||
c->peer.port = usa.sin.sin_port;
|
#if MG_ENABLE_IPV6
|
||||||
|
memcpy(c->peer.ip6, &usa.sin6.sin6_addr, sizeof(c->peer.ip6));
|
||||||
|
c->peer.port = usa.sin6.sin6_port;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
c->peer.ip = *(uint32_t *) &usa.sin.sin_addr;
|
||||||
|
c->peer.port = usa.sin.sin_port;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
n = recv(FD(c), buf, len, 0);
|
n = recv(FD(c), (char *) buf, len, MSG_NONBLOCKING);
|
||||||
}
|
}
|
||||||
*fail = (n == 0) || (n < 0 && mg_sock_failed());
|
*fail = (n == 0) || (n < 0 && mg_sock_failed());
|
||||||
return n;
|
return n;
|
||||||
@@ -89,9 +114,13 @@ static int mg_sock_send(struct mg_connection *c, const void *buf, int len,
|
|||||||
int n = 0;
|
int n = 0;
|
||||||
if (c->is_udp) {
|
if (c->is_udp) {
|
||||||
union usa usa = tousa(&c->peer);
|
union usa usa = tousa(&c->peer);
|
||||||
n = sendto(FD(c), buf, len, 0, &usa.sa, sizeof(usa.sin));
|
socklen_t slen = sizeof(usa.sin);
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
if (c->peer.is_ip6) slen = sizeof(usa.sin6);
|
||||||
|
#endif
|
||||||
|
n = sendto(FD(c), (char *) buf, len, 0, &usa.sa, slen);
|
||||||
} else {
|
} else {
|
||||||
n = send(FD(c), buf, len, 0);
|
n = send(FD(c), (char *) buf, len, MSG_NONBLOCKING);
|
||||||
}
|
}
|
||||||
*fail = (n == 0) || (n < 0 && mg_sock_failed());
|
*fail = (n == 0) || (n < 0 && mg_sock_failed());
|
||||||
return n;
|
return n;
|
||||||
@@ -101,12 +130,12 @@ static int ll_read(struct mg_connection *c, void *buf, int len, int *fail) {
|
|||||||
int n = c->is_tls ? mg_tls_recv(c, buf, len, fail)
|
int n = c->is_tls ? mg_tls_recv(c, buf, len, fail)
|
||||||
: mg_sock_recv(c, buf, len, fail);
|
: mg_sock_recv(c, buf, len, fail);
|
||||||
LOG(*fail ? LL_DEBUG : LL_VERBOSE_DEBUG,
|
LOG(*fail ? LL_DEBUG : LL_VERBOSE_DEBUG,
|
||||||
("%p %c%c%c %d/%d %d %d", c->fd, c->is_tls ? 'T' : 't',
|
("%lu %c%c%c %d/%d %d %d", c->id, c->is_tls ? 'T' : 't',
|
||||||
c->is_udp ? 'U' : 'u', c->is_connecting ? 'C' : 'c', n, len,
|
c->is_udp ? 'U' : 'u', c->is_connecting ? 'C' : 'c', n, len,
|
||||||
MG_SOCK_ERRNO, *fail));
|
MG_SOCK_ERRNO, *fail));
|
||||||
if (n > 0 && c->is_hexdumping) {
|
if (n > 0 && c->is_hexdumping) {
|
||||||
char *s = mg_hexdump(buf, len);
|
char *s = mg_hexdump(buf, n);
|
||||||
LOG(LL_INFO, ("\n-- %p %s %s %d\n%s--", c->fd, c->label, "<-", len, s));
|
LOG(LL_INFO, ("\n-- %lu %s %s %d\n%s--", c->id, c->label, "<-", n, s));
|
||||||
free(s);
|
free(s);
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
@@ -117,12 +146,12 @@ static int ll_write(struct mg_connection *c, const void *buf, int len,
|
|||||||
int n = c->is_tls ? mg_tls_send(c, buf, len, fail)
|
int n = c->is_tls ? mg_tls_send(c, buf, len, fail)
|
||||||
: mg_sock_send(c, buf, len, fail);
|
: mg_sock_send(c, buf, len, fail);
|
||||||
LOG(*fail ? LL_ERROR : LL_VERBOSE_DEBUG,
|
LOG(*fail ? LL_ERROR : LL_VERBOSE_DEBUG,
|
||||||
("%p %c%c%c %d/%d %d", c->fd, c->is_tls ? 'T' : 't',
|
("%lu %c%c%c %d/%d %d", c->id, c->is_tls ? 'T' : 't',
|
||||||
c->is_udp ? 'U' : 'u', c->is_connecting ? 'C' : 'c', n, len,
|
c->is_udp ? 'U' : 'u', c->is_connecting ? 'C' : 'c', n, len,
|
||||||
MG_SOCK_ERRNO));
|
MG_SOCK_ERRNO));
|
||||||
if (n > 0 && c->is_hexdumping) {
|
if (n > 0 && c->is_hexdumping) {
|
||||||
char *s = mg_hexdump(buf, len);
|
char *s = mg_hexdump(buf, len);
|
||||||
LOG(LL_INFO, ("\n-- %p %s %s %d\n%s--", c->fd, c->label, "->", len, s));
|
LOG(LL_INFO, ("\n-- %lu %s %s %d\n%s--", c->id, c->label, "->", len, s));
|
||||||
free(s);
|
free(s);
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
@@ -132,6 +161,7 @@ int mg_send(struct mg_connection *c, const void *buf, size_t len) {
|
|||||||
int fail, n = c->is_udp
|
int fail, n = c->is_udp
|
||||||
? ll_write(c, buf, (SOCKET) len, &fail)
|
? ll_write(c, buf, (SOCKET) len, &fail)
|
||||||
: (int) mg_iobuf_append(&c->send, buf, len, MG_IO_SIZE);
|
: (int) mg_iobuf_append(&c->send, buf, len, MG_IO_SIZE);
|
||||||
|
if (len > 0 && n == 0) fail = 1;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,46 +178,51 @@ static void mg_set_non_blocking_mode(SOCKET fd) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
SOCKET mg_open_listener(const char *ip, uint16_t port, int is_udp) {
|
SOCKET mg_open_listener(const char *url) {
|
||||||
union usa usa;
|
struct mg_addr addr;
|
||||||
int on = 1;
|
SOCKET fd = INVALID_SOCKET;
|
||||||
int proto = is_udp ? IPPROTO_UDP : IPPROTO_TCP;
|
|
||||||
int type = is_udp ? SOCK_DGRAM : SOCK_STREAM;
|
|
||||||
SOCKET fd;
|
|
||||||
|
|
||||||
memset(&usa, 0, sizeof(usa));
|
memset(&addr, 0, sizeof(addr));
|
||||||
usa.sin.sin_family = AF_INET;
|
addr.port = mg_htons(mg_url_port(url));
|
||||||
usa.sin.sin_port = mg_htons(port);
|
if (!mg_aton(mg_url_host(url), &addr)) {
|
||||||
mg_aton(ip, (uint32_t *) &usa.sin.sin_addr);
|
LOG(LL_ERROR, ("invalid listening URL: %s", url));
|
||||||
if (!mg_casecmp(ip, "localhost")) {
|
} else {
|
||||||
*(uint32_t *) &usa.sin.sin_addr = mg_htonl(0x7f000001);
|
union usa usa = tousa(&addr);
|
||||||
}
|
int on = 1, af = AF_INET;
|
||||||
|
int type = strncmp(url, "udp:", 4) == 0 ? SOCK_DGRAM : SOCK_STREAM;
|
||||||
|
int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
|
||||||
|
socklen_t slen = sizeof(usa.sin);
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
if (addr.is_ip6) af = AF_INET6, slen = sizeof(usa.sin6);
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((fd = socket(AF_INET, type, proto)) != INVALID_SOCKET &&
|
if ((fd = socket(af, type, proto)) != INVALID_SOCKET &&
|
||||||
#if !defined(_WIN32) || !defined(SO_EXCLUSIVEADDRUSE)
|
#if !defined(_WIN32) || !defined(SO_EXCLUSIVEADDRUSE)
|
||||||
// SO_RESUSEADDR is not enabled on Windows because the semantics of
|
// SO_RESUSEADDR is not enabled on Windows because the semantics of
|
||||||
// SO_REUSEADDR on UNIX and Windows is different. On Windows,
|
// SO_REUSEADDR on UNIX and Windows is different. On Windows,
|
||||||
// SO_REUSEADDR allows to bind a socket to a port without error even if
|
// SO_REUSEADDR allows to bind a socket to a port without error even if
|
||||||
// the port is already open by another program. This is not the behavior
|
// the port is already open by another program. This is not the behavior
|
||||||
// SO_REUSEADDR was designed for, and leads to hard-to-track failure
|
// SO_REUSEADDR was designed for, and leads to hard-to-track failure
|
||||||
// scenarios. Therefore, SO_REUSEADDR was disabled on Windows unless
|
// scenarios. Therefore, SO_REUSEADDR was disabled on Windows unless
|
||||||
// SO_EXCLUSIVEADDRUSE is supported and set on a socket.
|
// SO_EXCLUSIVEADDRUSE is supported and set on a socket.
|
||||||
!setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
|
!setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) &&
|
||||||
#endif
|
#endif
|
||||||
#if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE) && !defined(WINCE)
|
#if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE) && !defined(WINCE)
|
||||||
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
|
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
|
||||||
!setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &on,
|
//! setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof(on))
|
||||||
sizeof(on)) &&
|
//! &&
|
||||||
|
!setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *) &on,
|
||||||
|
sizeof(on)) &&
|
||||||
#endif
|
#endif
|
||||||
bind(fd, &usa.sa, sizeof(usa.sin)) == 0 &&
|
bind(fd, &usa.sa, slen) == 0 &&
|
||||||
// NOTE(lsm): FreeRTOS uses backlog value as a connection limit
|
// NOTE(lsm): FreeRTOS uses backlog value as a connection limit
|
||||||
(type == SOCK_DGRAM || listen(fd, 128) == 0)) {
|
(type == SOCK_DGRAM || listen(fd, 128) == 0)) {
|
||||||
mg_set_non_blocking_mode(fd);
|
mg_set_non_blocking_mode(fd);
|
||||||
} else if (fd >= 0) {
|
} else if (fd != INVALID_SOCKET) {
|
||||||
LOG(LL_ERROR,
|
LOG(LL_ERROR, ("Failed to listen on %s, errno %d", url, MG_SOCK_ERRNO));
|
||||||
("Failed to listen on %s:%hu, errno %d", ip, port, MG_SOCK_ERRNO));
|
closesocket(fd);
|
||||||
closesocket(fd);
|
fd = INVALID_SOCKET;
|
||||||
fd = INVALID_SOCKET;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
@@ -201,8 +236,9 @@ static void read_conn(struct mg_connection *c,
|
|||||||
// NOTE(lsm): do only one iteration of reads, cause some systems
|
// NOTE(lsm): do only one iteration of reads, cause some systems
|
||||||
// (e.g. FreeRTOS stack) return 0 instead of -1/EWOULDBLOCK when no data
|
// (e.g. FreeRTOS stack) return 0 instead of -1/EWOULDBLOCK when no data
|
||||||
if (c->recv.size - c->recv.len < MG_IO_SIZE &&
|
if (c->recv.size - c->recv.len < MG_IO_SIZE &&
|
||||||
c->recv.size < MG_MAX_RECV_BUF_SIZE) {
|
c->recv.size < MG_MAX_RECV_BUF_SIZE &&
|
||||||
mg_iobuf_resize(&c->recv, c->recv.size + MG_IO_SIZE);
|
!mg_iobuf_resize(&c->recv, c->recv.size + MG_IO_SIZE)) {
|
||||||
|
c->is_closing = 1;
|
||||||
}
|
}
|
||||||
buf = c->recv.buf + c->recv.len;
|
buf = c->recv.buf + c->recv.len;
|
||||||
len = (int) (c->recv.size - c->recv.len);
|
len = (int) (c->recv.size - c->recv.len);
|
||||||
@@ -228,22 +264,19 @@ static int write_conn(struct mg_connection *c) {
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void close_conn(struct mg_mgr *mgr, struct mg_connection *c) {
|
static void close_conn(struct mg_connection *c) {
|
||||||
// Unlink this connection from the list
|
// Unlink this connection from the list
|
||||||
LIST_DELETE(struct mg_connection, &mgr->conns, c);
|
LIST_DELETE(struct mg_connection, &c->mgr->conns, c);
|
||||||
#if 0
|
mg_resolve_cancel(c);
|
||||||
struct mg_connection **head = &mgr->conns;
|
if (c == c->mgr->dns4.c) c->mgr->dns4.c = NULL;
|
||||||
while (*head != c) head = &(*head)->next;
|
if (c == c->mgr->dns6.c) c->mgr->dns6.c = NULL;
|
||||||
*head = c->next;
|
|
||||||
#endif
|
|
||||||
mg_resolve_cancel(mgr, c);
|
|
||||||
mg_call(c, MG_EV_CLOSE, NULL);
|
mg_call(c, MG_EV_CLOSE, NULL);
|
||||||
// while (c->callbacks != NULL) mg_fn_del(c, c->callbacks->fn);
|
// while (c->callbacks != NULL) mg_fn_del(c, c->callbacks->fn);
|
||||||
LOG(LL_DEBUG, ("%p closed", c->fd));
|
LOG(LL_DEBUG, ("%lu closed", c->id));
|
||||||
if (FD(c) != INVALID_SOCKET) {
|
if (FD(c) != INVALID_SOCKET) {
|
||||||
closesocket(FD(c));
|
closesocket(FD(c));
|
||||||
#if MG_ARCH == MG_ARCH_FREERTOS
|
#if MG_ARCH == MG_ARCH_FREERTOS
|
||||||
FreeRTOS_FD_CLR(c->fd, mgr->ss, eSELECT_ALL);
|
FreeRTOS_FD_CLR(c->fd, c->mgr->ss, eSELECT_ALL);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
mg_tls_free(c);
|
mg_tls_free(c);
|
||||||
@@ -251,29 +284,31 @@ static void close_conn(struct mg_mgr *mgr, struct mg_connection *c) {
|
|||||||
free(c->send.buf);
|
free(c->send.buf);
|
||||||
memset(c, 0, sizeof(*c));
|
memset(c, 0, sizeof(*c));
|
||||||
free(c);
|
free(c);
|
||||||
if (c == mgr->dnsc) mgr->dnsc = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setsockopts(struct mg_connection *c) {
|
static void setsockopts(struct mg_connection *c) {
|
||||||
#if MG_ARCH == MG_ARCH_FREERTOS
|
#if MG_ARCH == MG_ARCH_FREERTOS
|
||||||
FreeRTOS_FD_SET(c->fd, c->mgr->ss, eSELECT_READ | eSELECT_EXCEPT);
|
FreeRTOS_FD_SET(c->fd, c->mgr->ss, eSELECT_READ | eSELECT_EXCEPT);
|
||||||
#else
|
#else
|
||||||
int on = 1, cnt = 3, intvl = 20;
|
int on = 1;
|
||||||
#if !defined(SOL_TCP)
|
#if !defined(SOL_TCP)
|
||||||
#define SOL_TCP IPPROTO_TCP
|
#define SOL_TCP IPPROTO_TCP
|
||||||
#endif
|
#endif
|
||||||
setsockopt(FD(c), SOL_TCP, TCP_NODELAY, (void *) &on, sizeof(on));
|
setsockopt(FD(c), SOL_TCP, TCP_NODELAY, (char *) &on, sizeof(on));
|
||||||
#if defined(TCP_QUICKACK)
|
#if defined(TCP_QUICKACK)
|
||||||
setsockopt(FD(c), SOL_TCP, TCP_QUICKACK, (void *) &on, sizeof(on));
|
setsockopt(FD(c), SOL_TCP, TCP_QUICKACK, (char *) &on, sizeof(on));
|
||||||
#endif
|
#endif
|
||||||
setsockopt(FD(c), SOL_SOCKET, SO_KEEPALIVE, (void *) &on, sizeof(on));
|
setsockopt(FD(c), SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on));
|
||||||
#if ESP32 || ESP8266 || defined(__linux__)
|
#if ESP32 || ESP8266 || defined(__linux__)
|
||||||
int idle = 60;
|
int idle = 60;
|
||||||
setsockopt(FD(c), IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle));
|
setsockopt(FD(c), IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle));
|
||||||
#endif
|
#endif
|
||||||
#ifndef _WIN32
|
#if !defined(_WIN32) && !defined(__QNX__)
|
||||||
setsockopt(FD(c), IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt));
|
{
|
||||||
setsockopt(FD(c), IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl));
|
int cnt = 3, intvl = 20;
|
||||||
|
setsockopt(FD(c), IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt));
|
||||||
|
setsockopt(FD(c), IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -281,12 +316,27 @@ static void setsockopts(struct mg_connection *c) {
|
|||||||
void mg_connect_resolved(struct mg_connection *c) {
|
void mg_connect_resolved(struct mg_connection *c) {
|
||||||
char buf[40];
|
char buf[40];
|
||||||
int type = c->is_udp ? SOCK_DGRAM : SOCK_STREAM;
|
int type = c->is_udp ? SOCK_DGRAM : SOCK_STREAM;
|
||||||
mg_call(c, MG_EV_RESOLVE, NULL);
|
int af = AF_INET;
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
if (c->peer.is_ip6) af = AF_INET6;
|
||||||
|
#endif
|
||||||
mg_straddr(c, buf, sizeof(buf));
|
mg_straddr(c, buf, sizeof(buf));
|
||||||
LOG(LL_DEBUG, ("%p resolved: %s", c->fd, buf));
|
c->fd = (void *) (long) socket(af, type, 0);
|
||||||
|
if (FD(c) == INVALID_SOCKET) {
|
||||||
|
mg_error(c, "socket(): %d", MG_SOCK_ERRNO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mg_set_non_blocking_mode(FD(c));
|
||||||
|
mg_call(c, MG_EV_RESOLVE, NULL);
|
||||||
if (type == SOCK_STREAM) {
|
if (type == SOCK_STREAM) {
|
||||||
union usa usa = tousa(&c->peer);
|
union usa usa = tousa(&c->peer);
|
||||||
int rc = connect(FD(c), &usa.sa, sizeof(usa.sin));
|
socklen_t slen =
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
c->peer.is_ip6 ? sizeof(usa.sin6) :
|
||||||
|
#endif
|
||||||
|
sizeof(usa.sin);
|
||||||
|
int rc = connect(FD(c), &usa.sa, slen);
|
||||||
int fail = rc < 0 && mg_sock_failed() ? MG_SOCK_ERRNO : 0;
|
int fail = rc < 0 && mg_sock_failed() ? MG_SOCK_ERRNO : 0;
|
||||||
if (fail) {
|
if (fail) {
|
||||||
mg_error(c, "connect: %d", MG_SOCK_ERRNO);
|
mg_error(c, "connect: %d", MG_SOCK_ERRNO);
|
||||||
@@ -300,21 +350,17 @@ void mg_connect_resolved(struct mg_connection *c) {
|
|||||||
struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
|
struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
|
||||||
mg_event_handler_t fn, void *fn_data) {
|
mg_event_handler_t fn, void *fn_data) {
|
||||||
struct mg_connection *c = NULL;
|
struct mg_connection *c = NULL;
|
||||||
int fd, type = strncmp(url, "udp:", 4) == 0 ? SOCK_DGRAM : SOCK_STREAM;
|
if ((c = alloc_conn(mgr, 1, INVALID_SOCKET)) == NULL) {
|
||||||
if ((fd = socket(AF_INET, type, 0)) == INVALID_SOCKET) {
|
LOG(LL_ERROR, ("OOM"));
|
||||||
LOG(LL_ERROR, ("socket(): %d", MG_SOCK_ERRNO));
|
|
||||||
} else if ((c = alloc_conn(mgr, 1, fd)) == NULL) {
|
|
||||||
LOG(LL_ERROR, ("%p OOM", c->fd));
|
|
||||||
} else {
|
} else {
|
||||||
struct mg_str host = mg_url_host(url);
|
struct mg_str host = mg_url_host(url);
|
||||||
LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
|
LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
|
||||||
mg_set_non_blocking_mode(FD(c));
|
c->is_udp = (strncmp(url, "udp:", 4) == 0);
|
||||||
c->is_udp = type == SOCK_DGRAM;
|
|
||||||
c->peer.port = mg_htons(mg_url_port(url));
|
c->peer.port = mg_htons(mg_url_port(url));
|
||||||
c->fn = fn;
|
c->fn = fn;
|
||||||
c->fn_data = fn_data;
|
c->fn_data = fn_data;
|
||||||
LOG(LL_DEBUG, ("%p -> %s", c->fd, url));
|
LOG(LL_DEBUG, ("%lu -> %s", c->id, url));
|
||||||
mg_resolve(mgr, c, &host, mgr->dnstimeout);
|
mg_resolve(c, &host, mgr->dnstimeout);
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@@ -322,25 +368,31 @@ struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
|
|||||||
static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
|
static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
|
||||||
struct mg_connection *c = NULL;
|
struct mg_connection *c = NULL;
|
||||||
union usa usa;
|
union usa usa;
|
||||||
socklen_t sa_len = sizeof(usa.sin);
|
socklen_t sa_len = sizeof(usa);
|
||||||
SOCKET fd = accept(FD(lsn), &usa.sa, &sa_len);
|
SOCKET fd = accept(FD(lsn), &usa.sa, &sa_len);
|
||||||
if (fd == INVALID_SOCKET) {
|
if (fd == INVALID_SOCKET) {
|
||||||
LOG(LL_ERROR,
|
LOG(LL_ERROR, ("%lu accept failed, errno %d", lsn->id, MG_SOCK_ERRNO));
|
||||||
("%p accept(%d) failed, errno %d", lsn->fd, FD(lsn), MG_SOCK_ERRNO));
|
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
} else if (fd >= FD_SETSIZE) {
|
} else if (fd >= FD_SETSIZE) {
|
||||||
LOG(LL_ERROR, ("%ld > %ld", (long) fd, (long) FD_SETSIZE));
|
LOG(LL_ERROR, ("%ld > %ld", (long) fd, (long) FD_SETSIZE));
|
||||||
closesocket(fd);
|
closesocket(fd);
|
||||||
#endif
|
#endif
|
||||||
} else if ((c = alloc_conn(mgr, 0, fd)) == NULL) {
|
} else if ((c = alloc_conn(mgr, 0, fd)) == NULL) {
|
||||||
LOG(LL_ERROR, ("%p OOM", lsn->fd));
|
LOG(LL_ERROR, ("%lu OOM", lsn->id));
|
||||||
closesocket(fd);
|
closesocket(fd);
|
||||||
} else {
|
} else {
|
||||||
char buf[40];
|
char buf[40];
|
||||||
c->peer.port = usa.sin.sin_port;
|
c->peer.port = usa.sin.sin_port;
|
||||||
memcpy(&c->peer.ip, &usa.sin.sin_addr, sizeof(c->peer.ip));
|
memcpy(&c->peer.ip, &usa.sin.sin_addr, sizeof(c->peer.ip));
|
||||||
|
#if MG_ENABLE_IPV6
|
||||||
|
if (sa_len == sizeof(usa.sin6)) {
|
||||||
|
memcpy(c->peer.ip6, &usa.sin6.sin6_addr, sizeof(c->peer.ip6));
|
||||||
|
c->peer.port = usa.sin6.sin6_port;
|
||||||
|
c->peer.is_ip6 = 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
mg_straddr(c, buf, sizeof(buf));
|
mg_straddr(c, buf, sizeof(buf));
|
||||||
LOG(LL_DEBUG, ("%p accepted %s", c->fd, buf));
|
LOG(LL_DEBUG, ("%lu accepted %s", c->id, buf));
|
||||||
mg_set_non_blocking_mode(FD(c));
|
mg_set_non_blocking_mode(FD(c));
|
||||||
setsockopts(c);
|
setsockopts(c);
|
||||||
LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
|
LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
|
||||||
@@ -356,17 +408,20 @@ static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
|
|||||||
|
|
||||||
#if MG_ENABLE_SOCKETPAIR
|
#if MG_ENABLE_SOCKETPAIR
|
||||||
bool mg_socketpair(int *s1, int *s2) {
|
bool mg_socketpair(int *s1, int *s2) {
|
||||||
#if MG_ARCH == MG_ARCH_UNIX
|
#ifdef MG_ENABLE_NATIVE_SOCKETPAIR
|
||||||
|
// For some reason, native socketpair() call fails on Macos
|
||||||
|
// Enable this codepath only when MG_ENABLE_NATIVE_SOCKETPAIR is defined
|
||||||
int sp[2], ret = 0;
|
int sp[2], ret = 0;
|
||||||
if (socketpair(AF_INET, SOCK_DGRAM, 0, sp) == 0) {
|
if (socketpair(AF_INET, SOCK_DGRAM, IPPROTO_UDP, sp) == 0) {
|
||||||
*s1 = sp[0], *s2 = sp[1], ret = 1;
|
*s1 = sp[0], *s2 = sp[1], ret = 1;
|
||||||
}
|
}
|
||||||
|
LOG(LL_INFO, ("errno %d", errno));
|
||||||
return ret;
|
return ret;
|
||||||
#else
|
#else
|
||||||
union usa sa, sa2;
|
union usa sa, sa2;
|
||||||
SOCKET sp[2] = {INVALID_SOCKET, INVALID_SOCKET};
|
SOCKET sp[2] = {INVALID_SOCKET, INVALID_SOCKET};
|
||||||
socklen_t len = sizeof(sa.sin);
|
socklen_t len = sizeof(sa.sin);
|
||||||
int ret = 0, res[2] = {-1, -1};
|
int ret = 0;
|
||||||
|
|
||||||
(void) memset(&sa, 0, sizeof(sa));
|
(void) memset(&sa, 0, sizeof(sa));
|
||||||
sa.sin.sin_family = AF_INET;
|
sa.sin.sin_family = AF_INET;
|
||||||
@@ -397,8 +452,7 @@ struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url,
|
|||||||
mg_event_handler_t fn, void *fn_data) {
|
mg_event_handler_t fn, void *fn_data) {
|
||||||
struct mg_connection *c = NULL;
|
struct mg_connection *c = NULL;
|
||||||
int is_udp = strncmp(url, "udp:", 4) == 0;
|
int is_udp = strncmp(url, "udp:", 4) == 0;
|
||||||
struct mg_str host = mg_url_host(url);
|
SOCKET fd = mg_open_listener(url);
|
||||||
SOCKET fd = mg_open_listener(host.ptr, mg_url_port(url), is_udp);
|
|
||||||
if (fd == INVALID_SOCKET) {
|
if (fd == INVALID_SOCKET) {
|
||||||
} else if ((c = alloc_conn(mgr, 0, fd)) == NULL) {
|
} else if ((c = alloc_conn(mgr, 0, fd)) == NULL) {
|
||||||
LOG(LL_ERROR, ("OOM %s", url));
|
LOG(LL_ERROR, ("OOM %s", url));
|
||||||
@@ -411,7 +465,7 @@ struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url,
|
|||||||
LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
|
LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
|
||||||
c->fn = fn;
|
c->fn = fn;
|
||||||
c->fn_data = fn_data;
|
c->fn_data = fn_data;
|
||||||
LOG(LL_INFO, ("%p accepting on %s", c->fd, url));
|
LOG(LL_INFO, ("%lu accepting on %s", c->id, url));
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@@ -449,7 +503,6 @@ static void mg_iotest(struct mg_mgr *mgr, int ms) {
|
|||||||
if (FD(c) > maxfd) maxfd = FD(c);
|
if (FD(c) > maxfd) maxfd = FD(c);
|
||||||
if (c->is_connecting || (c->send.len > 0 && c->is_tls_hs == 0))
|
if (c->is_connecting || (c->send.len > 0 && c->is_tls_hs == 0))
|
||||||
FD_SET(FD(c), &wset);
|
FD_SET(FD(c), &wset);
|
||||||
// LOG(LL_INFO, ("%d %d", c->fd, FD_ISSET(c->fd, &wset)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((rc = select(maxfd + 1, &rset, &wset, NULL, &tv)) < 0) {
|
if ((rc = select(maxfd + 1, &rset, &wset, NULL, &tv)) < 0) {
|
||||||
@@ -478,11 +531,8 @@ static void connect_conn(struct mg_connection *c) {
|
|||||||
char buf[40];
|
char buf[40];
|
||||||
mg_error(c, "error connecting to %s", mg_straddr(c, buf, sizeof(buf)));
|
mg_error(c, "error connecting to %s", mg_straddr(c, buf, sizeof(buf)));
|
||||||
} else {
|
} else {
|
||||||
if (c->is_tls_hs && mg_tls_handshake(c)) {
|
if (c->is_tls_hs) mg_tls_handshake(c);
|
||||||
c->is_tls_hs = 0;
|
mg_call(c, MG_EV_CONNECT, NULL);
|
||||||
mg_call(c, MG_EV_CONNECT, NULL);
|
|
||||||
}
|
|
||||||
if (c->is_tls == 0) mg_call(c, MG_EV_CONNECT, NULL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,59 +548,25 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
|
|||||||
tmp = c->next;
|
tmp = c->next;
|
||||||
mg_call(c, MG_EV_POLL, &now);
|
mg_call(c, MG_EV_POLL, &now);
|
||||||
LOG(LL_VERBOSE_DEBUG,
|
LOG(LL_VERBOSE_DEBUG,
|
||||||
("%p %c%c %c%c%c%c%c", c->fd, c->is_readable ? 'r' : '-',
|
("%lu %c%c %c%c%c%c%c", c->id, c->is_readable ? 'r' : '-',
|
||||||
c->is_writable ? 'w' : '-', c->is_tls ? 'T' : 't',
|
c->is_writable ? 'w' : '-', c->is_tls ? 'T' : 't',
|
||||||
c->is_connecting ? 'C' : 'c', c->is_tls_hs ? 'H' : 'h',
|
c->is_connecting ? 'C' : 'c', c->is_tls_hs ? 'H' : 'h',
|
||||||
c->is_resolving ? 'R' : 'r', c->is_closing ? 'C' : 'c'));
|
c->is_resolving ? 'R' : 'r', c->is_closing ? 'C' : 'c'));
|
||||||
if (c->is_resolving || c->is_closing) {
|
if (c->is_resolving || c->is_closing) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
} else if (c->is_listening) {
|
} else if (c->is_listening && c->is_udp == 0) {
|
||||||
if (c->is_readable) accept_conn(mgr, c);
|
if (c->is_readable) accept_conn(mgr, c);
|
||||||
#if 0
|
|
||||||
} else if (c->is_accepted && c->is_tls_hs) {
|
|
||||||
if (mg_tls_handshake(c)) c->is_tls_hs = 0;
|
|
||||||
#endif
|
|
||||||
} else if (c->is_connecting) {
|
} else if (c->is_connecting) {
|
||||||
if (c->is_readable || c->is_writable) {
|
if (c->is_readable || c->is_writable) connect_conn(c);
|
||||||
connect_conn(c);
|
|
||||||
}
|
|
||||||
} else if (c->is_tls_hs) {
|
} else if (c->is_tls_hs) {
|
||||||
if ((c->is_readable || c->is_writable) && mg_tls_handshake(c)) {
|
if ((c->is_readable || c->is_writable)) mg_tls_handshake(c);
|
||||||
c->is_tls_hs = 0;
|
|
||||||
mg_call(c, MG_EV_CONNECT, NULL);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (c->is_readable) read_conn(c, ll_read);
|
if (c->is_readable) read_conn(c, ll_read);
|
||||||
if (c->is_writable) write_conn(c);
|
if (c->is_writable) write_conn(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c->is_draining && c->send.len == 0) c->is_closing = 1;
|
if (c->is_draining && c->send.len == 0) c->is_closing = 1;
|
||||||
if (c->is_closing) close_conn(mgr, c);
|
if (c->is_closing) close_conn(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_mgr_free(struct mg_mgr *mgr) {
|
|
||||||
struct mg_connection *c;
|
|
||||||
for (c = mgr->conns; c != NULL; c = c->next) c->is_closing = 1;
|
|
||||||
mg_mgr_poll(mgr, 0);
|
|
||||||
#if MG_ARCH == MG_ARCH_FREERTOS
|
|
||||||
FreeRTOS_DeleteSocketSet(mgr->ss);
|
|
||||||
#endif
|
|
||||||
LOG(LL_INFO, ("All connections closed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_mgr_init(struct mg_mgr *mgr) {
|
|
||||||
#ifdef _WIN32
|
|
||||||
WSADATA data;
|
|
||||||
WSAStartup(MAKEWORD(2, 2), &data);
|
|
||||||
#elif MG_ARCH == MG_ARCH_FREERTOS
|
|
||||||
mgr->ss = FreeRTOS_CreateSocketSet();
|
|
||||||
#elif defined(__unix) || defined(__unix__) || defined(__APPLE__)
|
|
||||||
// Ignore SIGPIPE signal, so if client cancels the request, it
|
|
||||||
// won't kill the whole process.
|
|
||||||
signal(SIGPIPE, SIG_IGN);
|
|
||||||
#endif
|
|
||||||
memset(mgr, 0, sizeof(*mgr));
|
|
||||||
mgr->dnstimeout = 3000;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
#include "ssi.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#ifndef MG_MAX_SSI_DEPTH
|
||||||
|
#define MG_MAX_SSI_DEPTH 5
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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 = mg_fopen(path, "rb");
|
||||||
|
if (fp != NULL) {
|
||||||
|
char buf[BUFSIZ], arg[sizeof(buf)];
|
||||||
|
int ch, intag = 0;
|
||||||
|
size_t len = 0, align = MG_IO_SIZE;
|
||||||
|
while ((ch = fgetc(fp)) != EOF) {
|
||||||
|
if (intag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') {
|
||||||
|
buf[len++] = ch & 0xff;
|
||||||
|
if (sscanf(buf, "<!--#include file=\"%[^\"]", arg)) {
|
||||||
|
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 &&
|
||||||
|
(data = mg_ssi(tmp, root, depth + 1)) != NULL) {
|
||||||
|
mg_iobuf_append(&b, data, strlen(data), align);
|
||||||
|
free(data);
|
||||||
|
} else {
|
||||||
|
LOG(LL_ERROR, ("%s: file=%s error or too deep", path, arg));
|
||||||
|
}
|
||||||
|
} else if (sscanf(buf, "<!--#include virtual=\"%[^\"]", arg)) {
|
||||||
|
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) {
|
||||||
|
mg_iobuf_append(&b, data, strlen(data), align);
|
||||||
|
free(data);
|
||||||
|
} else {
|
||||||
|
LOG(LL_ERROR, ("%s: virtual=%s error or too deep", path, arg));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Unknown SSI tag
|
||||||
|
LOG(LL_INFO, ("Unknown SSI tag: %.*s", (int) len, buf));
|
||||||
|
mg_iobuf_append(&b, buf, len, align);
|
||||||
|
}
|
||||||
|
intag = 0;
|
||||||
|
len = 0;
|
||||||
|
} else if (ch == '<') {
|
||||||
|
intag = 1;
|
||||||
|
if (len > 0) mg_iobuf_append(&b, buf, len, align);
|
||||||
|
len = 0;
|
||||||
|
buf[len++] = ch & 0xff;
|
||||||
|
} else if (intag) {
|
||||||
|
if (len == 5 && strncmp(buf, "<!--#", 5) != 0) {
|
||||||
|
intag = 0;
|
||||||
|
} else if (len >= sizeof(buf) - 2) {
|
||||||
|
LOG(LL_ERROR, ("%s: SSI tag is too large", path));
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
buf[len++] = ch & 0xff;
|
||||||
|
} else {
|
||||||
|
buf[len++] = ch & 0xff;
|
||||||
|
if (len >= sizeof(buf)) {
|
||||||
|
mg_iobuf_append(&b, buf, len, align);
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (len > 0) mg_iobuf_append(&b, buf, len, align);
|
||||||
|
if (b.len > 0) mg_iobuf_append(&b, "", 1, align); // nul-terminate
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
(void) depth;
|
||||||
|
(void) root;
|
||||||
|
return (char *) b.buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mg_http_serve_ssi(struct mg_connection *c, const char *root,
|
||||||
|
const char *fullpath) {
|
||||||
|
char *data = mg_ssi(fullpath, root, 0);
|
||||||
|
mg_http_reply(c, 200, "", "%s", data == NULL ? "" : data);
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "http.h"
|
||||||
|
void mg_http_serve_ssi(struct mg_connection *c, const char *root,
|
||||||
|
const char *fullpath);
|
||||||
@@ -8,13 +8,15 @@
|
|||||||
#include <mbedtls/debug.h>
|
#include <mbedtls/debug.h>
|
||||||
#include <mbedtls/ssl.h>
|
#include <mbedtls/ssl.h>
|
||||||
|
|
||||||
// Different versions have those in different files, so declare here
|
#ifndef EXTERN_C
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#define EXTERN_C extern "C"
|
#define EXTERN_C extern "C"
|
||||||
#else
|
#else
|
||||||
#define EXTERN_C
|
#define EXTERN_C
|
||||||
#endif
|
#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_recv(void *, unsigned char *, size_t);
|
||||||
EXTERN_C int mbedtls_net_send(void *, const unsigned char *, size_t);
|
EXTERN_C int mbedtls_net_send(void *, const unsigned char *, size_t);
|
||||||
|
|
||||||
@@ -33,11 +35,12 @@ int mg_tls_handshake(struct mg_connection *c) {
|
|||||||
mbedtls_ssl_set_bio(&tls->ssl, &c->fd, mbedtls_net_send, mbedtls_net_recv, 0);
|
mbedtls_ssl_set_bio(&tls->ssl, &c->fd, mbedtls_net_send, mbedtls_net_recv, 0);
|
||||||
rc = mbedtls_ssl_handshake(&tls->ssl);
|
rc = mbedtls_ssl_handshake(&tls->ssl);
|
||||||
if (rc == 0) { // Success
|
if (rc == 0) { // Success
|
||||||
LOG(LL_DEBUG, ("%p OK", c->fd));
|
LOG(LL_DEBUG, ("%lu success", c->id));
|
||||||
|
c->is_tls_hs = 0;
|
||||||
} else if (rc == MBEDTLS_ERR_SSL_WANT_READ ||
|
} else if (rc == MBEDTLS_ERR_SSL_WANT_READ ||
|
||||||
rc == MBEDTLS_ERR_SSL_WANT_WRITE) { // Still pending
|
rc == MBEDTLS_ERR_SSL_WANT_WRITE) { // Still pending
|
||||||
LOG(LL_VERBOSE_DEBUG, ("%p pending, %d%d %d (-%#x)", c->fd, c->is_connecting,
|
LOG(LL_VERBOSE_DEBUG, ("%lu pending, %d%d %d (-%#x)", c->id,
|
||||||
c->is_tls_hs, rc, -rc));
|
c->is_connecting, c->is_tls_hs, rc, -rc));
|
||||||
} else {
|
} else {
|
||||||
mg_error(c, "TLS handshake: -%#x", -rc); // Error
|
mg_error(c, "TLS handshake: -%#x", -rc); // Error
|
||||||
}
|
}
|
||||||
@@ -61,8 +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) {
|
int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
|
||||||
struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
|
struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
LOG(LL_DEBUG, ("%p Setting TLS, CA: %s, cert: %s, key: %s", c->fd,
|
const char *ca = opts->ca == NULL ? "-"
|
||||||
opts->ca == NULL ? "null" : opts->ca,
|
: 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, ca,
|
||||||
opts->cert == NULL ? "null" : opts->cert,
|
opts->cert == NULL ? "null" : opts->cert,
|
||||||
opts->certkey == NULL ? "null" : opts->certkey));
|
opts->certkey == NULL ? "null" : opts->certkey));
|
||||||
mbedtls_ssl_init(&tls->ssl);
|
mbedtls_ssl_init(&tls->ssl);
|
||||||
@@ -87,17 +96,26 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
|
|||||||
tls->cafile = strdup(opts->ca);
|
tls->cafile = strdup(opts->ca);
|
||||||
rc = mbedtls_ssl_conf_ca_chain_file(&tls->conf, tls->cafile, NULL);
|
rc = mbedtls_ssl_conf_ca_chain_file(&tls->conf, tls->cafile, NULL);
|
||||||
if (rc != 0) {
|
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
mbedtls_x509_crt_init(&tls->ca);
|
mbedtls_x509_crt_init(&tls->ca);
|
||||||
if ((rc = mbedtls_x509_crt_parse_file(&tls->ca, opts->ca)) != 0) {
|
rc = opts->ca[0] == '-'
|
||||||
mg_error(c, "parse(%s) err %#x", opts->ca, -rc);
|
? 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;
|
goto fail;
|
||||||
}
|
}
|
||||||
mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, NULL);
|
mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, NULL);
|
||||||
#endif
|
#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);
|
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||||
}
|
}
|
||||||
if (opts->cert != NULL && opts->cert[0] != '\0') {
|
if (opts->cert != NULL && opts->cert[0] != '\0') {
|
||||||
@@ -126,6 +144,9 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
|
|||||||
c->tls = tls;
|
c->tls = tls;
|
||||||
c->is_tls = 1;
|
c->is_tls = 1;
|
||||||
c->is_tls_hs = 1;
|
c->is_tls_hs = 1;
|
||||||
|
if (c->is_client && c->is_resolving == 0 && c->is_connecting == 0) {
|
||||||
|
mg_tls_handshake(c);
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
fail:
|
fail:
|
||||||
c->is_closing = 1;
|
c->is_closing = 1;
|
||||||
@@ -162,7 +183,6 @@ int mg_tls_free(struct mg_connection *c) {
|
|||||||
}
|
}
|
||||||
#elif MG_ENABLE_OPENSSL ///////////////////////////////////////// OPENSSL
|
#elif MG_ENABLE_OPENSSL ///////////////////////////////////////// OPENSSL
|
||||||
|
|
||||||
#include <openssl/bio.h>
|
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
|
|
||||||
@@ -192,11 +212,17 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
|
|||||||
const char *id = "mongoose";
|
const char *id = "mongoose";
|
||||||
static unsigned char s_initialised = 0;
|
static unsigned char s_initialised = 0;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
if (tls == NULL) {
|
||||||
|
mg_error(c, "TLS OOM");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (!s_initialised) {
|
if (!s_initialised) {
|
||||||
SSL_library_init();
|
SSL_library_init();
|
||||||
s_initialised++;
|
s_initialised++;
|
||||||
}
|
}
|
||||||
LOG(LL_DEBUG, ("%p Setting TLS, CA: %s, cert: %s, key: %s", c->fd,
|
LOG(LL_DEBUG, ("%lu Setting TLS, CA: %s, cert: %s, key: %s", c->id,
|
||||||
opts->ca == NULL ? "null" : opts->ca,
|
opts->ca == NULL ? "null" : opts->ca,
|
||||||
opts->cert == NULL ? "null" : opts->cert,
|
opts->cert == NULL ? "null" : opts->cert,
|
||||||
opts->certkey == NULL ? "null" : opts->certkey));
|
opts->certkey == NULL ? "null" : opts->certkey));
|
||||||
@@ -219,12 +245,12 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (opts->ca != NULL && opts->ca[0] != '\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) {
|
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));
|
mg_error(c, "parse(%s): err %d", opts->ca, mg_tls_err(tls, rc));
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
SSL_set_verify(tls->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
|
||||||
0);
|
|
||||||
}
|
}
|
||||||
if (opts->cert != NULL && opts->cert[0] != '\0') {
|
if (opts->cert != NULL && opts->cert[0] != '\0') {
|
||||||
const char *key = opts->certkey;
|
const char *key = opts->certkey;
|
||||||
@@ -235,10 +261,12 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
|
|||||||
} else if ((rc = SSL_use_PrivateKey_file(tls->ssl, key, 1)) != 1) {
|
} else if ((rc = SSL_use_PrivateKey_file(tls->ssl, key, 1)) != 1) {
|
||||||
mg_error(c, "Invalid SSL key, err %d", mg_tls_err(tls, rc));
|
mg_error(c, "Invalid SSL key, err %d", mg_tls_err(tls, rc));
|
||||||
goto fail;
|
goto fail;
|
||||||
|
#if OPENSSL_VERSION_NUMBER > 0x10002000L
|
||||||
} else if ((rc = SSL_use_certificate_chain_file(tls->ssl, opts->cert)) !=
|
} else if ((rc = SSL_use_certificate_chain_file(tls->ssl, opts->cert)) !=
|
||||||
1) {
|
1) {
|
||||||
mg_error(c, "Invalid CA, err %d", mg_tls_err(tls, rc));
|
mg_error(c, "Invalid CA, err %d", mg_tls_err(tls, rc));
|
||||||
goto fail;
|
goto fail;
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
SSL_set_mode(tls->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
SSL_set_mode(tls->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||||
#if OPENSSL_VERSION_NUMBER > 0x10002000L
|
#if OPENSSL_VERSION_NUMBER > 0x10002000L
|
||||||
@@ -247,10 +275,19 @@ 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->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->tls = tls;
|
||||||
c->is_tls = 1;
|
c->is_tls = 1;
|
||||||
c->is_tls_hs = 1;
|
c->is_tls_hs = 1;
|
||||||
|
if (c->is_client && c->is_resolving == 0 && c->is_connecting == 0) {
|
||||||
|
mg_tls_handshake(c);
|
||||||
|
}
|
||||||
|
c->is_hexdumping = 1;
|
||||||
|
LOG(LL_DEBUG, ("%lu SSL %s OK", c->id, c->is_accepted ? "accept" : "client"));
|
||||||
return 1;
|
return 1;
|
||||||
fail:
|
fail:
|
||||||
c->is_closing = 1;
|
c->is_closing = 1;
|
||||||
@@ -261,14 +298,16 @@ fail:
|
|||||||
int mg_tls_handshake(struct mg_connection *c) {
|
int mg_tls_handshake(struct mg_connection *c) {
|
||||||
struct mg_tls *tls = (struct mg_tls *) c->tls;
|
struct mg_tls *tls = (struct mg_tls *) c->tls;
|
||||||
int rc;
|
int rc;
|
||||||
// if (SSL_get_fd(tls->ssl) == -1)
|
SSL_set_fd(tls->ssl, (long) c->fd);
|
||||||
SSL_set_fd(tls->ssl, (int) c->fd);
|
|
||||||
rc = c->is_client ? SSL_connect(tls->ssl) : SSL_accept(tls->ssl);
|
rc = c->is_client ? SSL_connect(tls->ssl) : SSL_accept(tls->ssl);
|
||||||
if (rc == 1) {
|
if (rc == 1) {
|
||||||
|
LOG(LL_DEBUG, ("%lu success", c->id));
|
||||||
|
c->is_tls_hs = 0;
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
|
int code;
|
||||||
ERR_print_errors_fp(stderr);
|
ERR_print_errors_fp(stderr);
|
||||||
int code = mg_tls_err(tls, rc);
|
code = mg_tls_err(tls, rc);
|
||||||
if (code != 0) mg_error(c, "tls hs: rc %d, err %d", rc, code);
|
if (code != 0) mg_error(c, "tls hs: rc %d, err %d", rc, code);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
|
||||||
struct mg_tls_opts {
|
struct mg_tls_opts {
|
||||||
const char *ca; // CA certificate file. For both listeners and clients
|
const char *ca; // CA certificate file. For both listeners and clients
|
||||||
const char *cert; // Certificate
|
const char *cert; // Certificate
|
||||||
const char *certkey; // Certificate key
|
const char *certkey; // Certificate key
|
||||||
const char *ciphers; // Cipher list
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
int mg_tls_init(struct mg_connection *, struct mg_tls_opts *);
|
int mg_tls_init(struct mg_connection *, struct mg_tls_opts *);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "url.h"
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include "url.h"
|
||||||
|
|
||||||
struct url {
|
struct url {
|
||||||
int key, user, pass, host, port, uri, end;
|
int key, user, pass, host, port, uri, end;
|
||||||
@@ -19,6 +19,8 @@ static struct url urlparse(const char *url) {
|
|||||||
if (i > 0 && url[i - 1] == '/' && url[i] == '/') {
|
if (i > 0 && url[i - 1] == '/' && url[i] == '/') {
|
||||||
u.host = i + 1;
|
u.host = i + 1;
|
||||||
u.port = 0;
|
u.port = 0;
|
||||||
|
} else if (url[i] == ']') {
|
||||||
|
u.port = 0; // IPv6 URLs, like http://[::1]/bar
|
||||||
} else if (url[i] == ':') {
|
} else if (url[i] == ':') {
|
||||||
u.port = i + 1;
|
u.port = i + 1;
|
||||||
} else if (url[i] == '@') {
|
} else if (url[i] == '@') {
|
||||||
@@ -41,7 +43,12 @@ struct mg_str mg_url_host(const char *url) {
|
|||||||
struct url u = urlparse(url);
|
struct url u = urlparse(url);
|
||||||
int n =
|
int n =
|
||||||
u.port ? u.port - u.host - 1 : u.uri ? u.uri - u.host : u.end - u.host;
|
u.port ? u.port - u.host - 1 : u.uri ? u.uri - u.host : u.end - u.host;
|
||||||
return mg_str_n(url + u.host, n);
|
struct mg_str s = mg_str_n(url + u.host, n);
|
||||||
|
if (s.len > 2 && s.ptr[0] == '[' && s.ptr[s.len - 1] == ']') {
|
||||||
|
s.len -= 2;
|
||||||
|
s.ptr++;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *mg_url_uri(const char *url) {
|
const char *mg_url_uri(const char *url) {
|
||||||
@@ -52,7 +59,7 @@ const char *mg_url_uri(const char *url) {
|
|||||||
unsigned short mg_url_port(const char *url) {
|
unsigned short mg_url_port(const char *url) {
|
||||||
struct url u = urlparse(url);
|
struct url u = urlparse(url);
|
||||||
unsigned short port = 0;
|
unsigned short port = 0;
|
||||||
if (memcmp(url, "http:", 5) == 0) port = 80;
|
if (memcmp(url, "http:", 5) == 0 || memcmp(url, "ws:", 3) == 0) port = 80;
|
||||||
if (memcmp(url, "wss:", 4) == 0 || memcmp(url, "https:", 6) == 0) port = 443;
|
if (memcmp(url, "wss:", 4) == 0 || memcmp(url, "https:", 6) == 0) port = 443;
|
||||||
if (memcmp(url, "mqtt:", 5) == 0) port = 1883;
|
if (memcmp(url, "mqtt:", 5) == 0) port = 1883;
|
||||||
if (memcmp(url, "mqtts:", 6) == 0) port = 8883;
|
if (memcmp(url, "mqtts:", 6) == 0) port = 8883;
|
||||||
|
|||||||
+86
-46
@@ -1,20 +1,43 @@
|
|||||||
|
#include "config.h"
|
||||||
#include "util.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
|
#if MG_ARCH == MG_ARCH_FREERTOS
|
||||||
struct FF_STAT st;
|
struct FF_STAT st;
|
||||||
return ff_stat(path, &st) == 0 ? st.st_size : 0;
|
return ff_stat(path, &st) == 0 ? st.st_size : 0;
|
||||||
#else
|
#else
|
||||||
struct stat st;
|
mg_stat_t st;
|
||||||
return stat(path, &st) == 0 ? st.st_size : 0;
|
return mg_stat(path, &st) == 0 ? st.st_size : 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
char *mg_file_read(const char *path) {
|
char *mg_file_read(const char *path) {
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char *data = NULL;
|
char *data = NULL;
|
||||||
size_t size = mg_file_size(path);
|
size_t size = (size_t) mg_file_size(path);
|
||||||
if ((fp = fopen(path, "rb")) != NULL) {
|
if ((fp = mg_fopen(path, "rb")) != NULL) {
|
||||||
data = (char *) malloc(size + 1);
|
data = (char *) malloc(size + 1);
|
||||||
if (data != NULL) {
|
if (data != NULL) {
|
||||||
if (fread(data, 1, size, fp) != size) {
|
if (fread(data, 1, size, fp) != size) {
|
||||||
@@ -29,32 +52,54 @@ char *mg_file_read(const char *path) {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mg_file_write(const char *path, const char *fmt, ...) {
|
bool mg_file_write(const char *path, const void *buf, size_t len) {
|
||||||
char tmp[100];
|
bool result = false;
|
||||||
int written = 0;
|
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
char tmp[MG_PATH_MAX];
|
||||||
snprintf(tmp, sizeof(tmp), "%s.%d", path, rand());
|
snprintf(tmp, sizeof(tmp), "%s.%d", path, rand());
|
||||||
fp = fopen(tmp, "wb");
|
fp = mg_fopen(tmp, "wb");
|
||||||
if (fp != NULL) {
|
if (fp != NULL) {
|
||||||
va_list ap;
|
result = fwrite(buf, 1, len, fp) == len;
|
||||||
va_start(ap, fmt);
|
|
||||||
written = vfprintf(fp, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
remove(path);
|
if (result) {
|
||||||
rename(tmp, path);
|
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) {
|
void mg_random(void *buf, size_t len) {
|
||||||
FILE *fp = fopen("/dev/urandom", "rb");
|
bool done = false;
|
||||||
size_t i, n = 0;
|
#if MG_ENABLE_FS
|
||||||
if (fp != NULL) n = fread(buf, 1, len, fp);
|
FILE *fp = mg_fopen("/dev/urandom", "rb");
|
||||||
if (fp == NULL || n <= 0) {
|
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;
|
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) {
|
bool mg_globmatch(const char *s1, int n1, const char *s2, int n2) {
|
||||||
@@ -107,16 +152,16 @@ uint16_t mg_ntohs(uint16_t net) {
|
|||||||
return ((uint16_t) data[1] << 0) | ((uint32_t) data[0] << 8);
|
return ((uint16_t) data[1] << 0) | ((uint32_t) data[0] << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *mg_hexdump(const void *buf, int len) {
|
char *mg_hexdump(const void *buf, size_t len) {
|
||||||
const unsigned char *p = (const unsigned char *) buf;
|
const unsigned char *p = (const unsigned char *) buf;
|
||||||
int i, idx, n = 0, ofs = 0, dlen = len * 5 + 100;
|
size_t i, idx, n = 0, ofs = 0, dlen = len * 5 + 100;
|
||||||
char ascii[17] = "", *dst = (char *) malloc(dlen);
|
char ascii[17] = "", *dst = (char *) malloc(dlen);
|
||||||
if (dst == NULL) return dst;
|
if (dst == NULL) return dst;
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
idx = i % 16;
|
idx = i % 16;
|
||||||
if (idx == 0) {
|
if (idx == 0) {
|
||||||
if (i > 0 && dlen > n) n += snprintf(dst + n, dlen - n, " %s\n", ascii);
|
if (i > 0 && dlen > n) n += snprintf(dst + n, dlen - n, " %s\n", ascii);
|
||||||
if (dlen > n) n += snprintf(dst + n, dlen - n, "%04x ", i + ofs);
|
if (dlen > n) n += snprintf(dst + n, dlen - n, "%04x ", (int) (i + ofs));
|
||||||
}
|
}
|
||||||
if (dlen < n) break;
|
if (dlen < n) break;
|
||||||
n += snprintf(dst + n, dlen - n, " %02x", p[i]);
|
n += snprintf(dst + n, dlen - n, " %02x", p[i]);
|
||||||
@@ -190,7 +235,7 @@ int mg_vasprintf(char **buf, size_t size, const char *fmt, va_list ap) {
|
|||||||
}
|
}
|
||||||
// Microsoft version of vsnprintf() is not always null-terminated, so put
|
// Microsoft version of vsnprintf() is not always null-terminated, so put
|
||||||
// the terminator manually
|
// the terminator manually
|
||||||
(*buf)[len] = 0;
|
if (*buf != NULL) (*buf)[len] = 0;
|
||||||
// LCOV_EXCL_STOP
|
// LCOV_EXCL_STOP
|
||||||
} else if (len >= (int) size) {
|
} else if (len >= (int) size) {
|
||||||
/// Standard-compliant code path. Allocate a buffer that is large enough
|
/// Standard-compliant code path. Allocate a buffer that is large enough
|
||||||
@@ -215,33 +260,27 @@ int mg_asprintf(char **buf, size_t size, const char *fmt, ...) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t mg_to64(const char *s) {
|
int64_t mg_to64(struct mg_str str) {
|
||||||
int64_t result = 0, neg = 1;
|
int64_t result = 0, neg = 1;
|
||||||
while (*s && isspace((unsigned char) *s)) s++;
|
size_t i = 0;
|
||||||
if (*s == '-') neg = -1, s++;
|
while (i < str.len && (str.ptr[i] == ' ' || str.ptr[i] == '\t')) i++;
|
||||||
while (isdigit((unsigned char) *s)) {
|
if (i < str.len && str.ptr[i] == '-') neg = -1, i++;
|
||||||
|
while (i < str.len && str.ptr[i] >= '0' && str.ptr[i] <= '9') {
|
||||||
result *= 10;
|
result *= 10;
|
||||||
result += (*s - '0');
|
result += (str.ptr[i] - '0');
|
||||||
s++;
|
i++;
|
||||||
}
|
}
|
||||||
return result * neg;
|
return result * neg;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mg_aton(const char *s, uint32_t *ip) {
|
uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len) {
|
||||||
uint8_t data[4] = {0, 0, 0, 0}, ok = 0;
|
int i;
|
||||||
if (s != NULL && sscanf(s, "%hhu.%hhu.%hhu.%hhu", &data[0], &data[1],
|
crc = ~crc;
|
||||||
&data[2], &data[3]) == 4) {
|
while (len--) {
|
||||||
memcpy(ip, data, sizeof(data));
|
crc ^= *(unsigned char *) buf++;
|
||||||
ok = 1;
|
for (i = 0; i < 8; i++) crc = crc & 1 ? (crc >> 1) ^ 0xedb88320 : crc >> 1;
|
||||||
}
|
}
|
||||||
return ok;
|
return ~crc;
|
||||||
}
|
|
||||||
|
|
||||||
char *mg_ntoa(uint32_t ipaddr, char *buf, size_t len) {
|
|
||||||
uint8_t p[4];
|
|
||||||
memcpy(p, &ipaddr, sizeof(p));
|
|
||||||
snprintf(buf, len, "%hhu.%hhu.%hhu.%hhu", p[0], p[1], p[2], p[3]);
|
|
||||||
return buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double mg_time(void) {
|
double mg_time(void) {
|
||||||
@@ -285,7 +324,8 @@ unsigned long mg_millis(void) {
|
|||||||
#elif MG_ARCH == MG_ARCH_ESP32
|
#elif MG_ARCH == MG_ARCH_ESP32
|
||||||
return esp_timer_get_time() / 1000;
|
return esp_timer_get_time() / 1000;
|
||||||
#elif MG_ARCH == MG_ARCH_ESP8266
|
#elif MG_ARCH == MG_ARCH_ESP8266
|
||||||
return system_get_time() / 1000;
|
// return system_get_time() / 1000;
|
||||||
|
return xTaskGetTickCount() * portTICK_PERIOD_MS;
|
||||||
#elif MG_ARCH == MG_ARCH_FREERTOS
|
#elif MG_ARCH == MG_ARCH_FREERTOS
|
||||||
return xTaskGetTickCount() * portTICK_PERIOD_MS;
|
return xTaskGetTickCount() * portTICK_PERIOD_MS;
|
||||||
#else
|
#else
|
||||||
|
|||||||
+17
-7
@@ -4,26 +4,36 @@
|
|||||||
#include "str.h"
|
#include "str.h"
|
||||||
|
|
||||||
char *mg_file_read(const char *path);
|
char *mg_file_read(const char *path);
|
||||||
size_t mg_file_size(const char *path);
|
int64_t mg_file_size(const char *path);
|
||||||
int mg_file_write(const char *path, const char *fmt, ...);
|
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);
|
void mg_random(void *buf, size_t len);
|
||||||
bool mg_globmatch(const char *pattern, int plen, const char *s, int n);
|
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);
|
bool mg_next_comma_entry(struct mg_str *s, struct mg_str *k, struct mg_str *v);
|
||||||
uint16_t mg_ntohs(uint16_t net);
|
uint16_t mg_ntohs(uint16_t net);
|
||||||
uint32_t mg_ntohl(uint32_t net);
|
uint32_t mg_ntohl(uint32_t net);
|
||||||
char *mg_hexdump(const void *buf, int len);
|
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);
|
char *mg_hex(const void *buf, int len, char *dst);
|
||||||
void mg_unhex(const char *buf, int len, unsigned char *to);
|
void mg_unhex(const char *buf, int len, unsigned char *to);
|
||||||
unsigned long mg_unhexn(const char *s, int len);
|
unsigned long mg_unhexn(const char *s, int len);
|
||||||
int mg_asprintf(char **buf, size_t size, const char *fmt, ...);
|
int mg_asprintf(char **buf, size_t size, const char *fmt, ...);
|
||||||
int mg_vasprintf(char **buf, size_t size, const char *fmt, va_list ap);
|
int mg_vasprintf(char **buf, size_t size, const char *fmt, va_list ap);
|
||||||
int64_t mg_to64(const char *s);
|
int64_t mg_to64(struct mg_str str);
|
||||||
bool mg_aton(const char *s, uint32_t *ipaddr);
|
|
||||||
char *mg_ntoa(uint32_t ipaddr, char *buf, size_t len);
|
|
||||||
double mg_time(void);
|
double mg_time(void);
|
||||||
unsigned long mg_millis(void);
|
unsigned long mg_millis(void);
|
||||||
void mg_usleep(unsigned long usecs);
|
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_htons(x) mg_ntohs(x)
|
||||||
#define mg_htonl(x) mg_ntohl(x)
|
#define mg_htonl(x) mg_ntohl(x)
|
||||||
|
|
||||||
@@ -34,7 +44,7 @@ void mg_usleep(unsigned long usecs);
|
|||||||
#if !defined(WEAK)
|
#if !defined(WEAK)
|
||||||
#if (defined(__GNUC__) || defined(__clang__) || \
|
#if (defined(__GNUC__) || defined(__clang__) || \
|
||||||
defined(__TI_COMPILER_VERSION__)) && \
|
defined(__TI_COMPILER_VERSION__)) && \
|
||||||
!defined(_WIN32)
|
!defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
#define WEAK __attribute__((weak))
|
#define WEAK __attribute__((weak))
|
||||||
#else
|
#else
|
||||||
#define WEAK
|
#define WEAK
|
||||||
|
|||||||
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#define MG_VERSION "7.0"
|
#define MG_VERSION "7.2"
|
||||||
@@ -15,25 +15,27 @@ struct ws_msg {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void ws_handshake(struct mg_connection *c, const char *key,
|
static void ws_handshake(struct mg_connection *c, const char *key,
|
||||||
size_t key_len) {
|
size_t key_len, const char *fmt, va_list ap) {
|
||||||
const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||||
unsigned char sha[20], b64_sha[30];
|
unsigned char sha[20], b64_sha[30];
|
||||||
// mem[256], *buf = mem;
|
char mem[128], *buf = mem;
|
||||||
// int len = 0;
|
|
||||||
mg_sha1_ctx sha_ctx;
|
mg_sha1_ctx sha_ctx;
|
||||||
mg_sha1_init(&sha_ctx);
|
mg_sha1_init(&sha_ctx);
|
||||||
mg_sha1_update(&sha_ctx, (unsigned char *) key, key_len);
|
mg_sha1_update(&sha_ctx, (unsigned char *) key, key_len);
|
||||||
mg_sha1_update(&sha_ctx, (unsigned char *) magic, 36);
|
mg_sha1_update(&sha_ctx, (unsigned char *) magic, 36);
|
||||||
mg_sha1_final(sha, &sha_ctx);
|
mg_sha1_final(sha, &sha_ctx);
|
||||||
mg_base64_encode(sha, sizeof(sha), (char *) b64_sha);
|
mg_base64_encode(sha, sizeof(sha), (char *) b64_sha);
|
||||||
|
buf[0] = '\0';
|
||||||
|
if (fmt != NULL) mg_vasprintf(&buf, sizeof(mem), fmt, ap);
|
||||||
mg_printf(c,
|
mg_printf(c,
|
||||||
"HTTP/1.1 101 Switching Protocols\r\n"
|
"HTTP/1.1 101 Switching Protocols\r\n"
|
||||||
"Upgrade: websocket\r\n"
|
"Upgrade: websocket\r\n"
|
||||||
"Connection: Upgrade\r\n"
|
"Connection: Upgrade\r\n"
|
||||||
"Sec-WebSocket-Accept: %s\r\n\r\n",
|
"Sec-WebSocket-Accept: %s\r\n"
|
||||||
b64_sha);
|
"%s\r\n",
|
||||||
// mg_send(c, buf, len);
|
b64_sha, buf);
|
||||||
// if (buf != mem) free(buf);
|
if (buf != mem) free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t ws_process(uint8_t *buf, size_t len, struct ws_msg *msg) {
|
static size_t ws_process(uint8_t *buf, size_t len, struct ws_msg *msg) {
|
||||||
@@ -72,7 +74,7 @@ size_t mg_ws_send(struct mg_connection *c, const char *buf, size_t len,
|
|||||||
if (len < 126) {
|
if (len < 126) {
|
||||||
header[1] = (unsigned char) len;
|
header[1] = (unsigned char) len;
|
||||||
header_len = 2;
|
header_len = 2;
|
||||||
} else if (len < 65535) {
|
} else if (len < 65536) {
|
||||||
uint16_t tmp = mg_htons((uint16_t) len);
|
uint16_t tmp = mg_htons((uint16_t) len);
|
||||||
header[1] = 126;
|
header[1] = 126;
|
||||||
memcpy(&header[2], &tmp, sizeof(tmp));
|
memcpy(&header[2], &tmp, sizeof(tmp));
|
||||||
@@ -95,7 +97,7 @@ size_t mg_ws_send(struct mg_connection *c, const char *buf, size_t len,
|
|||||||
}
|
}
|
||||||
LOG(LL_VERBOSE_DEBUG, ("WS out: %d [%.*s]", (int) len, (int) len, buf));
|
LOG(LL_VERBOSE_DEBUG, ("WS out: %d [%.*s]", (int) len, (int) len, buf));
|
||||||
mg_send(c, buf, len);
|
mg_send(c, buf, len);
|
||||||
if (c->is_client) {
|
if (c->is_client && c->send.buf != NULL) {
|
||||||
uint8_t *p = c->send.buf + c->send.len - len;
|
uint8_t *p = c->send.buf + c->send.len - len;
|
||||||
for (i = 0; i < len; i++) p[i] ^= mask[i & 3];
|
for (i = 0; i < len; i++) p[i] ^= mask[i & 3];
|
||||||
}
|
}
|
||||||
@@ -113,11 +115,14 @@ static void mg_ws_cb(struct mg_connection *c, int ev, void *ev_data,
|
|||||||
c->is_closing = 1; // Some just, not an HTTP request
|
c->is_closing = 1; // Some just, not an HTTP request
|
||||||
} else if (n > 0) {
|
} else if (n > 0) {
|
||||||
if (n < 15 || memcmp(c->recv.buf + 9, "101", 3) != 0) {
|
if (n < 15 || memcmp(c->recv.buf + 9, "101", 3) != 0) {
|
||||||
LOG(LL_ERROR, ("%p WS handshake error: %.*s", c->fd, 15, c->recv.buf));
|
LOG(LL_ERROR,
|
||||||
|
("%lu WS handshake error: %.*s", c->id, 15, c->recv.buf));
|
||||||
c->is_closing = 1;
|
c->is_closing = 1;
|
||||||
} else {
|
} else {
|
||||||
|
struct mg_http_message hm;
|
||||||
|
mg_http_parse((char *) c->recv.buf, c->recv.len, &hm);
|
||||||
c->is_websocket = 1;
|
c->is_websocket = 1;
|
||||||
mg_call(c, MG_EV_WS_OPEN, NULL);
|
mg_call(c, MG_EV_WS_OPEN, &hm);
|
||||||
}
|
}
|
||||||
mg_iobuf_delete(&c->recv, n);
|
mg_iobuf_delete(&c->recv, n);
|
||||||
} else {
|
} else {
|
||||||
@@ -127,24 +132,23 @@ static void mg_ws_cb(struct mg_connection *c, int ev, void *ev_data,
|
|||||||
|
|
||||||
while (ws_process(c->recv.buf, c->recv.len, &msg) > 0) {
|
while (ws_process(c->recv.buf, c->recv.len, &msg) > 0) {
|
||||||
char *s = (char *) c->recv.buf + msg.header_len;
|
char *s = (char *) c->recv.buf + msg.header_len;
|
||||||
|
struct mg_ws_message m = {{s, msg.data_len}, msg.flags};
|
||||||
switch (msg.flags & WEBSOCKET_FLAGS_MASK_OP) {
|
switch (msg.flags & WEBSOCKET_FLAGS_MASK_OP) {
|
||||||
case WEBSOCKET_OP_PING:
|
case WEBSOCKET_OP_PING:
|
||||||
LOG(LL_DEBUG, ("%s", "WS PONG"));
|
LOG(LL_DEBUG, ("%s", "WS PONG"));
|
||||||
mg_ws_send(c, s, msg.data_len, WEBSOCKET_OP_PONG);
|
mg_ws_send(c, s, msg.data_len, WEBSOCKET_OP_PONG);
|
||||||
|
mg_call(c, MG_EV_WS_CTL, &m);
|
||||||
break;
|
break;
|
||||||
case WEBSOCKET_OP_PONG:
|
case WEBSOCKET_OP_PONG:
|
||||||
// Ignore
|
mg_call(c, MG_EV_WS_CTL, &m);
|
||||||
break;
|
break;
|
||||||
case WEBSOCKET_OP_CLOSE: {
|
case WEBSOCKET_OP_CLOSE:
|
||||||
struct mg_ws_message evd = {{s, msg.data_len}, msg.flags};
|
LOG(LL_ERROR, ("%lu Got WS CLOSE", c->id));
|
||||||
LOG(LL_ERROR, ("%p Got WS CLOSE", c->fd));
|
mg_call(c, MG_EV_WS_CTL, &m);
|
||||||
mg_call(c, MG_EV_WS_MSG, &evd);
|
|
||||||
c->is_closing = 1;
|
c->is_closing = 1;
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
default: {
|
default: {
|
||||||
struct mg_ws_message evd = {{s, msg.data_len}, msg.flags};
|
mg_call(c, MG_EV_WS_MSG, &m);
|
||||||
mg_call(c, MG_EV_WS_MSG, &evd);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,9 +197,15 @@ struct mg_connection *mg_ws_connect(struct mg_mgr *mgr, const char *url,
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_ws_upgrade(struct mg_connection *c, struct mg_http_message *hm) {
|
void mg_ws_upgrade(struct mg_connection *c, struct mg_http_message *hm,
|
||||||
|
const char *fmt, ...) {
|
||||||
struct mg_str *wskey = mg_http_get_header(hm, "Sec-WebSocket-Key");
|
struct mg_str *wskey = mg_http_get_header(hm, "Sec-WebSocket-Key");
|
||||||
c->pfn = mg_ws_cb;
|
c->pfn = mg_ws_cb;
|
||||||
if (wskey != NULL) ws_handshake(c, wskey->ptr, wskey->len);
|
if (wskey != NULL) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
ws_handshake(c, wskey->ptr, wskey->len, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
c->is_websocket = 1;
|
c->is_websocket = 1;
|
||||||
}
|
}
|
||||||
@@ -20,5 +20,6 @@ struct mg_ws_message {
|
|||||||
struct mg_connection *mg_ws_connect(struct mg_mgr *, const char *url,
|
struct mg_connection *mg_ws_connect(struct mg_mgr *, const char *url,
|
||||||
mg_event_handler_t fn, void *fn_data,
|
mg_event_handler_t fn, void *fn_data,
|
||||||
const char *fmt, ...);
|
const char *fmt, ...);
|
||||||
void mg_ws_upgrade(struct mg_connection *, struct mg_http_message *);
|
void mg_ws_upgrade(struct mg_connection *, struct mg_http_message *,
|
||||||
|
const char *fmt, ...);
|
||||||
size_t mg_ws_send(struct mg_connection *, const char *buf, size_t len, int op);
|
size_t mg_ws_send(struct mg_connection *, const char *buf, size_t len, int op);
|
||||||
Loaded 100 of 107 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user