Compare commits

...
821 Commits
Author SHA1 Message Date
cpq 0a265e79a6 Remove debug log and add a comment 2022-08-29 13:10:11 +01:00
cpq 7f30c01c58 Correct condition check sequence for the prev fix 2022-08-29 13:01:56 +01:00
cpq 0661f5921a Fix #1690 - mg_json_get for keys with the same prefix 2022-08-29 12:40:50 +01:00
cpq 1c16e95b3a Fix driver link 2022-08-29 08:55:53 +01:00
cpq 44efa45d75 7.8 2022-08-28 14:11:08 +01:00
cpq ef89776517 Add reponse end to the http dir list 2022-08-28 13:58:41 +01:00
cpq 2f3f1357c8 Unbreak after mip init API change 2022-08-27 17:15:11 +01:00
cpq dcdeffff9a MIP refactor: use mg_hton*, move driver_data to ifp, parametrise f746 PLL setup 2022-08-27 16:45:31 +01:00
cpq 229b492ccc Minor refactorings, reduced MG_HTTP_MAX_HEADERS 40 -> 30 to reduce stack usage 2022-08-27 12:31:43 +01:00
cpq 2d45ba1981 Merge branch 'master' of github.com:cesanta/mongoose 2022-08-26 17:41:22 +01:00
cpq b73022096d Let RPC handle responses too 2022-08-26 17:41:13 +01:00
Sergio R. Caprile d1124703b7 Merge pull request #1687 from cesanta/webui-login
Fix SameSite cookie value
2022-08-26 10:24:00 -03:00
Sergio R. Caprile 4a8dd81c93 Fix SameSite cookie value 2022-08-26 10:22:31 -03:00
cpq f474a31484 Rebuild packed_fs.c 2022-08-26 14:21:33 +01:00
cpq e9ec2c5304 Add TLS support to MQTT 2022-08-26 14:20:54 +01:00
cpq c7b9ca68c2 Move mg_mqtt_next-* to the example, and some nits 2022-08-26 14:20:54 +01:00
Sergio R. Caprile ffa033cca9 Merge pull request #1686 from cesanta/device-dashboard
Fix SameSite cookie value
2022-08-26 10:19:08 -03:00
Sergio R. Caprile 3d3f6e09b6 Fix SameSite cookie value 2022-08-26 10:17:49 -03:00
Sergey Lyubka 7252f5385b Merge pull request #1683 from cesanta/multi-threaded
Show how to send data to a worker thread
2022-08-25 23:53:29 +01:00
Sergio R. Caprile ad641880a6 Show how to send data to a worker thread 2022-08-25 17:00:47 -03:00
Sergey Lyubka 1f6d62a635 Merge pull request #1684 from cesanta/nucleo-f746zg-baremetal
Workaround for aliased weak symbol override issue
2022-08-25 05:10:06 +01:00
Sergio R. Caprile 3cd4fd2d61 Workaround for aliased weak symbol override issue
Changed README to use picocom as cu is apparently not able to add carriage return after line feed
2022-08-24 19:02:11 -03:00
cpq d565faa75d Make non-initialised MIP poll work 2022-08-21 23:35:24 +01:00
cpq 786e118f06 Include mongoose_custom.h early to allow overrides 2022-08-20 18:26:29 +01:00
cpq eca612d514 Document all supported MG_ARCH choices 2022-08-20 03:44:29 +01:00
Sergey Lyubka 060f43839d Merge pull request #1680 from cesanta/esp8266
Expanded Makefile
2022-08-20 00:27:09 +01:00
cpq 9c3c4a6f4b MIP client 2022-08-20 00:03:15 +01:00
cpq 101cc1a672 Add define for strdup 2022-08-20 00:02:36 +01:00
Sergio R. Caprile e47f71344d Expanded Makefile 2022-08-19 18:17:52 -03:00
cpq fee6de6a7f Allow NULL head in struct mg_rpc 2022-08-19 15:08:01 +01:00
Sergey Lyubka 2bf25a1406 Merge pull request #1678 from cesanta/esp8266
Improved Makefile to be able to flash
2022-08-18 22:30:20 +01:00
Sergio R. Caprile dd59296be9 Improved Makefile to be able to flash
subtle mod in main.c comment
2022-08-18 17:41:05 -03:00
cpq b382726ed0 Build dashboard by default, fix FPU flag 2022-08-18 21:36:36 +01:00
Sergey Lyubka 01390fe540 Merge pull request #1675 from cesanta/stm32h743
Change README to point to new tutorial location
2022-08-17 08:30:41 +01:00
cpq 8596e1bef7 Enable FPU 2022-08-16 16:45:05 +01:00
Sergey Lyubka 13fffbc5b6 Merge pull request #1674 from cesanta/webui-preact
back to symbolic link
2022-08-16 11:56:08 +01:00
Sergey Lyubka 5f4857ddae Merge pull request #1673 from cesanta/docs
Change argument of %M handler to mg_pfn_t plus some cosmetic changes
2022-08-16 11:55:51 +01:00
Sergey Lyubka 5f36b41785 Merge pull request #1672 from cesanta/webui-push-rest
Change argument of %M handler to mg_pfn_t as in huge_response
2022-08-16 11:55:33 +01:00
Sergio R. Caprile bd8f0c90e1 back to symbolic link 2022-08-15 18:42:20 -03:00
Sergio R. Caprile f49683353d Change argument of %M handler to mg_pfn_t plus some cosmetic changes 2022-08-15 16:07:18 -03:00
Sergio R. Caprile 4f012d6bc6 Change argument of %M handler to mg_pfn_t as in huge_response 2022-08-15 16:04:17 -03:00
cpq e48e353066 Restore mg_file_write() to use tmp file 2022-08-15 16:08:34 +01:00
cpq 6ad7af54dc Fix docs, nits to freertos includes 2022-08-14 23:46:33 +01:00
cpq 6b69bef2ef mg_dtoa, mg_atod, mg_lld made static 2022-08-14 01:25:38 +01:00
cpq d2a27d3d91 mg_*rprintf -> mg_*xprintf 2022-08-13 20:34:20 +01:00
cpq 189aa80743 Update examples to NOT use mg_*mprintf 2022-08-13 20:09:51 +01:00
cpq f122bd5797 Update mg_log_set_fn() 2022-08-13 15:43:27 +01:00
cpq d76f86f7db Get rid of mg_*asprintf 2022-08-13 15:37:55 +01:00
cpq ccf5364187 Squash C++ warn 2022-08-13 14:57:15 +01:00
cpq a3bfe3e61a Use hand-crafted packet for large WS frame test 2022-08-13 14:52:43 +01:00
cpq de10e340b6 Update examples to use mg_http_reply 2022-08-13 14:52:10 +01:00
cpq 40ca26f23b Refactor mg_ws_connect() 2022-08-13 14:44:08 +01:00
cpq da28213613 Squash warning 2022-08-13 11:36:24 +01:00
cpq 6615a821f1 Test WS frames that are larger than 64k 2022-08-13 11:16:13 +01:00
Sergio R. Caprile d627d669bc Change README to point to new tutorial location 2022-08-12 17:08:18 -03:00
cpq ef6fbad0cb Better CFLAGS for SSL when building examples 2022-08-11 12:12:00 +01:00
cpq ef9f7d4c16 Change mg_ws_send: const char * -> const void * 2022-08-11 12:12:00 +01:00
Sergey Lyubka 44a0fa0986 Merge pull request #1670 from cesanta/index.gx-test
Add unit test for gzipped index when / is requested
2022-08-10 23:46:08 +01:00
Sergio R. Caprile 4d9338323a Add unit test for gzipped index when / is requested 2022-08-10 19:06:04 -03:00
Sergey Lyubka 1a6bfb65e6 Merge pull request #1669 from cesanta/embedded-filesystem
Add Embedded Filesystem example
2022-08-10 21:45:23 +01:00
Sergey Lyubka 3b112cc8c8 Merge pull request #1668 from cesanta/index.gz
check for gzipped index file when / is requested
2022-08-10 21:45:09 +01:00
Sergio R. Caprile 014a008c3a Add Embedded Filesystem example 2022-08-10 16:05:34 -03:00
Sergio R. Caprile 374be7b065 check for gzipped index file when / is requested 2022-08-10 15:54:24 -03:00
cpq 2ba3630de9 Remove dangerous mg_pfn_realloc(). Add %q printf specifier 2022-08-10 18:27:58 +01:00
cpq 24cb9467c0 Update docs for mg_rpc_process() 2022-08-10 15:35:07 +01:00
cpq 79c49e64e8 vc2017 -> vc17 2022-08-09 19:22:47 +01:00
cpq c8c0b8fb91 Squash vc98 warn 3 2022-08-09 19:17:40 +01:00
cpq e5585cb0e7 Squash vc98 warn 2 2022-08-09 18:58:58 +01:00
cpq bd32f6e2ef Squash warn on vc98 2022-08-09 15:49:54 +01:00
cpq 08f8ea0cd9 vc2017 -> vc17 2022-08-09 15:38:25 +01:00
cpq 2d48b28b0a Set dockerrun 2022-08-09 13:10:21 +01:00
cpq 9cfaee9b21 Multi-platform docker build 2022-08-09 13:02:50 +01:00
cpq 9393e271de Set dockercmd 2022-08-09 12:47:27 +01:00
cpq 948595fb3b Do not assert on SNTP and local clock diff, since local clock could be off 2022-08-09 12:45:10 +01:00
cpq 6149b619e7 Squash warnings 2022-08-09 12:39:40 +01:00
cpq b7406357c5 Fix #1600 - more precise SNTP time calculation 2022-08-09 12:13:23 +01:00
Sergey Lyubka 2279a51d52 Merge pull request #1666 from cesanta/tcp
Added TLS support
2022-08-08 20:57:11 +01:00
cpq 4d3d0995c9 Use only time.windows.com in SNTP test 2022-08-08 20:56:10 +01:00
Sergio R. Caprile 0ca752662d Added TLS support 2022-08-08 15:42:35 -03:00
cpq 4246f5d206 PATH_MAX -> MG_PATH_MAX 2022-08-06 22:26:07 +01:00
cpq e8289ec17d Fix #1648 - set MG_PATH_MAX to FILENAME_MAX on windows and unix 2022-08-06 22:19:55 +01:00
cpq cde441bca6 Remove tcpdump on port 123 2022-08-06 20:30:12 +01:00
cpq 740b609e1e Fix for deliver_normal_chunks() and a test case 2022-08-06 09:01:34 +01:00
cpq c459c17fab Update docs 2022-08-05 19:55:15 +01:00
cpq 11bbda9bb3 Update images 2022-08-05 19:44:55 +01:00
cpq 6a5c523948 Merge branch 'master' of github.com:cesanta/mongoose 2022-08-05 19:28:04 +01:00
cpq 99c23606c5 Add c->is_resp note 2022-08-05 19:27:56 +01:00
Sergey Lyubka 608b1ee156 Merge pull request #1665 from cesanta/esp32-device-dashboard
Changed README to point to new tutorial location
2022-08-05 19:20:35 +01:00
Sergey Lyubka 12ab5c9964 Merge pull request #1664 from gvanem/patch-1
Fix empty initializer
2022-08-05 19:19:55 +01:00
cpq 779c825e92 Fixes to chunked support when pipelining 2022-08-05 19:18:06 +01:00
Gisle Vanem 96df718304 Fix empty initializer
MSVC does not like such empty initializer:
  xamples/device-dashboard/net.c(116): error C2059: syntax error: '}'
2022-08-05 13:50:55 +02:00
Sergey Lyubka 4bee440a56 Merge pull request #1663 from cesanta/doc-rpc
Add pfn functions and RPC docs
2022-08-04 21:56:24 +01:00
Sergio R. Caprile bb4e4c7cda Add pfn functions docs
Add RPC docs
2022-08-04 17:20:00 -03:00
cpq 582ab220b3 Update mqtt docs 2022-08-04 18:50:20 +01:00
cpq 3e2ad83b2c Fix #1647 - add note in the doc that opts->root_dir is ignored by the mg_http_serve_file() 2022-08-04 17:47:48 +01:00
Sergey Lyubka ae29a1734c Merge pull request #1660 from cesanta/device-dashboard
device-dashboard: default to using packed fs, otherwise hw examples won't work
2022-08-04 17:13:03 +01:00
cpq 457ce5e563 Refactor chunking support. Fix #1656 2022-08-04 17:10:53 +01:00
Sergey Lyubka 154bdb08a9 Merge pull request #1659 from cesanta/scaprile-patch-1
Update README.md
2022-08-04 11:26:33 +01:00
Sergio R. Caprile 22b2dc9ea8 Update README.md 2022-08-03 14:38:12 -03:00
Sergey Lyubka 3ede1a4a5a Merge pull request #1658 from cesanta/ut-pause
Add unit test to check on server pausing between headers and data fir…
2022-08-03 16:20:14 +01:00
Sergio R. Caprile 9e3138b892 Add unit test to check on server pausing between headers and data firing a zero length MG_EV_HTTP_CHUNK 2022-08-03 12:09:24 -03:00
Sergey Lyubka 51cb40acd2 Enable epoll on linux 2022-08-03 15:07:26 +01:00
Sergey Lyubka 4702073458 Merge pull request #1655 from cesanta/esp32-uart-bridge
Fix for new mg_iobuf API
2022-08-03 08:40:04 +01:00
Sergio R. Caprile e01cffff46 Changed README to point to new tutorial location
Expanded Makefile to be able to flash with Docker and esputil
2022-08-02 16:10:34 -03:00
Sergio R. Caprile d88e438679 default to using packed fs, otherwise hw examples won't work 2022-08-02 16:06:19 -03:00
Sergio R. Caprile 70683fc8e7 Fix for new mg_iobuf API 2022-08-02 14:46:27 -03:00
Sergey Lyubka bd7ee0d1e8 Refactor mg_http_reply and mg_http_printf_chunk to use less allocs and mem copies 2022-08-01 21:07:42 +01:00
Sergey Lyubka 17e2fdd4cb Add align to struct mg_iobuf 2022-08-01 12:53:25 +01:00
Sergey Lyubka a468f58128 Use int debug level 2022-08-01 11:19:32 +01:00
Sergey Lyubka 581a0698af Expose rpc guts 2022-07-31 22:51:59 +01:00
Sergey Lyubka f02f88f336 mg_rpc_free -> mg_rpc_del 2022-07-30 21:13:30 +01:00
Sergey Lyubka 43d53b0616 Merge pull request #1650 from cesanta/esp32-uart
Fix Makefile
2022-07-30 07:57:37 +01:00
Sergey Lyubka 54d6bad5e5 Refactor JSON and RPC API 2022-07-30 07:55:26 +01:00
Sergio R. Caprile c37d4f768b Fix Makefile 2022-07-29 18:27:20 -03:00
Sergey Lyubka a4b003b7ac Merge pull request #1644 from cesanta/esp32_uart-bridge
Fix Makefile
2022-07-28 21:04:27 +01:00
Sergey Lyubka 433120ab22 Merge pull request #1637 from cesanta/webui-push-rest
Add data push using REST example
2022-07-28 20:54:20 +01:00
Sergio R. Caprile 109da5f515 Add data push using REST example 2022-07-28 10:20:22 -03:00
Sergey Lyubka 56e6cf406a Fix unamalgamated build 2022-07-28 10:47:12 +01:00
Sergey Lyubka a2289a0625 Fix unamalgamated build 2022-07-28 10:33:44 +01:00
Sergey Lyubka 02943a1082 Merge pull request #1649 from cesanta/tcp
Added plain TCP server and client example
2022-07-28 10:27:10 +01:00
Sergey Lyubka 64a36496e3 Merge pull request #1643 from cesanta/uart-bridge
Fixes to uart-bridge example
2022-07-28 10:26:51 +01:00
Sergey Lyubka f2009ebd62 Move mg_*printf* decls in fmt.h 2022-07-28 10:18:17 +01:00
Sergio R. Caprile 638892ca70 Fix incorrect oninput function call
Check a new config element is present before acting on the previous one

Correctly update config local copy

Fix TCP buffering for ever
2022-07-27 17:19:34 -03:00
Sergio R. Caprile 90fdbd36ec Added plain TCP server and client example 2022-07-27 13:40:02 -03:00
Sergey Lyubka 0dabc45780 Add RPC API 2022-07-27 00:46:05 +01:00
Sergio R. Caprile 0ffec91984 Fix Makefile 2022-07-25 11:27:19 -03:00
Sergey Lyubka 9cacf443e1 Merge pull request #1636 from cesanta/webui-push-ws
Added data push over WS example
2022-07-25 11:03:06 +01:00
Sergey Lyubka 3f21be4fb0 Merge pull request #1639 from cesanta/docs
Add mg_ws_printf()/vprintf() doc
2022-07-25 10:54:06 +01:00
Sergey Lyubka 7587f8212e Merge pull request #1642 from cesanta/fix-json
Fix json's MG_EOO in nested objects
2022-07-25 10:53:30 +01:00
Sergio R. Caprile 1eed80375d Fix MG_EOO 2022-07-22 11:50:23 -03:00
Sergio R. Caprile 806eed6040 Add mg_ws_printf()/vprintf() doc 2022-07-21 11:46:50 -03:00
Sergey Lyubka d1828ecdb4 Merge pull request #1634 from cesanta/webui-plain
Fix former config value not being freed
2022-07-18 21:24:07 +01:00
Sergey Lyubka 5cddb8ecda Merge pull request #1633 from cesanta/webui-login
Added web UI login example
2022-07-18 21:23:41 +01:00
Sergio R. Caprile 1651d9d6d9 Fix former config value not being freed 2022-07-18 16:21:02 -03:00
Sergio R. Caprile 40fc049cdc Added web UI login example 2022-07-18 14:12:42 -03:00
Sergey Lyubka 89afe62121 Merge pull request #1627 from cesanta/webui-rest
added webUI REST basics example
2022-07-17 18:09:02 +01:00
Sergey Lyubka e5b40ee29e Merge pull request #1630 from cesanta/webui-plain
added webUI plain JS example
2022-07-17 18:08:45 +01:00
Sergey Lyubka 4a3d760c06 Add timer ID attribute, for safe cleanup in the scripted environment 2022-07-17 12:52:30 +01:00
Sergio R. Caprile aa326f975d Added data push over WS example 2022-07-15 21:32:41 -03:00
Sergey Lyubka 1fbf534f9a Merge pull request #1631 from cesanta/webui-preact-example
added webUI Preact-based example
2022-07-15 09:15:43 +01:00
Sergey Lyubka 86aa38bfd5 Merge pull request #1629 from jbrzusto/fix-mg_ntp_parse
NTP reponse gives fractional (not micro-) seconds, per RFC5905
2022-07-15 00:43:31 +01:00
Sergio R. Caprile ca929031ee added webUI Preact-based example 2022-07-13 14:41:38 -03:00
Sergio R. Caprile f80477a093 added webUI plain JS example 2022-07-13 11:07:01 -03:00
Sergio R. Caprile abd7698d6d added webUI REST basics example 2022-07-13 10:45:49 -03:00
John Brzustowski d5fe3261f4 NTP reponse gives fractional (not micro-) seconds, per RFC5905 2022-07-13 04:08:54 -03:00
Sergey Lyubka 3f46ae7beb Make generated packed_fs.c independent 2022-07-12 15:09:33 +01:00
Sergey Lyubka 46af09f776 Change ff_open to explicit memcpy() 2022-07-11 18:13:46 +01:00
Sergey Lyubka f40b272eeb Fix #1626 - ignore @ in query string 2022-07-10 15:41:43 +01:00
Sergey Lyubka 9876e3afd7 Merge pull request #1622 from cesanta/percentM
added mg_rprintf(), updated doc to new %M API
2022-07-10 11:15:52 +01:00
Sergio R. Caprile 41df6a6c0b added mg_rprintf(), updated doc to new %M API 2022-07-07 14:15:55 -03:00
Sergey Lyubka dbd25daff8 Merge pull request #1621 from cesanta/percentM
Update (fix) to new %M API
2022-07-07 14:44:54 +01:00
Sergio R. Caprile 71eefb6272 Update to new %M API
Doc still references the old API and mg_rprintf() is not yet documented
2022-07-06 19:01:18 -03:00
Sergey Lyubka a4a340dbd4 Merge branch 'master' of github.com:cesanta/mongoose 2022-07-04 19:18:27 +01:00
Sergey Lyubka 2c01893bb1 Give more time for unit test to detect conn refused on windows 2022-07-04 19:18:20 +01:00
Sergey Lyubka c4e496b001 Merge pull request #1618 from cesanta/mqtt
updated docs and example to recently exported MQTT result codes
2022-07-04 19:07:28 +01:00
Sergio R. Caprile 16e90c3082 updated docs and example to recently exported MQTT result codes 2022-07-04 14:32:12 -03:00
Sergey Lyubka 543b4a132b Fix POLLERR usage 2022-07-04 18:25:13 +01:00
Sergey Lyubka e4a5296fbf Introduce c->is_mqtt5 for keeping mqtt version. Make mqtt over ws work again 2022-07-04 17:47:17 +01:00
Sergey Lyubka 6c796b8552 Fix memset in mg_iotest, add mg_random_str test 2022-07-04 16:13:38 +01:00
Sergey Lyubka e30ad43d36 Merge pull request #1612 from cesanta/mqtt
Exported MQTT result codes
2022-07-04 15:15:19 +01:00
Sergey Lyubka f841b85d7d Merge pull request #1614 from cesanta/udp-ssdp-search
Added parsing of remote responses
2022-07-04 15:14:39 +01:00
Sergey Lyubka 735b7bece6 Squash more warns 2022-07-04 11:43:52 +01:00
Sergey Lyubka 4c9fdaf8b0 Merge pull request #1617 from jameshilliard/osx-clock
util: use correct clock on OSX
2022-07-04 11:12:58 +01:00
Sergey Lyubka 2ccc4acf34 Squash warns for rp2040 builds 2022-07-04 11:10:08 +01:00
James Hilliard c24343f107 util: use correct clock on OSX
CLOCK_MONOTONIC_RAW on OSX is not the same as CLOCK_MONOTONIC_RAW on linux
2022-07-04 04:04:43 -06:00
Sergey Lyubka 81ffcd8ee9 Fix #1616 - randomize mqtt will and client id for parallel test 2022-07-04 11:00:06 +01:00
Sergey Lyubka 432452ea9a Fix #1615 - prefer monotonic clock. Add clock for rp2040 2022-07-04 10:08:21 +01:00
Sergey Lyubka 6c14c7d623 Unbreak mac build 2022-07-04 00:06:01 +01:00
Sergey Lyubka 30126072dc Add MG_ARCH_RP2040 2022-07-03 23:00:15 +01:00
Sergio R. Caprile f7812c9b0a Added parsing of remote responses 2022-07-02 13:16:49 -03:00
Sergey Lyubka dca43f430b Fix poll support for win32 2022-07-02 12:45:44 +01:00
Sergey Lyubka 0947ce9234 Merge branch 'master' of github.com:cesanta/mongoose 2022-07-02 11:57:09 +01:00
Sergey Lyubka 91fa2ad23b Enable poll support on windows 2022-07-02 11:52:16 +01:00
Sergey Lyubka 1b57c56fdc Merge pull request #1613 from cesanta/typo
fix typo
2022-07-02 11:15:43 +01:00
Sergio R. Caprile d13509e302 Update app.js 2022-07-01 15:58:03 -03:00
Sergio R. Caprile 85d300ce71 Exported MQTT result codes 2022-07-01 15:32:24 -03:00
Sergey Lyubka d6e1a3ab4c Unbreak my heart ^W the build 2022-07-01 18:10:40 +01:00
Sergey Lyubka f1da8542ce Nits 2022-07-01 17:28:06 +01:00
Sergey Lyubka a183621268 Fix ff_write() call 2022-07-01 13:22:36 +01:00
Sergey Lyubka 035de980e3 Fix ff_read() call 2022-07-01 13:18:49 +01:00
Sergey Lyubka 99f0688377 Change mg_http_upload API 2022-06-30 21:54:50 +01:00
Sergey Lyubka 56412193e7 Add mg_remove_double_dots(), hide mg_http_upload() 2022-06-30 20:27:43 +01:00
Sergey Lyubka c5751b0bd3 Add mg_json_get_long 2022-06-30 20:03:29 +01:00
Sergey Lyubka 86e57d243d Enhance esp32 makefile 2022-06-30 19:59:23 +01:00
Sergey Lyubka 7fc57a3be7 Merge pull request #1610 from cesanta/http-restful-server
updated SSL build options
2022-06-30 12:27:25 +01:00
Sergio R. Caprile 75069a44c7 updated SSL build options 2022-06-29 17:31:31 -03:00
Sergey Lyubka 2536865c4d Fix freertos-tcp build 2022-06-29 19:39:36 +01:00
Sergey Lyubka d266f822ca Merge branch 'master' of github.com:cesanta/mongoose 2022-06-29 19:19:28 +01:00
Sergey Lyubka 5b8979a0f1 Better connect() result test 2022-06-29 19:19:19 +01:00
Sergey Lyubka 3bc79b9dfd Merge pull request #1609 from cesanta/mqtt-over-ws-client
Added openSSL support
2022-06-29 19:18:25 +01:00
Sergio R. Caprile 0ae75e6db6 Added openSSL support 2022-06-29 14:57:11 -03:00
Sergey Lyubka 89e2a15eb7 Fix build 2022-06-29 18:03:04 +01:00
Sergey Lyubka b1896d9944 Fix typo 2022-06-29 17:57:59 +01:00
Sergey Lyubka d0dedcfd2e Fix build 2022-06-29 17:54:33 +01:00
Sergey Lyubka 73297c8e65 Use mg_putchar_iobuf in mg_vprintf 2022-06-29 17:42:55 +01:00
Sergey Lyubka 017c7290d6 Better error handling - report from iotest 2022-06-29 17:02:37 +01:00
Sergey Lyubka 6a8b5b06d0 Merge pull request #1608 from cesanta/fix_mqtt-over-ws-client
fix incorrect WS packet payload
2022-06-29 14:51:39 +01:00
Sergey Lyubka 93a6bc501e Refactor guess_mime_type() 2022-06-29 10:28:37 +01:00
Sergey Lyubka e8f050c194 Dont use realloc 2022-06-29 00:00:16 +01:00
Sergio R. Caprile 712517b6fa fix incorrect WS packet payload 2022-06-28 16:27:49 -03:00
Sergey Lyubka 434378eda5 Merge pull request #1602 from cesanta/device-dashboard
fixed watch() not being called after login
2022-06-28 20:24:36 +01:00
Sergey Lyubka cf38fdb720 Merge pull request #1606 from cesanta/mqtt-client
fixed TLS build comment
2022-06-28 20:23:45 +01:00
Sergey Lyubka 95d30cf482 Merge pull request #1607 from cesanta/http-client
fixed TLS build comment
2022-06-28 20:20:35 +01:00
Sergio R. Caprile 6542c02b7f fixed TLS build comment 2022-06-28 10:56:56 -03:00
Sergio R. Caprile a13144932a fixed TLS build comment 2022-06-28 10:49:45 -03:00
Sergio R. Caprile 6597830631 fixed watch() not being called after login 2022-06-28 10:26:32 -03:00
Sergey Lyubka ba08140197 Initial mqtt5 support 2022-06-28 11:31:13 +01:00
Sergey Lyubka d65ce3b596 Add mg_rprintf, mg_vrprintf 2022-06-28 00:45:52 +01:00
Sergey Lyubka 4864a6e618 Use SSL_set1_host() 2022-06-28 00:45:47 +01:00
Sergey Lyubka 2bbb2bb1db Merge branch 'master' of github.com:cesanta/mongoose 2022-06-24 14:27:29 +01:00
Sergey Lyubka 47ce004f61 docs nits 2022-06-24 14:24:14 +01:00
Sergey Lyubka 507e392509 Merge pull request #1601 from cesanta/device-dashboard
updated and cleaned up texts
2022-06-24 14:09:36 +01:00
Sergio R. Caprile dcfb014d1f updated and cleaned up texts 2022-06-23 15:33:31 -03:00
Sergey Lyubka 4e880fb6e0 Nit - fix openssl error message 2022-06-23 13:11:04 +01:00
Sergey Lyubka 898e2b1e30 Add mg_json_get_hex(), mg_json_get_b64() 2022-06-22 16:28:22 +01:00
Sergey Lyubka a68f3dc4eb Add %V and %H specifiers for mg_snrpintf() 2022-06-22 13:15:52 +01:00
Sergey Lyubka c446fe0c6d Make stm32 eth declared as volatile 2022-06-21 12:11:59 +01:00
Sergey Lyubka 4246e6c768 Fix #1599 2022-06-21 12:07:00 +01:00
Sergey Lyubka 4f9cfdf65d Merge pull request #1598 from cesanta/http-reverse-proxy
Added openSSL support
2022-06-20 22:00:14 +01:00
Sergey Lyubka b1cd233dda Merge pull request #1597 from cesanta/http-proxy-client
Added openSSL support
2022-06-20 21:59:48 +01:00
Sergey Lyubka 4f63b6093f Merge pull request #1595 from cesanta/http-client
fixed comment, updated TLS section in makefile
2022-06-20 21:59:24 +01:00
Sergio R. Caprile 380a50e39b Added openSSL support
Fixed missing parameter in makefile
Added URI handling
2022-06-20 15:27:46 -03:00
Sergio R. Caprile 3bd3a4ff7b fixed comment, updated TLS section in makefile 2022-06-20 14:50:45 -03:00
Sergey Lyubka 46bf79455c Add examples/esp32/uart-bridge 2022-06-19 18:27:37 +01:00
Sergey Lyubka 2d5c26d44f Rename mg_log_set_fn properly 2022-06-19 09:08:37 +01:00
Sergey Lyubka 9760b7c9d6 Add mg_log_set_fn(), MG_ENABLE_LOG 2022-06-19 09:04:22 +01:00
Sergey Lyubka 0b5a00c99a Change uart_read signature 2022-06-18 20:41:04 +01:00
Sergey Lyubka ba8482c707 Update uart bridge 2022-06-18 11:32:31 +01:00
Sergey Lyubka 1b34360b05 Update uart bridge 2022-06-18 11:30:44 +01:00
Sergey Lyubka c84dab21e4 Refactor UART example 2022-06-18 04:25:11 +01:00
Sergey Lyubka 1640287897 Add mg_http_var 2022-06-18 04:25:11 +01:00
Sergey Lyubka adcf5bab0e Merge pull request #1589 from cesanta/mqtt-client
Add support for openSSL
2022-06-17 22:04:38 +01:00
Sergey Lyubka e024700851 Merge pull request #1593 from cesanta/file-uploads
update file upload example set
2022-06-17 22:03:58 +01:00
Sergio R. Caprile f4fc33d111 brought back 7.5 file-upload as file-upload-multiple-posts; updated to latest API
renamed form-upload to file-upload-html-form
renamed file-upload to file-upload-single-post
2022-06-17 16:35:02 -03:00
Sergio R. Caprile fb446022e2 Added openSSL support
Backend host is https only if TLS is enabled
2022-06-16 11:59:06 -03:00
Sergio R. Caprile e021d7cd9d Add support for openSSL 2022-06-15 10:42:32 -03:00
Sergey Lyubka 3331ed2f49 Merge pull request #1591 from cesanta/jsondoc
fix JSON docs
2022-06-15 06:56:08 +01:00
Sergio R. Caprile 939a8ddc26 fix JSON docs 2022-06-14 14:19:25 -03:00
Sergey Lyubka 3774f676cf Less verbose unit test 2022-06-13 21:12:11 +01:00
Sergey Lyubka 7923509d1e More json docs 2022-06-13 15:04:52 +01:00
Sergey Lyubka 30d6a44b0d Fix mg_http_upload() 2022-06-13 14:48:52 +01:00
Sergey Lyubka 6d46ecaa6c Add mip-pcap example 2022-06-13 02:03:52 +01:00
Sergey Lyubka 5a448ab4f5 Compile driver_stm32.c only for __arm__ 2022-06-13 01:04:09 +01:00
Sergey Lyubka a71262437d Use mip for arm and riscv targets 2022-06-12 12:43:01 +01:00
Sergey Lyubka 52ab963845 Update images 2022-06-11 22:59:20 +01:00
Sergey Lyubka 67280724ba Remove pragma 2022-06-11 19:05:07 +01:00
Sergey Lyubka d8a4b5aa34 Make mip MSVC friendly 2022-06-11 18:54:32 +01:00
Sergey Lyubka fe0b2d0646 Fix typo 2022-06-11 17:40:48 +01:00
Sergey Lyubka d3368e4aad Move mip into mip/ 2022-06-11 17:29:45 +01:00
Sergey Lyubka 903b510411 Merge pull request #1587 from cesanta/timers
fixed poll timeout being larger than timer period
2022-06-10 22:57:44 +01:00
Sergio R. Caprile 0dbc99d9ee fixed poll timeout being larger than timer period 2022-06-10 16:59:14 -03:00
Sergio R. Caprile 505ca96547 fixed typo 2022-06-10 16:25:56 -03:00
Sergey Lyubka 89623d00f9 Update readme 2022-06-10 18:48:32 +01:00
Sergey Lyubka e47bcb3fb6 Merge pull request #1583 from cesanta/multi-threaded
Remove outdated comments
2022-06-10 15:21:32 +01:00
Sergey Lyubka 50d0d68f45 Docs nitpick 2022-06-10 15:00:34 +01:00
Sergio R. Caprile 2f75418c70 Remove outdated comments 2022-06-10 10:37:12 -03:00
Sergey Lyubka 013bc58371 Add json docs 2022-06-10 13:01:52 +01:00
Sergey Lyubka 55948cd431 Allow to set log level 2022-06-10 12:33:30 +01:00
Sergey Lyubka dfca896a64 Update huge response. More tests 2022-06-10 12:14:42 +01:00
Sergey Lyubka 8fc6f3f744 Remove mjson dependency 2022-06-10 09:40:22 +01:00
Sergey Lyubka f65058fa03 Remove mjson dependency
Signed-off-by: Sergey Lyubka <valenok@gmail.com>
2022-06-10 09:39:53 +01:00
Sergey Lyubka 33567bab41 Add %g support to mg_snprintf() 2022-06-10 09:38:36 +01:00
Sergey Lyubka 106662b1d7 Add JSON API 2022-06-09 17:17:33 +01:00
Sergey Lyubka b73115c002 Unbreak build 2022-06-08 22:09:11 +01:00
Sergey Lyubka cff208c5a9 Introduce %Q format specifier, rework device dashboard 2022-06-08 21:44:01 +01:00
Sergey Lyubka a83dd9569d Unbreak esp32 example 2022-06-08 20:04:35 +01:00
Sergey Lyubka 807cd4df9e Make sock.c less verbose 2022-06-08 19:55:24 +01:00
Sergey Lyubka ac3151f871 Make dashboard more robust 2022-06-08 19:53:29 +01:00
Sergey Lyubka d4106b5cbd Send puback for qos > 0 2022-06-08 19:51:03 +01:00
Sergey Lyubka bcb6c2675f Unbreak esp32 device dashboard build 2022-06-08 13:54:20 +01:00
Sergey Lyubka 6b51666248 Move esp32 example 2022-06-08 13:24:41 +01:00
Sergey Lyubka 628a007112 Refresh packed filesystems 2022-06-08 13:22:09 +01:00
Sergey Lyubka ee65342545 docs 2022-06-08 11:30:54 +01:00
Sergey Lyubka 94ea973fb5 Update docs 2022-06-08 11:01:30 +01:00
Sergey Lyubka 9f8424e93f Update readme 2022-06-08 09:06:14 +01:00
Sergey Lyubka 2e750236be Add uart-bridge example 2022-06-08 08:58:32 +01:00
Sergey Lyubka c701315ab5 Merge pull request #1581 from behnejad/patch-1
fixing offset of Content-Length value.
2022-06-07 08:35:24 +01:00
Sergey Lyubka a53dc5c0a0 Fix #1580 - uri_to_path2 for / corner case 2022-06-07 04:33:46 +01:00
Behnejad 895ca80b2b fixing offset of Content-Length value.
in very large HTTP response, this offset might cause a problem with HTTP header format.
2022-06-07 08:00:12 +04:30
Sergey Lyubka 1dcb7dd13d Update mingw target 2022-06-07 00:25:15 +01:00
Sergey Lyubka e75afcba42 Update dash UI 2022-06-05 17:17:19 +01:00
Sergey Lyubka 0f0cf7a5db Integrate #1579 - properly clear c->is_readable and c->is_writable flags in mg_iotest() 2022-06-05 15:27:16 +01:00
Sergey Lyubka 31c7d66245 Rework dashboard 2022-06-05 14:59:59 +01:00
Sergey Lyubka cac7f653c9 Add mg_ws_printf() 2022-06-05 14:59:50 +01:00
Sergey Lyubka 219428c249 Change device dashboard to use MQTT 2022-06-04 22:21:59 +01:00
Sergey Lyubka f4fa1e097d docs 2022-06-04 08:45:34 +01:00
Sergey Lyubka 35b517b434 docs 2022-06-04 08:29:03 +01:00
Sergey Lyubka b3f956ba63 docs 2022-06-04 08:23:25 +01:00
Sergio R. Caprile 3ae8b3f8a7 Merge pull request #1577 from cesanta/sntp
Add sntp-time-sync example
2022-06-03 10:38:25 -03:00
Sergey Lyubka c48349ba56 Add sntp-time-sync example 2022-06-03 13:57:57 +01:00
Sergey Lyubka 0763146254 Fix #1476 - introduce c->is_full to cap the recv buf len for streaming connections 2022-06-03 11:37:35 +01:00
Sergio R. Caprile 7da5d42009 Merge pull request #1573 from cesanta/timers
Minor cosmetic changes
2022-06-02 10:06:41 -03:00
Sergey Lyubka 5ac847076a Change long read_conn -> void read_conn 2022-06-02 14:02:09 +01:00
Sergey Lyubka a88ea776a9 Change MG_MAX_RECV_BUF_SIZE -> MG_MAX_RECV_SIZE 2022-06-02 13:50:44 +01:00
Sergey Lyubka 73a5ff1fb6 Use only TFLAGS, get rid of EXTRA 2022-06-02 12:02:41 +01:00
Sergey Lyubka 7e8901c99f Docs - amend images 2022-06-02 12:02:26 +01:00
Sergey Lyubka 45816ef5db Add missing test file 2022-06-02 06:18:43 +01:00
Sergey Lyubka fe682f8399 Fix #1560 - implement precompressed .gz file serving 2022-06-02 06:13:37 +01:00
Sergey Lyubka 9ffb6fb26a Merge pull request #1570 from behnejad/patch-2
Update README.md
2022-06-01 21:17:52 +01:00
Sergey Lyubka 063244e4ca Minor cosmetic changes 2022-06-01 21:15:31 +01:00
Sergey Lyubka d7b7a0a577 Merge pull request #1572 from cesanta/timers
Modify times example
2022-06-01 17:22:24 +01:00
Sergey Lyubka f735585239 Update timers example 2022-06-01 17:09:15 +01:00
Sergey Lyubka 30349ec217 Update timers example 2022-06-01 17:09:13 +01:00
Sergey Lyubka 55517d48ed Change linux target 2022-06-01 16:25:04 +01:00
Behnejad 0f93ab84e9 Update README.md
after sending buffer to socket, MG_EV_WRITE will generated.
2022-06-01 14:36:17 +04:30
Sergey Lyubka 4dd1891594 Add mg_http_serve_opts.page404 2022-05-31 23:44:03 +01:00
Sergey Lyubka 27e1472d88 Merge pull request #1568 from behnejad/master
adding new api to enable separation of query string with '&'.
2022-05-31 18:25:12 +01:00
Sergey Lyubka a3d63c095a Handle #1562 - add udp/tcp extra param to mg_mkpipe() 2022-05-31 18:23:32 +01:00
Sergey Lyubka dc486a2aa3 Add pics 2022-05-31 12:01:06 +01:00
Sergey Lyubka 9963bdee09 Docs images 2022-05-31 11:38:03 +01:00
Hooman Behnejad 499401d457 adding mg_split function 2022-05-31 14:11:14 +04:30
Sergey Lyubka e2fcf5f92c Fix #1565 - mg_snprintf %.*s with zero len printing 2022-05-30 18:40:44 +01:00
Sergey Lyubka b8bba7513a Fix #1566 - proper error cleanup in mg_listen 2022-05-30 17:56:50 +01:00
Sergey Lyubka 65957527cb Fix #1558 - add opts.extra_headers in 304 responses 2022-05-30 17:44:26 +01:00
Sergey Lyubka e2ce68e3ef Fix build: delete -> del 2022-05-30 16:20:14 +01:00
Sergey Lyubka 44cf02e5ba Fix #1545 - do not send MG_EV_HTTP_MSG if chunks were deleted 2022-05-30 16:02:59 +01:00
Sergey Lyubka a4a70270ee Merge pull request #1564 from behnejad/patch-1
Update README.md
2022-05-30 14:32:17 +01:00
Behnejad 82e1cac1c7 Update README.md
added missing parameter in sample code of `mg_match`.
2022-05-29 18:22:56 +04:30
Sergey Lyubka 21ffe8e3f3 docs 2022-05-29 12:59:33 +01:00
Sergey Lyubka 45f20d5089 Update http_message diagram 2022-05-29 12:03:54 +01:00
Sergey Lyubka cea12a35b7 Merge pull request #1563 from vkoskiv/fix-docs
Small fix to mg_timer_add() documentation
2022-05-28 18:28:27 +01:00
Sergey Lyubka 686320a805 Remove verbose log in mg_iotest() 2022-05-27 23:18:23 +01:00
Sergey Lyubka 14ad51d2d2 More SNtp debug 12 2022-05-27 22:47:12 +01:00
Sergey Lyubka 28c15b3ff4 More SNtp debug 11 2022-05-27 22:36:34 +01:00
Sergey Lyubka f5af28c886 More SNtp debug 10 2022-05-27 22:26:17 +01:00
Sergey Lyubka 6b50039863 More SNtp debug 9 2022-05-27 22:24:45 +01:00
Sergey Lyubka 34c5f63c00 More SNtp debug 8 2022-05-27 22:18:14 +01:00
Sergey Lyubka 53bca4efab More SNtp debug 7 2022-05-27 22:08:05 +01:00
Sergey Lyubka 9029593691 More SNtp debug 6 2022-05-27 21:59:13 +01:00
Sergey Lyubka 4aad859e20 More SNtp debug 5 2022-05-27 21:44:03 +01:00
Sergey Lyubka b9d1d4a94f More SNtp debug 4 2022-05-27 20:48:19 +01:00
Sergey Lyubka be8b01e289 More SNtp debug 4 2022-05-27 20:43:30 +01:00
Sergey Lyubka 360dedd9b2 More SNtp debug 3 2022-05-27 20:39:37 +01:00
Sergey Lyubka e5d3d02307 More SNtp debug 2022-05-27 20:16:08 +01:00
Sergey Lyubka d3e14ca7e5 More SNTP debug 3 2022-05-27 20:05:14 +01:00
Sergey Lyubka 5998208449 More SNTP debug 2022-05-27 19:57:15 +01:00
Sergey Lyubka 4fc84621ae More SNTP debug 2022-05-27 19:55:39 +01:00
Valtteri Koskivuori 8253a84689 Small fix to mg_timer_add() documentation
The return value was not documented.
2022-05-26 23:43:56 +03:00
Sergey Lyubka 6b7f14c69d docs 2022-05-26 20:25:20 +01:00
Sergey Lyubka cfaca604f5 Debug SNTP issue 2 2022-05-26 17:50:56 +01:00
Sergey Lyubka 0226b9db31 Debug SNTP issue 2022-05-26 17:45:52 +01:00
Sergey Lyubka 7f8d12b9f7 Use time.windows.com too 2022-05-26 16:22:44 +01:00
Sergey Lyubka 2ae341cf5e Add nucleo-f746zg-baremetal 2022-05-26 13:53:36 +01:00
Sergey Lyubka 7850b550d8 Unbreak test 2022-05-26 11:18:36 +01:00
Sergey Lyubka 10596a8bdc Proper TLS handling for poll(). Make poll() default on linux 2022-05-26 08:55:28 +01:00
Sergey Lyubka 252e4715d4 Merge pull request #1561 from vkoskiv/add-poll
Add optional poll() implementation under MG_ENABLE_POLL define
2022-05-26 07:53:02 +01:00
Valtteri Koskivuori 420b989adb Add optional poll() implementation under MG_ENABLE_POLL
This adds the ability to substitute select() with poll() on supported
unix environments when MG_ENABLE_POLL is defined. A make flag called
USE_POLL is provided as well.
Using poll() removes the limitation of FD_SETSIZE concurrent sockets,
generally 1024 on Linux environments.
2022-05-26 06:00:27 +03:00
Sergey Lyubka bdb388c79d Fix pedantic warnings 2022-05-26 03:08:08 +01:00
Sergey Lyubka 87148f95f2 Clean up pedantic warnings 2022-05-26 02:50:15 +01:00
Sergey Lyubka fe124354cd Update custom build instructions 2022-05-26 02:10:28 +01:00
Sergey Lyubka 9a28fa71f0 Add -pedantic to gcc/clang CFLAGS 2022-05-26 02:10:07 +01:00
Sergey Lyubka 4139cdaf35 Remove poll() support 2022-05-26 02:07:37 +01:00
Sergey Lyubka ebe04620e1 Better custom build reference 2022-05-25 13:36:39 +01:00
Sergey Lyubka 7e053cd632 Typo fs docs 2022-05-25 13:29:49 +01:00
Sergey Lyubka 1fd65c77fe Enhance fs docs 2022-05-25 13:28:25 +01:00
Sergey Lyubka 2bfc838614 Fix build 2022-05-25 11:18:54 +01:00
Sergey Lyubka 69082db381 Regenerated packed fs 2022-05-25 11:15:00 +01:00
Sergey Lyubka 5ce2130f05 Minor formatting fix 2022-05-25 11:14:42 +01:00
Sergey Lyubka 5b448ec7a6 Integrate #1561 with some minor tweaks - add MG_ENABLE_POLL for poll() support 2022-05-25 11:14:12 +01:00
Sergey Lyubka f72b27d1c1 docs 2022-05-24 20:36:21 +01:00
Sergey Lyubka 9973c5f2b7 docs 2022-05-24 19:20:20 +01:00
Sergey Lyubka 88ee415dd1 docs 2022-05-24 19:19:42 +01:00
Sergey Lyubka 4f168cf346 docs 2022-05-24 19:18:42 +01:00
Sergey Lyubka ad7b5d2cd8 Change packed image 2022-05-24 19:14:20 +01:00
Sergey Lyubka 1e522de4a7 Change mg_iobuf image 2022-05-24 18:57:22 +01:00
Sergey Lyubka c2d2d085cd Add chart example 2022-05-23 15:27:19 +01:00
Sergey Lyubka b3a4c12d67 Handle #1559 - set no flags in send() call 2022-05-22 23:49:38 +01:00
Sergey Lyubka d5993ba27e Fix #1550 - excladdrinuse 2022-05-21 16:18:34 +01:00
Sergey Lyubka ef563603a9 Merge pull request #1557 from cesanta/pc
Remove mg_log_set_callback. Use MG_PUTCHAR macro instead
2022-05-20 10:16:57 +01:00
Sergey Lyubka 7e2ca72310 Remove mg_log_set_callback. Use MG_PUTCHAR macro instead 2022-05-20 09:45:17 +01:00
Sergey Lyubka 7c17c806ad 7.6 -> 7.7 2022-05-19 11:44:32 +01:00
Sergey Lyubka 8e0f529a00 Add MIP - an experimental TCP/IP stack 2022-05-18 21:19:21 +01:00
Sergey Lyubka 47e15a3d47 RTX nits 2022-05-17 19:29:53 +01:00
Sergey Lyubka cac7007069 Merge pull request #1554 from zudwalex/zephyr_ci
Use docker for Zephyr CI
2022-05-16 13:39:25 +01:00
Alex Alashkin ac55c900e7 Use docker for Zephyr CI 2022-05-16 15:30:25 +03:00
Sergey Lyubka 25806e48dc Fix ESP32 build 2022-05-16 11:54:26 +01:00
Sergey Lyubka 3871f4b6ab Fix #1546 - dont send excess for range requests 2022-05-16 11:45:08 +01:00
Sergey Lyubka 27c892806b Fix #1540 - case sensitive match in mg_is_chunked() 2022-05-16 11:19:45 +01:00
Sergey Lyubka 2b9f0480a1 Fix #1549 - fix typo in log format specifier 2022-05-15 21:02:41 +01:00
Sergey Lyubka 72cc433265 Make SNTP test more resilient 2022-05-15 19:41:37 +01:00
Sergey Lyubka 7721b074e6 Log ms in test_sntp() 2022-05-15 19:31:29 +01:00
Sergey Lyubka f5fd176b35 Increate SNTP timeout 3s->5s. Change mg_sntp_send() to mg_sntp_request(), remove one unnecessary parameter 2022-05-15 18:41:01 +01:00
Sergey Lyubka 6db1d7925e Merge pull request #1552 from zudwalex/ti_merged
Add TI support
2022-05-15 17:40:46 +01:00
Alex Alashkin 0ed7545947 Add TI support 2022-05-15 19:25:50 +03:00
Sergey Lyubka 95e22e8d4f Exporting only dashboard func 2022-05-15 14:40:58 +01:00
Sergey Lyubka cf7d1d8041 Address #1551 - better timers handling 2022-05-15 14:29:34 +01:00
Sergey Lyubka 443d0f0c6c Rename complete -> device-dashboard, remove multiple-logins and dashboard 2022-05-14 09:08:23 +01:00
Sergey Lyubka c20e48179f Un-break the test and untie serving code in dash example 2022-05-13 22:15:33 +01:00
Sergey Lyubka 3fbb7de712 Refactor dashboard example 2022-05-13 20:08:08 +01:00
Sergey Lyubka 0294603dfc MG_ARCH_RTX nits 2022-05-12 15:07:02 +01:00
Sergey Lyubka 5458252e4a Add missing src/arch_rtx.h 2022-05-12 08:23:17 +01:00
Sergey Lyubka 31ce219544 Add MG_ARCH_RTX 2022-05-12 08:07:51 +01:00
Sergey Lyubka 86cd567968 Nit - use quotes, not brackets for custom arch 2022-05-11 21:14:44 +01:00
Sergey Lyubka 5c66d32bc0 Refactor mg_open_listener() 2022-05-10 13:43:47 +01:00
Sergey Lyubka 5ac5c93c90 Refactor mg_open_listener() 2022-05-10 13:41:45 +01:00
Sergey Lyubka 84480f4072 Fix #1539 - proper timer cleanup 2022-05-10 07:38:03 +01:00
Sergey Lyubka b82953405d Fix valgrind test 2022-05-09 19:11:27 +01:00
Sergey Lyubka 5271626947 Disable SSI by default 2022-05-08 21:54:15 +01:00
Sergey Lyubka bc16854ccb Get rid of MG_ENABLE_LOG, change mg_hexdump() 2022-05-06 21:09:13 +01:00
Sergey Lyubka 6db0485c7b Set c->loc for accepted and UDP connections 2022-05-06 20:19:40 +01:00
Sergey Lyubka b5fc0d30a8 Add extraconnsize 2022-05-04 17:18:35 +01:00
Sergey Lyubka 38557aac7f Add MG_ARCH_NEWLIB 2022-05-01 13:47:33 +01:00
Sergey Lyubka d621fbfab1 Remove unused macros 2022-05-01 08:18:18 +01:00
Sergey Lyubka f19eec7fae Refactor multithreading API 2022-04-25 14:56:15 +01:00
Sergey Lyubka 8174842b05 docs 2022-04-24 11:39:54 +01:00
Sergey Lyubka ff07d261b2 docs 2022-04-24 11:37:23 +01:00
Sergey Lyubka c55db8a895 docs 2022-04-24 11:33:47 +01:00
Sergey Lyubka 70a9554b72 docs 2022-04-24 11:26:25 +01:00
Sergey Lyubka bdd7d92108 Fix #1533 - fix iotest error on windows 2022-04-22 20:53:54 +01:00
Sergey Lyubka a7cbc19755 Fix #1532 - improve ipv6 DNS lookup 2022-04-22 20:44:53 +01:00
Sergey Lyubka 93ff3e4d1f Add message sequence test 2022-04-21 03:13:31 +01:00
Sergey Lyubka 1dfc748e87 Add message sequence test 2022-04-21 02:50:50 +01:00
Sergey Lyubka e1f17a7ff1 Merge pull request #1531 from zudwalex/fix_tests
Fix zephyr tests
2022-04-20 11:38:00 +01:00
Alex Alashkin 56c40ff0fd Fix zephyr tests 2022-04-20 09:28:36 +03:00
Sergey Lyubka 9dd3b75165 Handle #1529 - do not mark normal conn termination as an error 2022-04-19 20:28:10 +01:00
Sergey Lyubka 20fc8f0279 Handle #1529: add automatic linkage against ws2_32.lib on _WIN32 targets 2022-04-19 18:51:28 +01:00
Sergey Lyubka 944704a12d Fix #1528: pack.c build on Win32 2022-04-19 18:46:29 +01:00
Sergey Lyubka fba9f14b2c Merge pull request #1526 from zudwalex/zephyr3
Add Zephyr build to Github actions
2022-04-19 09:03:30 +01:00
Alex Alaskin a7c24aeeee Add Zephyr build to Github actions 2022-04-13 19:54:08 +03:00
Sergey Lyubka 186eb998ba Adjust to timer API change, add root makefile 2022-04-13 14:03:00 +01:00
Sergey Lyubka d630ba743d Merge pull request #1524 from zudwalex/zephyr2
Add Zephyr examples
2022-04-13 11:17:22 +01:00
Sergey Lyubka e9fabdcc96 Handle #1523 - multiple WS messages 2022-04-13 11:14:57 +01:00
Sergey Lyubka 31698678fb Squash warning 2022-04-13 10:52:06 +01:00
Sergey Lyubka ebd2e89faa Handle #1522 - Fix TLS buffering 2022-04-13 10:48:17 +01:00
Alex Alashkin 17e0fb1c15 Add Zephyr examples 2022-04-13 11:10:22 +03:00
Sergey Lyubka 6e3e77a1a0 Enhance http-streaming-client 2022-04-12 19:06:37 +01:00
Sergey Lyubka ef44f90491 Fix #1520 - move state to struct mg_mgr 2022-04-12 14:14:55 +01:00
Sergey Lyubka 66376885e9 Fix #1521 - add mg_tou64() 2022-04-12 10:20:43 +01:00
Sergey Lyubka db941e2627 Fix #1519 - make opts structs in API calls const 2022-04-12 10:04:55 +01:00
Sergey Lyubka 5f78d34f4d Fix #1513 - fix mg_strdup() documentation 2022-04-12 09:57:25 +01:00
Sergey Lyubka 85281ae128 Fix #1514 - explicitely initialize io in mg_iobuf_init() 2022-04-12 09:54:05 +01:00
Sergey Lyubka e5d1b213c9 Merge pull request #1518 from jameshilliard/mqtt-suback
Ensure MQTT_CMD_SUBACK is received before calling mg_mqtt_pub in tests
2022-04-11 10:45:07 +01:00
James Hilliard e4ab9a4130 Ensure MQTT_CMD_SUBACK is received before calling mg_mqtt_pub in tests 2022-04-07 19:11:51 -06:00
Sergey Lyubka a1ec179229 Use uint64_t for uptime in millis, not int64_t 2022-04-07 13:50:25 +01:00
Sergey Lyubka 2f77855ec1 Handle #1502 - send CLOSE when CLOSE is received 2022-04-05 14:45:39 +01:00
Sergey Lyubka d11173fe90 Fix #1510 - wrap X509_VERIFY_PARAM_set1_host() usage inside a conditional 2022-04-05 13:09:17 +01:00
Sergey Lyubka fde8b82b78 Merge pull request #1507 from jameshilliard/mbedtls-reset
Handle MBEDTLS_ERR_NET_CONN_RESET errors
2022-04-05 13:06:06 +01:00
Sergey Lyubka b20eded30e Fix ESP32 example 2022-04-05 12:54:20 +01:00
James Hilliard 3ec17c41be Handle MBEDTLS_ERR_NET_CONN_RESET errors 2022-04-04 17:17:17 -06:00
Sergey Lyubka 0ed64707f3 Introduce MG_ENABLE_CUSTOM_MILLIS 2022-04-04 18:14:59 +01:00
Sergey Lyubka 417533e90c Merge pull request #1509 from jameshilliard/wakeup-conflict
Fix mg_mgr_wakeup conflicting types error
2022-04-04 09:16:34 +01:00
James Hilliard e268affb5a Fix mg_mgr_wakeup conflicting types error 2022-04-02 22:10:17 -06:00
Sergey Lyubka 4474ada291 Fix #1505: let mg_wakeup() return status 2022-04-03 00:17:31 +01:00
Sergey Lyubka a65c3288d8 Merge pull request #1508 from jameshilliard/mqtt-debug
Print mqtt buffer on error in tests
2022-04-03 00:11:25 +01:00
Sergey Lyubka affcef7e37 Fix clean targets 2022-04-03 00:04:58 +01:00
James Hilliard 173c2ba338 Print mqtt buffer on error in tests
This test seems to fail randomly a lot, print the buffer on error to
make it easier to isolate issues.
2022-04-02 15:26:15 -06:00
Sergey Lyubka b5fcf95b88 Enable mbedTLS 2022-04-01 21:33:09 +01:00
Sergey Lyubka d954851d43 Drop CRL from mbedTLS integration - let customer do a custom init if required 2022-04-01 16:42:41 +01:00
Sergey Lyubka df602c27d5 Disable SSI on Zephyr by default 2022-04-01 16:38:37 +01:00
Sergey Lyubka 3d9fa10485 Increase sock limit, fix multiple connections issue 2022-04-01 15:42:15 +01:00
Sergey Lyubka 6990040626 Set DNS error on UDP send error 2022-04-01 15:41:23 +01:00
Sergey Lyubka b42ea6cd3c Better logging 2022-04-01 15:41:03 +01:00
Sergey Lyubka 8c7fd8b330 Set default socket in mg_connect() to -1 2022-04-01 15:40:53 +01:00
Sergey Lyubka 4e0039625e Remove cruft 2022-03-31 18:07:15 +01:00
Sergey Lyubka 6c909f8935 Disable SNTP 2022-03-31 18:02:29 +01:00
Sergey Lyubka 4f5d385e52 Enable SNTP in zephyr example 2022-03-31 17:42:09 +01:00
Sergey Lyubka 84fe1d87b3 Enable DHCP 2022-03-31 17:26:58 +01:00
Sergey Lyubka bb0bc41f99 Add zephyr example skeleton 2022-03-31 16:58:27 +01:00
Sergey Lyubka 1c2d67ded7 Add missing arch_zephyr.h, add musl target 2022-03-30 09:06:00 +01:00
Sergey Lyubka 7372a05ce5 Add initial Zephyr support 2022-03-30 07:56:44 +01:00
Sergey Lyubka 642befa8d5 Remove unused mg_hmac_sha1() 2022-03-22 13:30:25 +00:00
Sergey Lyubka 3b5a9e2d4b Add tests for mg_ws_wrap() and messages > 128 bytes 2022-03-22 12:46:55 +00:00
Sergey Lyubka 6b3d9d9baf Add failed TLS host validation 2022-03-22 10:51:37 +00:00
Sergey Lyubka 436852d077 Enable TLS host validation in test_http_client() 2022-03-22 10:48:50 +00:00
Sergey Lyubka b78ced4fa9 Honor hostname validation for openssl 2022-03-22 08:50:37 +00:00
Sergey Lyubka 1bc81df00e Fix mg_dns_parse_name_depth() 2022-03-21 16:29:27 +00:00
Sergey Lyubka bf025537b6 Merge pull request #1495 from jameshilliard/optimize-valgrind
Run valgrind tests with appropriate compiler optimizations.
2022-03-21 15:18:58 +00:00
Sergey Lyubka ad4812218d Handle #1497 - handshake format 2022-03-21 15:17:09 +00:00
Sergey Lyubka 0fbc4b8ff4 Reuse sock.c logic in mbedtls integration 2022-03-21 14:39:27 +00:00
Sergey Lyubka 7ef82f5caf Add vc2017 target 2022-03-21 14:38:42 +00:00
Sergey Lyubka 1141ea7933 Add connection timeout 2022-03-20 18:50:01 +00:00
James Hilliard 1e9344161b Run valgrind tests with appropriate compiler optimizations. 2022-03-18 13:51:05 -06:00
Sergey Lyubka 6c021765bb Merge pull request #1479 from zudwalex/infineon_rtx_support
Add RTX-RTOS support
2022-03-18 09:18:49 +00:00
Sergey Lyubka bc151af51d Set IPv6=0 for valgrind test 2022-03-18 09:10:24 +00:00
Sergey Lyubka 8bd09e0e80 Add valgrind test 2022-03-18 09:03:18 +00:00
Sergey Lyubka 5978cb9703 Add valgrind test 2022-03-18 08:56:12 +00:00
Sergey Lyubka 8c447a95dd Fix #1483 - add valgrind target, do not use stdlib strcasecmp() 2022-03-18 08:52:54 +00:00
Sergey Lyubka 870431dc1a Enhance HTTP client example 2022-03-15 14:14:36 +00:00
Sergey Lyubka 1125b1f545 Fix #1490 - add winerror.h to fix old mingw build 2022-03-15 10:10:08 +00:00
Sergey Lyubka d255fc737a Fix mongoose.exe target 2022-03-15 10:03:00 +00:00
Sergey Lyubka 37cb51ee94 Fix #1488 - properly set non-blocking flags on accepted connections 2022-03-14 13:26:00 +00:00
Sergey Lyubka 02cabcc0ec Fix busy loop in TLS case 2022-03-14 11:16:41 +00:00
Sergey Lyubka 3ffb6c046e Merge branch 'master' of github.com:cesanta/mongoose 2022-03-11 15:40:22 +00:00
Sergey Lyubka 7bf8b81995 Fix mg_http_delete_chunk() 2022-03-11 15:38:59 +00:00
Sergey Lyubka 0ddda4a267 Merge pull request #1487 from jameshilliard/update-actions
Update actions/checkout@v2 to actions/checkout@v3
2022-03-08 12:06:08 +00:00
James Hilliard c46ad970cb Update actions/checkout@v2 to actions/checkout@v3 2022-03-06 21:59:25 -07:00
Sergey Lyubka 733abcffbc Merge pull request #1485 from jameshilliard/fix-pack-rebuild
Regenerate pack file when dependencies are changed.
2022-03-06 16:50:03 +00:00
Sergey Lyubka 139f928731 Fix #1481 - use stricter compilation flags 2022-03-06 14:31:42 +00:00
James Hilliard 3da9986232 Regenerate pack file when dependencies are changed.
Should help prevent some spurious test failures due to stale
test/packed_fs.c file.
2022-03-02 10:12:48 -07:00
Sergey Lyubka a284df01d1 Fix #1480 - use memmove instead of memcpy in mg_iobuf_resize() 2022-02-28 16:51:46 +00:00
Alex Alashkin 412f5cf3e0 Add RTX-RTOS support 2022-02-23 19:56:37 +02:00
Sergey Lyubka 42ba1e4aed Fix #1473 - calm static analyzer 2022-02-23 13:34:20 +00:00
Sergey Lyubka 1893b06c13 Fix #1472 - calm static analyzer 2022-02-23 13:31:00 +00:00
Sergey Lyubka b0cbb70e53 Fix #1471 - calm static analyzer 2022-02-23 13:30:14 +00:00
Sergey Lyubka 78e81fef27 Fix #1471 - calm static analyzer 2022-02-23 13:28:56 +00:00
Sergey Lyubka dd08231a34 Fix #1470 - calm static analyzer 2022-02-23 13:25:25 +00:00
Sergey Lyubka 8c78b7ef53 Refactor mg_alloc_conn() 2022-02-23 10:51:01 +00:00
Sergey Lyubka c650fdcdfc Move mg_listen() to net.c 2022-02-23 03:06:02 +00:00
Sergey Lyubka e99973d4b7 Introduce local address 2022-02-22 22:00:55 +00:00
Sergey Lyubka 4012a86bd8 Remove gitter chat link 2022-02-22 21:46:07 +00:00
Sergey Lyubka 048fee5c88 Fix build after mg_connect() move 2022-02-22 21:35:03 +00:00
Sergey Lyubka a287fd97e4 Factor mg_connect() to net.c 2022-02-22 21:27:08 +00:00
Sergey Lyubka 3a249183f8 Factor out mg_alloc_conn() 2022-02-22 21:14:29 +00:00
Sergey Lyubka 393dad97e0 Get rid of ctype dependencies 2022-02-22 20:20:56 +00:00
Sergey Lyubka 113abc71d4 Add SPDX identifier. Fix #1387 2022-02-22 18:13:06 +00:00
Sergey Lyubka 63261ec0d5 Use mg_http_status() 2022-02-19 16:19:51 +00:00
Sergey Lyubka 507935d067 Tiny refactoring - move clearance of the c->is_resolving flag to the mg_connect_resolved() 2022-02-19 16:17:03 +00:00
Sergey Lyubka c579b73f75 Update docs 2022-02-19 15:31:22 +00:00
Sergey Lyubka e69ec148cc Better mbedtls debug 2022-02-19 13:46:07 +00:00
Sergey Lyubka a76ade9bb2 Update packed fs 2022-02-14 17:44:43 +00:00
Sergey Lyubka 4fec149345 Disable dirlist by default 2022-02-14 11:32:01 +00:00
Sergey Lyubka 5bc164de76 Remove MG_ENABLE_DIRLIST 2022-02-14 11:19:24 +00:00
Sergey Lyubka 969b84043c Fix #1465 - rename LL_* constants, introduce MG_* log macros 2022-02-12 18:17:25 +00:00
Sergey Lyubka da72dafbfb Fix #1462 - add helper function for getting HTTP response status code. 2022-02-12 16:51:37 +00:00
Sergey Lyubka 1adf7f6b2b Handle #1463 - add missing includes for windows 2022-02-12 16:43:08 +00:00
Sergey Lyubka 3e085ccbaa Eliminate explicit _WIN32 checks 2022-02-12 14:33:43 +00:00
Sergey Lyubka 3e8e2ab513 Add optional zip cmd to pack.c 2022-02-12 14:28:02 +00:00
Sergey Lyubka 4f802ece52 Enhance mg_snrpintf tests 2022-02-11 18:15:34 +00:00
Sergey Lyubka 313ac34e59 Handle minus in the fmt spec 2022-02-11 11:02:06 +00:00
Sergey Lyubka 54f75889fa Using mg_snprintf() everywhere 2022-02-10 17:11:03 +00:00
Sergey Lyubka f64c86d23f Use mg_snprintf() 2022-02-10 11:56:55 +00:00
Sergey Lyubka 9e634310b4 Use MG_EV_HTTP_CHUNK for streaming upload 2022-02-09 12:24:06 +00:00
Sergey Lyubka 33666e7d6b Fix ESP32 example 2022-02-08 14:13:47 +00:00
Sergey Lyubka 40d4c7e410 Fix ESP32 example 2022-02-08 13:43:34 +00:00
Sergey Lyubka 8cd4699dbc Rename FS API functions to avoid conflicts 2022-02-08 13:36:04 +00:00
Sergey Lyubka 49d5aff8f9 Call realpath() against root_dir only when there are no overrides 2022-02-01 11:10:01 +00:00
Sergey Lyubka b2ee9cb363 Update docs 2022-01-29 11:12:31 +00:00
Sergey Lyubka e9c20ad992 Update docs 2022-01-29 11:11:22 +00:00
Sergey Lyubka 63b880e624 Handle #1459 - deprecate mg_globmatch, introduce mg_match() 2022-01-29 11:03:54 +00:00
Sergey Lyubka 768f67ae0a Fix #1458 - fail on example build error, and fix examples/mqtt-server 2022-01-27 12:10:03 +00:00
Sergey Lyubka fbf5fa53c6 Refactor ff_open() 2022-01-25 10:50:08 +00:00
Sergey Lyubka 4a5824e7a7 Silence error in clean target 2022-01-24 13:07:56 +00:00
Sergey Lyubka 32f3c48b65 Fix FreeBSD build 2022-01-24 02:20:45 +00:00
Sergey Lyubka f7fbcd2451 Disable leaks detection on macos 2022-01-23 06:58:06 +00:00
Sergey Lyubka c6253854ba Disable leaks detection on macos 2022-01-23 06:12:36 +00:00
Sergey Lyubka 544644e94b Refactor - always enable LOG macro. Enhance iolog 2022-01-23 06:10:14 +00:00
Sergey Lyubka f6cebf6956 Listen on INADDR_ANY by default 2022-01-22 17:03:27 +00:00
Sergey Lyubka 1b82aa02aa 7.5 -> 7.6 2022-01-21 12:41:52 +00:00
Sergey Lyubka e565a7e73d Fix #1453 - do not allow empty wakeup buffer 2022-01-21 12:35:28 +00:00
Sergey Lyubka 59c4dfa33b Fix 1452 - byte order issue in mg_check_ip_acl 2022-01-21 12:24:58 +00:00
Sergey Lyubka 1a8e3c2e31 Decrese debug verbosity 2022-01-19 18:15:47 +00:00
Sergey Lyubka 226917e1cd Use mg_str, not pointers, in mg_mqtt_{sub,pub} 2022-01-19 09:57:27 +00:00
Sergey Lyubka fe813ee247 Add buf,len params to mg_mgr_wakeup() 2022-01-19 09:25:01 +00:00
Sergey Lyubka 4cd830a0bf Improve ff_write - save large blocks in chunks 2022-01-19 08:43:34 +00:00
Sergey Lyubka 1259ca9ac9 Add missing mkdir() on ARM targets 2022-01-18 19:31:10 +00:00
Sergey Lyubka d0857fe36c Add mkdir to the FS API 2022-01-18 19:19:34 +00:00
Sergey Lyubka 56a7438114 Add fs arg to mg_file* and mg_http_upload API 2022-01-18 17:11:02 +00:00
Sergey Lyubka 09df542db8 Fix unamalgamated build 2022-01-18 08:02:41 +00:00
Sergey Lyubka 1df102ab93 Add Fat FS support 2022-01-18 07:44:30 +00:00
Sergey Lyubka 02b3b780bb Add missing fs.c 2022-01-17 14:44:59 +00:00
Sergey Lyubka f84f3da012 Change in FS API for fs->open() and fs->close() 2022-01-17 14:42:41 +00:00
Sergey Lyubka c65c8fdaaa Protect against the directory traversal in mg_upload() 2022-01-17 12:08:23 +00:00
Sergey Lyubka b484123f1b gcc and clang 2022-01-15 01:45:31 +00:00
Sergey Lyubka b60119790e Fix wrong memcmp usage in mg_url_port() 2022-01-14 12:45:55 +00:00
Sergey Lyubka 216427cea0 Cleanup suseconds_t usage 2022-01-14 12:33:06 +00:00
Sergey Lyubka c53e2fcc14 Fix #1444 - clang warns on undefined behavior with null pointers 2022-01-14 09:55:15 +00:00
Sergey Lyubka 9fd80fd136 Fix #1445 - send error to a resolving connection when DNS error happens 2022-01-14 08:50:01 +00:00
Sergey Lyubka 5fc284722f Fix #1448 - fix MG_ENABLE_FILE build 2022-01-14 08:21:12 +00:00
Sergey Lyubka ad6e395da0 Fix #1447 - typo in mg_random() 2022-01-14 08:18:28 +00:00
Sergey Lyubka 6c79a406cd Fix localtime_r and gmtmime_r signatures 2022-01-11 19:15:38 +00:00
Sergey Lyubka 456e8bd249 Use 3 params for fcntl() 2022-01-10 18:21:13 +00:00
Sergey Lyubka de95f28598 Make stat and struct stat changeable 2022-01-10 18:07:45 +00:00
Sergey Lyubka 43405afdb2 Dont use ctype.h from str.h 2022-01-10 17:30:51 +00:00
Sergey Lyubka 97f95e17db Better strategy for restoring multicast address 2022-01-07 18:40:48 +00:00
Sergey Lyubka 6725d61b3f Re-init SSDP peer address before every search 2022-01-07 18:28:51 +00:00
Sergey Lyubka ebda2cb100 Use sendto on Mac too 2022-01-07 16:31:29 +00:00
Sergey Lyubka bb72b2494d Fix unamalgamated target 2022-01-07 15:48:09 +00:00
Sergey Lyubka 3b0a509cae Change mg_resolve() 2022-01-07 15:00:10 +00:00
Sergey Lyubka 2f981f9383 Skip connect() on UDP connection 2022-01-06 15:42:55 +00:00
Sergey Lyubka fc3c08e411 Change mg_straddr() API 2022-01-05 19:09:11 +00:00
Sergey Lyubka ff811f287a Squash warnings 2022-01-05 13:57:30 +00:00
Sergey Lyubka 8ebb3bc37b More detailed debug log - show ip/port for sender and receiver 2022-01-05 13:47:11 +00:00
Sergey Lyubka f7ff571c5f Added SSDP search example 2022-01-05 13:22:00 +00:00
Sergey Lyubka 6a82cbee71 Send MG_EV_WRITE for UDP messages 2022-01-05 13:03:56 +00:00
Sergey Lyubka b0585bd0a9 Do not set c->label for DNS connections - let labels be user-only-settable 2022-01-05 11:46:26 +00:00
Sergey Lyubka 6ad4d242c2 Better cleanup 2022-01-05 11:45:22 +00:00
Sergey Lyubka 030b1d9826 Remove wrong comment 2021-12-27 03:31:33 +00:00
Sergey Lyubka f6ffa7b3b9 Add huge-response example 2021-12-27 03:25:28 +00:00
Sergey Lyubka 137efe2233 Show requests in flight 2021-12-24 20:46:31 +00:00
Sergey Lyubka 62411d039e Increase mqtt timeouts 2021-12-24 12:14:06 +00:00
novlean 54b1716e77 Merge pull request #1436 from cesanta/novlean-patch-1
Update README.md
2021-12-23 17:18:55 +00:00
novlean 9f7aba8039 Update README.md 2021-12-23 17:18:45 +00:00
Sergey Lyubka a176b8d566 Upate docs w.r.t. mg_mqtt_opts 2021-12-23 11:12:10 +00:00
Sergey Lyubka 26a97ec36c Fix #1434 - set will QoS in CONNECT message correctly, and rename qos -> will_qos in struct mg_mqtt_opts 2021-12-23 11:00:18 +00:00
Sergey Lyubka f29807aad8 Resolve root path before serving to avoid double dots 2021-12-22 18:05:03 +00:00
Sergey Lyubka 92d3c7a4cd Add realpath() for Win32 2021-12-22 18:04:36 +00:00
Sergey Lyubka af3a0f6af0 Add realpath() for Win32 2021-12-22 18:04:27 +00:00
Sergey Lyubka ce6164ca20 Fail stat() if S_ISDIR is not defined 2021-12-22 18:04:16 +00:00
Sergey Lyubka e9fc3fcecf Update event enum 2021-12-21 22:20:42 +00:00
Sergey Lyubka 25a1a24890 Fallback to time(0) in mg_millis() 2021-12-21 22:04:03 +00:00
Sergey Lyubka bf7fc1d5a9 Amalgamate 2021-12-21 21:58:03 +00:00
Sergey Lyubka 2126b49ab3 Merge pull request #1433 from ryuukk/patch-2
Remove debugging left over
2021-12-21 21:56:41 +00:00
Sergey Lyubka ae6767b1d2 Use int64_t for timers and mg_millis() 2021-12-21 21:50:18 +00:00
ryuukk 133629dbee Remove debugging left over 2021-12-21 21:28:22 +01:00
Sergey Lyubka fb0a9bc7e3 Fix build 2021-12-21 18:16:12 +00:00
Sergey Lyubka 2a3492766f Remove mg_time() and mg_usleep() 2021-12-21 17:44:34 +00:00
Sergey Lyubka 2ec7e5653e Merge branch 'master' of github.com:cesanta/mongoose 2021-12-21 17:40:04 +00:00
Sergey Lyubka 30bfb245f5 Make mongoose more bare-metal Keil friendly. Declare settings after arch. Introduce MG_ENABLE_FILE 2021-12-21 17:39:55 +00:00
Sergey Lyubka 84d89bc4f5 Merge pull request #1431 from ryuukk/patch-1
Closed WS connection is not an error for the logger
2021-12-21 08:47:21 +00:00
ryuukk 7f55fabfec Closed WS connection is not an error for the logger 2021-12-21 01:34:48 +01:00
Sergey Lyubka 9e0f04dc8b Add -S option 2021-12-20 16:35:16 +00:00
Sergey Lyubka 574c2954b3 Docs nitpick 2021-12-19 10:53:17 +00:00
Sergey Lyubka 9d38e26b81 Add MG_HTTP_INDEX build var 2021-12-17 13:54:01 +00:00
Sergey Lyubka 4e75a0c81e 7.4 -> 7.5 2021-12-17 13:34:32 +00:00
Sergey Lyubka d311e967fa Add mingw target 2021-12-16 09:22:28 +00:00
Sergey Lyubka d0a6c111cb Call MG_EV_ERROR with c->is_closing set 2021-12-15 11:31:42 +00:00
Sergey Lyubka aa6d8b4662 Remove TLS custom_init() API 2021-12-15 11:04:43 +00:00
Sergey Lyubka 3f5fd89fd7 Pass more args to custom TLS init 2021-12-14 13:21:59 +00:00
Sergey Lyubka f43a5a005c Introduce custom TLS init function 2021-12-14 13:04:11 +00:00
Sergey Lyubka 755bf3c412 Split TLS files and introduce MG_ENABLE_CUSTOM_TLS 2021-12-14 12:42:41 +00:00
Sergey Lyubka 84f3fb0ba5 Move EXTERN_C to util.h 2021-12-14 12:11:05 +00:00
Sergey Lyubka f2df6c114d Example for mg_http_bauth 2021-12-13 15:14:29 +00:00
Sergey Lyubka f93659e303 Merge branch 'master' of github.com:cesanta/mongoose 2021-12-13 15:08:14 +00:00
Sergey Lyubka 226404d39c Example for mg_http_bauth 2021-12-13 15:08:05 +00:00
Sergey Lyubka c1bcc143b9 Merge pull request #1417 from DavidKorczynski/cifuzz-integration
Add CIFuzz integration
2021-12-13 11:35:31 +00:00
Sergey Lyubka 5ca9062d45 Less verbose serve_dir 2021-12-07 15:23:02 +00:00
Sergey Lyubka 0b209eaabb Add mg_http_get_header_var() 2021-12-03 09:54:03 +00:00
David Korczynski 47ef191ea2 Add CIFuzz integration 2021-11-30 22:48:20 +00:00
Sergey Lyubka 25e76d761e Fix usage message 2021-11-29 14:00:03 +00:00
Sergey Lyubka 9731a51dae Recognise :PORT as a valid URL 2021-11-29 13:57:33 +00:00
Sergey Lyubka 81220fa590 Remove noisy debug 2021-11-26 16:23:06 +00:00
Sergey Lyubka 24e8c4d81a Increase SNMP test timeout 2021-11-25 17:31:41 +00:00
Sergey Lyubka 013520b0c0 Add note for mg_http_serve_dir() 2021-11-25 12:29:45 +00:00
Sergey Lyubka f012bcb027 Update issue template 2021-11-25 11:47:26 +00:00
Sergey Lyubka 922e1ce529 Make captive portal work on Linux 2021-11-23 17:52:54 +00:00
Sergey Lyubka 7a707cc64b Add README 2021-11-23 15:08:34 +00:00
Sergey Lyubka 1967acfef2 Make it build on vc98 2021-11-23 13:24:21 +00:00
Sergey Lyubka e24cb04003 Update URL 2021-11-23 09:37:03 +00:00
Sergey Lyubka 67974746ff Add json-rpc-over-ws example 2021-11-22 16:45:14 +00:00
Sergey Lyubka 8d916d41d7 Fix #1409 - remove VLA which confuses MSVC 2021-11-22 12:24:58 +00:00
Sergey Lyubka 08444e3942 Fix links and typos 2021-11-16 12:30:40 +00:00
Sergey Lyubka 9c41a0cd26 Fix links 2021-11-16 09:54:36 +00:00
Sergey Lyubka 2c50069d98 Do not clean the recv buffer 2021-11-14 16:47:40 +00:00
Sergey Lyubka 31059f6728 Add test.html 2021-11-14 14:31:51 +00:00
Sergey Lyubka 2000752b2c Remove dead code 2021-11-11 15:15:47 +00:00
Sergey Lyubka dd34830443 Update README 2021-11-11 15:11:57 +00:00
Sergey Lyubka c58f4ee51b Add symlinks 2021-11-11 14:21:52 +00:00
Sergey Lyubka 00f7e8cb2a Support wildcards 2021-11-11 12:08:17 +00:00
Sergey Lyubka 439904e27f Add signal handler 2021-11-11 10:35:41 +00:00
Sergey Lyubka 4d6590ece2 Add readme 2021-11-11 10:29:16 +00:00
Sergey Lyubka 9b0c4b970d Add README.md 2021-11-11 08:26:31 +00:00
Sergey Lyubka a80ce1b12a Add signal handler 2021-11-11 07:36:25 +00:00
Sergey Lyubka 57dd74c180 Add reconnection logic 2021-11-10 12:57:02 +00:00
Sergey Lyubka 90c67e4226 Reformatting for better readability 2021-11-06 11:29:56 +00:00
Sergey Lyubka 093cd6a6a3 Fix FD_CLOEXEC setting 2021-11-05 13:30:12 +00:00
Sergey Lyubka 975db86306 Add READMEs 2021-11-05 13:02:36 +00:00
Sergey Lyubka eba688e11b Update docs 2021-11-04 23:07:47 +00:00
Sergey Lyubka 05b44204d5 Set FD_CLOEXEC properly 2021-11-04 18:28:32 +00:00
Sergey Lyubka 0bb017c1d5 Add examples/mqtt-client-aws-iot 2021-11-03 20:58:57 +00:00
Sergey Lyubka a6efd0b335 Merge branch 'master' into dec 2021-11-02 22:43:59 +00:00
Sergey Lyubka c3d237e9c6 More verbose log 2021-11-02 22:43:23 +00:00
Sergey Lyubka 09d28f5570 Print a clarifying message at start 2021-11-02 16:53:57 +00:00
Sergey Lyubka ba02937ec6 Squash warnings 2021-11-02 16:40:25 +00:00
Sergey Lyubka 3d78b14deb Fix #1396 - JS sorting code for dir listing 2021-11-02 16:01:06 +00:00
Sergey Lyubka f558551d1d Fix #1395 - show decoded URI in dir listing 2021-11-02 15:11:56 +00:00
Sergey Lyubka 12fe66370f Fix #1393 - cleanup mime types 2021-11-01 20:31:45 +00:00
Sergey Lyubka 423aaa492c Fix #1394 - mg_mqtt_sub(). Add MG_EV_OPEN, too. 2021-11-01 16:20:00 +00:00
Sergey Lyubka 2016586475 Clearer client init 2021-11-01 13:29:44 +00:00
Sergey Lyubka bf88167152 Add missing test files 2021-10-31 12:50:06 +00:00
Sergey Lyubka 52be84f04e Add user and pass to struct mg_mqtt_opts 2021-10-31 12:48:32 +00:00
Sergey Lyubka 03d187b147 Fix #1375 - change event processing order 2021-10-31 12:40:56 +00:00
Sergey Lyubka 3329047579 More explicit check on hm->uri.len 2021-10-31 12:37:40 +00:00
Sergey Lyubka 86c70e5abb Fix #1391 - make remove_double_dots less aggressive 2021-10-31 12:36:34 +00:00
Sergey Lyubka b17f4108ea Change MG_PATH_MAX for ESP8266 2021-10-30 19:34:53 +01:00
Sergey Lyubka 4e523cc455 Remove binary section 2021-10-27 20:13:05 +01:00
Sergey Lyubka 49c9be9159 Set MG_IO_SIZE -> 128 2021-10-27 19:20:52 +01:00
Sergey Lyubka f1bfe0760f Optimise TLS read 2021-10-27 19:18:44 +01:00
Sergey Lyubka 35f02fdaad Use small IO buffer 2021-10-27 19:18:19 +01:00
Sergey Lyubka 6ac09966ba Fix #1374 - fix ESP32 build 2021-10-22 22:06:10 +01:00
Sergey Lyubka af9a7617f5 Merge pull request #1381 from ptsolakos/master
Certificate revocation checking when using mbedtls
2021-10-22 20:30:47 +01:00
Sergey Lyubka 42c89732c8 Remove private.h 2021-10-22 19:41:26 +01:00
Sergey Lyubka 054475ddbf Fix #1376 - handle comma for unquoted header vars 2021-10-22 14:33:51 +01:00
Sergey Lyubka 126d556d6a Merge pull request #1380 from jameshilliard/fix-time
util: Actually return uptime on OSX/Linux for mg_millis
2021-10-22 14:06:44 +01:00
Sergey Lyubka 529a302e77 Merge pull request #1379 from jameshilliard/fix-sntp
sntp: Don't set Leap Indicator in client messages.
2021-10-22 14:04:54 +01:00
Sergey Lyubka acbf978452 Merge pull request #1378 from jameshilliard/undef
Fix some undefined macro warnings.
2021-10-22 14:03:42 +01:00
Sergey Lyubka 90b22716ea Merge branch 'master' into undef 2021-10-22 14:03:25 +01:00
Sergey Lyubka fb90c504a6 Remove private.h 2021-10-22 14:00:31 +01:00
Sergey Lyubka 65fd834654 Increate mqtt test timeout 2021-10-22 13:58:51 +01:00
Sergey Lyubka a84acf5b8b Merge pull request #1385 from zudwalex/move_stm32_examples
Move STM32 examples to stm32 folder
2021-10-22 13:39:13 +01:00
Sergey Lyubka e9505db146 Merge pull request #1384 from zudwalex/master
Add more NXP examples and move them to nxp folder
2021-10-22 13:39:02 +01:00
Sergey Lyubka 4fb49b011e Merge pull request #1377 from jameshilliard/missing-prototypes
Make private functions static and add missing prototypes.
2021-10-22 13:16:06 +01:00
Alex Alashkin 6742991469 Move STM32 examples to stm32 folder 2021-10-22 14:19:50 +03:00
Alex Alashkin 2430cc5aac Add more NXP examples and move them to nxp folder 2021-10-22 14:04:15 +03:00
Sergey Lyubka 54590aaf26 Use UDP sendto() on win32 only 2021-10-22 09:14:18 +01:00
Sergey Lyubka 7c5e67b272 Fix #1382 - use sendto for UDP send 2021-10-22 08:56:45 +01:00
Sergey Lyubka c62c8ea4dd Correct licensing URL 2021-10-20 10:04:49 +01:00
Panagiotis Tsolakos 383653d608 mbedtls CRL support
Certificate revocation checking when using mbedtls
2021-10-14 17:56:31 +02:00
James Hilliard 001dc3f33d util: Actually return uptime on OSX/Linux for mg_millis
The documentation for mg_millis indicates it will:
Return current uptime in milliseconds.

So we should use API's that actually return uptime.

Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
2021-10-13 17:06:18 -06:00
James Hilliard 37d45b3fbb sntp: Don't set Leap Indicator in client messages.
Per RFC4330:
This field is significant only in server messages

Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
2021-10-13 16:48:33 -06:00
James Hilliard f72b8c6034 Fix some undefined macro warnings.
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
2021-10-13 13:06:00 -06:00
James Hilliard c11e5a9383 Make private functions static and add missing prototypes.
Fixes:
mongoose/mongoose.c:180:8: warning: no previous prototype for ‘mg_dns_parse_name’ [-Wmissing-prototypes]
  180 | size_t mg_dns_parse_name(const uint8_t *s, size_t n, size_t ofs, char *dst,
      |        ^~~~~~~~~~~~~~~~~
mongoose/mongoose.c:306:6: warning: no previous prototype for ‘mg_dns_send’ [-Wmissing-prototypes]
  306 | void mg_dns_send(struct mg_connection *c, const struct mg_str *name,
      |      ^~~~~~~~~~~
mongoose/mongoose.c:925:6: warning: no previous prototype for ‘mg_http_parse_headers’ [-Wmissing-prototypes]
  925 | void mg_http_parse_headers(const char *s, const char *end,
      |      ^~~~~~~~~~~~~~~~~~~~~
mongoose/mongoose.c:1125:7: warning: no previous prototype for ‘mg_http_etag’ [-Wmissing-prototypes]
 1125 | char *mg_http_etag(char *buf, size_t len, size_t size, time_t mtime) {
      |       ^~~~~~~~~~~~
mongoose/mongoose.c:2578:6: warning: no previous prototype for ‘mg_sha1_transform’ [-Wmissing-prototypes]
 2578 | void mg_sha1_transform(uint32_t state[5], const unsigned char buffer[64]) {
      |      ^~~~~~~~~~~~~~~~~
mongoose/mongoose.c:2976:8: warning: no previous prototype for ‘mg_open_listener’ [-Wmissing-prototypes]
 2976 | SOCKET mg_open_listener(const char *url, struct mg_addr *addr) {
      |        ^~~~~~~~~~~~~~~~

Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
2021-10-12 20:18:11 -06:00
Sergey Lyubka b5147a149e Merge pull request #1373 from zudwalex/fix_board_ci
Use mongoose.[ch] from main repo
2021-10-06 12:31:27 +01:00
Alex Alashkin 655529f30b Use mongoose.[ch] from parent repo 2021-10-06 13:15:12 +03:00
novlean fd5319e0ce Merge pull request #1372 from cesanta/novlean-patch-1
license
2021-10-05 17:09:43 +01:00
novlean f8c84ca672 license 2021-10-05 17:09:35 +01:00
novlean 1b81ac8916 Merge pull request #1371 from cesanta/novlean-patch-1
mongoose.ws
2021-10-05 16:54:43 +01:00
novlean c64e2ebb16 mongoose.ws 2021-10-05 16:54:34 +01:00
Sergey Lyubka 3771f2c088 Merge branch 'master' of github.com:cesanta/mongoose 2021-10-04 19:47:34 +01:00
Sergey Lyubka 6d398bd5c7 Fix mg_random() for ESP32 2021-10-04 19:47:24 +01:00
Sergey Lyubka 5c355a5ff3 Merge pull request #1368 from zudwalex/nxp_examples
Add NXP examples
2021-10-04 12:04:00 +01:00
Alex Alashkin d2f8b346e6 Add nxp to actions 2021-10-04 13:15:32 +03:00
Alex Alashkin 5cdaa931f9 Add NXP examples 2021-10-04 12:54:15 +03:00
Sergey Lyubka 693863a51e Merge pull request #1366 from zudwalex/fix_rtos_lwip
Add missed include for FreeRTOS/LwIP arch
2021-10-02 22:45:08 +01:00
Sergey Lyubka a204c80308 Update ca.pem links 2021-10-01 09:25:34 +01:00
Sergey Lyubka 7d620965e2 Update ca.pem: DST root CA has expired 2021-10-01 09:22:49 +01:00
Sergey Lyubka 0149654791 Update README 2021-10-01 08:26:34 +01:00
Sergey Lyubka f08d280429 Version 7.4 2021-09-30 13:35:44 +01:00
Sergey Lyubka 6fbb749431 7.4 -> 7.5 2021-09-30 13:34:55 +01:00
Alex Alashkin bc7178e5f7 Add missed include 2021-09-29 12:25:25 +03:00
Sergey Lyubka 61070d136d Add nxp-mimxrt1020-azurertos to Actions 2021-09-27 13:55:19 +01:00
Sergey Lyubka ea85f93e37 Merge branch 'master' of github.com:cesanta/mongoose 2021-09-27 13:52:59 +01:00
Sergey Lyubka 46029c501a Fix #1359 - add conditional for MSVC, _DEBUG and strdup 2021-09-27 13:52:39 +01:00
Sergey Lyubka 78e1fdd1c9 Merge pull request #1365 from zudwalex/mimxrt1020_example
Add NXP MIMXRT1020 AzureRTOS example
2021-09-27 11:50:48 +01:00
Alex Alashkin 9ef5c7c667 Add NXP MIMXRT1020 AzureRTOS example 2021-09-27 11:12:15 +03:00
Sergey Lyubka cdf279e438 Merge pull request #1358 from yermin/master
makes it more readable
2021-09-27 09:00:11 +01:00
Sergey Lyubka cdd192abe4 Merge pull request #1363 from tophatgeeks/patch-1
Update README - Jordan Ramsey Edits.md
2021-09-27 08:44:42 +01:00
Sergey Lyubka 9af6f4b02e Merge pull request #1360 from zudwalex/azure_basics
Add AzureRTOS basic support
2021-09-27 08:39:15 +01:00
Alex Alashkin d86ceecd8c Add AzureRTOS basic support 2021-09-26 10:25:44 +03:00
yermin 8f693b92a7 makes it more readable
Signed-off-by: yermin <yermin@buaa.edu.cn>
2021-09-24 11:30:21 +08:00
tophatgeeks 6b1ff37cf3 Update README.md
I have gone through and edited for consistency, punctuation, wording, and grammar. If you have questions feel free to reach out.  I fixed some spelling errors "if" instead of "is" "update" instead of "updatw", etc. 

-Jordan Ramsey
2021-09-23 12:07:00 -04:00
Sergey Lyubka c490ff8ae7 Fix typo 2021-09-22 20:38:28 +01:00
Sergey Lyubka f73ebbf689 Fix #1354 - report correct errno in mg_open_listener() 2021-09-22 18:52:42 +01:00
Sergey Lyubka 1928ba9c1f Merge branch 'master' of github.com:cesanta/mongoose 2021-09-22 11:51:26 +01:00
Sergey Lyubka ad3655fb92 Docs spelling 2021-09-22 11:51:16 +01:00
novlean 29e0158689 Merge pull request #1355 from cesanta/novlean-patch-1
2021
2021-09-21 18:07:33 +01:00
novlean aaf55b6da0 2021 2021-09-21 18:02:11 +01:00
Sergey Lyubka 90a131bd29 Include ipv6 wrapping brackets [] in the result of mg_url_host() 2021-09-21 08:10:27 +01:00
Sergey Lyubka 8652006aea Remove dead code 2021-09-20 12:26:09 +01:00
Sergey Lyubka 2139fbc4b7 Support multiple web roots 2021-09-20 12:24:44 +01:00
Sergey Lyubka 2b48e8b03a Send suback 2021-09-18 20:56:56 +01:00
Sergey Lyubka a7afea0963 Handle ipv4-mapped addresses 2021-09-18 19:38:59 +01:00
Sergey Lyubka 9d1e61de93 Update docs 2021-09-17 15:59:15 +01:00
Sergey Lyubka 9b6b1a68f4 Add MQTT version check 2021-09-17 14:02:29 +01:00
Sergey Lyubka c7bd63ef53 Fix #1351 - squash warning 2021-09-17 11:07:20 +01:00
Sergey Lyubka 40b3382023 Enable WS data size check 2021-09-17 10:56:58 +01:00
Sergey Lyubka a70c5e726d Merge branch 'master' of github.com:cesanta/mongoose 2021-09-16 11:17:02 +01:00
Sergey Lyubka 409fdaec59 Rename posix_* -> p_* to avoid build conflict on linux 2021-09-16 11:16:10 +01:00
Sergey Lyubka 372aa369c4 Merge pull request #1350 from zudwalex/mg_parameters_retval
Add parameters descriptions to documentation
2021-09-15 20:51:18 +01:00
Alex Alashkin eb94704d8d Add params and retvals 2021-09-15 22:18:44 +03:00
Sergey Lyubka 894a168833 Get rid of fs->realpath 2021-09-15 07:43:48 +01:00
Sergey Lyubka f3eb466af3 Update docs 2021-09-15 07:43:24 +01:00
Sergey Lyubka df848973dc Fix unamalgamated target 2021-09-14 12:27:02 +01:00
Sergey Lyubka f37e5ecc38 WS frame len sanity check 2021-09-14 10:26:03 +01:00
Sergey Lyubka 6316609a5f Show log level 2021-09-13 13:48:02 +01:00
Sergey Lyubka dca08d32bd Fix URL 2021-09-13 13:47:49 +01:00
Sergey Lyubka 2b287f50f1 Add gitter badge 2021-09-02 10:28:16 +01:00
Sergey Lyubka acf58972f7 Fix posix_open() 2021-09-02 10:20:55 +01:00
Sergey Lyubka 5bf5516b29 struct iobuf doc 2021-08-30 13:06:45 +01:00
Sergey Lyubka 40b99e3751 Print openssl error on TLS error 2021-08-30 11:45:30 +01:00
Sergey Lyubka 28a56370d4 Fix zeromem() call in mg_iobuf_del() 2021-08-30 11:39:19 +01:00
Sergey Lyubka e3589577ed Update OpenSSL handshake error codepath 2021-08-29 16:54:24 +01:00
Sergey Lyubka 38beb4cbc0 Update readme 2021-08-28 22:00:46 +01:00
Sergey Lyubka 167af7f160 docs update 2021-08-28 20:27:55 +01:00
Sergey Lyubka 7d91885413 Update docs 2021-08-28 11:16:45 +01:00
Sergey Lyubka 0de83157dc Update docs 2021-08-28 08:52:41 +01:00
Sergey Lyubka cc9639b3cb Update docs 2021-08-28 08:48:47 +01:00
Sergey Lyubka cb0ac1868f Update docs 2021-08-28 08:46:01 +01:00
Sergey Lyubka e653147119 Merge pull request #1344 from timgates42/bugfix_typo_priority
docs: fix simple typo, priorty -> priority
2021-08-28 08:37:26 +01:00
Sergey Lyubka f3d15a0440 Update docs 2021-08-28 08:25:31 +01:00
Sergey Lyubka 0bc736d384 Update docs 2021-08-28 08:23:33 +01:00
Sergey Lyubka 3bf7b817f6 Update docs 2021-08-28 08:21:29 +01:00
Sergey Lyubka 477e48bf54 mg_iobuf_append -> mg_iobuf_add 2021-08-28 08:08:54 +01:00
Sergey Lyubka 913e730ec2 mg_iobuf_delete -> mg_iobuf_del 2021-08-28 07:16:38 +01:00
Sergey Lyubka bd64043377 mg_comma -> mg_commalist 2021-08-28 06:54:56 +01:00
Tim Gates 9f827feeaa docs: fix simple typo, priorty -> priority
There is a small typo in examples/stm32-freertos-tcp/stm32f7/core_cm7.h.

Should read `priority` rather than `priorty`.
2021-08-28 07:46:08 +10:00
Sergey Lyubka 714b7a8145 Handle WS fragmentation 2021-08-27 10:25:24 +01:00
Sergey Lyubka 7ba6fda236 Add stm32-nucleo-h743z and stm32-nucleo-f429z 2021-08-26 11:40:47 +01:00
Sergey Lyubka fc9c454518 Add mg_check_ip_acl() 2021-08-25 07:59:31 +01:00
Sergey Lyubka 1c456fc2df mg_next_comma_entry -> mg_comma 2021-08-23 16:54:58 +01:00
Sergey Lyubka 9b37ac384f Merge pull request #1341 from lnksz/bugfix-1340-http_chunked
Fix #1340: Long HTTP Chunks
2021-08-23 14:50:39 +01:00
Sergey Lyubka 99b279d5e5 Add examples/stm32-nucleo-f746z 2021-08-23 10:38:11 +01:00
Kristof Havasi 4d07a99ee2 Fix bug in long HTTP chunk handling
Due to a copy/paste error, the start of the payload in the latest parsed
chunk was compared to chunk-length of the terminating chunk (5 chars).
So only chunks were parsed as expected, which also had a single hex
digit length.
2021-08-23 08:50:58 +02:00
Kristof Havasi f6f0e49de4 Add failing test for HTTP chunk
This test would have caught #1340: handling chunks longer than 15 chars
2021-08-23 08:19:46 +02:00
Sergey Lyubka 07568a8f06 Docs nits 2021-08-22 10:51:40 +01:00
Sergey Lyubka 71e9019211 Docs nitpicks 2021-08-20 20:31:32 +01:00
Sergey Lyubka 0937213f4b Merge pull request #1336 from zudwalex/freertos_lwip_support
Update FREERTOS + LWIP support
2021-08-12 12:57:06 +01:00
Sergey Lyubka 6c42350fcf docs 2021-08-12 12:24:28 +01:00
Alex Alashkin 453d4be4d0 Update FREERTOS + LWIP support 2021-08-12 13:54:43 +03:00
Sergey Lyubka 104c4fab19 More docs 2021-08-11 19:24:33 +01:00
Sergey Lyubka fd5eb2d3f9 Refactor mg_mkpipe() 2021-08-11 19:17:04 +01:00
Sergey Lyubka 8b770d2a0d Fix #1334 - typo in mg_call(..MG_EV_WS_OPEN) call 2021-08-11 04:52:39 +01:00
Sergey Lyubka b739aa89f1 Update readme 2021-08-09 09:43:21 +01:00
Sergey Lyubka 11c07470bb Refactor UDP handling 2021-08-07 22:55:13 +01:00
Sergey Lyubka 76865cbe14 Fix STM32 build 2021-08-07 17:52:51 +01:00
Sergey Lyubka b7ce8213d7 Better multithreading support: remove mg_socketpair, add mg_mkpipe() and mg_rmpipe() 2021-08-07 17:22:47 +01:00
Sergey Lyubka 86f43cd8d6 Refactor mg_socketpair and document MG_ENABLE_NATIVE_SOCKETPAIR 2021-08-06 10:23:08 +01:00
Sergey Lyubka 2407509ce0 More detailed environment questions 2021-08-05 10:49:24 +01:00
Sergey Lyubka 47ce072af7 Fix #1331 - add comment about order of operations in conn_close() 2021-08-05 10:39:24 +01:00
Sergey Lyubka c2c6ff11ed Fix #1329 - send MG_EV_WS_OPEN for server connections 2021-08-04 11:38:32 +01:00
Sergey Lyubka 9b18a6350a Make ws_upgrade() respond with error if request is not and upgrade 2021-08-03 23:37:50 +01:00
Sergey Lyubka a36050ab4b Fix #1326 - spelling errors 2021-08-02 00:23:01 +01:00
Sergey Lyubka 568484f079 Fix #920 - add MQTT over Websocket client example 2021-08-01 14:10:21 +01:00
Sergey Lyubka 3ea4f1fda8 Merge pull request #1324 from ignacionr/fix/issue-1323
allow for in-url colon, when port is not specified
2021-07-31 22:30:04 +01:00
Sergey Lyubka 5366844581 Fix #1325 - squash gcc 10 warning, and optimise casts 2021-07-31 22:26:43 +01:00
Ignacio Rodriguez e52a6184c4 test and fix 2021-07-30 12:34:55 -05:00
Sergey Lyubka b40b1232cc Enhance packed fs serving 2021-07-30 17:41:23 +01:00
Sergey Lyubka 3a46055e52 Better packed test 2021-07-30 13:19:20 +01:00
Sergey Lyubka 2af5d07467 Fix stm32 GA 2021-07-29 14:28:20 +01:00
Sergey Lyubka c2176f969b Implement FS virtualization 2021-07-29 14:21:20 +01:00
Sergey Lyubka 9346122c29 Add FS API layer 2021-07-28 21:11:07 +01:00
Sergey Lyubka b98556a4dc Enable mg_fopen_packed on ARM 2021-07-27 09:54:45 +01:00
Sergey Lyubka 55d102e450 Enable mg_fopen_packed in newlib 2021-07-27 09:50:11 +01:00
Sergey Lyubka dfc22af10f Run docker non-interactive 2021-07-26 18:18:29 +01:00
Sergey Lyubka 2d585474c1 Add riscv target, enhance arm target 2021-07-26 11:00:37 +01:00
Sergey Lyubka 53ee984eb7 Fix mg_prefix test 2021-07-26 09:26:52 +01:00
Sergey Lyubka bdb747f9de Fix mg_prefix test 2021-07-26 09:15:17 +01:00
Sergey Lyubka 299075c930 Add test for fopen_packed() 2021-07-26 09:05:34 +01:00
Sergey Lyubka b0e0247b21 Add ascii to the packed data 2021-07-25 21:08:02 +01:00
Sergey Lyubka 35abd695cd Add packed FS 2021-07-25 10:22:56 +01:00
Sergey Lyubka df2ffd1187 Refactor serve dir even more 2021-07-24 22:00:37 +01:00
Sergey Lyubka b378082ec4 Refactor mg_http_serve_dir() 2021-07-24 21:48:19 +01:00
Sergey Lyubka fb4fae9174 Optimise file serving path 2021-07-24 21:23:52 +01:00
Sergey Lyubka cddff2b1b8 Cleanup on riscv baremetal build 2021-07-24 11:40:52 +01:00
Sergey Lyubka d6dbf831f7 Remove mg_stat 2021-07-24 10:35:48 +01:00
Sergey Lyubka 7e1d4325ec Fail examples target if any example fails 2021-07-24 08:45:51 +01:00
Sergey Lyubka 2a2c17a232 Remove MG_ENABLE_STDIO and cleanup 2021-07-24 03:44:00 +01:00
Sergey Lyubka d130c6f42d Remove leftovers 2021-07-24 02:44:25 +01:00
Sergey Lyubka a09238debd Place config.h before arch*.h 2021-07-23 20:48:48 +01:00
Sergey Lyubka 328a87b02a Remove mg_file_size() 2021-07-23 20:18:34 +01:00
Sergey Lyubka 529faa1172 MG_ENABLE_FS -> MG_ENABLE_STDIO 2021-07-23 19:47:26 +01:00
Sergey Lyubka 8e5efd4804 7.3 -> 7.4 2021-07-23 12:17:05 +01:00
405 changed files with 30015 additions and 12569 deletions

No files matched your search

+3 -2
View File
@@ -7,5 +7,6 @@
# Environment # Environment
- mongoose version: _X.Y_ - mongoose version: _X.Y_
- OS: _?_ - Compiler/IDE and SDK: ZZZ version _X.Y_
- Compiler/IDE: _?_ - Target hardware/board: _?_
- Connectivity chip/module: _?_
+26
View File
@@ -0,0 +1,26 @@
name: CIFuzz
on: [pull_request]
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'mongoose'
dry-run: false
language: c++
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'mongoose'
fuzz-seconds: 600
dry-run: false
language: c++
- name: Upload Crash
uses: actions/upload-artifact@v1
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts
+109 -32
View File
@@ -3,49 +3,126 @@ on: [push, pull_request]
jobs: jobs:
linux: linux:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
cc: [gcc, clang]
target: [test, test++, valgrind]
ssl: [MBEDTLS, OPENSSL]
name: linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }}
env:
IPV6: 0
CC: ${{ matrix.cc }}
SSL: ${{ matrix.ssl }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Install packages - name: Install packages
run: sudo apt-get install libmbedtls-dev run: sudo apt-get update ; sudo apt-get install libmbedtls-dev valgrind
- name: make - name: test
run: make test test++ IPV6=0 run: make ${{ matrix.target }}
- name: openssl - name: unamalgamated
run: make test SSL=OPENSSL IPV6=0 run: make unamalgamated
examples: examples:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Install packages - run: sudo apt-get install libmbedtls-dev libpcap-dev
run: sudo apt-get install libmbedtls-dev - run: make clean examples
- name: examples - run: make clean test IPV6=0 MG_ENABLE_POLL=1
run: make ex
macos: macos:
runs-on: macos-latest runs-on: macos-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Install packages - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install jq mbedtls openssl
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install jq mbedtls openssl - run: make test++ upload-coverage IPV6=0 ASAN_OPTIONS=
- name: make - run: make test SSL=OPENSSL IPV6=0 ASAN_OPTIONS= OPENSSL=`echo /usr/local/Cellar/openssl*/*`
run: make test++ upload-coverage IPV6=0 - run: make mg_prefix
- name: openssl
run: make test SSL=OPENSSL IPV6=0 OPENSSL=`echo /usr/local/Cellar/openssl*/*`
- name: exports
run: make mg_prefix
windows: windows:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: vc98 - run: make vc98
run: make vc98 - run: make vc17
- name: vc2017 - run: make vc22
run: make vc2017 - run: make mingw
- name: mingw - run: make mingw++
run: make mingw
- name: mingw++
run: make mingw++
arm: arm:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: arm - run: make arm
run: make arm matrix_examples:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
example:
- name: esp32/device-dashboard
path: esp32/device-dashboard
- name: esp8266
path: esp8266
- name: stm32-freertos-tcp
path: stm32/stm32-freertos-tcp
- name: stm32-nucleo-f746z
path: stm32/stm32-nucleo-f746z
- name: stm32-nucleo-f429z
path: stm32/stm32-nucleo-f429z
- name: stm32-nucleo-h743z
path: stm32/stm32-nucleo-h743z
- name: stm32-nucleo-f746zg-baremetal
path: stm32/nucleo-f746zg-baremetal
- name: nxp-mimxrt1020-azurertos
path: nxp/nxp-mimxrt1020-azurertos
- name: nxp-frdmk66f-freertos
path: nxp/nxp-frdmk66f-freertos
- name: nxp-lpcxpresso54s018m-freertos
path: nxp/nxp-lpcxpresso54s018m-freertos
- name: nxp-mimxrt1020-freertos
path: nxp/nxp-mimxrt1020-freertos
- name: nxp-evkbimxrt1050-lwip-freertos
path: nxp/nxp-evkbimxrt1050-lwip-freertos
- name: nxp-evkmimxrt1020-lwip-freertos
path: nxp/nxp-evkmimxrt1020-lwip-freertos
- name: nxp-evkmimxrt1024-lwip-freertos
path: nxp/nxp-evkmimxrt1024-lwip-freertos
- name: nxp-evkmimxrt1060-lwip-freertos
path: nxp/nxp-evkmimxrt1060-lwip-freertos
- name: nxp-evkmimxrt1064-lwip-freertos
path: nxp/nxp-evkmimxrt1064-lwip-freertos
- name: nxp-evkmimxrt1160-cm7-lwip-freertos
path: nxp/nxp-evkmimxrt1160-cm7-lwip-freertos
- name: nxp-evkmimxrt1170-cm7-lwip-freertos
path: nxp/nxp-evkmimxrt1170-cm7-lwip-freertos
- name: nxp-frdmk64f-lwip-freertos
path: nxp/nxp-frdmk64f-lwip-freertos
- name: nxp-frdmk66f-lwip-freertos
path: nxp/nxp-frdmk66f-lwip-freertos
- name: nxp-lpcxpresso54018-lwip-freertos
path: nxp/nxp-lpcxpresso54018-lwip-freertos
- name: nxp-lpcxpresso54608-lwip-freertos
path: nxp/nxp-lpcxpresso54608-lwip-freertos
- name: nxp-lpcxpresso54618-lwip-freertos
path: nxp/nxp-lpcxpresso54618-lwip-freertos
- name: nxp-lpcxpresso54628-lwip-freertos
path: nxp/nxp-lpcxpresso54628-lwip-freertos
- name: nxp-twrk65f180m-lwip-freertos
path: nxp/nxp-twrk65f180m-lwip-freertos
- name: nxp-twrkv58f220m-lwip-freertos
path: nxp/nxp-twrkv58f220m-lwip-freertos
- name: infineon-xmc4700_4800-lwip-rtx-rtos
path: infineon/infineon-xmc4700_4800-lwip-rtx-rtos
- name: ti
path: ti/ti-ek-tm4c1294xl-http-server
- name: nucleo_f746zg-zephyr-http-client
path: zephyr/http-client
- name: nucleo_f746zg-zephyr-http-server
path: zephyr/http-server
- name: nucleo_f746zg-zephyr-mqtt-aws-client
path: zephyr/mqtt-aws-client
- name: nucleo_f746zg-zephyr-websocket-server
path: zephyr/websocket-server
name: ${{ matrix.example.name }}
steps:
- uses: actions/checkout@v3
- name: ${{ matrix.example.name }}
run: make -C examples/${{ matrix.example.path }} build
+2 -2
View File
@@ -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
@@ -13,4 +13,4 @@ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details. See the GNU General Public License for more details.
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://mongoose.ws/licensing/>.
+108 -69
View File
@@ -1,98 +1,140 @@
SRCS = $(wildcard src/*.c) SRCS = mongoose.c test/unit_test.c test/packed_fs.c
HDRS = $(wildcard src/*.h) HDRS = $(wildcard src/*.h) $(wildcard mip/*.h)
DEFS ?= -DMG_MAX_HTTP_HEADERS=5 -DMG_ENABLE_LINES -DMG_ENABLE_DIRECTORY_LISTING=1 -DMG_ENABLE_SSI=1 DEFS ?= -DMG_MAX_HTTP_HEADERS=7 -DMG_ENABLE_LINES -DMG_ENABLE_PACKED_FS=1 -DMG_ENABLE_SSI=1
WARN ?= -W -Wall -Werror -Wshadow -Wdouble-promotion -fno-common -Wconversion C_WARN ?= -Wmissing-prototypes -Wstrict-prototypes
WARN ?= -pedantic -W -Wall -Werror -Wshadow -Wdouble-promotion -fno-common -Wconversion -Wundef $(C_WARN)
OPTS ?= -O3 -g3 OPTS ?= -O3 -g3
VALGRIND_OPTS ?= -O0 -g3
INCS ?= -Isrc -I. INCS ?= -Isrc -I.
CFLAGS ?= $(OPTS) $(WARN) $(INCS) $(DEFS) $(TFLAGS) $(EXTRA)
SSL ?= MBEDTLS SSL ?= MBEDTLS
CDIR ?= $(realpath $(CURDIR)) CWD ?= $(realpath $(CURDIR))
VC98 = docker run --rm -e WINEDEBUG=-all -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/vc98 ENV ?= -e Tmp=. -e WINEDEBUG=-all
VC2017 = docker run --rm -e WINEDEBUG=-all -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/vc2017 DOCKER ?= docker run --platform linux/amd64 --rm $(ENV) -v $(CWD):$(CWD) -w $(CWD)
MINGW = docker run --rm -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/mingw VCFLAGS = /nologo /W3 /O2 /MD /I. $(DEFS) $(TFLAGS)
GCC = docker run --rm -v $(CDIR):$(CDIR) -w $(CDIR) mdashnet/cc2
ARM = docker run -v $(CDIR):$(CDIR) -w $(CDIR) mdashnet/armgcc
VCFLAGS = /nologo /W3 /O2 /I. $(DEFS) $(TFLAGS)
CLANG ?= clang # /usr/local/opt/llvm\@9/bin/clang
IPV6 ?= 1 IPV6 ?= 1
ASAN_OPTIONS ?= ASAN ?= -fsanitize=address,undefined -fno-sanitize-recover=all
EXAMPLES := $(wildcard examples/*) ASAN_OPTIONS ?= detect_leaks=1
EXAMPLE_TARGET ?= example EXAMPLES := $(dir $(wildcard examples/*/Makefile)) examples/stm32/nucleo-f746zg-baremetal
PREFIX ?= /usr/local PREFIX ?= /usr/local
SOVERSION = 7.2 VERSION ?= $(shell cut -d'"' -f2 src/version.h)
.PHONY: ex test COMMON_CFLAGS ?= $(WARN) $(INCS) $(DEFS) -DMG_ENABLE_IPV6=$(IPV6) $(TFLAGS)
CFLAGS ?= $(OPTS) $(ASAN) $(COMMON_CFLAGS)
VALGRIND_CFLAGS ?= $(VALGRIND_OPTS) $(COMMON_CFLAGS)
VALGRIND_RUN ?= valgrind --tool=memcheck --gen-suppressions=all --leak-check=full --show-leak-kinds=all --leak-resolution=high --track-origins=yes --error-exitcode=1 --exit-on-first-error=yes
.PHONY: examples test valgrind
ifeq "$(SSL)" "MBEDTLS" ifeq "$(SSL)" "MBEDTLS"
MBEDTLS ?= /usr MBEDTLS ?= /usr/local
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS)/include -I/usr/include 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"
OPENSSL ?= /usr OPENSSL ?= /usr/local
CFLAGS += -DMG_ENABLE_OPENSSL=1 -I$(OPENSSL)/include CFLAGS += -DMG_ENABLE_OPENSSL=1 -I$(OPENSSL)/include
LDFLAGS ?= -L$(OPENSSL)/lib -lssl -lcrypto LDFLAGS ?= -L$(OPENSSL)/lib -lssl -lcrypto
endif endif
all: mg_prefix test test++ ex vc98 vc2017 mingw mingw++ linux linux++ infer fuzz all: mg_prefix unamalgamated unpacked test test++ arm examples vc98 vc17 vc22 mingw mingw++ linux linux++ fuzz
ex: examples:
@for X in $(EXAMPLES); do $(MAKE) -C $$X $(EXAMPLE_TARGET); done @for X in $(EXAMPLES); do test -f $$X/Makefile || continue; $(MAKE) -C $$X example || exit 1; done
test/packed_fs.c: Makefile src/ssi.h test/fuzz.c test/data/a.txt
$(CC) $(CFLAGS) test/pack.c -o pack
$(RUN) ./pack Makefile src/ssi.h test/fuzz.c test/data/a.txt test/data/range.txt > $@
DIR ?= test/data/
OUT ?= fs_packed.c
mkfs:
$(CC) $(CFLAGS) test/pack.c -o pack
$(RUN) ./pack -s $(DIR) `find $(DIR) -type f` > $(OUT)
# find $(DIR) -type f | sed -e s,^$(DIR),,g -e s,^/,,g
# Check that all external (exported) symbols have "mg_" prefix # Check that all external (exported) symbols have "mg_" prefix
mg_prefix: mongoose.c mongoose.h mg_prefix: mongoose.c mongoose.h
$(CLANG) mongoose.c $(CFLAGS) -c -o /tmp/x.o && nm /tmp/x.o | grep ' T' | grep -v 'mg_' ; test $$? = 1 $(CC) mongoose.c $(CFLAGS) -c -o /tmp/x.o && nm /tmp/x.o | grep ' T' | grep -v 'mg_' ; test $$? = 1
# C++ build # C++ build
test++: CLANG = g++
test++: WARN += -Wno-shadow -Wno-missing-field-initializers -Wno-deprecated
test++: test test++: test
test++: CC = g++
test++: C_WARN = -std=c++2a -Wno-vla -Wno-shadow -Wno-missing-field-initializers -Wno-deprecated
musl: test
musl: ASAN =
musl: WARN += -Wno-sign-conversion
musl: CC = $(DOCKER) mdashnet/cc1 gcc
musl: RUN = $(DOCKER) mdashnet/cc1
# Make sure we can build from an unamalgamated sources # Make sure we can build from an unamalgamated sources
unamalgamated: $(SRCS) $(HDRS) Makefile unamalgamated: $(HDRS) Makefile test/packed_fs.c
$(CLANG) src/*.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -g -o unit_test $(CC) src/*.c test/packed_fs.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -g -o unit_test
fuzz: mongoose.c mongoose.h Makefile test/fuzz.c
$(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
# make CLANG=/usr/local/opt/llvm\@8/bin/clang ASAN_OPTIONS=detect_leaks=1 unpacked:
test: CFLAGS += -DMG_ENABLE_IPV6=$(IPV6) -fsanitize=address#,undefined $(CC) -I. mongoose.c test/unit_test.c -o $@
test: mongoose.c mongoose.h Makefile test/unit_test.c
$(CLANG) mongoose.c test/unit_test.c $(CFLAGS) -coverage $(LDFLAGS) -g -o unit_test
ASAN_OPTIONS=$(ASAN_OPTIONS) $(DEBUGGER) ./unit_test
fuzzer: mongoose.c mongoose.h Makefile test/fuzz.c
clang++ mongoose.c test/fuzz.c $(WARN) $(INCS) $(TFLAGS) -DMG_ENABLE_LINES -fsanitize=fuzzer,signed-integer-overflow,address -Wno-deprecated -Wno-vla-extension -o $@
fuzz: fuzzer
$(RUN) ./fuzzer
unit_test: Makefile mongoose.h $(SRCS)
$(CC) $(SRCS) $(CFLAGS) $(LDFLAGS) -g -o unit_test
# make CC=/usr/local/opt/llvm\@8/bin/clang ASAN_OPTIONS=detect_leaks=1
test: unit_test
ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./unit_test
coverage: CFLAGS += -coverage
coverage: test 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 -t mongoose.c > mongoose.gcov
upload-coverage: coverage upload-coverage: coverage
curl -s https://codecov.io/bash | /bin/bash curl -s https://codecov.io/bash | /bin/bash
valgrind_unit_test: Makefile mongoose.h $(SRCS)
$(CC) $(SRCS) $(VALGRIND_CFLAGS) $(LDFLAGS) -g -o valgrind_unit_test
valgrind: valgrind_unit_test
$(VALGRIND_RUN) ./valgrind_unit_test
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
#vc98: VCFLAGS += -DMG_ENABLE_IPV6=1 arm: DEFS += -DMG_ENABLE_FILE=0 -DMG_ENABLE_MIP=1 -DMG_ARCH=MG_ARCH_NEWLIB
vc98: Makefile mongoose.c mongoose.h test/unit_test.c arm: mongoose.h $(SRCS)
$(VC98) wine cl mongoose.c test/unit_test.c $(VCFLAGS) ws2_32.lib /Fe$@.exe $(DOCKER) mdashnet/armgcc arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb $(SRCS) $(OPTS) $(WARN) $(INCS) $(DEFS) $(TFLAGS) -o unit_test -nostartfiles --specs nosys.specs -e 0
$(VC98) wine $@.exe
#vc2017: VCFLAGS += -DMG_ENABLE_IPV6=1 riscv: DEFS += -DMG_ENABLE_FILE=0 -DMG_ENABLE_MIP=1 -DMG_ARCH=MG_ARCH_NEWLIB
vc2017: Makefile mongoose.c mongoose.h test/unit_test.c riscv: mongoose.h $(SRCS)
$(VC2017) wine64 cl mongoose.c test/unit_test.c $(VCFLAGS) ws2_32.lib /Fe$@.exe $(DOCKER) mdashnet/riscv riscv-none-elf-gcc -march=rv32imc -mabi=ilp32 $(SRCS) $(OPTS) $(WARN) $(INCS) $(DEFS) $(TFLAGS) -o unit_test
$(VC2017) wine64 $@.exe
mingw: Makefile mongoose.c mongoose.h test/unit_test.c vc98: Makefile mongoose.h $(SRCS)
$(MINGW) i686-w64-mingw32-gcc mongoose.c test/unit_test.c -W -Wall -Werror -I. $(DEFS) -lwsock32 -o test.exe $(DOCKER) mdashnet/vc98 wine cl $(SRCS) $(VCFLAGS) ws2_32.lib /Fe$@.exe
$(VC98) wine test.exe $(DOCKER) mdashnet/vc98 wine $@.exe
mingw++: Makefile mongoose.c mongoose.h test/unit_test.c # vc17: DEFS += -DMG_ENABLE_IPV6=1
$(MINGW) i686-w64-mingw32-g++ mongoose.c test/unit_test.c -W -Wall -Werror -I. $(DEFS) -lwsock32 -o test.exe vc17: Makefile mongoose.h $(SRCS)
# Note: for some reason, a binary built with mingw g++, fails to run $(DOCKER) mdashnet/vc17 wine64 cl $(SRCS) $(VCFLAGS) ws2_32.lib /Fe$@.exe
$(DOCKER) mdashnet/vc17 wine64 $@.exe
#linux: CFLAGS += -DMG_ENABLE_IPV6=$(IPV6) # vc22: DEFS += -DMG_ENABLE_IPV6=$(IPV6)
linux: CFLAGS += -fsanitize=address,undefined vc22: Makefile mongoose.h $(SRCS)
linux: Makefile mongoose.c mongoose.h test/unit_test.c $(DOCKER) mdashnet/vc22 wine64 cl $(SRCS) $(VCFLAGS) ws2_32.lib /Fe$@.exe
$(GCC) $(CC) mongoose.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -o unit_test_gcc $(DOCKER) mdashnet/vc22 wine64 $@.exe
$(GCC) ./unit_test_gcc
mingw: Makefile mongoose.h $(SRCS)
$(DOCKER) mdashnet/mingw x86_64-w64-mingw32-gcc $(SRCS) -W -Wall -Werror -I. $(DEFS) -lwsock32 -o $@.exe
$(DOCKER) mdashnet/mingw wine64 $@.exe
mingw++: Makefile mongoose.h $(SRCS)
$(DOCKER) mdashnet/mingw x86_64-w64-mingw32-g++ $(SRCS) -W -Wall -Werror -I. $(DEFS) -lwsock32 -o $@.exe
linux: IPV6=0
linux: Makefile mongoose.h $(SRCS)
$(DOCKER) mdashnet/cc2 gcc $(SRCS) $(CFLAGS) $(LDFLAGS) -o unit_test_gcc
$(DOCKER) mdashnet/cc2 ./unit_test_gcc
linux++: CC = g++ linux++: CC = g++
linux++: WARN += -Wno-missing-field-initializers linux++: WARN += -Wno-missing-field-initializers
@@ -100,26 +142,23 @@ linux++: linux
linux-libs: CFLAGS += -fPIC linux-libs: CFLAGS += -fPIC
linux-libs: mongoose.o linux-libs: mongoose.o
$(CC) mongoose.o $(LDFLAGS) -shared -o libmongoose.so.$(SOVERSION) $(CC) mongoose.o $(LDFLAGS) -shared -o libmongoose.so.$(VERSION)
$(AR) rcs libmongoose.a mongoose.o $(AR) rcs libmongoose.a mongoose.o
install: linux-libs install: linux-libs
install -Dm644 libmongoose.a libmongoose.so.$(SOVERSION) $(DESTDIR)$(PREFIX)/lib install -Dm644 libmongoose.a libmongoose.so.$(VERSION) $(DESTDIR)$(PREFIX)/lib
ln -s libmongoose.so.$(SOVERSION) $(DESTDIR)$(PREFIX)/lib/libmongoose.so ln -s libmongoose.so.$(VERSION) $(DESTDIR)$(PREFIX)/lib/libmongoose.so
install -Dm644 mongoose.h $(DESTDIR)$(PREFIX)/include/mongoose.h install -Dm644 mongoose.h $(DESTDIR)$(PREFIX)/include/mongoose.h
uninstall: uninstall:
rm -rf $(DESTDIR)$(PREFIX)/lib/libmongoose.a $(DESTDIR)$(PREFIX)/lib/libmongoose.so.$(SOVERSION) $(DESTDIR)$(PREFIX)/include/mongoose.h $(DESTDIR)$(PREFIX)/lib/libmongoose.so rm -rf $(DESTDIR)$(PREFIX)/lib/libmongoose.a $(DESTDIR)$(PREFIX)/lib/libmongoose.so.$(VERSION) $(DESTDIR)$(PREFIX)/include/mongoose.h $(DESTDIR)$(PREFIX)/lib/libmongoose.so
arm: Makefile mongoose.c mongoose.h test/unit_test.c mongoose.c: Makefile $(wildcard src/*) $(wildcard mip/*.c)
$(ARM) arm-none-eabi-gcc mongoose.c -c -Itest -DMG_ARCH=MG_ARCH_CUSTOM $(OPTS) $(WARN) $(INCS) -DMG_MAX_HTTP_HEADERS=5 -DMG_ENABLE_LINES -DMG_ENABLE_DIRECTORY_LISTING=0 -DMG_ENABLE_SSI=1 (cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c mip/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@
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))> $@
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/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,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@ (cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/config.h src/str.h src/fmt.h src/log.h src/timer.h src/fs.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/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h mip/mip.h | sed -e 's,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
clean: EXAMPLE_TARGET = clean clean:
clean: ex rm -rf $(PROG) *.exe *.o *.dSYM unit_test* valgrind_unit_test* ut fuzzer *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb slow-unit* _CL_* infer-out data.txt crash-* test/packed_fs.c pack unpacked
rm -rf $(PROG) *.o *.dSYM unit_test* ut fuzzer *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb slow-unit* _CL_* infer-out data.txt crash-* @for X in $(EXAMPLES); do $(MAKE) -C $$X clean; done
+7 -27
View File
@@ -21,7 +21,8 @@ robust, and easy. Features include:
- Source code is both ISO C and ISO C++ compliant - Source code is both ISO C and ISO C++ compliant
- Works with any network stack with socket API, like LwIP or FreeRTOS-Plus-TCP - Works with any network stack with socket API, like LwIP or FreeRTOS-Plus-TCP
- Very easy to integrate: just copy `mongoose.c` and `mongoose.h` files to your build tree - Very easy to integrate: just copy `mongoose.c` and `mongoose.h` files to your build tree
- Detailed [documentation](https://cesanta.com/docs/) - Detailed [documentation](https://mongoose.ws/documentation/) and
[tutorials](https://mongoose.ws/tutorials/)
# Commercial use # Commercial use
@@ -31,15 +32,11 @@ robust, and easy. Features include:
interface on devices, RESTful API services, telemetry data exchange, remote interface on devices, RESTful API services, telemetry data exchange, remote
control for a product, remote software updates, remote monitoring, and others control for a product, remote software updates, remote monitoring, and others
- Deployed to hundreds of millions devices in production environment worldwide - Deployed to hundreds of millions devices in production environment worldwide
- See [Case Studies](https://cesanta.com/case-studies.html) from our respected - See [Case Studies](https://mongoose.ws/case-studies/) from our respected
customers like Schneider Electric (industrial automation), Broadcom (semiconductors), Schenck Process customers like [Schneider Electric](https://mongoose.ws/case-studies/schneider-electric/) (industrial automation), [Broadcom](https://mongoose.ws/case-studies/broadcom/) (semiconductors), [Pilz](https://mongoose.ws/case-studies/pilz/) (industrial automation), and others
(industrial engineering), and others - See [Testimonials](https://mongoose.ws/testimonials/) from engineers that integrated Mongoose in their commercial products
- See [Testimonials](https://cesanta.com/testimonials.html) from engineers that - We provide [Evaluation and Commercial licensing](https://mongoose.ws/licensing/), [support](https://mongoose.ws/support/), consultancy and integration
integrated Mongoose in their commercial products assistance - don't hesitate to [contact us](https://mongoose.ws/contact/)
- We provide [commercial licensing](https://cesanta.com/licensing.html),
[support](https://cesanta.com/support.html), consultancy and integration
assistance - don't hesitate to
[contact us](https://www.cesanta.com/contact.html)
# Security # Security
@@ -67,23 +64,6 @@ We take security seriously:
have specific security requirements and run independent security audits, have specific security requirements and run independent security audits,
of which we get notified and in case of any issue, act similar to (3). of which we get notified and in case of any issue, act similar to (3).
# Supplement software
This software is often used together with Mongoose:
- [mjson](https://github.com/cesanta/mjson) - a JSON parser. Used to implement
RESTful APIs that use JSON, or implement data exchange (e.g. over MQTT
or Websocket) that use JSON for data encapsulation
- [elk](https://github.com/cesanta/elk) - a tiny JavaScript interpreter.
Used to implement scripting support for customers
# Precompiled web server binary
We have built a ready-to-go, precompiled web server binary for Windows
and Mac. It is a great tool for sharing your files or website. It has
a unique feature - an ability to share your local files via a global URL.
Interested? Go to [download](https://mongoose.ws/)
# Contributions # Contributions
+3379 -523
View File
File diff suppressed because it is too large. Load diff
+97
View File
@@ -0,0 +1,97 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1034 239" style="enable-background:new 0 0 1034 239;" xml:space="preserve">
<style type="text/css">
.st0{fill:#576174;}
.st1{fill:#FFFFFF;}
.st2{font-family:'Courier-Bold';}
.st3{font-size:16.7604px;}
.st4{fill:#00983A;}
.st5{fill:none;stroke:#45CFFF;stroke-width:2.7934;stroke-linecap:round;stroke-linejoin:round;}
.st6{fill:#45CFFF;}
.st7{fill:none;stroke:#A000FF;stroke-width:2.7934;stroke-linecap:round;stroke-linejoin:round;}
.st8{fill:#A000FF;}
.st9{fill:none;stroke:#FFDE00;stroke-width:2.793;stroke-linecap:round;stroke-linejoin:round;}
.st10{fill:#FFDE00;}
.st11{fill:none;stroke:#EA5B0C;stroke-width:2.793;stroke-linecap:round;stroke-linejoin:round;}
.st12{fill:#EA5B0C;}
</style>
<g>
<path class="st0" d="M485.3,224.22H8.5c-4.7,0-8.5-3.8-8.5-8.5V27.22c0-4.7,3.8-8.5,8.5-8.5h476.8c4.7,0,8.5,3.8,8.5,8.5v188.5
C493.8,220.32,490,224.22,485.3,224.22z"/>
<g>
<g>
<g>
<text transform="matrix(1 0 0 1 21.294 60.1267)" class="st1 st2 st3">struct mg_str k,v,s = mg_str(”a=333, b=777”);</text>
</g>
</g>
<g>
<g>
<text transform="matrix(1 0 0 1 21.294 136.2499)" class="st1 st2 st3">mg_commalist(&amp;s, &amp;k, &amp;v); </text>
</g>
</g>
<g>
<g>
<text transform="matrix(1 0 0 1 21.294 197.1485)" class="st1 st2 st3">mg_commalist(&amp;s, &amp;k, &amp;v); </text>
</g>
</g>
<g>
<g>
<text transform="matrix(1 0 0 1 291.5096 140.18)" class="st4 st2 st3">// 1st call</text>
<text transform="matrix(1 0 0 1 291.5096 199.8101)" class="st4 st2 st3">// 2nd call</text>
</g>
</g>
</g>
<g>
<polyline class="st5" points="336.4,64.52 336.4,68.52 317.8,68.52 317.8,64.52 "/>
<g>
<path class="st5" d="M122.3,59.62"/>
<g>
<polyline class="st5" points="327.5,76.82 327.6,94.02 203.3,94.02 203.3,116.12 "/>
<path class="st6" d="M331,77.62c0,1.8-1.4,3.2-3.2,3.3c-1.8,0.1-3.2-1.4-3.3-3.2c0-1.8,1.4-3.2,3.2-3.3l0,0
C329.5,74.42,331,75.92,331,77.62z"/>
</g>
</g>
<path class="st6" d="M203.2,114.92c-1.8,0-3.2,1.3-3.3,3s1.4,3,3.2,3s3.2-1.3,3.3-3l0,0C206.5,116.32,205,114.92,203.2,114.92z"/>
</g>
<g>
<polyline class="st7" points="407.4,64.52 407.4,68.52 388.8,68.52 388.8,64.52 "/>
<g>
<path class="st5" d="M193.4,59.62"/>
<g>
<polyline class="st7" points="398.6,76.82 398.6,149.02 203.4,149.02 203.4,177.12 "/>
<path class="st8" d="M402,77.62c0,1.8-1.4,3.2-3.2,3.3c-1.8,0.1-3.2-1.4-3.3-3.2c0-1.8,1.4-3.2,3.2-3.3l0,0
C400.6,74.42,402,75.92,402,77.62z"/>
</g>
</g>
<path class="st8" d="M203.2,175.42c-1.8,0-3.2,1.3-3.3,3s1.4,3,3.2,3s3.2-1.3,3.3-3l0,0C206.5,176.82,205,175.42,203.2,175.42z"/>
</g>
<g>
<polyline class="st9" points="440.8,64.52 440.8,68.52 414.2,68.52 414.2,64.52 "/>
<g>
<path class="st5" d="M218.8,59.62"/>
<g>
<polyline class="st9" points="428,76.82 428,163.02 245.7,163.02 245.7,176.12 "/>
<path class="st10" d="M431.4,77.62c0,1.8-1.4,3.2-3.2,3.3c-1.8,0.1-3.2-1.4-3.3-3.2c0-1.8,1.4-3.2,3.2-3.3l0,0
C430,74.42,431.4,75.92,431.4,77.62z"/>
</g>
</g>
<path class="st10" d="M245.4,175.42c-1.8,0-3.2,1.3-3.3,3s1.4,3,3.2,3s3.2-1.3,3.3-3l0,0C248.7,176.82,247.2,175.42,245.4,175.42z
"/>
</g>
<g>
<polyline class="st11" points="372.8,64.52 372.8,68.52 343.2,68.52 343.2,64.52 "/>
<g>
<path class="st5" d="M164.7,59.62"/>
<g>
<polyline class="st11" points="358.3,76.62 358.3,104.82 245.7,105.02 245.7,116.12 "/>
<path class="st12" d="M361.4,77.62c0,1.8-1.4,3.2-3.2,3.3c-1.8,0.1-3.2-1.4-3.3-3.2c0-1.8,1.4-3.2,3.2-3.3l0,0
C359.9,74.42,361.4,75.92,361.4,77.62z"/>
</g>
</g>
<path class="st12" d="M245.7,114.92c-1.8,0-3.2,1.3-3.3,3s1.4,3,3.2,3s3.2-1.3,3.3-3l0,0C248.9,116.32,247.4,114.92,245.7,114.92z
"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

+48
View File
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1034 158.07" style="enable-background:new 0 0 1034 158.07;" xml:space="preserve">
<style type="text/css">
.st0{fill:#67748A;}
.st1{fill:#FFFFFF;}
.st2{font-family:'Courier-Bold';}
.st3{font-size:16.7604px;}
.st4{fill:none;stroke:#45CFFF;stroke-width:2.793;stroke-linecap:round;stroke-linejoin:round;}
.st5{fill:#45CFFF;}
.st6{font-family:'Arial-BoldMT';}
</style>
<g>
<path class="st0" d="M516.7,39.8v56.33c0,4.17-3.8,7.54-8.5,7.54H14.6H8.5c-4.7,0-8.5-3.37-8.5-7.54V39.8c0-4.17,3.8-7.54,8.5-7.54
h499.7C512.9,32.26,516.7,35.63,516.7,39.8z"/>
<text transform="matrix(1 0 0 1 51.0379 69.3318)" class="st1 st2 st3">GET /test \n\nGET /test \n\nGET test \n\n</text>
<g>
<polyline class="st4" points="189.5,76.47 189.5,80.47 51.8,80.47 51.8,76.47 "/>
<polyline class="st4" points="331.3,76.47 331.3,80.47 195.6,80.47 195.6,76.47 "/>
<polyline class="st4" points="462.7,76.47 462.7,80.47 336.9,80.47 336.9,76.47 "/>
</g>
<g>
<text transform="matrix(1 0 0 1 78.8909 148.8896)" class="st5 st6 st3">1st request</text>
<g>
<line class="st4" x1="120.2" y1="93.57" x2="120.3" y2="129.57"/>
<path class="st5" d="M117.1,92.57c0-1.8,1.4-3.2,3.2-3.3c1.8,0,3.2,1.4,3.3,3.2c0,1.8-1.4,3.2-3.2,3.3l0,0
C118.5,95.77,117.1,94.37,117.1,92.57z"/>
</g>
</g>
<g>
<text transform="matrix(1 0 0 1 217.3594 148.8891)" class="st5 st6 st3">2nd request </text>
<g>
<line class="st4" x1="263.8" y1="93.57" x2="263.9" y2="129.57"/>
<path class="st5" d="M260.7,92.57c0-1.8,1.4-3.2,3.2-3.3c1.8,0,3.2,1.4,3.3,3.2c0,1.8-1.4,3.2-3.2,3.3l0,0
C262.1,95.77,260.7,94.37,260.7,92.57z"/>
</g>
</g>
<g>
<text transform="matrix(1 0 0 1 354.7297 148.8896)" class="st5 st6 st3">3rd request </text>
<g>
<line class="st4" x1="399.4" y1="93.57" x2="399.4" y2="129.57"/>
<path class="st5" d="M396.2,92.57c0-1.8,1.4-3.2,3.2-3.3c1.8,0,3.2,1.4,3.3,3.2c0,1.8-1.4,3.2-3.2,3.3l0,0
C397.7,95.77,396.2,94.37,396.2,92.57z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

+113
View File
@@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1035.4 429.9" style="enable-background:new 0 0 1035.4 429.9;" xml:space="preserve">
<style type="text/css">
.st0{fill:#576174;}
.st1{fill:#67748A;}
.st2{fill:none;stroke:#87005B;stroke-width:2.7934;stroke-linecap:round;stroke-linejoin:round;}
.st3{fill:#87005B;}
.st4{fill:#FFFFFF;}
.st5{font-family:'Courier-Bold';}
.st6{font-size:16.7604px;}
.st7{fill:none;stroke:#EA5B0C;stroke-width:2.793;stroke-linecap:round;stroke-linejoin:round;}
.st8{fill:#EA5B0C;}
.st9{fill:none;stroke:#CA70FF;stroke-width:2.7934;stroke-linecap:round;stroke-linejoin:round;}
.st10{fill:#CA70FF;}
.st11{fill:none;stroke:#FFDE00;stroke-width:2.793;stroke-linecap:round;stroke-linejoin:round;}
.st12{fill:#FFDE00;}
.st13{fill:none;stroke:#00CF4F;stroke-width:2.7934;stroke-linecap:round;stroke-linejoin:round;}
.st14{fill:#00CF4F;}
.st15{fill:none;stroke:#45CFFF;stroke-width:2.7934;stroke-linecap:round;stroke-linejoin:round;}
.st16{fill:none;stroke:#EA5B0C;stroke-width:2.7934;stroke-linecap:round;stroke-linejoin:round;}
.st17{font-family:'Arial-BoldMT';}
.st18{font-size:24px;}
.st19{fill:#45CFFF;}
</style>
<g>
<path class="st0" d="M755.8,391.8H8.5c-4.7,0-8.5-3.8-8.5-8.5v-153c0-4.7,3.8-8.5,8.5-8.5h747.3c4.7,0,8.5,3.8,8.5,8.5v153
C764.3,388,760.5,391.8,755.8,391.8z"/>
<path class="st1" d="M996.9,261.5h-427c-4.7,0-8.5-3.8-8.5-8.5V81.2c0-4.7,3.8-8.5,8.5-8.5h427c4.7,0,8.5,3.8,8.5,8.5V253
C1005.4,257.7,1001.5,261.5,996.9,261.5z"/>
<g>
<polyline class="st2" points="598.1,238.2 598.1,242.3 787.7,242.3 787.7,238.2 "/>
<g>
<line class="st2" x1="689.3" y1="342.2" x2="276.4" y2="343.3"/>
<g>
<line class="st2" x1="689.4" y1="253.3" x2="689.4" y2="342.1"/>
<path class="st3" d="M689.4,249.3c1.8,0,3.2,1.4,3.3,3.2c0,1.8-1.4,3.2-3.2,3.3c-1.8,0-3.2-1.4-3.3-3.2l0,0
C686.1,250.7,687.6,249.3,689.4,249.3z"/>
</g>
</g>
<path class="st3" d="M274.2,340.4c1.8,0,3.2,1.4,3.3,3.2s-1.4,3.2-3.2,3.3c-1.8,0-3.2-1.4-3.3-3.2l0,0
C270.9,341.8,272.4,340.4,274.2,340.4z"/>
</g>
<text transform="matrix(1 0 0 1 26.0923 262.5192)" class="st4 st5 st6">struct mg_http_message {</text>
<text transform="matrix(1 0 0 1 45.542 286.2874)" class="st4 st5 st6">struct mg_str method; uri, query, proto; </text>
<text transform="matrix(1 0 0 1 45.542 306.3874)" class="st4 st5 st6">struct mg_http_header headers[MG_MAX_HTTP_HEADERS];</text>
<text transform="matrix(1 0 0 1 45.542 326.4874)" class="st4 st5 st6">struct mg_str body;</text>
<text transform="matrix(1 0 0 1 45.542 346.5874)" class="st4 st5 st6">struct mg_str message; </text>
<g>
<g>
<polyline class="st7" points="621.1,89.6 621.1,78.6 215.4,79.7 215.3,269.4 "/>
<path class="st8" d="M624.3,90.6c0,1.8-1.4,3.2-3.2,3.3c-1.8,0-3.2-1.4-3.3-3.2c0-1.8,1.4-3.2,3.2-3.3l0,0
C622.8,87.4,624.3,88.8,624.3,90.6z"/>
</g>
<path class="st8" d="M212.3,269.4c0-1.8,1.4-3.2,3.2-3.3c1.8,0,3.2,1.4,3.3,3.2c0,1.8-1.4,3.2-3.2,3.3l0,0
C213.7,272.6,212.3,271.2,212.3,269.4z"/>
</g>
<g>
<polyline class="st9" points="597.2,183.6 593.1,183.6 593.1,127.8 597.2,127.8 "/>
<g>
<polyline class="st9" points="582.4,156.2 575.2,156.2 575,302.8 563.4,302.8 "/>
<path class="st10" d="M586.1,156.2c0-1.8-1.4-3.2-3.2-3.3c-1.8,0-3.2,1.4-3.3,3.2c0,1.8,1.4,3.2,3.2,3.3l0,0
C584.7,159.4,586.1,158,586.1,156.2z"/>
<path class="st10" d="M564.2,303c0-1.8-1.4-3.2-3.2-3.3c-1.8,0-3.2,1.4-3.3,3.2s1.4,3.2,3.2,3.3l0,0
C562.7,306.2,564.2,304.7,564.2,303z"/>
</g>
</g>
<text transform="matrix(1 0 0 1 601.1215 118.1291)" class="st4 st5 st6">POST /foo/bar/baz?aa=b&amp;cc=ddd HTTP/1.1</text>
<text transform="matrix(1 0 0 1 601.1215 138.2291)" class="st4 st5 st6">Content-Type: application/json</text>
<text transform="matrix(1 0 0 1 601.1215 158.3291)" class="st4 st5 st6">Content-Length: 19</text>
<text transform="matrix(1 0 0 1 601.1215 178.4291)" class="st4 st5 st6">Host: reqbin.com</text>
<g>
<g>
<g>
<polyline class="st11" points="712.3,90.6 712.4,67.6 277.8,67.6 279.7,269.3 "/>
<path class="st12" d="M715.6,90.8c0,1.8-1.4,3.2-3.2,3.3c-1.8,0-3.2-1.4-3.3-3.2c0-1.8,1.4-3.2,3.2-3.3l0,0
C714.1,87.6,715.6,89.1,715.6,90.8z"/>
</g>
<path class="st12" d="M276.5,269.4c0-1.8,1.4-3.2,3.2-3.3s3.2,1.4,3.3,3.2s-1.4,3.2-3.2,3.3l0,0
C278,272.6,276.5,271.2,276.5,269.4z"/>
</g>
<polyline class="st11" points="771.5,104.3 771.5,100.3 652.7,100.3 652.7,104.3 "/>
</g>
<g>
<g>
<g>
<polyline class="st13" points="836.3,90.6 836.3,56.6 342.8,56.6 344.7,268.3 "/>
<path class="st14" d="M839.5,90.6c0,1.8-1.4,3.2-3.2,3.3c-1.8,0-3.2-1.4-3.3-3.2c0-1.8,1.4-3.2,3.2-3.3l0,0
C838,87.4,839.5,88.9,839.5,90.6z"/>
</g>
<path class="st14" d="M341.4,269.3c0-1.8,1.4-3.2,3.2-3.3c1.8,0,3.2,1.4,3.3,3.2c0,1.8-1.4,3.2-3.2,3.3l0,0
C342.9,272.5,341.4,271.1,341.4,269.3z"/>
</g>
<polyline class="st15" points="981.4,104.2 981.4,100.2 902.6,100.2 902.6,104.2 "/>
</g>
<text transform="matrix(1 0 0 1 596.891 232.3658)" class="st4 st5 st6">{&quot;success&quot;: &quot;true&quot;}</text>
<polyline class="st16" points="643.1,104.4 643.1,100.4 599.3,100.4 599.3,104.4 "/>
<text transform="matrix(1 0 0 1 9.5506 207.5157)" class="st17 st18">Source Code</text>
<text transform="matrix(1 0 0 1 797.0799 32.3923)" class="st17 st18">HTTP message</text>
<text transform="matrix(1 0 0 1 26.0924 359.209)" class="st4 st5 st6">};</text>
<polyline class="st13" points="894.2,104.2 894.2,100.2 774.4,100.2 774.4,104.2 "/>
<g>
<g>
<polyline class="st15" points="941.3,90.6 941.3,45.6 412.8,45.6 414.7,268.3 "/>
<path class="st19" d="M944.5,90.6c0,1.8-1.4,3.2-3.2,3.3c-1.8,0-3.2-1.4-3.3-3.2c0-1.8,1.4-3.2,3.2-3.3l0,0
C943,87.4,944.5,88.9,944.5,90.6z"/>
</g>
<path class="st19" d="M411.4,269.3c0-1.8,1.4-3.2,3.2-3.3c1.8,0,3.2,1.4,3.3,3.2c0,1.8-1.4,3.2-3.2,3.3l0,0
C412.9,272.5,411.4,271.1,411.4,269.3z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.0 KiB

+109
View File
@@ -0,0 +1,109 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1034 663.54" style="enable-background:new 0 0 1034 663.54;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#45CFFF;stroke-width:2.7934;stroke-linecap:round;stroke-linejoin:round;}
.st1{fill:#45CFFF;}
.st2{fill:#576174;}
.st3{fill:#FFFFFF;}
.st4{font-family:'Courier-Bold';}
.st5{font-size:16.7604px;}
.st6{font-family:'Arial-BoldMT';}
.st7{font-size:24px;}
.st8{fill:#67748A;}
.st9{fill:#8B9CBA;}
.st10{fill:none;stroke:#00CF4F;stroke-width:2.7934;stroke-linecap:round;stroke-linejoin:round;}
.st11{fill:#00CF4F;}
.st12{fill:none;stroke:#EA5B0C;stroke-width:2.793;stroke-linecap:round;stroke-linejoin:round;}
.st13{fill:#EA5B0C;}
.st14{fill:#414857;}
</style>
<g>
<g>
<polyline class="st0" points="498.5,624.21 498.5,628.21 447.9,628.21 447.9,624.21 "/>
<g>
<path class="st0" d="M491.8,844.81"/>
<g>
<path class="st1" d="M473.8,636.11c-1.8,0-3.2,1.4-3.3,3.2c0,1.8,1.4,3.2,3.2,3.3c1.8,0,3.2-1.4,3.3-3.2l0,0
C477.1,637.61,475.6,636.11,473.8,636.11z"/>
</g>
</g>
<path class="st1" d="M296.7,852.71c-1.8,0-3.2,1.3-3.3,3c0,1.7,1.4,3,3.2,3c1.8,0,3.2-1.3,3.3-3l0,0
C299.9,854.01,298.5,852.71,296.7,852.71z"/>
</g>
<g>
<path class="st2" d="M584.6,199.01H8.5c-4.7,0-8.5-3.8-8.5-8.5V60.71c0-4.7,3.8-8.5,8.5-8.5h576.1c4.7,0,8.5,3.8,8.5,8.5v129.8
C593.1,195.21,589.3,199.01,584.6,199.01z"/>
<g>
<g>
<g>
<text transform="matrix(1 0 0 1 28.7 90.8107)" class="st3 st4 st5">struct mg_http_part part;</text>
<text transform="matrix(1 0 0 1 28.7 110.9108)" class="st3 st4 st5">size_t pos = 0;</text>
<text transform="matrix(1 0 0 1 28.7 151.1107)" class="st3 st4 st5">pos = mg_http_next_multipart(&amp;hm-&gt;body, pos, &amp;part);</text>
<text transform="matrix(1 0 0 1 28.7 171.3107)" class="st3 st4 st5">pos = mg_http_next_multipart(&amp;hm-&gt;body, pos, &amp;part);</text>
</g>
</g>
</g>
<text transform="matrix(1 0 0 1 1.3738 40.559)" class="st6 st7">Source Code</text>
</g>
<g>
<g>
<path class="st8" d="M685.5,646.41H8.5c-4.7,0-8.5-3.8-8.5-8.5v-362.9c0-4.7,3.8-8.5,8.5-8.5h677c4.7,0,8.5,3.8,8.5,8.5v362.9
C694,642.61,690.2,646.41,685.5,646.41z"/>
</g>
<path class="st9" d="M640.2,629.41H26.3c-4.7,0-8.5-3.8-8.5-8.5v-106.5c0-4.7,3.8-8.5,8.5-8.5h613.9c4.7,0,8.5,3.8,8.5,8.5v106.5
C648.7,625.61,644.8,629.41,640.2,629.41z"/>
<path class="st9" d="M644,490.91H30.1c-4.7,0-8.5-3.8-8.5-8.5v-106.5c0-4.7,3.8-8.5,8.5-8.5H644c4.7,0,8.5,3.8,8.5,8.5v106.5
C652.5,487.11,648.7,490.91,644,490.91z"/>
<g>
<text transform="matrix(1 0 0 1 0.0299 253.0343)" class="st6 st7">HTTP message</text>
</g>
<g>
<text transform="matrix(1 0 0 1 28.7 302.8107)" class="st3 st4 st5">POST /upload HTTP/1.1 </text>
<text transform="matrix(1 0 0 1 28.7 322.9107)" class="st3 st4 st5">Content-Type: multipart/form-data; boundary=&quot;--xyz&quot;</text>
<text transform="matrix(1 0 0 1 28.7 363.1107)" class="st3 st4 st5">--xyz</text>
<text transform="matrix(1 0 0 1 28.7 383.3107)" class="st3 st4 st5">Content-Disposition: form-data; name=&quot;foo&quot;; filename=&quot;a.txt&quot;</text>
<text transform="matrix(1 0 0 1 28.7 403.4107)" class="st3 st4 st5">Content-Type: text/plain</text>
<text transform="matrix(1 0 0 1 28.7 443.6107)" class="st3 st4 st5">hello world</text>
<text transform="matrix(1 0 0 1 28.7 483.8107)" class="st3 st4 st5">--xyz---</text>
<text transform="matrix(1 0 0 1 28.7 524.0107)" class="st3 st4 st5">Content-Disposition: form-data; name=&quot;bar&quot;; filename=&quot;b.txt&quot;</text>
<text transform="matrix(1 0 0 1 28.7 544.2108)" class="st3 st4 st5">Content-Type: text/plain</text>
<text transform="matrix(1 0 0 1 28.7 584.4108)" class="st3 st4 st5">hello world again</text>
<text transform="matrix(1 0 0 1 28.7 624.6107)" class="st3 st4 st5">--xyz--</text>
</g>
</g>
<g>
<g>
<polyline class="st10" points="569.5,162.51 574.5,162.51 574.5,176.11 569.5,176.11 "/>
<g>
<path class="st0" d="M726.8,392.91"/>
<g>
<polyline class="st10" points="587.3,169.71 726.7,169.71 726.6,569.31 684.3,569.31 "/>
<path class="st11" d="M585,166.41c-1.8,0-3.2,1.4-3.3,3.2c0,1.8,1.4,3.2,3.2,3.3c1.8,0,3.2-1.4,3.3-3.2l0,0
C588.2,167.91,586.8,166.41,585,166.41z"/>
</g>
</g>
<path class="st11" d="M685,566.31c-1.7,0-3,1.3-3,3s1.3,3,3,3s3-1.3,3-3l0,0C688,567.61,686.6,566.31,685,566.31z"/>
</g>
<polyline class="st10" points="657.9,501.61 673.9,501.61 673.9,634.21 657.9,634.21 "/>
</g>
<g>
<g>
<polyline class="st12" points="569.5,143.21 574.5,143.21 574.5,156.81 569.5,156.81 "/>
<g>
<path class="st0" d="M726.8,254.61"/>
<g>
<polyline class="st12" points="587.3,150.41 710.7,150.41 710.6,431.01 684.3,431.01 "/>
<path class="st13" d="M585,147.11c-1.8,0-3.2,1.4-3.3,3.2s1.4,3.2,3.2,3.3c1.8,0,3.2-1.4,3.3-3.2l0,0
C588.2,148.61,586.8,147.11,585,147.11z"/>
</g>
</g>
<path class="st13" d="M685,428.01c-1.7,0-3,1.3-3,3s1.3,3,3,3s3-1.3,3-3l0,0C688,429.31,686.6,428.01,685,428.01z"/>
</g>
<polyline class="st12" points="657.9,363.31 673.9,363.31 673.9,495.91 657.9,495.91 "/>
</g>
<text transform="matrix(1 0 0 1 537.9671 462.1467)" class="st14 st6 st7">Part 1</text>
<text transform="matrix(1 0 0 1 537.9671 600.4373)" class="st14 st6 st7">Part 2</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.5 KiB

+94
View File
@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1034 480.6" style="enable-background:new 0 0 1034 480.6;" xml:space="preserve">
<style type="text/css">
.st0{fill:#67748A;}
.st1{fill:#8B9CBA;}
.st2{fill:#FFFFFF;}
.st3{font-family:'Courier-Bold';}
.st4{font-size:16.7604px;}
.st5{fill:#414857;}
.st6{font-family:'Arial-BoldMT';}
.st7{font-size:30px;}
.st8{font-size:24px;}
.st9{fill:#576174;}
.st10{fill:none;stroke:#45CFFF;stroke-width:2.7934;stroke-linecap:round;stroke-linejoin:round;}
.st11{fill:#45CFFF;}
.st12{fill:none;stroke:#EA5B0C;stroke-width:2.793;stroke-linecap:round;stroke-linejoin:round;}
.st13{fill:#EA5B0C;}
.st14{fill:none;stroke:#EA5B0C;stroke-width:2.7934;stroke-linecap:round;stroke-linejoin:round;}
.st15{fill:none;stroke:#FFDE00;stroke-width:2.793;stroke-linecap:round;stroke-linejoin:round;}
.st16{fill:#FFDE00;}
</style>
<g>
<g>
<path class="st0" d="M908.4,454.9H272c-4.7,0-8.5-3.8-8.5-8.5V216c0-4.7,3.8-8.5,8.5-8.5h636.4c4.7,0,8.5,3.8,8.5,8.5v230.4
C916.9,451.1,913.1,454.9,908.4,454.9z"/>
<g>
<path class="st1" d="M898.6,430.8H284.7c-4.7,0-8.5-3.8-8.5-8.5V315.9c0-4.7,3.8-8.5,8.5-8.5h613.9c4.7,0,8.5,3.8,8.5,8.5v106.5
C907.1,427,903.3,430.8,898.6,430.8z"/>
<text transform="matrix(1 0 0 1 295.3688 243.086)" class="st2 st3 st4">POST /upload HTTP/1.1 </text>
<text transform="matrix(1 0 0 1 295.3688 263.186)" class="st2 st3 st4">Content-Type: multipart/form-data: boundary=&quot;--xyz&quot;</text>
<text transform="matrix(1 0 0 1 295.3688 303.386)" class="st2 st3 st4">--xyz</text>
<text transform="matrix(1 0 0 1 295.3688 323.586)" class="st2 st3 st4">Content-Disposition: form-data; name=&quot;foo&quot;; filename=&quot;a.txt&quot;</text>
<text transform="matrix(1 0 0 1 295.3688 343.686)" class="st2 st3 st4">Content-Type: text/plain</text>
<text transform="matrix(1 0 0 1 295.3688 383.886)" class="st2 st3 st4">hello world</text>
<text transform="matrix(1 0 0 1 295.3688 424.086)" class="st2 st3 st4">--xyz---</text>
</g>
</g>
<text transform="matrix(1 0 0 1 739.2766 414.2906)" class="st5 st6 st7">HTTP part</text>
<text transform="matrix(1 0 0 1 739.2764 193.4305)" class="st6 st8">HTTP message</text>
<path class="st9" d="M304.9,198H8.5c-4.7,0-8.5-3.8-8.5-8.5V64.8c0-4.7,3.8-8.5,8.5-8.5H305c4.7,0,8.5,3.8,8.5,8.5v124.7
C313.4,194.2,309.6,198,304.9,198z"/>
<g>
<g>
<text transform="matrix(1 0 0 1 25.2409 91.1617)" class="st2 st3 st4">struct mg_http_part {</text>
<text transform="matrix(1 0 0 1 47.0734 113.7079)" class="st2 st3 st4">struct mg_str name;</text>
<text transform="matrix(1 0 0 1 47.0734 133.8079)" class="st2 st3 st4">strucy mg_str filename;</text>
<text transform="matrix(1 0 0 1 47.0734 153.9079)" class="st2 st3 st4">struct mg_str body;</text>
</g>
</g>
<g>
<polyline class="st10" points="237.4,159 237.4,163 185.8,163 185.8,159 "/>
<g>
<polyline class="st10" points="211.7,348.3 349.5,348.4 349.5,355.6 "/>
<g>
<line class="st10" x1="211.6" y1="174.4" x2="211.6" y2="348.1"/>
<path class="st11" d="M211.6,170.3c-1.8,0-3.2,1.4-3.3,3.2c0,1.8,1.4,3.2,3.2,3.3c1.8,0,3.2-1.4,3.3-3.2l0,0
C214.8,171.8,213.4,170.3,211.6,170.3z"/>
</g>
</g>
<path class="st11" d="M349.6,353.6c-1.8,0-3.2,1.4-3.3,3.2s1.4,3.2,3.2,3.3c1.8,0,3.2-1.4,3.3-3.2l0,0
C352.8,355.1,351.4,353.6,349.6,353.6z"/>
<polyline class="st10" points="237.4,159 237.4,163 185.8,163 185.8,159 "/>
<polyline class="st10" points="407.3,371.1 407.3,367.1 293.3,367.1 293.3,371.1 "/>
</g>
<g>
<g>
<g>
<polyline class="st12" points="693.7,291.6 693.7,277.7 280.7,278.8 280.5,109.4 248.3,109.4 "/>
<path class="st13" d="M696.9,293.6c0,1.8-1.4,3.2-3.2,3.3c-1.8,0-3.2-1.4-3.3-3.2c0-1.8,1.4-3.2,3.2-3.3l0,0
C695.4,290.4,696.9,291.9,696.9,293.6z"/>
</g>
<path class="st13" d="M243.9,109.5c0-1.8,1.4-3.2,3.2-3.3c1.8,0,3.2,1.4,3.3,3.2c0,1.8-1.4,3.2-3.2,3.3l0,0
C245.3,112.7,243.9,111.3,243.9,109.5z"/>
</g>
<polyline class="st14" points="707.6,309.2 707.6,305.2 679.9,305.2 679.9,309.2 "/>
</g>
<text transform="matrix(1 0 0 1 0.8627 37.8099)" class="st6 st8">Source Code</text>
<text transform="matrix(1 0 0 1 25.2408 177.7241)" class="st2 st3 st4">};</text>
<g>
<g>
<g>
<polyline class="st15" points="863.8,291.5 863.7,218.6 329.7,218.7 329.6,130.3 298.4,130.3 "/>
<path class="st16" d="M867.1,293.6c0,1.8-1.4,3.2-3.2,3.3c-1.8,0-3.2-1.4-3.3-3.2c0-1.8,1.4-3.2,3.2-3.3l0,0
C865.6,290.3,867.1,291.8,867.1,293.6z"/>
</g>
<path class="st16" d="M293,130.1c0-1.8,1.4-3.2,3.2-3.3c1.8,0,3.2,1.4,3.3,3.2c0,1.8-1.4,3.2-3.2,3.3l0,0
C294.4,133.3,293,131.9,293,130.1z"/>
</g>
<polyline class="st15" points="888.7,309.1 888.7,305.1 838.9,305.1 838.9,309.1 "/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.9 KiB

+84
View File
@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1034 331.2" style="enable-background:new 0 0 1034 331.2;" xml:space="preserve">
<style type="text/css">
.st0{fill:#576174;}
.st1{fill:#67748A;}
.st2{fill:#FFFFFF;}
.st3{font-family:'Courier-Bold';}
.st4{font-size:16.7604px;}
.st5{font-family:'Arial-BoldMT';}
.st6{font-size:24px;}
.st7{fill:none;stroke:#45CFFF;stroke-width:2.7934;stroke-linecap:round;stroke-linejoin:round;}
.st8{fill:#45CFFF;}
.st9{fill:none;stroke:#EA5B0C;stroke-width:2.793;stroke-linecap:round;stroke-linejoin:round;}
.st10{fill:#EA5B0C;}
.st11{fill:none;stroke:#EA5B0C;stroke-width:2.7934;stroke-linecap:round;stroke-linejoin:round;}
.st12{fill:none;stroke:#00CF4F;stroke-width:2.7934;stroke-linecap:round;stroke-linejoin:round;}
.st13{fill:#00CF4F;}
</style>
<g>
<path class="st0" d="M541.43,184.2H8.53c-4.7,0-8.5-3.8-8.5-8.5V54.8c0-4.7,3.8-8.5,8.5-8.5h532.9c4.7,0,8.5,3.8,8.5,8.5v120.9
C549.93,180.4,546.13,184.2,541.43,184.2z"/>
<g>
<path class="st1" d="M829.23,315.5h-370c-4.7,0-8.5-3.8-8.5-8.5V157c0-4.7,3.8-8.5,8.5-8.5h370c4.7,0,8.5,3.8,8.5,8.5v150
C837.83,311.7,833.93,315.5,829.23,315.5z"/>
<g>
<text transform="matrix(1 0 0 1 490.6096 184.0905)" class="st2 st3 st4">HTTP/1.1 200 OK</text>
<text transform="matrix(1 0 0 1 490.6096 204.1905)" class="st2 st3 st4">Content-Length; 13</text>
<text transform="matrix(1 0 0 1 490.6096 224.2905)" class="st2 st3 st4">X-Header-1: additional value 1</text>
<text transform="matrix(1 0 0 1 490.6096 244.3905)" class="st2 st3 st4">X-Header-2: additional value 2</text>
<text transform="matrix(1 0 0 1 490.8657 293.1559)" class="st2 st3 st4">Hello, world!</text>
</g>
</g>
<text transform="matrix(1 0 0 1 660.5036 137.3383)" class="st5 st6">HTTP message</text>
<g>
<g>
<text transform="matrix(1 0 0 1 20.7331 85.1617)" class="st2 st3 st4">mg_http_reply(c, 200</text>
<text transform="matrix(1 0 0 1 159.5657 113.7079)" class="st2 st3 st4">&quot;X-Header-1: additional value 1\r\n&quot;</text>
<text transform="matrix(1 0 0 1 159.5657 133.8079)" class="st2 st3 st4">&quot;X-Header-2: additional value 2\r\n&quot;,</text>
<text transform="matrix(1 0 0 1 159.5657 153.9079)" class="st2 st3 st4">&quot;Hello, %s!&quot;, &quot;world&quot;);</text>
</g>
</g>
<g>
<polyline class="st7" points="362.93,159 362.93,163 167.33,163 167.33,159 "/>
<g>
<polyline class="st7" points="265.93,256.6 552.13,256.7 552.13,264.4 "/>
<g>
<line class="st7" x1="265.83" y1="174.4" x2="265.83" y2="256.6"/>
<path class="st8" d="M265.83,170.3c-1.8,0-3.2,1.4-3.3,3.2c0,1.8,1.4,3.2,3.2,3.3c1.8,0,3.2-1.4,3.3-3.2l0,0
C269.03,171.8,267.53,170.3,265.83,170.3z"/>
</g>
</g>
<path class="st8" d="M552.23,261.6c-1.8,0-3.2,1.4-3.3,3.2c0,1.8,1.4,3.2,3.2,3.3c1.8,0,3.2-1.4,3.3-3.2l0,0
C555.43,263.1,554.03,261.6,552.23,261.6z"/>
</g>
<g>
<g>
<g>
<polyline class="st9" points="206.33,53.6 206.43,37.6 596.43,38.7 596.53,161.3 "/>
<path class="st10" d="M203.23,54.6c0,1.8,1.4,3.2,3.2,3.3c1.8,0,3.2-1.4,3.3-3.2c0-1.8-1.4-3.2-3.2-3.3l0,0
C204.63,51.4,203.23,52.8,203.23,54.6z"/>
</g>
<path class="st10" d="M599.83,164c0-1.8-1.4-3.2-3.2-3.3c-1.8,0-3.2,1.4-3.3,3.2c0,1.8,1.4,3.2,3.2,3.3l0,0
C598.33,167.2,599.83,165.8,599.83,164z"/>
</g>
<polyline class="st11" points="192.43,69.2 192.43,65.2 220.23,65.2 220.23,69.2 "/>
</g>
<text transform="matrix(1 0 0 1 -1.917133e-04 35.0037)" class="st5 st6">Source Code</text>
<g>
<polyline class="st12" points="160.13,135.9 156.03,135.9 156.03,100.1 160.13,100.1 "/>
<g>
<line class="st12" x1="123.93" y1="231" x2="469.73" y2="231"/>
<polyline class="st12" points="144.73,117.2 123.83,117.2 123.73,230.8 "/>
<path class="st13" d="M147.83,117.2c0-1.8-1.4-3.2-3.2-3.3c-1.8,0-3.2,1.4-3.3,3.2c0,1.8,1.4,3.2,3.2,3.3l0,0
C146.33,120.4,147.83,119,147.83,117.2z"/>
<path class="st13" d="M474.83,230.8c0-1.8-1.4-3.2-3.2-3.3c-1.8,0-3.2,1.4-3.3,3.2c0,1.8,1.4,3.2,3.2,3.3l0,0
C473.43,234,474.83,232.5,474.83,230.8z"/>
</g>
</g>
<polyline class="st7" points="489.03,279.6 489.03,275.6 620.63,275.6 620.63,279.6 "/>
<polyline class="st12" points="487.63,248.3 483.63,248.3 483.63,211.5 487.63,211.5 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

+124
View File
@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 869.6 185.67" style="enable-background:new 0 0 869.6 185.67;" xml:space="preserve">
<style type="text/css">
.st0{font-family:'Arial-BoldMT';}
.st1{font-size:24px;}
.st2{opacity:0.2;fill:#00983A;enable-background:new ;}
.st3{fill:none;stroke:#7A8387;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;}
.st4{fill:#00983A;}
.st5{fill:none;stroke:#576174;stroke-miterlimit:10;}
.st6{fill:#F2F3F3;stroke:#7A8387;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;}
.st7{fill:none;stroke:#576174;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;}
.st8{font-family:'Courier-Bold';}
.st9{font-size:16.7604px;}
.st10{fill:none;stroke:#00983A;stroke-linecap:round;stroke-linejoin:round;}
.st11{fill:#576174;}
.st12{font-family:'Courier';}
.st13{fill:none;}
.st14{fill:#7A8387;}
</style>
<g>
<text transform="matrix(1 0 0 1 1.0956 32.4549)" class="st0 st1">Memory</text>
<polyline class="st2" points="424.58,115.4 219.88,115.4 219.88,90.7 424.58,90.7 "/>
<g>
<g>
<g>
<polyline class="st3" points="458.98,115.4 218.98,115.4 218.98,90.7 458.98,90.7 "/>
<polyline class="st4" points="219.18,115.1 2.98,115.1 2.98,91.3 219.18,91.3 "/>
<line class="st3" x1="2.98" y1="69.2" x2="2.98" y2="130.4"/>
<line class="st5" x1="219.78" y1="69.2" x2="219.78" y2="130.4"/>
<line class="st5" x1="425.28" y1="69.2" x2="425.28" y2="130.4"/>
<path class="st6" d="M458.98,115.4"/>
<path class="st7" d="M33.98,114.6"/>
<path class="st7" d="M33.98,90.9"/>
<path class="st7" d="M2.98,90.7h216.8v24.9l-216.8-0.2C2.98,115.4,3.18,90.7,2.98,90.7z"/>
<line class="st3" x1="425.18" y1="90.8" x2="425.18" y2="115.3"/>
<path class="st6" d="M251.98,115.6"/>
<path class="st6" d="M251.98,91.9"/>
</g>
<g>
<text transform="matrix(1 0 0 1 -2.290726e-04 175.3858)" class="st4 st8 st9">buf</text>
</g>
<g>
<g>
<line class="st10" x1="2.68" y1="158.2" x2="2.68" y2="137.2"/>
<g>
<polygon class="st4" points="0.28,137.6 5.08,137.6 2.68,135.1 "/>
</g>
</g>
</g>
<g>
<g>
<text transform="matrix(1 0 0 1 214.6515 175.3858)" class="st4 st8 st9">len</text>
</g>
</g>
<g>
<g>
<line class="st10" x1="219.78" y1="158.2" x2="219.78" y2="137.2"/>
<g>
<polygon class="st4" points="217.38,137.6 222.18,137.6 219.78,135.1 "/>
</g>
</g>
</g>
<g>
<g>
<text transform="matrix(1 0 0 1 421.6186 175.3858)" class="st4 st8 st9">size</text>
</g>
</g>
<g>
<g>
<line class="st10" x1="425.38" y1="158.2" x2="425.38" y2="137.2"/>
<g>
<polygon class="st4" points="422.98,137.6 427.78,137.6 425.38,135.1 "/>
</g>
</g>
</g>
<g>
<g>
<text transform="matrix(1 0 0 1 93.1143 69.4458)" class="st11 st12 st9">data</text>
</g>
<g>
<g>
<text transform="matrix(1 0 0 1 273.8231 69.4458)" class="st11 st12 st9">free space</text>
</g>
</g>
<g>
<g>
<line class="st5" x1="132.98" y1="76.3" x2="13.98" y2="76.3"/>
<g>
<polygon class="st11" points="14.28,78.7 14.28,73.8 11.88,76.3 "/>
</g>
</g>
</g>
<g>
<line class="st13" x1="123.88" y1="76.3" x2="210.88" y2="76.3"/>
<g>
<line class="st5" x1="123.88" y1="76.3" x2="208.78" y2="76.3"/>
<g>
<polygon class="st11" points="208.48,73.8 208.48,78.7 210.88,76.3 "/>
</g>
</g>
</g>
<g>
<g>
<line class="st5" x1="320.38" y1="76.3" x2="414.28" y2="76.3"/>
<g>
<polygon class="st14" points="413.98,73.8 413.98,78.7 416.38,76.3 "/>
</g>
</g>
</g>
<g>
<g>
<line class="st5" x1="322.28" y1="76.3" x2="233.28" y2="76.3"/>
<g>
<polygon class="st14" points="233.68,78.7 233.68,73.8 231.18,76.3 "/>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

+52
View File
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 869 124.66" style="enable-background:new 0 0 869 124.66;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F2F3F3;stroke:#7A8387;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;}
.st1{fill:none;stroke:#7A8387;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;}
.st2{fill:#00983A;}
.st3{font-family:'Courier-Bold';}
.st4{font-size:16.7604px;}
.st5{fill:none;stroke:#00983A;stroke-linecap:round;stroke-linejoin:round;}
.st6{fill:#7A8387;}
</style>
<g>
<g>
<g>
<polyline class="st0" points="830.92,78.4 5.52,78.4 5.52,53.7 830.92,53.6 "/>
<line class="st1" x1="5.52" y1="32.2" x2="5.52" y2="93.4"/>
<path class="st0" d="M830.92,78.4"/>
<line class="st1" x1="36.52" y1="53.9" x2="36.52" y2="77.6"/>
<line class="st1" x1="68.92" y1="53.9" x2="68.92" y2="77.6"/>
<line class="st1" x1="101.42" y1="53.9" x2="101.42" y2="77.6"/>
<line class="st1" x1="133.72" y1="53.9" x2="133.72" y2="77.6"/>
<line class="st1" x1="166.22" y1="53.9" x2="166.22" y2="77.6"/>
<line class="st1" x1="198.52" y1="54.6" x2="198.52" y2="78.3"/>
<line class="st1" x1="230.92" y1="54.6" x2="230.92" y2="78.3"/>
</g>
<g>
<text transform="matrix(1 0 0 1 59.1908 40.8585)" class="st2 st3 st4">buf=NULL, len=0, size=0 </text>
</g>
<g>
<text transform="matrix(1 0 0 1 -1.811981e-04 109.9024)" class="st2 st3 st4">0</text>
</g>
<g>
<g>
<g>
<line class="st5" x1="46.72" y1="37.7" x2="17.72" y2="37.7"/>
<g>
<polygon class="st2" points="18.12,40.1 18.12,35.2 15.62,37.7 "/>
</g>
</g>
</g>
</g>
<g>
<path class="st6" d="M511.52,66.4c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6s0.7-1.6,1.6-1.6S511.52,65.5,511.52,66.4z"/>
<path class="st6" d="M525.32,66.4c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6s0.7-1.6,1.6-1.6S525.32,65.5,525.32,66.4z"/>
<path class="st6" d="M539.02,66.4c0,0.9-0.7,1.6-1.6,1.6c-0.9,0-1.6-0.7-1.6-1.6s0.7-1.6,1.6-1.6S539.02,65.5,539.02,66.4z"/>
<path class="st6" d="M552.82,66.4c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6s0.7-1.6,1.6-1.6S552.82,65.5,552.82,66.4z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

+185
View File
@@ -0,0 +1,185 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 869.6 127.5" style="enable-background:new 0 0 869.6 127.5;" xml:space="preserve">
<style type="text/css">
.st0{opacity:0.2;fill:#00983A;enable-background:new ;}
.st1{fill:#F2F3F3;}
.st2{fill:none;stroke:#7A8387;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;}
.st3{fill:#00983A;}
.st4{fill:#F2F3F3;stroke:#7A8387;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;}
.st5{fill:none;stroke:#576174;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;}
.st6{fill:none;stroke:#576174;stroke-width:1.2;stroke-linecap:square;stroke-linejoin:round;}
.st7{font-family:'Courier-Bold';}
.st8{font-size:16.7604px;}
.st9{fill:none;stroke:#00983A;stroke-linecap:round;stroke-linejoin:round;}
.st10{fill:#7A8387;}
.st11{fill:#576174;}
.st12{fill:none;stroke:#576174;stroke-linecap:round;stroke-linejoin:round;}
.st13{fill:none;stroke:#7A8387;stroke-linecap:round;stroke-linejoin:round;}
.st14{fill:#333A45;}
</style>
<g>
<g>
<polyline class="st0" points="577.2,72.8 282.4,72.8 282.4,48 577.2,48 "/>
<g>
<g>
<g>
<polyline class="st1" points="122.6,72.8 5.9,72.8 5.9,48 122.6,48 "/>
<polyline class="st2" points="831.51,72.8 5.5,72.8 5.5,48 831.51,48 "/>
<polyline class="st3" points="282.7,72.5 122.5,72.5 122.5,47.7 282.7,47.7 "/>
<line class="st2" x1="122.5" y1="26.6" x2="122.5" y2="87.8"/>
<line class="st2" x1="283.3" y1="26.6" x2="283.3" y2="87.8"/>
<line class="st2" x1="576.8" y1="26.6" x2="576.8" y2="87.8"/>
<path class="st4" d="M831.51,72.8"/>
<line class="st5" x1="153.5" y1="48.3" x2="153.5" y2="72"/>
<line class="st2" x1="36.5" y1="48.3" x2="36.5" y2="72"/>
<line class="st2" x1="67.6" y1="48.3" x2="67.6" y2="72"/>
<line class="st5" x1="186" y1="48.3" x2="186" y2="72"/>
<line class="st5" x1="218.4" y1="48.3" x2="218.4" y2="72"/>
<line class="st5" x1="250.9" y1="48.3" x2="250.9" y2="72"/>
<line class="st2" x1="315.9" y1="48.3" x2="315.9" y2="72"/>
<line class="st2" x1="348.4" y1="48.3" x2="348.4" y2="72"/>
<line class="st2" x1="381.2" y1="48.3" x2="381.2" y2="72"/>
<line class="st2" x1="413.8" y1="48.3" x2="413.8" y2="72"/>
<line class="st2" x1="446.3" y1="48.3" x2="446.3" y2="72"/>
<line class="st2" x1="478.9" y1="48.3" x2="478.9" y2="72"/>
<line class="st5" x1="511.51" y1="48.3" x2="511.51" y2="72"/>
<line class="st2" x1="511.51" y1="48.3" x2="511.51" y2="72"/>
<line class="st5" x1="544.01" y1="48.3" x2="544.01" y2="72"/>
<line class="st2" x1="544.1" y1="48.3" x2="544.1" y2="72"/>
<line class="st6" x1="283.3" y1="73" x2="122.5" y2="72.8"/>
<line class="st6" x1="122.5" y1="48" x2="283.3" y2="48.1"/>
<path class="st4" d="M385.5,73"/>
<path class="st4" d="M385.5,49.3"/>
</g>
<g>
<text transform="matrix(1 0 0 1 127.5176 105.8013)" class="st3 st7 st8">buf</text>
</g>
<g>
<g>
<line class="st9" x1="122.2" y1="105.6" x2="122.2" y2="94.6"/>
<g>
<polygon class="st3" points="119.8,94.9 124.6,94.9 122.2,92.5 "/>
</g>
</g>
</g>
<g>
<text transform="matrix(1 0 0 1 286.6495 105.8008)" class="st3 st7 st8">len=5</text>
</g>
<g>
<g>
<line class="st9" x1="283.3" y1="105.6" x2="283.3" y2="94.6"/>
<g>
<polygon class="st3" points="280.9,94.9 285.8,94.9 283.3,92.5 "/>
</g>
</g>
</g>
<g>
<text transform="matrix(1 0 0 1 581.4624 105.8013)" class="st3 st7 st8">size=16</text>
</g>
<g>
<g>
<line class="st9" x1="576.9" y1="105.6" x2="576.9" y2="94.6"/>
<g>
<polygon class="st3" points="574.51,94.9 579.4,94.9 576.9,92.5 "/>
</g>
</g>
</g>
<g>
<path class="st10" d="M687.51,60.7c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6S687.51,59.9,687.51,60.7z"/>
<path class="st10" d="M701.2,60.7c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6S701.2,59.9,701.2,60.7z"/>
<path class="st10" d="M714.9,60.7c0,0.9-0.7,1.6-1.6,1.6c-0.9,0-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6
C714.2,59.1,714.9,59.9,714.9,60.7z"/>
<path class="st10" d="M728.7,60.7c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6
C728.01,59.1,728.7,59.9,728.7,60.7z"/>
</g>
<g>
<path class="st10" d="M82.8,60.7c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6S82.8,59.9,82.8,60.7z"/>
<path class="st10" d="M96.5,60.7c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6C95.8,59.1,96.5,59.9,96.5,60.7
z"/>
<path class="st10" d="M110.2,60.7c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6S110.2,59.9,110.2,60.7z"/>
</g>
<g>
<g>
<text transform="matrix(1 0 0 1 180.6541 26.8123)" class="st11 st7 st8">data</text>
</g>
<g>
<text transform="matrix(1 0 0 1 387.363 26.8123)" class="st10 st7 st8">free space</text>
</g>
<g>
<g>
<line class="st12" x1="272.2" y1="33.6" x2="133.5" y2="33.6"/>
<g>
<polygon class="st11" points="271.9,36.2 273.5,33.6 271.9,31.1 271.8,31.1 271.8,36.2 "/>
</g>
<g>
<polygon class="st11" points="133.8,36.1 133.8,31.2 131.4,33.6 "/>
</g>
</g>
</g>
<g>
<g>
<line class="st13" x1="563.7" y1="33.6" x2="295.9" y2="33.6"/>
<g>
<polygon class="st10" points="563.4,36.1 563.4,31.2 565.8,33.6 "/>
</g>
<g>
<polygon class="st10" points="296.2,36.1 296.2,31.2 293.7,33.6 "/>
</g>
</g>
</g>
<g>
<text transform="matrix(1 0 0 1 615.4679 25.1898)" class="st10 st7 st8">non-allocated space</text>
</g>
<g>
<g>
<line class="st13" x1="593.7" y1="33.6" x2="829.7" y2="33.6"/>
<g>
<polygon class="st10" points="829.4,31.2 829.4,36.1 831.8,33.6 "/>
</g>
</g>
</g>
<g>
<g>
<line class="st13" x1="678.7" y1="33.6" x2="589.7" y2="33.6"/>
<g>
<polygon class="st10" points="590.01,36.1 590.01,31.2 587.6,33.6 "/>
</g>
</g>
</g>
</g>
<g>
<g>
<text transform="matrix(1 0 0 1 133.1212 64.9593)" class="st14 st7 st8">h</text>
</g>
</g>
<g>
<g>
<text transform="matrix(1 0 0 1 165.1564 64.9593)" class="st14 st7 st8">e</text>
</g>
</g>
<g>
<g>
<text transform="matrix(1 0 0 1 196.8744 64.9593)" class="st14 st7 st8">l</text>
</g>
</g>
<g>
<g>
<text transform="matrix(1 0 0 1 229.8611 64.9593)" class="st14 st7 st8">l</text>
</g>
</g>
<g>
<g>
<text transform="matrix(1 0 0 1 262.2135 64.9593)" class="st14 st7 st8">o</text>
</g>
</g>
</g>
</g>
</g>
<g>
<text transform="matrix(1 0 0 1 1.811981e-04 105.8011)" class="st3 st7 st8">0</text>
</g>
<line class="st2" x1="5.5" y1="26.4" x2="5.5" y2="87.6"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.1 KiB

+347
View File
@@ -0,0 +1,347 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 869.6 247.73" style="enable-background:new 0 0 869.6 247.73;" xml:space="preserve">
<style type="text/css">
.st0{opacity:0.2;fill:#00983A;enable-background:new ;}
.st1{fill:#00983A;}
.st2{fill:#FF80A4;}
.st3{fill:#F2F3F3;}
.st4{fill:none;stroke:#7A8387;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;}
.st5{fill:#F2F3F3;stroke:#7A8387;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;}
.st6{fill:none;stroke:#576174;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;}
.st7{fill:none;stroke:#576174;stroke-width:1.2;stroke-linejoin:round;}
.st8{fill:none;stroke:#576174;stroke-width:1.2;stroke-linecap:square;stroke-linejoin:round;}
.st9{font-family:'Courier-Bold';}
.st10{font-size:16.7604px;}
.st11{fill:none;stroke:#00983A;stroke-linecap:round;stroke-linejoin:round;}
.st12{fill:#7A8387;}
.st13{fill:#576174;}
.st14{fill:none;stroke:#576174;stroke-linecap:round;stroke-linejoin:round;}
.st15{fill:none;stroke:#7A8387;stroke-linecap:round;stroke-linejoin:round;}
.st16{fill:#333A45;}
</style>
<g>
<g>
<polyline class="st0" points="577.2,72.8 282.4,72.8 282.4,48 577.2,48 "/>
<g>
<g>
<g>
<rect x="250.9" y="47.7" class="st1" width="32.4" height="24.8"/>
<rect x="153.5" y="47.7" class="st2" width="97.3" height="24.8"/>
<polyline class="st3" points="122.6,72.8 5.9,72.8 5.9,48 122.6,48 "/>
<polyline class="st4" points="831.51,72.8 5.5,72.8 5.5,48 831.51,48 "/>
<rect x="122.5" y="47.7" class="st1" width="31" height="24.8"/>
<line class="st4" x1="122.5" y1="26.6" x2="122.5" y2="87.8"/>
<line class="st4" x1="576.8" y1="26.6" x2="576.8" y2="87.8"/>
<path class="st5" d="M831.51,72.8"/>
<line class="st6" x1="153.5" y1="48.3" x2="153.5" y2="72"/>
<line class="st4" x1="36.5" y1="48.3" x2="36.5" y2="72"/>
<line class="st4" x1="67.6" y1="48.3" x2="67.6" y2="72"/>
<line class="st6" x1="186" y1="48.3" x2="186" y2="72"/>
<line class="st6" x1="218.4" y1="48.3" x2="218.4" y2="72"/>
<line class="st7" x1="250.9" y1="73" x2="250.81" y2="47.7"/>
<line class="st4" x1="315.9" y1="48.3" x2="315.9" y2="72"/>
<line class="st4" x1="348.4" y1="48.3" x2="348.4" y2="72"/>
<line class="st4" x1="381.2" y1="48.3" x2="381.2" y2="72"/>
<line class="st4" x1="413.8" y1="48.3" x2="413.8" y2="72"/>
<line class="st4" x1="446.3" y1="48.3" x2="446.3" y2="72"/>
<line class="st4" x1="478.9" y1="48.3" x2="478.9" y2="72"/>
<line class="st6" x1="511.51" y1="48.3" x2="511.51" y2="72"/>
<line class="st4" x1="511.51" y1="48.3" x2="511.51" y2="72"/>
<line class="st6" x1="544.01" y1="48.3" x2="544.01" y2="72"/>
<line class="st4" x1="544.1" y1="48.3" x2="544.1" y2="72"/>
<line class="st8" x1="283.3" y1="73" x2="122.5" y2="72.8"/>
<line class="st8" x1="122.5" y1="48" x2="283.3" y2="48.1"/>
<path class="st5" d="M385.5,73"/>
<path class="st5" d="M385.5,49.3"/>
<line class="st4" x1="283.3" y1="26.6" x2="283.3" y2="87.8"/>
</g>
<g>
<text transform="matrix(1 0 0 1 127.5176 105.8013)" class="st1 st9 st10">buf</text>
</g>
<g>
<g>
<line class="st11" x1="122.2" y1="105.6" x2="122.2" y2="94.6"/>
<g>
<polygon class="st1" points="119.8,94.9 124.6,94.9 122.2,92.5 "/>
</g>
</g>
</g>
<g>
<text transform="matrix(1 0 0 1 286.6495 105.8008)" class="st1 st9 st10">len=5</text>
</g>
<g>
<g>
<line class="st11" x1="283.3" y1="105.6" x2="283.3" y2="94.6"/>
<g>
<polygon class="st1" points="280.9,94.9 285.8,94.9 283.3,92.5 "/>
</g>
</g>
</g>
<g>
<text transform="matrix(1 0 0 1 581.4624 105.8013)" class="st1 st9 st10">size=16</text>
</g>
<g>
<g>
<line class="st11" x1="576.9" y1="105.6" x2="576.9" y2="94.6"/>
<g>
<polygon class="st1" points="574.51,94.9 579.4,94.9 576.9,92.5 "/>
</g>
</g>
</g>
<g>
<path class="st12" d="M687.51,60.7c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6S687.51,59.9,687.51,60.7z"/>
<path class="st12" d="M701.2,60.7c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6S701.2,59.9,701.2,60.7z"/>
<path class="st12" d="M714.9,60.7c0,0.9-0.7,1.6-1.6,1.6c-0.9,0-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6
C714.2,59.1,714.9,59.9,714.9,60.7z"/>
<path class="st12" d="M728.7,60.7c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6
C728.01,59.1,728.7,59.9,728.7,60.7z"/>
</g>
<g>
<path class="st12" d="M82.8,60.7c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6S82.8,59.9,82.8,60.7z"/>
<path class="st12" d="M96.5,60.7c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6C95.8,59.1,96.5,59.9,96.5,60.7
z"/>
<path class="st12" d="M110.2,60.7c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6S110.2,59.9,110.2,60.7z"/>
</g>
<g>
<g>
<text transform="matrix(1 0 0 1 180.6541 26.8123)" class="st13 st9 st10">data</text>
</g>
<g>
<text transform="matrix(1 0 0 1 387.363 26.8123)" class="st12 st9 st10">free space</text>
</g>
<g>
<g>
<line class="st14" x1="272.2" y1="33.6" x2="133.5" y2="33.6"/>
<g>
<polygon class="st13" points="271.9,36.2 273.5,33.6 271.9,31.1 271.8,31.1 271.8,36.2 "/>
</g>
<g>
<polygon class="st13" points="133.8,36.1 133.8,31.2 131.4,33.6 "/>
</g>
</g>
</g>
<g>
<g>
<line class="st15" x1="563.7" y1="33.6" x2="295.9" y2="33.6"/>
<g>
<polygon class="st12" points="563.4,36.1 563.4,31.2 565.8,33.6 "/>
</g>
<g>
<polygon class="st12" points="296.2,36.1 296.2,31.2 293.7,33.6 "/>
</g>
</g>
</g>
<g>
<text transform="matrix(1 0 0 1 615.4679 25.1898)" class="st12 st9 st10">non-allocated space</text>
</g>
<g>
<g>
<line class="st15" x1="593.7" y1="33.6" x2="829.7" y2="33.6"/>
<g>
<polygon class="st12" points="829.4,31.2 829.4,36.1 831.8,33.6 "/>
</g>
</g>
</g>
<g>
<g>
<line class="st15" x1="678.7" y1="33.6" x2="589.7" y2="33.6"/>
<g>
<polygon class="st12" points="590.01,36.1 590.01,31.2 587.6,33.6 "/>
</g>
</g>
</g>
</g>
<g>
<g>
<text transform="matrix(1 0 0 1 133.1212 64.9593)" class="st16 st9 st10">h</text>
</g>
</g>
<g>
<g>
<g>
<text transform="matrix(1 0 0 1 165.1564 64.9593)" class="st16 st9 st10">e</text>
</g>
</g>
</g>
<g>
<g>
<g>
<text transform="matrix(1 0 0 1 196.8744 64.9593)" class="st16 st9 st10">l</text>
</g>
</g>
</g>
<g>
<g>
<g>
<text transform="matrix(1 0 0 1 229.8611 64.9593)" class="st16 st9 st10">l</text>
</g>
</g>
</g>
<g>
<g>
<text transform="matrix(1 0 0 1 262.2135 64.9593)" class="st16 st9 st10">o</text>
</g>
</g>
</g>
</g>
</g>
<g>
<text transform="matrix(1 0 0 1 1.811981e-04 105.8011)" class="st1 st9 st10">0</text>
</g>
<line class="st4" x1="5.5" y1="26.4" x2="5.5" y2="87.6"/>
</g>
<g>
<g>
<polyline class="st0" points="577.2,207.99 186.3,207.99 186.3,183.19 577.2,183.19 "/>
<g>
<g>
<g>
<polyline class="st3" points="122.6,207.99 5.9,207.99 5.9,183.19 122.6,183.19 "/>
<polyline class="st4" points="831.51,207.99 5.5,207.99 5.5,183.19 831.51,183.19 "/>
<polyline class="st1" points="186.3,207.69 122.5,207.69 122.5,182.89 186.3,182.89 "/>
<line class="st4" x1="122.5" y1="161.79" x2="122.5" y2="222.99"/>
<line class="st4" x1="186" y1="161.79" x2="186" y2="222.99"/>
<line class="st4" x1="576.8" y1="161.79" x2="576.8" y2="222.99"/>
<path class="st5" d="M831.51,207.99"/>
<line class="st6" x1="153.5" y1="183.49" x2="153.5" y2="207.19"/>
<line class="st4" x1="36.5" y1="183.49" x2="36.5" y2="207.19"/>
<line class="st4" x1="67.6" y1="183.49" x2="67.6" y2="207.19"/>
<line class="st6" x1="186" y1="183.49" x2="186" y2="207.99"/>
<line class="st4" x1="218.4" y1="183.49" x2="218.4" y2="207.19"/>
<line class="st4" x1="250.9" y1="183.49" x2="250.9" y2="207.19"/>
<line class="st4" x1="283.3" y1="183.49" x2="283.3" y2="207.19"/>
<line class="st4" x1="315.9" y1="183.49" x2="315.9" y2="207.19"/>
<line class="st4" x1="348.4" y1="183.49" x2="348.4" y2="207.19"/>
<line class="st4" x1="381.2" y1="183.49" x2="381.2" y2="207.19"/>
<line class="st4" x1="413.8" y1="183.49" x2="413.8" y2="207.19"/>
<line class="st4" x1="446.3" y1="183.49" x2="446.3" y2="207.19"/>
<line class="st4" x1="478.9" y1="183.49" x2="478.9" y2="207.19"/>
<line class="st6" x1="511.51" y1="183.49" x2="511.51" y2="207.19"/>
<line class="st4" x1="511.51" y1="183.49" x2="511.51" y2="207.19"/>
<line class="st6" x1="544.01" y1="183.49" x2="544.01" y2="207.19"/>
<line class="st4" x1="544.1" y1="183.49" x2="544.1" y2="207.19"/>
<line class="st8" x1="186" y1="208.19" x2="122.5" y2="207.99"/>
<line class="st8" x1="122.5" y1="183.19" x2="186" y2="183.29"/>
<path class="st5" d="M385.5,208.19"/>
<path class="st5" d="M385.5,184.49"/>
</g>
<g>
<text transform="matrix(1 0 0 1 127.5176 240.9952)" class="st1 st9 st10">buf</text>
</g>
<g>
<g>
<line class="st11" x1="122.2" y1="240.79" x2="122.2" y2="229.79"/>
<g>
<polygon class="st1" points="119.8,230.09 124.6,230.09 122.2,227.69 "/>
</g>
</g>
</g>
<g>
<text transform="matrix(1 0 0 1 189.2273 240.9947)" class="st1 st9 st10">len=2</text>
</g>
<g>
<g>
<line class="st11" x1="185.88" y1="240.79" x2="185.88" y2="229.79"/>
<g>
<polygon class="st1" points="183.48,230.09 188.38,230.09 185.88,227.69 "/>
</g>
</g>
</g>
<g>
<text transform="matrix(1 0 0 1 581.4624 240.9952)" class="st1 st9 st10">size=16</text>
</g>
<g>
<g>
<line class="st11" x1="576.9" y1="240.79" x2="576.9" y2="229.79"/>
<g>
<polygon class="st1" points="574.51,230.09 579.4,230.09 576.9,227.69 "/>
</g>
</g>
</g>
<g>
<path class="st12" d="M687.51,195.89c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6
S687.51,195.09,687.51,195.89z"/>
<path class="st12" d="M701.2,195.89c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6S701.2,195.09,701.2,195.89z
"/>
<path class="st12" d="M714.9,195.89c0,0.9-0.7,1.6-1.6,1.6c-0.9,0-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6
S714.9,195.09,714.9,195.89z"/>
<path class="st12" d="M728.7,195.89c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6
C728.01,194.29,728.7,195.09,728.7,195.89z"/>
</g>
<g>
<path class="st12" d="M82.8,195.89c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6S82.8,195.09,82.8,195.89z"/>
<path class="st12" d="M96.5,195.89c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6
C95.8,194.29,96.5,195.09,96.5,195.89z"/>
<path class="st12" d="M110.2,195.89c0,0.9-0.7,1.6-1.6,1.6s-1.6-0.7-1.6-1.6c0-0.9,0.7-1.6,1.6-1.6S110.2,195.09,110.2,195.89z
"/>
</g>
<g>
<g>
<text transform="matrix(1 0 0 1 133.6541 162.0062)" class="st13 st9 st10">data</text>
</g>
<g>
<text transform="matrix(1 0 0 1 327.363 162.0062)" class="st12 st9 st10">free space</text>
</g>
<g>
<g>
<line class="st14" x1="175.2" y1="168.79" x2="133.5" y2="168.79"/>
<g>
<polygon class="st13" points="174.9,171.39 176.5,168.79 174.9,166.29 174.8,166.29 174.8,171.39 "/>
</g>
<g>
<polygon class="st13" points="133.8,171.29 133.8,166.39 131.4,168.79 "/>
</g>
</g>
</g>
<g>
<g>
<line class="st15" x1="563.7" y1="168.79" x2="197.49" y2="168.79"/>
<g>
<polygon class="st12" points="563.4,171.29 563.4,166.39 565.8,168.79 "/>
</g>
<g>
<polygon class="st12" points="197.79,171.29 197.79,166.39 195.29,168.79 "/>
</g>
</g>
</g>
<g>
<text transform="matrix(1 0 0 1 615.4679 160.3837)" class="st12 st9 st10">non-allocated space</text>
</g>
<g>
<g>
<line class="st15" x1="593.7" y1="168.79" x2="829.7" y2="168.79"/>
<g>
<polygon class="st12" points="829.4,166.39 829.4,171.29 831.8,168.79 "/>
</g>
</g>
</g>
<g>
<g>
<line class="st15" x1="678.7" y1="168.79" x2="589.7" y2="168.79"/>
<g>
<polygon class="st12" points="590.01,171.29 590.01,166.39 587.6,168.79 "/>
</g>
</g>
</g>
</g>
<g>
<g>
<text transform="matrix(1 0 0 1 133.1212 200.1532)" class="st16 st9 st10">h</text>
</g>
</g>
<g>
<g>
<text transform="matrix(1 0 0 1 165.1565 200.1532)" class="st16 st9 st10">o</text>
</g>
</g>
</g>
</g>
</g>
<g>
<text transform="matrix(1 0 0 1 1.811981e-04 240.995)" class="st1 st9 st10">0</text>
</g>
<line class="st4" x1="5.5" y1="161.59" x2="5.5" y2="222.79"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

+384
View File
@@ -0,0 +1,384 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 858.5 424.3" style="enable-background:new 0 0 858.5 424.3;" xml:space="preserve">
<style type="text/css">
.st0{fill:#9E9B83;}
.st1{fill:#9E8900;}
.st2{font-family:Arial;font-weight:bold;}
.st3{font-size:11px;}
.st4{display:none;fill:#576174;}
.st5{fill:#1F5F75;}
.st6{clip-path:url(#SVGID_3_);fill:#FFFFFF;fill-opacity:0.1;}
.st7{fill:#277691;}
.st8{fill:#FFFFFF;}
.st9{font-family:Arial;font-weight:bold;}
.st10{fill:#004219;}
.st11{clip-path:url(#SVGID_6_);fill:#FFFFFF;fill-opacity:0.1;}
.st12{fill:#005721;}
.st13{fill:url(#SVGID_7_);}
.st14{clip-path:url(#XMLID_13_);fill:#FFFFFF;fill-opacity:0.1;}
.st15{fill:#752E06;}
.st16{fill:#963B08;}
.st17{fill:#59008F;}
.st18{clip-path:url(#XMLID_15_);fill:#FFFFFF;fill-opacity:0.1;}
.st19{fill:#7300B8;}
.st20{fill:#FFDE00;}
.st21{fill:#576174;}
.st22{font-size:13px;}
.st23{fill:#8A8C8E;}
.st24{font-size:12px;}
.st25{opacity:0.69;}
.st26{fill:#B3B1B3;}
.st27{clip-path:url(#XMLID_17_);fill:#FFFFFF;fill-opacity:0.1;}
.st28{fill:#919091;}
.st29{fill:#BFBEBF;}
.st30{fill:#454445;}
.st31{font-size:9px;}
.st32{clip-path:url(#XMLID_19_);fill:#FFFFFF;fill-opacity:0.1;}
.st33{fill:#8695B3;}
.st34{fill:url(#SVGID_8_);}
.st35{font-size:18px;}
.st36{clip-path:url(#XMLID_20_);fill:#610041;fill-opacity:0.1;}
.st37{fill:#610041;}
.st38{clip-path:url(#XMLID_22_);fill:url(#SVGID_9_);fill-opacity:0.1;}
.st39{fill:none;stroke:#86005B;stroke-width:0.5;stroke-linecap:round;stroke-miterlimit:10;}
.st40{fill:none;stroke:#86005B;stroke-width:0.75;stroke-linecap:round;stroke-miterlimit:10;}
.st41{fill:url(#SVGID_10_);}
.st42{fill:url(#SVGID_11_);}
.st43{fill:#610042;}
.st44{fill:url(#SVGID_12_);}
</style>
<g>
<g>
<path class="st0" d="M457.9,111.2l0.1,87.3c0,1.4-1.1,2.6-2.5,2.6h-76.3c-4.4-0.2-7.3-3.9-7.3-5.3l4.7-101.8
c0-1.4,0.8-7.4,2.2-7.4l54-0.1L457.9,111.2z"/>
</g>
<g>
<text transform="matrix(1 0 0 1 383.2604 149.9447)" class="st1 st2 st3">packed_fs.c</text>
</g>
</g>
<rect x="84" y="25" class="st4" width="727.7" height="429.8"/>
<g>
<g>
<path class="st5" d="M207.5,104.6v87.4c0,1.4-1.1,2.6-2.5,2.6h-78.3c-1.4,0-2.5-1.1-2.5-2.6V84.5c0-1.4,1.1-2.5,2.5-2.5h58
L207.5,104.6z"/>
<g>
<defs>
<path id="SVGID_1_" d="M205.5,102.6v87.4c0,1.4-1.1,2.6-2.5,2.6h-78.3c-1.4,0-2.5-1.1-2.5-2.6v-57.5V82.5c0-1.4,1.1-2.5,2.5-2.5
h58L205.5,102.6z"/>
</defs>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="122.1091" y1="136.2824" x2="205.5191" y2="136.2824">
<stop offset="0" style="stop-color:#45CFFF"/>
<stop offset="1" style="stop-color:#85DDFA"/>
</linearGradient>
<use xlink:href="#SVGID_1_" style="overflow:visible;fill:url(#SVGID_2_);"/>
<clipPath id="SVGID_3_">
<use xlink:href="#SVGID_1_" style="overflow:visible;"/>
</clipPath>
<path class="st6" d="M121.4,101.4c9.4,0.7,36.6,1.5,53.2,14.7c25,20,31.2,47.1,31.2,47.1l0.4,35.3l-84.8,0.2V101.4z"/>
</g>
<path class="st5" d="M205.9,104.4l-20.6,0c-1.4,0-2.6-1.2-2.6-2.6l0-21.8l22.9,22.7L205.9,104.4z"/>
<path class="st7" d="M205.7,102.8h-20.5c-1.4,0-2.5-1.1-2.5-2.5V79.9l0,0l22.9,22.7L205.7,102.8z"/>
<g>
<text transform="matrix(1 0 0 1 129.0689 92.8531)" class="st8 st9 st3">filex.y</text>
</g>
</g>
<g>
<path class="st10" d="M191.4,121.6V209c0,1.4-1.1,2.6-2.5,2.6h-78.3c-1.4,0-2.5-1.1-2.5-2.6V101.4c0-1.4,1.1-2.5,2.5-2.5h58
L191.4,121.6z"/>
<g>
<defs>
<path id="SVGID_4_" d="M189.4,119.6V207c0,1.4-1.1,2.6-2.5,2.6h-78.3c-1.4,0-2.5-1.1-2.5-2.6v-57.5V99.4c0-1.4,1.1-2.5,2.5-2.5
h58L189.4,119.6z"/>
</defs>
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="106.0386" y1="153.2384" x2="189.4486" y2="153.2384">
<stop offset="0" style="stop-color:#00983A"/>
<stop offset="1" style="stop-color:#3A985D"/>
</linearGradient>
<use xlink:href="#SVGID_4_" style="overflow:visible;fill:url(#SVGID_5_);"/>
<clipPath id="SVGID_6_">
<use xlink:href="#SVGID_4_" style="overflow:visible;"/>
</clipPath>
<path class="st11" d="M105.3,118.3c9.4,0.7,36.6,1.5,53.2,14.7c25,20,31.2,47.1,31.2,47.1l0.4,35.3l-84.8,0.2V118.3z"/>
</g>
<path class="st10" d="M189.8,121.3l-20.6,0c-1.4,0-2.6-1.2-2.6-2.6l0-21.8l22.9,22.7L189.8,121.3z"/>
<path class="st12" d="M189.6,119.7h-20.5c-1.4,0-2.5-1.1-2.5-2.5V96.9l0,0l22.9,22.7L189.6,119.7z"/>
<g>
<text transform="matrix(1 0 0 1 113.9984 109.809)" class="st8 st9 st3">main.js</text>
</g>
</g>
<g>
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="93.2369" y1="173.2516" x2="176.6469" y2="173.2516">
<stop offset="0" style="stop-color:#EA5B0C"/>
<stop offset="1" style="stop-color:#EA671E"/>
</linearGradient>
<path class="st13" d="M176.6,139.6V227c0,1.4-1.1,2.6-2.5,2.6H95.8c-1.4,0-2.5-1.1-2.5-2.6V119.5c0-1.4,1.1-2.5,2.5-2.5h58
L176.6,139.6z"/>
<g>
<defs>
<path id="XMLID_2_" d="M174.6,137.6V225c0,1.4-1.1,2.6-2.5,2.6H93.8c-1.4,0-2.5-1.1-2.5-2.6v-57.5v-50.1c0-1.4,1.1-2.5,2.5-2.5
h58L174.6,137.6z"/>
</defs>
<linearGradient id="XMLID_12_" gradientUnits="userSpaceOnUse" x1="91.2369" y1="171.2516" x2="174.6469" y2="171.2516">
<stop offset="0" style="stop-color:#EA5B0C"/>
<stop offset="1" style="stop-color:#EA7B3D"/>
</linearGradient>
<use xlink:href="#XMLID_2_" style="overflow:visible;fill:url(#XMLID_12_);"/>
<clipPath id="XMLID_13_">
<use xlink:href="#XMLID_2_" style="overflow:visible;"/>
</clipPath>
<path class="st14" d="M90.5,136.3c9.4,0.7,36.6,1.5,53.2,14.7c25,20,31.2,47.1,31.2,47.1l0.4,35.3l-84.8,0.2V136.3z"/>
</g>
<path class="st15" d="M175,139.3l-20.6,0c-1.4,0-2.6-1.2-2.6-2.6l0-21.8l22.9,22.7L175,139.3z"/>
<path class="st16" d="M174.8,137.7h-20.5c-1.4,0-2.5-1.1-2.5-2.5v-20.3l0,0l22.9,22.7L174.8,137.7z"/>
<g>
<text transform="matrix(1 0 0 1 97.1967 127.8222)" class="st8 st9 st3">style.css</text>
</g>
</g>
<g>
<path class="st17" d="M164.6,157.7v87.4c0,1.4-1.1,2.6-2.5,2.6H83.8c-1.4,0-2.5-1.1-2.5-2.6V137.5c0-1.4,1.1-2.5,2.5-2.5h58
L164.6,157.7z"/>
<g>
<defs>
<path id="XMLID_1_" d="M162.6,155.7v87.4c0,1.4-1.1,2.6-2.5,2.6H81.8c-1.4,0-2.5-1.1-2.5-2.6v-57.5v-50.1c0-1.4,1.1-2.5,2.5-2.5
h58L162.6,155.7z"/>
</defs>
<linearGradient id="XMLID_14_" gradientUnits="userSpaceOnUse" x1="79.2009" y1="189.3131" x2="162.6108" y2="189.3131">
<stop offset="0" style="stop-color:#A000FF"/>
<stop offset="1" style="stop-color:#C96EFF"/>
</linearGradient>
<use xlink:href="#XMLID_1_" style="overflow:visible;fill:url(#XMLID_14_);"/>
<clipPath id="XMLID_15_">
<use xlink:href="#XMLID_1_" style="overflow:visible;"/>
</clipPath>
<path class="st18" d="M78.5,154.4c9.4,0.7,36.6,1.5,53.2,14.7c25,20,31.2,47.1,31.2,47.1l0.4,35.3l-84.8,0.2V154.4z"/>
</g>
<path class="st17" d="M163,157.4l-20.6,0c-1.4,0-2.6-1.2-2.6-2.6l0-21.8l22.9,22.7L163,157.4z"/>
<path class="st19" d="M162.8,155.8h-20.5c-1.4,0-2.5-1.1-2.5-2.5V133l0,0l22.9,22.7L162.8,155.8z"/>
<g>
<text transform="matrix(1 0 0 1 83.1607 145.8838)" class="st8 st9 st3">index.html</text>
</g>
</g>
</g>
<g>
<g>
<path class="st20" d="M455.2,108.2v87.4c0,1.4-1.1,2.6-2.5,2.6h-78.3c-1.4,0-2.5-1.1-2.5-2.6V88.1c0-1.4,1.1-2.5,2.5-2.5h58
L455.2,108.2z"/>
<path class="st0" d="M455.3,110.3l-18.4,0c-1.4,0-2.5-1.1-2.5-2.5V87.5l0,0l20.9,20.7L455.3,110.3z"/>
<polygon class="st0" points="435.2,109.7 432.9,107.3 436.3,106.9 "/>
<path class="st1" d="M455.4,108.3h-20.5c-1.4,0-2.5-1.1-2.5-2.5V85.5l0,0l22.9,22.7L455.4,108.3z"/>
</g>
<g>
<text transform="matrix(1 0 0 1 379.2604 144.9447)" class="st21 st9 st22">packed_fs.c</text>
</g>
</g>
<g>
<polygon class="st23" points="483.6,195.4 397.3,195.4 394.3,193.4 397.3,162.8 481.5,159.7 483.6,162.8 "/>
<rect x="394.3" y="159.8" class="st21" width="87.3" height="33.7"/>
<g>
<g>
<text transform="matrix(1 0 0 1 400.0845 171.7588)" class="st8 st9 st24">mg_unpack()</text>
</g>
<g>
<text transform="matrix(1 0 0 1 400.0845 186.935)" class="st8 st9 st24">mg_unlist()</text>
</g>
</g>
</g>
<g class="st25">
<g>
<path class="st26" d="M467.7,256.6V344c0,1.4-1.1,2.6-2.5,2.6h-78.3c-1.4,0-2.5-1.1-2.5-2.6V236.4c0-1.4,1.1-2.5,2.5-2.5h58
L467.7,256.6z"/>
<g>
<defs>
<path id="XMLID_9_" d="M465.7,254.6V342c0,1.4-1.1,2.6-2.5,2.6h-78.3c-1.4,0-2.5-1.1-2.5-2.6v-57.5v-50.1c0-1.4,1.1-2.5,2.5-2.5
h58L465.7,254.6z"/>
</defs>
<linearGradient id="XMLID_16_" gradientUnits="userSpaceOnUse" x1="382.3115" y1="288.2073" x2="465.7215" y2="288.2073">
<stop offset="0" style="stop-color:#D6D4D6"/>
<stop offset="1" style="stop-color:#FFFDFE"/>
</linearGradient>
<use xlink:href="#XMLID_9_" style="overflow:visible;fill:url(#XMLID_16_);"/>
<clipPath id="XMLID_17_">
<use xlink:href="#XMLID_9_" style="overflow:visible;"/>
</clipPath>
<path class="st27" d="M381.6,253.3c9.4,0.7,36.6,1.5,53.2,14.7c25,20,31.2,47.1,31.2,47.1l0.4,35.3l-84.8,0.2V253.3z"/>
</g>
<path class="st28" d="M466.1,256.3l-20.6,0c-1.4,0-2.6-1.2-2.6-2.6l0-21.8l22.9,22.7L466.1,256.3z"/>
<path class="st29" d="M465.9,254.7h-20.5c-1.4,0-2.5-1.1-2.5-2.5v-20.3l0,0l22.9,22.7L465.9,254.7z"/>
<text transform="matrix(1 0 0 1 386.2713 244.7779)" class="st30 st9 st31">mongoose.c</text>
</g>
<g>
<path class="st26" d="M455.7,276.6v87.4c0,1.4-1.1,2.6-2.5,2.6h-78.3c-1.4,0-2.5-1.1-2.5-2.6V256.5c0-1.4,1.1-2.5,2.5-2.5h58
L455.7,276.6z"/>
<g>
<defs>
<path id="XMLID_8_" d="M453.7,274.6v87.4c0,1.4-1.1,2.6-2.5,2.6h-78.3c-1.4,0-2.5-1.1-2.5-2.6v-57.5v-50.1
c0-1.4,1.1-2.5,2.5-2.5h58L453.7,274.6z"/>
</defs>
<linearGradient id="XMLID_18_" gradientUnits="userSpaceOnUse" x1="370.2755" y1="308.2689" x2="453.6855" y2="308.2689">
<stop offset="0" style="stop-color:#D6D4D6"/>
<stop offset="1" style="stop-color:#FFFDFE"/>
</linearGradient>
<use xlink:href="#XMLID_8_" style="overflow:visible;fill:url(#XMLID_18_);"/>
<clipPath id="XMLID_19_">
<use xlink:href="#XMLID_8_" style="overflow:visible;"/>
</clipPath>
<path class="st32" d="M369.6,273.3c9.4,0.7,36.6,1.5,53.2,14.7c25,20,31.2,47.1,31.2,47.1l0.4,35.3l-84.8,0.2V273.3z"/>
<use xlink:href="#XMLID_8_" style="overflow:visible;fill:none;stroke:#FFFDFE;stroke-width:0.25;stroke-miterlimit:10;"/>
</g>
<path class="st28" d="M454,276.4l-20.6,0c-1.4,0-2.6-1.2-2.6-2.6l0-21.8l22.9,22.7L454,276.4z"/>
<path class="st29" d="M453.8,274.8h-20.5c-1.4,0-2.5-1.1-2.5-2.5v-20.3l0,0l22.9,22.7L453.8,274.8z"/>
<text transform="matrix(1 0 0 1 379.2353 264.8395)" class="st30 st9 st31">app.c</text>
</g>
</g>
<g>
<polygon class="st33" points="342.3,123.3 351.1,141.7 342.3,160.7 234.8,160.9 234.8,122.6 "/>
<path class="st23" d="M347.4,145.4"/>
<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="233.6667" y1="139.4088" x2="350.0318" y2="139.4088">
<stop offset="0" style="stop-color:#C1D5FF"/>
<stop offset="0.1995" style="stop-color:#BACDF6"/>
<stop offset="0.6001" style="stop-color:#B0C3EA"/>
<stop offset="1" style="stop-color:#ADC0E6"/>
</linearGradient>
<polygon class="st34" points="341.2,120.9 350,139.3 341.2,158.3 233.7,158.5 233.7,120.3 "/>
<text transform="matrix(1 0 0 1 262.9869 146.2633)" class="st8 st9 st35">PACK</text>
<polygon class="st33" points="234.8,160.9 233.7,158.5 238,158.7 "/>
</g>
<g>
<path class="st23" d="M634.9,144.6L634.9,144.6z"/>
</g>
<g>
<polygon class="st33" points="619.6,139.3 619.6,139.3 618.7,137.4 618.7,137.4 "/>
<path class="st23" d="M623.1,168.2L623.1,168.2z"/>
</g>
<g>
<polygon class="st33" points="619.6,288.1 618.7,290 618.7,290 619.6,288.1 "/>
<path class="st23" d="M623.1,259.2L623.1,259.2z"/>
</g>
<g>
<path class="st23" d="M617,282L617,282z"/>
</g>
<g>
<g>
<g>
<defs>
<path id="XMLID_10_" d="M722.7,276.5h-71.2c-11.6,0-21.1-9.4-21.1-21.1v-71.2c0-11.6,9.4-21.1,21.1-21.1h71.2
c11.6,0,21.1,9.4,21.1,21.1v71.2C743.8,267,734.4,276.5,722.7,276.5z"/>
</defs>
<use xlink:href="#XMLID_10_" style="overflow:visible;fill:#610041;"/>
<clipPath id="XMLID_20_">
<use xlink:href="#XMLID_10_" style="overflow:visible;"/>
</clipPath>
<path class="st36" d="M754.3,172.5c-2.7,8-17.3,30.9-65.8,30.8c-24.5,0-48.4-7.4-65.7-24.7l-12.1-12l69.3-64.6L754.3,172.5z"/>
</g>
<polygon class="st37" points="637.6,271.2 632.5,266.1 640.3,269.4 "/>
<polygon class="st37" points="738.3,169.9 734.6,166.2 736.4,171 "/>
<g>
<defs>
<path id="XMLID_5_" d="M719.7,273.5h-71.2c-11.6,0-21.1-9.4-21.1-21.1v-71.2c0-11.6,9.4-21.1,21.1-21.1h71.2
c11.6,0,21.1,9.4,21.1,21.1v71.2C740.8,264,731.4,273.5,719.7,273.5z"/>
</defs>
<radialGradient id="XMLID_21_" cx="684.119" cy="216.7761" r="56.6929" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#8B005D;stop-opacity:0.7"/>
<stop offset="1" style="stop-color:#8B005D"/>
</radialGradient>
<use xlink:href="#XMLID_5_" style="overflow:visible;fill:url(#XMLID_21_);"/>
<clipPath id="XMLID_22_">
<use xlink:href="#XMLID_5_" style="overflow:visible;"/>
</clipPath>
<radialGradient id="SVGID_9_" cx="678.486" cy="148.5836" r="90.2195" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#8B005D"/>
<stop offset="1" style="stop-color:#FFFFFF"/>
</radialGradient>
<path class="st38" d="M750.3,168.5c-2.7,8-17.3,30.9-65.8,30.8c-24.5,0-48.4-7.4-65.7-24.7l-12.1-12L676,97.9L750.3,168.5z"/>
</g>
<g>
<g>
<g>
<g>
<text transform="matrix(1 0 0 1 646.3768 216.49)" class="st8 st9 st35">APP.EXE</text>
</g>
</g>
</g>
</g>
</g>
<g>
<g>
<g>
<path class="st8" d="M732,240.1c-0.3-1.4-0.8-2.7-1.4-3.9l1.7-2.3c-0.3-0.5-0.6-0.9-1-1.4c-0.3-0.5-0.7-0.9-1.1-1.3l-2.7,1
c-1-1-2.2-1.8-3.4-2.4l0-2.9c-1-0.4-2.1-0.8-3.2-1l-1.5,2.4c-1.4-0.2-2.8-0.2-4.1,0l-1.7-2.4c-1.1,0.2-2.1,0.6-3.1,1.1l0.2,2.9
c-0.6,0.3-1.2,0.7-1.7,1.1c-0.6,0.4-1.1,0.9-1.5,1.4l-2.7-0.9l-1.9,2.7l1.8,2.3c-0.6,1.3-1,2.6-1.1,4l-2.7,0.9
c-0.1,1.1,0,2.2,0.1,3.3l2.8,0.8c0.3,1.3,0.8,2.7,1.4,3.9l-1.7,2.3c0.3,0.5,0.6,0.9,1,1.4c0.3,0.4,0.7,0.9,1.1,1.3l2.7-1
c1,1,2.2,1.8,3.4,2.4l0,2.9c1,0.4,2.1,0.8,3.2,1l1.5-2.4c1.4,0.2,2.8,0.2,4.1,0l1.7,2.4c1.1-0.3,2.1-0.6,3.1-1.1l-0.2-2.9
c0.6-0.3,1.2-0.7,1.7-1.1c0.6-0.4,1.1-0.9,1.5-1.4l2.8,0.9c0.7-0.8,1.3-1.8,1.9-2.7L731,249c0.6-1.3,1-2.6,1.1-4l2.7-0.9
c0.1-1.1,0-2.2-0.1-3.3L732,240.1z M724,251c-4.6,3.5-11.1,2.6-14.6-2c-3.5-4.6-2.6-11.1,2-14.6s11.1-2.6,14.6,2
C729.5,241,728.6,247.5,724,251z"/>
</g>
</g>
<g>
<g>
<path class="st8" d="M700.5,249.3c-0.2-0.8-0.5-1.6-0.8-2.4l1-1.4c-0.2-0.3-0.4-0.6-0.6-0.8c-0.2-0.3-0.4-0.5-0.7-0.8l-1.6,0.6
c-0.6-0.6-1.3-1.1-2.1-1.4l0-1.7c-0.6-0.3-1.3-0.5-1.9-0.6l-0.9,1.4c-0.8-0.1-1.7-0.1-2.5,0l-1-1.4c-0.6,0.1-1.3,0.4-1.9,0.6
l0.1,1.7c-0.4,0.2-0.7,0.4-1,0.7c-0.3,0.3-0.6,0.5-0.9,0.8l-1.6-0.6l-1.1,1.6l1.1,1.4c-0.3,0.8-0.6,1.6-0.7,2.4l-1.6,0.5
c0,0.7,0,1.3,0.1,2l1.7,0.5c0.2,0.8,0.4,1.6,0.9,2.4l-1,1.4c0.2,0.3,0.4,0.6,0.6,0.8c0.2,0.3,0.4,0.5,0.7,0.8l1.6-0.6
c0.6,0.6,1.3,1.1,2.1,1.4l0,1.7c0.6,0.3,1.3,0.5,1.9,0.6l0.9-1.4c0.8,0.1,1.7,0.1,2.5,0l1,1.4c0.6-0.2,1.3-0.4,1.9-0.6l-0.1-1.7
c0.4-0.2,0.7-0.4,1-0.7c0.3-0.3,0.6-0.5,0.9-0.8l1.6,0.6c0.4-0.5,0.8-1.1,1.1-1.6l-1.1-1.4c0.3-0.8,0.6-1.6,0.7-2.4l1.6-0.5
c0-0.7,0-1.3-0.1-2L700.5,249.3z M694.5,254.2c-1.8,1.4-4.5,1-5.9-0.8c-1.4-1.8-1-4.5,0.8-5.9c1.8-1.4,4.5-1,5.9,0.8
C696.8,250.2,696.4,252.8,694.5,254.2z"/>
</g>
</g>
<path class="st39" d="M708.9,234.5"/>
<path class="st39" d="M706.7,237.9"/>
<path class="st40" d="M705.7,242.7c0-1.7,0.4-3.4,1-4.9"/>
<path class="st40" d="M708.9,234.5c2.2-2.4,5.3-3.8,8.8-3.8"/>
<path class="st40" d="M687.4,247.3c1.1-1.4,2.7-2.2,4.6-2.2"/>
<path class="st39" d="M686.4,249.5"/>
<path class="st40" d="M686.2,250.9c0-0.5,0.1-1,0.2-1.4"/>
<path class="st39" d="M686.7,253.2"/>
</g>
</g>
<g>
<path class="st33" d="M611.7,174.2l-23,3.3l-13.1-9.6c-6.3-4.6-13.9-7.1-21.7-7l-55.5,0.1l-1.1-2.4h1.1l64.2-0.2h0.1l3.9,0h0.1
l3.2,2.4l19.2,14l0.2,0.2l23.4-3.3L611.7,174.2z"/>
<path class="st23" d="M595.9,145.5L595.9,145.5z"/>
<linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="497.2089" y1="147.636" x2="612.739" y2="147.636">
<stop offset="0" style="stop-color:#C1D5FF"/>
<stop offset="0.1995" style="stop-color:#BACDF6"/>
<stop offset="0.6001" style="stop-color:#B0C3EA"/>
<stop offset="1" style="stop-color:#ADC0E6"/>
</linearGradient>
<path class="st41" d="M612.7,171.7l-3,0.4l-20.3,2.8l-0.2-0.1l-13.6-9.9l0,0c-3.7-2.7-8.7-4.4-12.9-5.4c-2.9-0.7-6-1-9-1l-35.5,0.1
l-19.8,0.1h-1.1v-38.3l13.5,0.2l4,0l42.6,0.2l7.9,0c7,0,14,1.6,20.2,4.9c0,0,0,0,0,0c0.8,0.5,1.6,0.9,2.4,1.5l7.5,5.6l0.1,0.1l0,0
l15.4,11.3v0l0.1,3.2L612.7,171.7z"/>
<linearGradient id="SVGID_11_" gradientUnits="userSpaceOnUse" x1="597.6228" y1="138.4046" x2="598.5728" y2="138.4046">
<stop offset="0" style="stop-color:#C1D5FF"/>
<stop offset="0.1995" style="stop-color:#BACDF6"/>
<stop offset="0.6001" style="stop-color:#B0C3EA"/>
<stop offset="1" style="stop-color:#ADC0E6"/>
</linearGradient>
<polygon class="st42" points="598.6,139.3 598.6,139.4 597.6,137.4 597.7,137.5 "/>
<text transform="matrix(1 0 0 1 513.7678 146.3103)" class="st8 st9 st35">BUILD</text>
</g>
<g>
<path class="st33" d="M612.7,258.8l-0.1,2.2l-1.8-0.2l-20.3-2.8l-0.2,0.1l-13.6,9.9l0-0.1c-3.7,2.7-8.7,4.4-12.9,5.4
c-2.9,0.7-6,1-9,1l-35.5-0.1l-19.8-0.1h-1.1v35.4l-1.1,0.4l1.1,2.4l13.5-0.2l4,0l42.6-0.2l7.9-0.1c7,0,14-1.6,20.2-4.9c0,0,0,0,0,0
c0.8-0.5,1.6-0.9,2.4-1.5l7.5-5.6l0.1-0.1l0,0l15.4-11.3l1-0.9l1.9-26.7L612.7,258.8z"/>
<path class="st43" d="M593.5,272.5"/>
<g>
<path class="st23" d="M598.5,285L598.5,285z"/>
<linearGradient id="SVGID_12_" gradientUnits="userSpaceOnUse" x1="497.2089" y1="451.0054" x2="612.739" y2="451.0054" gradientTransform="matrix(1 0 0 -1 0 733.8616)">
<stop offset="0" style="stop-color:#C1D5FF"/>
<stop offset="0.1995" style="stop-color:#BACDF6"/>
<stop offset="0.6001" style="stop-color:#B0C3EA"/>
<stop offset="1" style="stop-color:#ADC0E6"/>
</linearGradient>
<path class="st44" d="M612.7,258.8l-3-0.4l-20.3-2.8l-0.2,0.1l-13.6,9.9l0,0c-3.7,2.7-8.7,4.4-12.9,5.4c-2.9,0.7-6,1-9,1
l-35.5-0.1l-19.8-0.1h-1.1v38.3l13.5-0.2l4,0l42.6-0.2l7.9,0c7,0,14-1.6,20.2-4.9c0,0,0,0,0,0c0.8-0.5,1.6-0.9,2.4-1.5l7.5-5.6
l0.1-0.1l0,0l15.4-11.3v0l0.1-3.2L612.7,258.8z"/>
<text transform="matrix(1 0 0 1 513.7682 298.0848)" class="st8 st9 st35">BUILD</text>
</g>
</g>
<path class="st33" d="M619.9,149.1"/>
</svg>

After

Width:  |  Height:  |  Size: 18 KiB

+1
View File
@@ -0,0 +1 @@
See detailed tutorial at https://mongoose.ws/tutorials/captive-dns-portal/
+8 -5
View File
@@ -21,11 +21,14 @@ uint8_t answer[] = {
}; };
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_READ) { if (ev == MG_EV_OPEN) {
c->is_hexdumping = 1;
} else if (ev == MG_EV_READ) {
struct mg_dns_rr rr; // Parse first question, offset 12 is header size 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); size_t n = mg_dns_parse_rr(c->recv.buf, c->recv.len, 12, true, &rr);
MG_INFO(("DNS request parsed, result=%d", (int) n));
if (n > 0) { if (n > 0) {
char buf[12 + n + sizeof(answer)]; char buf[512];
struct mg_dns_header *h = (struct mg_dns_header *) buf; struct mg_dns_header *h = (struct mg_dns_header *) buf;
memset(buf, 0, sizeof(buf)); // Clear the whole datagram memset(buf, 0, sizeof(buf)); // Clear the whole datagram
h->txnid = ((struct mg_dns_header *) c->recv.buf)->txnid; // Copy tnxid h->txnid = ((struct mg_dns_header *) c->recv.buf)->txnid; // Copy tnxid
@@ -34,9 +37,9 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
h->flags = mg_htons(0x8400); // Authoritative response h->flags = mg_htons(0x8400); // Authoritative response
memcpy(buf + sizeof(*h), c->recv.buf + sizeof(*h), n); // Copy question memcpy(buf + sizeof(*h), c->recv.buf + sizeof(*h), n); // Copy question
memcpy(buf + sizeof(*h) + n, answer, sizeof(answer)); // And answer memcpy(buf + sizeof(*h) + n, answer, sizeof(answer)); // And answer
mg_send(c, buf, sizeof(buf)); // And send it! mg_send(c, buf, 12 + n + sizeof(answer)); // And send it!
} }
mg_iobuf_delete(&c->recv, c->recv.len); mg_iobuf_del(&c->recv, 0, c->recv.len);
} }
(void) fn_data; (void) fn_data;
(void) ev_data; (void) ev_data;
@@ -45,7 +48,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; struct mg_mgr mgr;
mg_log_set("3"); // Set log level mg_log_set(MG_LL_DEBUG); // Set log level
mg_mgr_init(&mgr); // Initialise event manager mg_mgr_init(&mgr); // Initialise event manager
mg_listen(&mgr, s_listen_url, fn, NULL); // Start DNS server mg_listen(&mgr, s_listen_url, fn, NULL); // Start DNS server
for (;;) mg_mgr_poll(&mgr, 1000); // Event loop for (;;) mg_mgr_poll(&mgr, 1000); // Event loop
-34
View File
@@ -1,34 +0,0 @@
# 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
![](screenshots/login.png)
# Main dashboard
A main dashboard page shows internal data, live video stream, and a form
![](screenshots/dashboard.png)
A live log page shows live log stream coming from device
![](screenshots/logs.png)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

-204
View File
@@ -1,204 +0,0 @@
// Copyright (c) 2020 Cesanta Software Limited
// All rights reserved
#include "mjson.h"
#include "mongoose.h"
// Authenticated user.
// A user can be authenticated by:
// - a name:pass pair
// - a token
// When a user is shown a login screen, she enters a user:pass. If successful,
// a server returns user info which includes token. From that point on,
// client can use token for authentication. Tokens could be refreshed/changed
// on a server side, forcing clients to re-login.
struct user {
const char *name, *pass, *token;
};
// This is a configuration structure we're going to show on a dashboard
static struct config {
int value1;
char *value2;
} s_config = {123, NULL};
// Stringifies the config. A caller must free() it.
static char *stringify_config(struct config *cfg) {
char *s = NULL;
mjson_printf(mjson_print_dynamic_buf, &s, "{%Q:%d,%Q:%Q}", "value1",
cfg->value1, "value2", cfg->value2);
return s;
}
// Update config structure. Return true if changed, false otherwise
static bool update_config(struct mg_http_message *hm, struct config *cfg) {
bool changed = false;
char buf[256];
double dv;
if (mjson_get_number(hm->body.ptr, hm->body.len, "$.value1", &dv)) {
s_config.value1 = dv;
changed = true;
}
if (mjson_get_string(hm->body.ptr, hm->body.len, "$.value2", buf,
sizeof(buf)) > 0) {
free(s_config.value2);
s_config.value2 = strdup(buf);
changed = true;
}
return changed;
}
// Parse HTTP requests, return authenticated user or NULL
static struct user *getuser(struct mg_http_message *hm) {
// In production, make passwords strong and tokens randomly generated
// In this example, user list is kept in RAM. In production, it can
// be backed by file, database, or some other method.
static struct user users[] = {
{"admin", "admin", "admin_token"},
{"user1", "pass1", "user1_token"},
{"user2", "pass2", "user2_token"},
{NULL, NULL, NULL},
};
char user[256], pass[256];
struct user *u;
mg_http_creds(hm, user, sizeof(user), pass, sizeof(pass));
if (user[0] != '\0' && pass[0] != '\0') {
// Both user and password is set, search by user/password
for (u = users; u->name != NULL; u++)
if (strcmp(user, u->name) == 0 && strcmp(pass, u->pass) == 0) return u;
} else if (user[0] == '\0') {
// Only password is set, search by token
for (u = users; u->name != NULL; u++)
if (strcmp(pass, u->token) == 0) return u;
}
return NULL;
}
// Notify all config watchers about the config change
static void notify_config_change(struct mg_mgr *mgr) {
struct mg_connection *c;
char *s = stringify_config(&s_config);
for (c = mgr->conns; c != NULL; c = c->next) {
if (c->label[0] == 'W') mg_http_printf_chunk(c, "%s\n", s);
}
free(s);
}
// HTTP request handler function
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 = (struct mg_http_message *) ev_data;
struct user *u = getuser(hm);
// LOG(LL_INFO, ("%p [%.*s] auth %s", c->fd, (int) hm->uri.len, hm->uri.ptr,
// u ? u->name : "NULL"));
if (u == NULL && mg_http_match_uri(hm, "/api/#")) {
// All URIs starting with /api/ must be authenticated
mg_printf(c, "%s", "HTTP/1.1 403 Denied\r\nContent-Length: 0\r\n\r\n");
} else if (mg_http_match_uri(hm, "/api/config/get")) {
char *s = stringify_config(&s_config);
mg_printf(c, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s\n",
(int) strlen(s) + 1, s);
free(s);
} else if (mg_http_match_uri(hm, "/api/config/set")) {
// Admins only
if (strcmp(u->name, "admin") == 0) {
if (update_config(hm, &s_config)) notify_config_change(fn_data);
mg_printf(c, "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
} else {
mg_printf(c, "%s", "HTTP/1.1 403 Denied\r\nContent-Length: 0\r\n\r\n");
}
} else if (mg_http_match_uri(hm, "/api/config/watch")) {
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");
} else if (mg_http_match_uri(hm, "/api/video1")) {
c->label[0] = 'S'; // Mark that connection as live streamer
mg_printf(
c, "%s",
"HTTP/1.0 200 OK\r\n"
"Cache-Control: no-cache\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");
} else if (mg_http_match_uri(hm, "/api/log/static")) {
mg_http_serve_file(c, hm, "log.txt", "text/plain", "");
} else if (mg_http_match_uri(hm, "/api/log/live")) {
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");
} else if (mg_http_match_uri(hm, "/api/login")) {
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
mg_http_printf_chunk(c, "{\"user\":\"%s\",\"token\":\"%s\"}\n", u->name,
u->token);
mg_http_printf_chunk(c, "");
} else {
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
mg_http_serve_dir(c, ev_data, &opts);
}
}
}
// The image stream is simulated by sending MJPEG frames specified by the
// "files" array of file names.
static void broadcast_mjpeg_frame(struct mg_mgr *mgr) {
const char *files[] = {"images/1.jpg", "images/2.jpg", "images/3.jpg",
"images/4.jpg", "images/5.jpg", "images/6.jpg"};
size_t nfiles = sizeof(files) / sizeof(files[0]);
static size_t i;
const char *path = files[i++ % nfiles];
size_t size = 0;
char *data = mg_file_read(path, &size); // Read next file
struct mg_connection *c;
for (c = mgr->conns; c != NULL; c = c->next) {
if (c->label[0] != 'S') continue; // Skip non-stream connections
if (data == NULL || size == 0) continue; // Skip on file read error
mg_printf(c,
"--foo\r\nContent-Type: image/jpeg\r\n"
"Content-Length: %lu\r\n\r\n",
(unsigned long) size);
mg_send(c, data, size);
mg_send(c, "\r\n", 2);
}
free(data);
}
static void mjpeg_cb(void *arg) {
broadcast_mjpeg_frame(arg);
}
static void log_message(const char *filename, const char *message) {
FILE *fp = fopen(filename, "a");
if (fp != NULL) {
fprintf(fp, "%s", message);
fclose(fp);
}
}
static void broadcast_message(struct mg_mgr *mgr, const char *message) {
struct mg_connection *c;
for (c = mgr->conns; c != NULL; c = c->next) {
if (c->label[0] == 'L') mg_http_printf_chunk(c, "%s", message);
}
}
// Timer function - called periodically.
// Prepare log message. Save it to a file, and broadcast.
static void log_cb(void *arg) {
char buf[64];
snprintf(buf, sizeof(buf), "Time is: %lu\n", (unsigned long) time(NULL));
log_message("log.txt", buf);
broadcast_message(arg, buf);
}
int main(void) {
struct mg_mgr mgr;
struct mg_timer t1, t2;
mg_mgr_init(&mgr);
mg_http_listen(&mgr, "http://localhost:8000", cb, &mgr);
mg_timer_init(&t1, 500, MG_TIMER_REPEAT, mjpeg_cb, &mgr);
mg_timer_init(&t2, 1000, MG_TIMER_REPEAT, log_cb, &mgr);
for (;;) mg_mgr_poll(&mgr, 50);
mg_timer_free(&t1);
mg_timer_free(&t2);
mg_mgr_free(&mgr);
return 0;
}
-981
View File
@@ -1,981 +0,0 @@
// Copyright (c) 2018-2020 Cesanta Software Limited
// All rights reserved
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "mjson.h"
#if !defined(_MSC_VER) || _MSC_VER >= 1700
#else
#define va_copy(x, y) (x) = (y)
#define snprintf _snprintf
#define alloca _alloca
#endif
static int mjson_esc(int c, int esc) {
const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\"";
for (p = esc ? esc1 : esc2; *p != '\0'; p++) {
if (*p == c) return esc ? esc2[p - esc1] : esc1[p - esc2];
}
return 0;
}
static int mjson_pass_string(const char *s, int len) {
int i;
for (i = 0; i < len; i++) {
if (s[i] == '\\' && i + 1 < len && mjson_esc(s[i + 1], 1)) {
i++;
} else if (s[i] == '\0') {
return MJSON_ERROR_INVALID_INPUT;
} else if (s[i] == '"') {
return i;
}
}
return MJSON_ERROR_INVALID_INPUT;
}
int mjson(const char *s, int len, mjson_cb_t cb, void *ud) {
enum { S_VALUE, S_KEY, S_COLON, S_COMMA_OR_EOO } expecting = S_VALUE;
unsigned char nesting[MJSON_MAX_DEPTH];
int i, depth = 0;
#define MJSONCALL(ev) \
if (cb != NULL && cb(ev, s, start, i - start + 1, ud)) return i + 1;
// In the ascii table, the distance between `[` and `]` is 2.
// Ditto for `{` and `}`. Hence +2 in the code below.
#define MJSONEOO() \
do { \
if (c != nesting[depth - 1] + 2) return MJSON_ERROR_INVALID_INPUT; \
depth--; \
if (depth == 0) { \
MJSONCALL(tok); \
return i + 1; \
} \
} while (0)
for (i = 0; i < len; i++) {
int start = i;
unsigned char c = ((unsigned char *) s)[i];
int tok = c;
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue;
// printf("- %c [%.*s] %d %d\n", c, i, s, depth, expecting);
switch (expecting) {
case S_VALUE:
if (c == '{') {
if (depth >= (int) sizeof(nesting)) return MJSON_ERROR_TOO_DEEP;
nesting[depth++] = c;
expecting = S_KEY;
break;
} else if (c == '[') {
if (depth >= (int) sizeof(nesting)) return MJSON_ERROR_TOO_DEEP;
nesting[depth++] = c;
break;
} else if (c == ']' && depth > 0) { // Empty array
MJSONEOO();
} else if (c == 't' && i + 3 < len && memcmp(&s[i], "true", 4) == 0) {
i += 3;
tok = MJSON_TOK_TRUE;
} else if (c == 'n' && i + 3 < len && memcmp(&s[i], "null", 4) == 0) {
i += 3;
tok = MJSON_TOK_NULL;
} else if (c == 'f' && i + 4 < len && memcmp(&s[i], "false", 5) == 0) {
i += 4;
tok = MJSON_TOK_FALSE;
} else if (c == '-' || ((c >= '0' && c <= '9'))) {
char *end = NULL;
strtod(&s[i], &end);
if (end != NULL) i += end - &s[i] - 1;
tok = MJSON_TOK_NUMBER;
} else if (c == '"') {
int n = mjson_pass_string(&s[i + 1], len - i - 1);
if (n < 0) return n;
i += n + 1;
tok = MJSON_TOK_STRING;
} else {
return MJSON_ERROR_INVALID_INPUT;
}
if (depth == 0) {
MJSONCALL(tok);
return i + 1;
}
expecting = S_COMMA_OR_EOO;
break;
case S_KEY:
if (c == '"') {
int n = mjson_pass_string(&s[i + 1], len - i - 1);
if (n < 0) return n;
i += n + 1;
tok = MJSON_TOK_KEY;
expecting = S_COLON;
} else if (c == '}') { // Empty object
MJSONEOO();
expecting = S_COMMA_OR_EOO;
} else {
return MJSON_ERROR_INVALID_INPUT;
}
break;
case S_COLON:
if (c == ':') {
expecting = S_VALUE;
} else {
return MJSON_ERROR_INVALID_INPUT;
}
break;
case S_COMMA_OR_EOO:
if (depth <= 0) return MJSON_ERROR_INVALID_INPUT;
if (c == ',') {
expecting = (nesting[depth - 1] == '{') ? S_KEY : S_VALUE;
} else if (c == ']' || c == '}') {
MJSONEOO();
} else {
return MJSON_ERROR_INVALID_INPUT;
}
break;
}
MJSONCALL(tok);
}
return MJSON_ERROR_INVALID_INPUT;
}
struct msjon_get_data {
const char *path; // Lookup json path
int pos; // Current path index
int d1; // Current depth of traversal
int d2; // Expected depth of traversal
int i1; // Index in an array
int i2; // Expected index in an array
int obj; // If the value is array/object, offset where it starts
const char **tokptr; // Destination
int *toklen; // Destination length
int tok; // Returned token
};
static int mjson_plen(const char *s) {
int i = 0;
while (s[i] != '\0' && s[i] != '.' && s[i] != '[') i++;
return i;
}
static int mjson_get_cb(int tok, const char *s, int off, int len, void *ud) {
struct msjon_get_data *data = (struct msjon_get_data *) ud;
// printf("--> %2x %2d %2d %2d %2d\t'%s'\t'%.*s'\t\t'%.*s'\n", tok, data->d1,
// data->d2, data->i1, data->i2, data->path + data->pos, off, s, len,
// s + off);
if (data->tok != MJSON_TOK_INVALID) return 1; // Found
if (tok == '{') {
if (!data->path[data->pos] && data->d1 == data->d2) data->obj = off;
data->d1++;
} else if (tok == '[') {
if (data->d1 == data->d2 && data->path[data->pos] == '[') {
data->i1 = 0;
data->i2 = (int) strtod(&data->path[data->pos + 1], NULL);
if (data->i1 == data->i2) {
data->d2++;
data->pos += 3;
}
}
if (!data->path[data->pos] && data->d1 == data->d2) data->obj = off;
data->d1++;
} else if (tok == ',') {
if (data->d1 == data->d2 + 1) {
data->i1++;
if (data->i1 == data->i2) {
while (data->path[data->pos] != ']') data->pos++;
data->pos++;
data->d2++;
}
}
} else if (tok == MJSON_TOK_KEY && data->d1 == data->d2 + 1 &&
data->path[data->pos] == '.' && s[off] == '"' &&
s[off + len - 1] == '"' &&
mjson_plen(&data->path[data->pos + 1]) == len - 2 &&
!memcmp(s + off + 1, &data->path[data->pos + 1], len - 2)) {
data->d2++;
data->pos += len - 1;
} else if (tok == MJSON_TOK_KEY && data->d1 == data->d2) {
return 1; // Exhausted path, not found
} else if (tok == '}' || tok == ']') {
data->d1--;
// data->d2--;
if (!data->path[data->pos] && data->d1 == data->d2 && data->obj != -1) {
data->tok = tok - 2;
if (data->tokptr) *data->tokptr = s + data->obj;
if (data->toklen) *data->toklen = off - data->obj + 1;
return 1;
}
} else if (MJSON_TOK_IS_VALUE(tok)) {
// printf("TOK --> %d\n", tok);
if (data->d1 == data->d2 && !data->path[data->pos]) {
data->tok = tok;
if (data->tokptr) *data->tokptr = s + off;
if (data->toklen) *data->toklen = len;
return 1;
}
}
return 0;
}
enum mjson_tok mjson_find(const char *s, int len, const char *jp,
const char **tokptr, int *toklen) {
struct msjon_get_data data = {jp, 1, 0, 0, 0,
0, -1, tokptr, toklen, MJSON_TOK_INVALID};
if (jp[0] != '$') return MJSON_TOK_INVALID;
if (mjson(s, len, mjson_get_cb, &data) < 0) return MJSON_TOK_INVALID;
return (enum mjson_tok) data.tok;
}
int mjson_get_number(const char *s, int len, const char *path, double *v) {
const char *p;
int tok, n;
if ((tok = mjson_find(s, len, path, &p, &n)) == MJSON_TOK_NUMBER) {
if (v != NULL) *v = strtod(p, NULL);
}
return tok == MJSON_TOK_NUMBER ? 1 : 0;
}
int mjson_get_bool(const char *s, int len, const char *path, int *v) {
int tok = mjson_find(s, len, path, NULL, NULL);
if (tok == MJSON_TOK_TRUE && v != NULL) *v = 1;
if (tok == MJSON_TOK_FALSE && v != NULL) *v = 0;
return tok == MJSON_TOK_TRUE || tok == MJSON_TOK_FALSE ? 1 : 0;
}
static int mjson_unescape(const char *s, int len, char *to, int n) {
int i, j;
for (i = 0, j = 0; i < len && j < n; i++, j++) {
if (s[i] == '\\' && i + 1 < len) {
int c = mjson_esc(s[i + 1], 0);
if (c == 0) return -1;
to[j] = c;
i++;
} else {
to[j] = s[i];
}
}
if (j >= n) return -1;
if (n > 0) to[j] = '\0';
return j;
}
int mjson_get_string(const char *s, int len, const char *path, char *to,
int n) {
const char *p;
int sz;
if (mjson_find(s, len, path, &p, &sz) != MJSON_TOK_STRING) return -1;
return mjson_unescape(p + 1, sz - 2, to, n);
}
int mjson_get_hex(const char *s, int len, const char *x, char *to, int n) {
const char *p;
int i, j, sz;
if (mjson_find(s, len, x, &p, &sz) != MJSON_TOK_STRING) return -1;
for (i = j = 0; i < sz - 3 && j < n; i += 2, j++) {
#define HEXTOI(x) (x >= '0' && x <= '9' ? x - '0' : x - 'W')
unsigned char a = *(const unsigned char *) (p + i + 1);
unsigned char b = *(const unsigned char *) (p + i + 2);
((unsigned char *) to)[j] = (HEXTOI(a) << 4) | HEXTOI(b);
}
if (j < n) to[j] = '\0';
return j;
}
#if MJSON_ENABLE_BASE64
static int mjson_base64rev(int c) {
if (c >= 'A' && c <= 'Z') {
return c - 'A';
} else if (c >= 'a' && c <= 'z') {
return c + 26 - 'a';
} else if (c >= '0' && c <= '9') {
return c + 52 - '0';
} else if (c == '+') {
return 62;
} else if (c == '/') {
return 63;
} else {
return 64;
}
}
int mjson_base64_dec(const char *src, int n, char *dst, int dlen) {
const char *end = src + n;
int len = 0;
while (src + 3 < end && len < dlen) {
int a = mjson_base64rev(src[0]), b = mjson_base64rev(src[1]),
c = mjson_base64rev(src[2]), d = mjson_base64rev(src[3]);
dst[len++] = (a << 2) | (b >> 4);
if (src[2] != '=' && len < dlen) {
dst[len++] = (b << 4) | (c >> 2);
if (src[3] != '=' && len < dlen) {
dst[len++] = (c << 6) | d;
}
}
src += 4;
}
if (len < dlen) dst[len] = '\0';
return len;
}
int mjson_get_base64(const char *s, int len, const char *path, char *to,
int n) {
const char *p;
int sz;
if (mjson_find(s, len, path, &p, &sz) != MJSON_TOK_STRING) return 0;
return mjson_base64_dec(p + 1, sz - 2, to, n);
}
#endif // MJSON_ENABLE_BASE64
#if MJSON_ENABLE_NEXT
struct nextdata {
int off, len, depth, t, vo, arrayindex;
int *koff, *klen, *voff, *vlen, *vtype;
};
static int next_cb(int tok, const char *s, int off, int len, void *ud) {
struct nextdata *d = (struct nextdata *) ud;
// int i;
switch (tok) {
case '{':
case '[':
if (d->depth == 0 && tok == '[') d->arrayindex = 0;
if (d->depth == 1 && off > d->off) {
d->vo = off;
d->t = tok == '{' ? MJSON_TOK_OBJECT : MJSON_TOK_ARRAY;
if (d->voff) *d->voff = off;
if (d->vtype) *d->vtype = d->t;
}
d->depth++;
break;
case '}':
case ']':
d->depth--;
if (d->depth == 1 && d->vo) {
d->len = off + len;
if (d->vlen) *d->vlen = d->len - d->vo;
if (d->arrayindex >= 0) {
if (d->koff) *d->koff = d->arrayindex; // koff holds array index
if (d->klen) *d->klen = 0; // klen holds 0
}
return 1;
}
if (d->depth == 1 && d->arrayindex >= 0) d->arrayindex++;
break;
case ',':
case ':':
break;
case MJSON_TOK_KEY:
if (d->depth == 1 && d->off < off) {
if (d->koff) *d->koff = off; // And report back to the user
if (d->klen) *d->klen = len; // If we have to
}
break;
default:
if (d->depth != 1) break;
// If we're iterating over the array
if (off > d->off) {
d->len = off + len;
if (d->vlen) *d->vlen = len; // value length
if (d->voff) *d->voff = off; // value offset
if (d->vtype) *d->vtype = tok; // value type
if (d->arrayindex >= 0) {
if (d->koff) *d->koff = d->arrayindex; // koff holds array index
if (d->klen) *d->klen = 0; // klen holds 0
}
return 1;
}
if (d->arrayindex >= 0) d->arrayindex++;
break;
}
(void) s;
return 0;
}
int mjson_next(const char *s, int n, int off, int *koff, int *klen, int *voff,
int *vlen, int *vtype) {
struct nextdata d = {off, 0, 0, 0, 0, -1, koff, klen, voff, vlen, vtype};
mjson(s, n, next_cb, &d);
return d.len;
}
#endif
#if MJSON_ENABLE_PRINT
int mjson_print_fixed_buf(const char *ptr, int len, void *fndata) {
struct mjson_fixedbuf *fb = (struct mjson_fixedbuf *) fndata;
int i, left = fb->size - 1 - fb->len;
if (left < len) len = left;
for (i = 0; i < len; i++) fb->ptr[fb->len + i] = ptr[i];
fb->len += len;
fb->ptr[fb->len] = '\0';
return len;
}
int mjson_print_dynamic_buf(const char *ptr, int len, void *fndata) {
char *s, *buf = *(char **) fndata;
int curlen = buf == NULL ? 0 : strlen(buf);
if ((s = (char *) realloc(buf, curlen + len + 1)) == NULL) {
return 0;
} else {
memcpy(s + curlen, ptr, len);
s[curlen + len] = '\0';
*(char **) fndata = s;
return len;
}
}
int mjson_print_null(const char *ptr, int len, void *userdata) {
(void) ptr;
(void) userdata;
return len;
}
int mjson_print_file(const char *ptr, int len, void *userdata) {
return fwrite(ptr, 1, len, (FILE *) userdata);
}
int mjson_print_buf(mjson_print_fn_t fn, void *fndata, const char *buf,
int len) {
return fn(buf, len, fndata);
}
int mjson_print_int(mjson_print_fn_t fn, void *fndata, int value,
int is_signed) {
char buf[20];
int len = snprintf(buf, sizeof(buf), is_signed ? "%d" : "%u", value);
return fn(buf, len, fndata);
}
int mjson_print_long(mjson_print_fn_t fn, void *fndata, long value,
int is_signed) {
char buf[20];
const char *fmt = (is_signed ? "%ld" : "%lu");
int len = snprintf(buf, sizeof(buf), fmt, value);
return fn(buf, len, fndata);
}
int mjson_print_dbl(mjson_print_fn_t fn, void *fndata, double d,
const char *fmt) {
char buf[40];
int n = snprintf(buf, sizeof(buf), fmt, d);
return fn(buf, n, fndata);
}
int mjson_print_str(mjson_print_fn_t fn, void *fndata, const char *s, int len) {
int i, n = fn("\"", 1, fndata);
for (i = 0; i < len; i++) {
char c = mjson_esc(s[i], 1);
if (c) {
n += fn("\\", 1, fndata);
n += fn(&c, 1, fndata);
} else {
n += fn(&s[i], 1, fndata);
}
}
return n + fn("\"", 1, fndata);
}
#if MJSON_ENABLE_BASE64
int mjson_print_b64(mjson_print_fn_t fn, void *fndata, const unsigned char *s,
int n) {
const char *t =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int i, len = fn("\"", 1, fndata);
for (i = 0; i < n; i += 3) {
int a = s[i], b = i + 1 < n ? s[i + 1] : 0, c = i + 2 < n ? s[i + 2] : 0;
char buf[4] = {t[a >> 2], t[(a & 3) << 4 | (b >> 4)], '=', '='};
if (i + 1 < n) buf[2] = t[(b & 15) << 2 | (c >> 6)];
if (i + 2 < n) buf[3] = t[c & 63];
len += fn(buf, sizeof(buf), fndata);
}
return len + fn("\"", 1, fndata);
}
#endif /* MJSON_ENABLE_BASE64 */
int mjson_vprintf(mjson_print_fn_t fn, void *fndata, const char *fmt,
va_list xap) {
int i = 0, n = 0;
va_list ap;
va_copy(ap, xap);
while (fmt[i] != '\0') {
if (fmt[i] == '%') {
char fc = fmt[++i];
int is_long = 0;
if (fc == 'l') {
is_long = 1;
fc = fmt[i + 1];
}
if (fc == 'Q') {
char *buf = va_arg(ap, char *);
n += mjson_print_str(fn, fndata, buf ? buf : "", buf ? strlen(buf) : 0);
} else if (strncmp(&fmt[i], ".*Q", 3) == 0) {
int len = va_arg(ap, int);
char *buf = va_arg(ap, char *);
n += mjson_print_str(fn, fndata, buf, len);
i += 2;
} else if (fc == 'd' || fc == 'u') {
int is_signed = (fc == 'd');
if (is_long) {
long val = va_arg(ap, long);
n += mjson_print_long(fn, fndata, val, is_signed);
i++;
} else {
int val = va_arg(ap, int);
n += mjson_print_int(fn, fndata, val, is_signed);
}
} else if (fc == 'B') {
const char *s = va_arg(ap, int) ? "true" : "false";
n += mjson_print_buf(fn, fndata, s, strlen(s));
} else if (fc == 's') {
char *buf = va_arg(ap, char *);
n += mjson_print_buf(fn, fndata, buf, strlen(buf));
} else if (strncmp(&fmt[i], ".*s", 3) == 0) {
int len = va_arg(ap, int);
char *buf = va_arg(ap, char *);
n += mjson_print_buf(fn, fndata, buf, len);
i += 2;
} else if (fc == 'g') {
n += mjson_print_dbl(fn, fndata, va_arg(ap, double), "%g");
} else if (fc == 'f') {
n += mjson_print_dbl(fn, fndata, va_arg(ap, double), "%f");
#if MJSON_ENABLE_BASE64
} else if (fc == 'V') {
int len = va_arg(ap, int);
const char *buf = va_arg(ap, const char *);
n += mjson_print_b64(fn, fndata, (unsigned char *) buf, len);
#endif
} else if (fc == 'H') {
const char *hex = "0123456789abcdef";
int i, len = va_arg(ap, int);
const unsigned char *p = va_arg(ap, const unsigned char *);
n += fn("\"", 1, fndata);
for (i = 0; i < len; i++) {
n += fn(&hex[(p[i] >> 4) & 15], 1, fndata);
n += fn(&hex[p[i] & 15], 1, fndata);
}
n += fn("\"", 1, fndata);
} else if (fc == 'M') {
mjson_vprint_fn_t vfn = va_arg(ap, mjson_vprint_fn_t);
n += vfn(fn, fndata, &ap);
}
i++;
} else {
n += mjson_print_buf(fn, fndata, &fmt[i++], 1);
}
}
va_end(xap);
va_end(ap);
return n;
}
int mjson_printf(mjson_print_fn_t fn, void *fndata, const char *fmt, ...) {
va_list ap;
int len;
va_start(ap, fmt);
len = mjson_vprintf(fn, fndata, fmt, ap);
va_end(ap);
return len;
}
#endif /* MJSON_ENABLE_PRINT */
#if MJSON_IMPLEMENT_STRTOD
static inline int is_digit(int c) {
return c >= '0' && c <= '9';
}
/* NOTE: strtod() implementation by Yasuhiro Matsumoto. */
double strtod(const char *str, char **end) {
double d = 0.0;
int sign = 1, n = 0;
const char *p = str, *a = str;
/* decimal part */
if (*p == '-') {
sign = -1;
++p;
} else if (*p == '+')
++p;
if (is_digit(*p)) {
d = (double) (*p++ - '0');
while (*p && is_digit(*p)) {
d = d * 10.0 + (double) (*p - '0');
++p;
++n;
}
a = p;
} else if (*p != '.')
goto done;
d *= sign;
/* fraction part */
if (*p == '.') {
double f = 0.0;
double base = 0.1;
++p;
if (is_digit(*p)) {
while (*p && is_digit(*p)) {
f += base * (*p - '0');
base /= 10.0;
++p;
++n;
}
}
d += f * sign;
a = p;
}
/* exponential part */
if ((*p == 'E') || (*p == 'e')) {
int e = 0;
++p;
sign = 1;
if (*p == '-') {
sign = -1;
++p;
} else if (*p == '+')
++p;
if (is_digit(*p)) {
while (*p == '0') ++p;
e = (int) (*p++ - '0');
while (*p && is_digit(*p)) {
e = e * 10 + (int) (*p - '0');
++p;
}
e *= sign;
} else if (!is_digit(*(a - 1))) {
a = str;
goto done;
} else if (*p == 0)
goto done;
if (d == 2.2250738585072011 && e == -308) {
d = 0.0;
a = p;
goto done;
}
if (d == 2.2250738585072012 && e <= -308) {
d *= 1.0e-308;
a = p;
goto done;
}
{
int i;
for (i = 0; i < 10; i++) d *= 10;
}
a = p;
} else if (p > str && !is_digit(*(p - 1))) {
a = str;
goto done;
}
done:
if (end) *end = (char *) a;
return d;
}
#endif
#if MJSON_ENABLE_MERGE
int mjson_merge(const char *s, int n, const char *s2, int n2,
mjson_print_fn_t fn, void *userdata) {
int koff, klen, voff, vlen, t, t2, k, off = 0, len = 0, comma = 0;
if (n < 2) return len;
len += fn("{", 1, userdata);
while ((off = mjson_next(s, n, off, &koff, &klen, &voff, &vlen, &t)) != 0) {
#if !defined(_MSC_VER) || _MSC_VER >= 1700
char path[klen + 1];
#else
char *path = (char *) alloca(klen + 1);
#endif
const char *val;
memcpy(path, "$.", 2);
memcpy(path + 2, s + koff + 1, klen - 2);
path[klen] = '\0';
if ((t2 = mjson_find(s2, n2, path, &val, &k)) != MJSON_TOK_INVALID) {
if (t2 == MJSON_TOK_NULL) continue; // null deletes the key
} else {
val = s + voff; // Key is not found in the update. Copy the old value.
}
if (comma) len += fn(",", 1, userdata);
len += fn(s + koff, klen, userdata);
len += fn(":", 1, userdata);
if (t == MJSON_TOK_OBJECT && t2 == MJSON_TOK_OBJECT) {
len += mjson_merge(s + voff, vlen, val, k, fn, userdata);
} else {
if (t2 != MJSON_TOK_INVALID) vlen = k;
len += fn(val, vlen, userdata);
}
comma = 1;
}
// Add missing keys
off = 0;
while ((off = mjson_next(s2, n2, off, &koff, &klen, &voff, &vlen, &t)) != 0) {
#if !defined(_MSC_VER) || _MSC_VER >= 1700
char path[klen + 1];
#else
char *path = (char *) alloca(klen + 1);
#endif
const char *val;
if (t == MJSON_TOK_NULL) continue;
memcpy(path, "$.", 2);
memcpy(path + 2, s2 + koff + 1, klen - 2);
path[klen] = '\0';
if (mjson_find(s, n, path, &val, &vlen) != MJSON_TOK_INVALID) continue;
if (comma) len += fn(",", 1, userdata);
len += fn(s2 + koff, klen, userdata);
len += fn(":", 1, userdata);
len += fn(s2 + voff, vlen, userdata);
comma = 1;
}
len += fn("}", 1, userdata);
return len;
}
#endif // MJSON_ENABLE_MERGE
#if MJSON_ENABLE_PRETTY
struct prettydata {
int level;
int len;
int prev;
const char *pad;
int padlen;
mjson_print_fn_t fn;
void *userdata;
};
static int pretty_cb(int ev, const char *s, int off, int len, void *ud) {
struct prettydata *d = (struct prettydata *) ud;
int i;
switch (ev) {
case '{':
case '[':
d->level++;
d->len += d->fn(s + off, len, d->userdata);
break;
case '}':
case ']':
d->level--;
if (d->prev != '[' && d->prev != '{' && d->padlen > 0) {
d->len += d->fn("\n", 1, d->userdata);
for (i = 0; i < d->level; i++)
d->len += d->fn(d->pad, d->padlen, d->userdata);
}
d->len += d->fn(s + off, len, d->userdata);
break;
case ',':
d->len += d->fn(s + off, len, d->userdata);
if (d->padlen > 0) {
d->len += d->fn("\n", 1, d->userdata);
for (i = 0; i < d->level; i++)
d->len += d->fn(d->pad, d->padlen, d->userdata);
}
break;
case ':':
d->len += d->fn(s + off, len, d->userdata);
if (d->padlen > 0) d->len += d->fn(" ", 1, d->userdata);
break;
case MJSON_TOK_KEY:
if (d->prev == '{' && d->padlen > 0) {
d->len += d->fn("\n", 1, d->userdata);
for (i = 0; i < d->level; i++)
d->len += d->fn(d->pad, d->padlen, d->userdata);
}
d->len += d->fn(s + off, len, d->userdata);
break;
default:
if (d->prev == '[' && d->padlen > 0) {
d->len += d->fn("\n", 1, d->userdata);
for (i = 0; i < d->level; i++)
d->len += d->fn(d->pad, d->padlen, d->userdata);
}
d->len += d->fn(s + off, len, d->userdata);
break;
}
d->prev = ev;
return 0;
}
int mjson_pretty(const char *s, int n, const char *pad, mjson_print_fn_t fn,
void *userdata) {
struct prettydata d = {0, 0, 0, pad, strlen(pad), fn, userdata};
if (mjson(s, n, pretty_cb, &d) < 0) return -1;
return d.len;
}
#endif // MJSON_ENABLE_PRETTY
#if MJSON_ENABLE_RPC
struct jsonrpc_ctx jsonrpc_default_context;
struct jsonrpc_userdata {
mjson_print_fn_t fn;
void *fndata;
};
int mjson_globmatch(const char *s1, int n1, const char *s2, int n2) {
int i = 0, j = 0, ni = 0, nj = 0;
while (i < n1 || j < n2) {
if (i < n1 && j < n2 && (s1[i] == '?' || s2[j] == s1[i])) {
i++, j++;
} else if (i < n1 && (s1[i] == '*' || s1[i] == '#')) {
ni = i, nj = j + 1, i++;
} else if (nj > 0 && nj <= n2 && (s1[i - 1] == '#' || s2[j] != '/')) {
i = ni, j = nj;
} else {
return 0;
}
}
return 1;
}
static int jsonrpc_printer(const char *buf, int len, void *userdata) {
struct jsonrpc_userdata *u = (struct jsonrpc_userdata *) userdata;
return u->fn(buf, len, u->fndata);
}
void jsonrpc_return_errorv(struct jsonrpc_request *r, int code,
const char *message, const char *data_fmt,
va_list ap) {
if (r->id_len == 0) return;
mjson_printf(r->fn, r->fndata,
"{\"id\":%.*s,\"error\":{\"code\":%d,\"message\":%Q", r->id_len,
r->id, code, message == NULL ? "" : message);
if (data_fmt != NULL) {
mjson_printf(r->fn, r->fndata, ",\"data\":");
mjson_vprintf(r->fn, r->fndata, data_fmt, ap);
}
mjson_printf(r->fn, r->fndata, "}}\n");
}
void jsonrpc_return_error(struct jsonrpc_request *r, int code,
const char *message, const char *data_fmt, ...) {
va_list ap;
va_start(ap, data_fmt);
jsonrpc_return_errorv(r, code, message, data_fmt, ap);
va_end(ap);
}
void jsonrpc_return_successv(struct jsonrpc_request *r, const char *result_fmt,
va_list ap) {
if (r->id_len == 0) return;
mjson_printf(r->fn, r->fndata, "{\"id\":%.*s,\"result\":", r->id_len, r->id);
if (result_fmt != NULL) {
mjson_vprintf(r->fn, r->fndata, result_fmt, ap);
} else {
mjson_printf(r->fn, r->fndata, "%s", "null");
}
mjson_printf(r->fn, r->fndata, "}\n");
}
void jsonrpc_return_success(struct jsonrpc_request *r, const char *result_fmt,
...) {
va_list ap;
va_start(ap, result_fmt);
jsonrpc_return_successv(r, result_fmt, ap);
va_end(ap);
}
void jsonrpc_ctx_process(struct jsonrpc_ctx *ctx, const char *req, int req_sz,
mjson_print_fn_t fn, void *fndata) {
const char *result = NULL, *error = NULL;
int result_sz = 0, error_sz = 0;
struct jsonrpc_method *m = NULL;
struct jsonrpc_userdata d;
struct jsonrpc_request r = {req, req_sz, 0, 0, 0, 0, 0,
0, &jsonrpc_printer, NULL, NULL};
d.fn = fn;
d.fndata = fndata;
r.fndata = &d;
// Is is a response frame?
mjson_find(req, req_sz, "$.result", &result, &result_sz);
if (result == NULL) mjson_find(req, req_sz, "$.error", &error, &error_sz);
if (result_sz > 0 || error_sz > 0) {
if (ctx->response_cb != NULL) ctx->response_cb(req, req_sz, ctx->userdata);
return;
}
// Method must exist and must be a string
if (mjson_find(req, req_sz, "$.method", &r.method, &r.method_len) !=
MJSON_TOK_STRING) {
mjson_printf(fn, fndata, "{\"error\":{\"code\":-32700,\"message\":%.*Q}}\n",
req_sz, req);
ctx->in_len = 0;
return;
}
// id and params are optional
mjson_find(req, req_sz, "$.id", &r.id, &r.id_len);
mjson_find(req, req_sz, "$.params", &r.params, &r.params_len);
for (m = ctx->methods; m != NULL; m = m->next) {
if (mjson_globmatch(m->method, m->method_sz, r.method + 1,
r.method_len - 2) > 0) {
if (r.params == NULL) r.params = "";
r.userdata = m->cbdata;
m->cb(&r);
break;
}
}
if (m == NULL) {
jsonrpc_return_error(&r, JSONRPC_ERROR_NOT_FOUND, "method not found", NULL);
}
}
static int jsonrpc_print_methods(mjson_print_fn_t fn, void *fndata,
va_list *ap) {
struct jsonrpc_ctx *ctx = va_arg(*ap, struct jsonrpc_ctx *);
struct jsonrpc_method *m;
int len = 0;
for (m = ctx->methods; m != NULL; m = m->next) {
if (m != ctx->methods) len += mjson_print_buf(fn, fndata, ",", 1);
len += mjson_print_str(fn, fndata, m->method, strlen(m->method));
}
return len;
}
static void rpclist(struct jsonrpc_request *r) {
jsonrpc_return_success(r, "[%M]", jsonrpc_print_methods, r->userdata);
}
void jsonrpc_ctx_init(struct jsonrpc_ctx *ctx, mjson_print_fn_t response_cb,
void *userdata) {
ctx->response_cb = response_cb;
ctx->userdata = userdata;
jsonrpc_ctx_export(ctx, MJSON_RPC_LIST_NAME, rpclist, ctx);
}
void jsonrpc_ctx_process_byte(struct jsonrpc_ctx *ctx, unsigned char ch,
mjson_print_fn_t fn, void *p) {
if (ctx->in_len >= (int) sizeof(ctx->in)) ctx->in_len = 0; // Overflow
if (ch == '\n') { // If new line, parse frame
if (ctx->in_len > 1) jsonrpc_ctx_process(ctx, ctx->in, ctx->in_len, fn, p);
ctx->in_len = 0;
} else {
ctx->in[ctx->in_len] = ch; // Append to the buffer
ctx->in_len++;
}
}
void jsonrpc_init(mjson_print_fn_t response_cb, void *userdata) {
jsonrpc_ctx_init(&jsonrpc_default_context, response_cb, userdata);
}
#endif // MJSON_ENABLE_RPC
-220
View File
@@ -1,220 +0,0 @@
// Copyright (c) 2018-2020 Cesanta Software Limited
// All rights reserved
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef MJSON_H
#define MJSON_H
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef MJSON_ENABLE_PRINT
#define MJSON_ENABLE_PRINT 1
#endif
#ifndef MJSON_ENABLE_RPC
#define MJSON_ENABLE_RPC 1
#endif
#ifndef MJSON_ENABLE_BASE64
#define MJSON_ENABLE_BASE64 1
#endif
#ifndef MJSON_ENABLE_MERGE
#define MJSON_ENABLE_MERGE 0
#elif MJSON_ENABLE_MERGE
#define MJSON_ENABLE_NEXT 1
#endif
#ifndef MJSON_ENABLE_PRETTY
#define MJSON_ENABLE_PRETTY 0
#elif MJSON_ENABLE_PRETTY
#define MJSON_ENABLE_NEXT 1
#endif
#ifndef MJSON_ENABLE_NEXT
#define MJSON_ENABLE_NEXT 0
#endif
#ifndef MJSON_RPC_IN_BUF_SIZE
#define MJSON_RPC_IN_BUF_SIZE 256
#endif
#ifndef MJSON_RPC_LIST_NAME
#define MJSON_RPC_LIST_NAME "rpc.list"
#endif
#ifdef __cplusplus
extern "C" {
#endif
enum {
MJSON_ERROR_INVALID_INPUT = -1,
MJSON_ERROR_TOO_DEEP = -2,
};
enum mjson_tok {
MJSON_TOK_INVALID = 0,
MJSON_TOK_KEY = 1,
MJSON_TOK_STRING = 11,
MJSON_TOK_NUMBER = 12,
MJSON_TOK_TRUE = 13,
MJSON_TOK_FALSE = 14,
MJSON_TOK_NULL = 15,
MJSON_TOK_ARRAY = 91,
MJSON_TOK_OBJECT = 123,
};
#define MJSON_TOK_IS_VALUE(t) ((t) > 10 && (t) < 20)
typedef int (*mjson_cb_t)(int ev, const char *s, int off, int len, void *ud);
#ifndef MJSON_MAX_DEPTH
#define MJSON_MAX_DEPTH 20
#endif
int mjson(const char *s, int len, mjson_cb_t cb, void *ud);
enum mjson_tok mjson_find(const char *s, int len, const char *jp,
const char **tokptr, int *toklen);
int mjson_get_number(const char *s, int len, const char *path, double *v);
int mjson_get_bool(const char *s, int len, const char *path, int *v);
int mjson_get_string(const char *s, int len, const char *path, char *to, int n);
int mjson_get_hex(const char *s, int len, const char *path, char *to, int n);
#if MJSON_ENABLE_NEXT
int mjson_next(const char *s, int n, int off, int *koff, int *klen, int *voff,
int *vlen, int *vtype);
#endif
#if MJSON_ENABLE_BASE64
int mjson_get_base64(const char *s, int len, const char *path, char *to, int n);
int mjson_base64_dec(const char *src, int n, char *dst, int dlen);
#endif
#if MJSON_ENABLE_PRINT
typedef int (*mjson_print_fn_t)(const char *buf, int len, void *userdata);
typedef int (*mjson_vprint_fn_t)(mjson_print_fn_t, void *, va_list *);
struct mjson_fixedbuf {
char *ptr;
int size, len;
};
int mjson_printf(mjson_print_fn_t, void *, const char *fmt, ...);
int mjson_vprintf(mjson_print_fn_t, void *, const char *fmt, va_list ap);
int mjson_print_str(mjson_print_fn_t, void *, const char *s, int len);
int mjson_print_int(mjson_print_fn_t, void *, int value, int is_signed);
int mjson_print_long(mjson_print_fn_t, void *, long value, int is_signed);
int mjson_print_buf(mjson_print_fn_t fn, void *, const char *buf, int len);
int mjson_print_null(const char *ptr, int len, void *userdata);
int mjson_print_file(const char *ptr, int len, void *userdata);
int mjson_print_fixed_buf(const char *ptr, int len, void *userdata);
int mjson_print_dynamic_buf(const char *ptr, int len, void *userdata);
#if MJSON_ENABLE_PRETTY
int mjson_pretty(const char *, int, const char *, mjson_print_fn_t, void *);
#endif
#if MJSON_ENABLE_MERGE
int mjson_merge(const char *, int, const char *, int, mjson_print_fn_t, void *);
#endif
#endif // MJSON_ENABLE_PRINT
#if MJSON_ENABLE_RPC
void jsonrpc_init(mjson_print_fn_t, void *userdata);
int mjson_globmatch(const char *s1, int n1, const char *s2, int n2);
struct jsonrpc_request {
const char *frame; // Points to the whole frame
int frame_len; // Frame length
const char *params; // Points to the "params" in the request frame
int params_len; // Length of the "params"
const char *id; // Points to the "id" in the request frame
int id_len; // Length of the "id"
const char *method; // Points to the "method" in the request frame
int method_len; // Length of the "method"
mjson_print_fn_t fn; // Printer function
void *fndata; // Printer function data
void *userdata; // Callback's user data as specified at export time
};
struct jsonrpc_method {
const char *method;
int method_sz;
void (*cb)(struct jsonrpc_request *);
void *cbdata;
struct jsonrpc_method *next;
};
// Main RPC context, stores current request information and a list of
// exported RPC methods.
struct jsonrpc_ctx {
struct jsonrpc_method *methods;
void *userdata;
mjson_print_fn_t response_cb;
int in_len;
char in[MJSON_RPC_IN_BUF_SIZE];
};
// Registers function fn under the given name within the given RPC context
#define jsonrpc_ctx_export(ctx, name, fn, ud) \
do { \
static struct jsonrpc_method m = {(name), sizeof(name) - 1, (fn), 0, 0}; \
m.cbdata = (ud); \
m.next = (ctx)->methods; \
(ctx)->methods = &m; \
} while (0)
void jsonrpc_ctx_init(struct jsonrpc_ctx *ctx, mjson_print_fn_t, void *);
void jsonrpc_return_error(struct jsonrpc_request *r, int code,
const char *message, const char *data_fmt, ...);
void jsonrpc_return_success(struct jsonrpc_request *r, const char *result_fmt,
...);
void jsonrpc_ctx_process(struct jsonrpc_ctx *ctx, const char *req, int req_sz,
mjson_print_fn_t fn, void *fndata);
void jsonrpc_ctx_process_byte(struct jsonrpc_ctx *ctx, unsigned char ch,
mjson_print_fn_t fn, void *fndata);
extern struct jsonrpc_ctx jsonrpc_default_context;
#define jsonrpc_export(name, fn, ud) \
jsonrpc_ctx_export(&jsonrpc_default_context, (name), (fn), (ud))
#define jsonrpc_process(buf, len, fn, data) \
jsonrpc_ctx_process(&jsonrpc_default_context, (buf), (len), (fn), (data))
#define jsonrpc_process_byte(x, fn, data) \
jsonrpc_ctx_process_byte(&jsonrpc_default_context, (x), (fn), (data))
#define JSONRPC_ERROR_INVALID -32700 /* Invalid JSON was received */
#define JSONRPC_ERROR_NOT_FOUND -32601 /* The method does not exist */
#define JSONRPC_ERROR_BAD_PARAMS -32602 /* Invalid params passed */
#define JSONRPC_ERROR_INTERNAL -32603 /* Internal JSON-RPC error */
#endif // MJSON_ENABLE_RPC
#ifdef __cplusplus
}
#endif
#endif // MJSON_H
Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

-312
View File
@@ -1,312 +0,0 @@
const {h, render, Component} = preact;
const html = htm.bind(h);
class Login extends Component {
state = {user: '', pass: ''};
onclick = (app) => {
const authhdr = 'Basic ' + btoa(this.state.user + ':' + this.state.pass);
const headers = {Authorization: authhdr};
return axios.get('/api/login', {headers})
.then(res => app.setUser(res.data.token))
.catch(err => alert('Login failed'));
};
onpassinput = (ev) => this.setState({pass: ev.target.value});
onuserinput = (ev) => this.setState({user: ev.target.value});
render({app}, {user, pass, signup}) {
return html`
<div class='mx-auto bg-light rounded border my-5' style='max-width: 480px;'>
<div class='form p-5 rounded form-sm'>
<h4 class="text-muted mb-4">Login </h4>
<input type='email' placeholder='Email' class='my-2 form-control'
oninput=${this.onuserinput} value=${user} />
<input type="password" placeholder="Password" class="my-2 form-control"
oninput=${this.onpassinput} value=${pass}
onchange=${ev => this.onclick(app)} />
<div class="mb-4">
<button class="btn btn-info btn-block"
disabled=${!user || !pass} onclick="${ev => this.onclick(app)}"
> Login </button>
</div>
<div class="text-muted small">
Valid logins: admin:admin, user1:pass1, user2:pass2
</div>
</div>
</div>
`
}
};
class Dropdown extends Component {
state = {show: false};
render(props, state) {
const onclick = x => this.setState({show: x});
const show = state.show ? 'show' : '';
return html`
<div class="dropdown autoexpand ${props.cls}">
<div type="buttonx" onclick=${() => onclick(!state.show)}
class="dropdown-toggle my-0 ${props.bcls}"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
${props.title}
</div>
<div onclick=${() => onclick(false)} style=${props.dstyle}
class="dropdown-menu ${props.dcls} ${show}">
${props.children}
</div>
</div>`;
}
};
const NavLink = ({href, title, url}) => html`<a class="nav-item nav-link
${url == href ? 'active' : ''}"
target=${href.match(/^http/) ? '_blank' : ''}
href="${href.match(/^http/) ? '' : '#'}${href}">${title}</a>`;
class Header extends Component {
state = {expanded: false};
ontoggle = () => this.setState({expanded: !this.state.expanded});
render(props, state) {
const u = props.app.state.user || {};
return html`
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
<a class="navbar-brand" href="#">
<img src="images/logo.png" width="26" height="26" alt="" class="mr-2" />
MyProduct
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"
onclick=${() => this.ontoggle()} >
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse ${state.expanded ? '' : 'collapse'}"
id="navbarNav">
<div class="nav navbar-nav mr-auto">
<${NavLink} href="/" title="Dashboard" url=${props.url} />
<${NavLink} href="/logs" title="Logs" url=${props.url} />
</div>
</div>
<form class="form-inline">
<${Dropdown} title="${u.user}" cls="mr-2"
bcls="btn btn-sm btn-outline-light pointer" dcls="m-0 dropdown-menu-right">
<div onclick=${() => props.app.setUser('')}
class="dropdown-item small pointer text-center">logout</div>
</${Dropdown}>
<img src="images/user.png" class="rounded-circle nav-item mr-2" width="30" />
</form>
</nav>
`
}
};
const Info = () => html`<div class="alert alert-secondary my-3">
This dashboard shows values kept in server memory. Many clients
can open this page. As soon as any client changes any value,
all clients update automatically.
The JS code that watches state changes, reconnects on network failures.
That means if server restarts, dashboard on all connected clients
refresh automatically.
You can use <code>curl</code> command-line utility:
<br/><code>curl localhost:8000/api/config/get</code>
<br/><code>curl localhost:8000/api/config/watch</code>
<br/><code>curl localhost:8000/api/config/set -d '{"a":123}'</code>
<br/><span class="badge badge-danger">NOTE:</span> administrators
can change settings values, whilst users cannot.
</div>`;
class DashVideo extends Component {
render(props, state) {
const onclick = ev => axios.post(
'/api/config/set', {value1: +state.value1, value2: state.value2});
// alert(JSON.stringify(state));
return html`<div id="form">
<div><b>Change values</b></div>
<table>
<tr><td>Value 1 (number):</td><td><input value=${state.value1}
onInput=${linkState(this, 'value1')} /></td></tr>
<tr><td>Value 2 (string):</td><td><input value=${state.value2}
onInput=${linkState(this, 'value2')}/></td></tr>
<tr><td></td>
<td><button onClick=${onclick}>Save values</button></td></tr>
</table>
</div>`
}
};
class DashForm extends Component {
render(props, state) {
const onclick = ev => axios.post(
'/api/config/set', {value1: +state.value1, value2: state.value2});
// alert(JSON.stringify(state));
return html`<div id="form">
<div><b>Change values</b></div>
<table>
<tr><td>Value 1 (number):</td><td><input class="form-control form-control-sm"
value=${state.value1}
onInput=${linkState(this, 'value1')} /></td></tr>
<tr><td>Value 2 (string):</td><td><input class="form-control form-control-sm"
value=${state.value2}
onInput=${linkState(this, 'value2')}/></td></tr>
<tr><td></td>
<td><button class="btn btn-primary btn-block"
onClick=${onclick}>Save values</button></td></tr>
</table>
</div>`
}
};
class DashSettings extends Component {
state = {value1: null, value2: null};
componentDidMount() {
axios.get('/api/config/get')
.then(r => this.setState(r.data))
.catch(e => console.log(e));
var self = this;
var f = function(reader) {
return reader.read().then(function(result) {
var data = String.fromCharCode.apply(null, result.value);
self.setState(JSON.parse(data));
// console.log(JSON.parse(data));
if (!result.done) return f(reader);
});
};
fetch('/api/config/watch')
.then(r => r.body.getReader())
.then(f)
.catch(e => setTimeout(x => self.componentDidMount(), 1000));
}
render(props, state) {
return html
`<div id="dashboard" style="display: flex; justify-content: flex-evenly;">
<div style="width:50%;text-align:center;">Value 1 (number):
<div style="font-size:140%;"><b>${state.value1}</b></div></div>
<div style="width:50%;text-align:center;">Value 2 (string):
<div style="font-size:140%;"><b>${state.value2}</b></div></div>
</div>`
}
};
class AdminDashboard extends Component {
render(props, state) {
return html`<div class="container-fluid">
<${Info} />
<div class="card-deck">
<div class="card">
<div class="card-header">Settings</div>
<div class="card-body"><${DashSettings} /></div>
</div>
<div class="card">
<div class="card-header">Video stream</div>
<div class="card-body"><img src="/api/video1" class="mw-100" /></div>
</div>
<div class="card">
<div class="card-header">Change settings</div>
<div class="card-body"><${DashForm} /></div>
</div>
</div>
</div>`
}
}
class UserDashboard extends Component {
render(props, state) {
return html`<div class="container-fluid">
<${Info} />
<div class="card-deck">
<div class="card">
<div class="card-header">Settings</div>
<div class="card-body"><${DashSettings} /></div>
</div>
<div class="card">
<div class="card-header">Video stream</div>
<div class="card-body"><img src="/api/video1" class="mw-100" /></div>
</div>
</div>
</div>`
}
}
class Logs extends Component {
state = {live: '', static: ''};
componentDidMount() {
var self = this;
var f = function(r) {
return r.read().then(function(result) {
var data = String.fromCharCode.apply(null, result.value);
var live = self.state.live + data;
self.setState({live}); // Append live log
if (!result.done) f(r); // Read next chunk
});
};
fetch('/api/log/static')
.then(r => r.text())
.then(r => {
self.setState({static: r});
})
.then(r => fetch('/api/log/live'))
.then(r => r.body.getReader())
.then(f);
}
render(props, state) {
return html`<div class="container-fluid">
<div class="alert alert-secondary my-3">
A div below shows file log.txt, which is produced by the server.
The server appends a new log message to that file every second,
and a div below also shows that, implementing a "live log" feature.
JS code on this page first fetches /api/log/static that returns
log.txt contents, then fetches /api/log/live that does not return,
but feeds chunks of data as they arrive (live log).
<br/><br/>
You can also use <code>curl</code> command-line utility to see
live logs:
<br/><code>curl localhost:8000/api/log/live</code>
</div>
<div class="card-deck">
<div class="card">
<div class="card-header">Static</div>
<div class="card-body"><pre class="log">${state.static}</pre></div>
</div>
<div class="card">
<div class="card-header">Live</div>
<div class="card-body"><pre class="log">${state.live}</pre></div>
</div>
</div>
</div>`
}
}
class App extends Component {
state = {user: null, url: '/'};
setUser(token) {
const maxAge = token ? 86400 : 0;
document.cookie = `access_token=${token};path=/;max-age=${maxAge}`;
// this.setState({token});
return axios.get('/api/login')
.then(res => this.setState({user: res.data}))
.catch(err => this.setState({user: {}}));
}
componentDidMount() {
const getCookie = name => {
var v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');
return v ? v[2] : '';
};
this.setUser(getCookie('access_token')); // Move from state1 to 2 or 3
}
render(props, state) {
// We have three states:
// 1. Beginning. We don't know if we have a valid auth token or not
// 2. We sent an /api/login request, and failed to login
// 3. We sent an /api/login request, and succeeded to login
if (!state.user) return ''; // State 1
if (!state.user.user) return h(Login, {app: this}); // State 2
return h( // State 3
'div', {}, h(Header, {url: state.url, app: this}),
h(preactRouter.Router, {
history: History.createHashHistory(),
onChange: ev => this.setState({url: ev.url}),
},
h(state.user.user == 'admin' ? AdminDashboard : UserDashboard,
{default: true, app: this}),
h(Logs, {path: 'logs', app: this})));
}
};
window.onload = () => render(h(App), document.body);
-3
View File
@@ -1,3 +0,0 @@
/* 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(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
//# sourceMappingURL=axios.min.map
-7
View File
@@ -1,7 +0,0 @@
/*!
* Bootstrap v4.3.1 (https://getbootstrap.com/)
* Copyright 2011-2019 The Bootstrap Authors
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,Line truncated
/*# sourceMappingURL=bootstrap.min.css.map */
-1
View File
@@ -1 +0,0 @@
!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.History=n():t.History=n()}(this,function(){return function(t){function n(o){if(e[o])return e[o].exports;var r=e[o]={exports:{},id:o,loaded:!1};return t[o].call(r.exports,r,r.exports,n),r.loaded=!0,r.exports}var e={};return n.m=t,n.c=e,n.p="",n(0)}([function(t,n,e){"use strict";function o(t){return t&&t.__esModule?t:{default:t}}n.__esModule=!0,n.createPath=n.parsePath=n.locationsAreEqual=n.createLocation=n.createMemoryHistory=n.createHashHistory=n.createBrowserHistory=void 0;var r=e(2);Object.defineProperty(n,"createLocation",{enumerable:!0,get:function(){return r.createLocation}}),Object.defineProperty(n,"locationsAreEqual",{enumerable:!0,get:function(){return r.locationsAreEqual}});var i=e(1);Object.defineProperty(n,"parsePath",{enumerable:!0,get:function(){return i.parsePath}}),Object.defineProperty(n,"createPath",{enumerable:!0,get:function(){return i.createPath}});var a=e(7),c=o(a),u=e(8),s=o(u),f=e(9),l=o(f);n.createBrowserHistory=c.default,n.createHashHistory=s.default,n.createMemoryHistory=l.default},function(t,n){"use strict";n.__esModule=!0;n.addLeadingSlash=function(t){return"/"===t.charAt(0)?t:"/"+t},n.stripLeadingSlash=function(t){return"/"===t.charAt(0)?t.substr(1):t},n.stripPrefix=function(t,n){return 0===t.indexOf(n)?t.substr(n.length):t},n.stripTrailingSlash=function(t){return"/"===t.charAt(t.length-1)?t.slice(0,-1):t},n.parsePath=function(t){var n=t||"/",e="",o="",r=n.indexOf("#");r!==-1&&(o=n.substr(r),n=n.substr(0,r));var i=n.indexOf("?");return i!==-1&&(e=n.substr(i),n=n.substr(0,i)),n=decodeURI(n),{pathname:n,search:"?"===e?"":e,hash:"#"===o?"":o}},n.createPath=function(t){var n=t.pathname,e=t.search,o=t.hash,r=encodeURI(n||"/");return e&&"?"!==e&&(r+="?"===e.charAt(0)?e:"?"+e),o&&"#"!==o&&(r+="#"===o.charAt(0)?o:"#"+o),r}},function(t,n,e){"use strict";function o(t){return t&&t.__esModule?t:{default:t}}n.__esModule=!0,n.locationsAreEqual=n.createLocation=void 0;var r=Object.assign||function(t){for(var n=1;n<arguments.length;n++){var e=arguments[n];for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=e[o])}return t},i=e(10),a=o(i),c=e(11),u=o(c),s=e(1);n.createLocation=function(t,n,e,o){var i=void 0;return"string"==typeof t?(i=(0,s.parsePath)(t),i.state=n):(i=r({},t),void 0===i.pathname&&(i.pathname=""),i.search?"?"!==i.search.charAt(0)&&(i.search="?"+i.search):i.search="",i.hash?"#"!==i.hash.charAt(0)&&(i.hash="#"+i.hash):i.hash="",void 0!==n&&void 0===i.state&&(i.state=n)),i.key=e,o&&(i.pathname?"/"!==i.pathname.charAt(0)&&(i.pathname=(0,a.default)(i.pathname,o.pathname)):i.pathname=o.pathname),i},n.locationsAreEqual=function(t,n){return t.pathname===n.pathname&&t.search===n.search&&t.hash===n.hash&&t.key===n.key&&(0,u.default)(t.state,n.state)}},function(t,n,e){"use strict";var o=function(){};t.exports=o},function(t,n,e){"use strict";function o(t){return t&&t.__esModule?t:{default:t}}n.__esModule=!0;var r=e(3),i=(o(r),function(){var t=null,n=function(n){return t=n,function(){t===n&&(t=null)}},e=function(n,e,o,r){if(null!=t){var i="function"==typeof t?t(n,e):t;"string"==typeof i?"function"==typeof o?o(i,r):r(!0):r(i!==!1)}else r(!0)},o=[],r=function(t){var n=!0,e=function(){n&&t.apply(void 0,arguments)};return o.push(e),function(){n=!1,o=o.filter(function(t){return t!==e})}},i=function(){for(var t=arguments.length,n=Array(t),e=0;e<t;e++)n[e]=arguments[e];o.forEach(function(t){return t.apply(void 0,n)})};return{setPrompt:n,confirmTransitionTo:e,appendListener:r,notifyListeners:i}});n.default=i},function(t,n){"use strict";n.__esModule=!0;n.canUseDOM=!("undefined"==typeof window||!window.document||!window.document.createElement),n.addEventListener=function(t,n,e){return t.addEventListener?t.addEventListener(n,e,!1):t.attachEvent("on"+n,e)},n.removeEventListener=function(t,n,e){return t.removeEventListener?t.removeEventListener(n,e,!1):t.detachEvent("on"+n,e)},n.getConfirmation=function(t,n){return n(window.confirm(t))},n.supportsHistory=function(){var t=window.navigator.userAgent;return(t.indexOf("Android 2.")===-1&&t.indexOf("Android 4.0")===-1||t.indexOf("Mobile Safari")===-1||t.indexOf("Chrome")!==-1||t.indexOf("Windows Phone")!==-1)&&(window.history&&"pushState"in window.history)},n.supportsPopStateOnHashChange=function(){return window.navigator.userAgent.indexOf("Trident")===-1},n.supportsGoWithoutReloadUsingHash=function(){return window.navigator.userAgent.indexOf("Firefox")===-1},n.isExtraneousPopstateEvent=function(t){return void 0===t.state&&navigator.userAgent.indexOf("CriOS")===-1}},function(t,n,e){"use strict";var o=function(t,n,e,o,r,i,a,c){if(!t){var u;if(void 0===n)u=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var s=[e,o,r,i,a,c],f=0;u=new Error(n.replace(/%s/g,function(){return s[f++]})),u.name="InLine truncated
-1
View File
@@ -1 +0,0 @@
!function(){function n(n){var t=e.get(this);return t||(t=new Map,e.set(this,t)),1<(t=a(this,t.get(n)||(t.set(n,t=function(n){function t(n){1===u&&(n||(r=r.replace(/^\s*\n\s*|\s*\n\s*$/g,"")))?p.push(0,n,r):3===u&&(n||r)?(p.push(3,n,r),u=2):2===u&&"..."===r&&n?p.push(4,n,0):2===u&&r&&!n?p.push(5,0,!0,r):5<=u&&((r||!n&&5===u)&&(p.push(u,0,r,s),u=6),n&&(p.push(u,n,0,s),u=6)),r=""}for(var e,s,u=1,r="",h="",p=[0],a=0;a<n.length;a++){a&&(1===u&&t(),t(a));for(var o=0;o<n[a].length;o++)e=n[a][o],1===u?"<"===e?(t(),p=[p],u=3):r+=e:4===u?r="--"===r&&">"===e?(u=1,""):e+r[0]:h?e===h?h="":r+=e:'"'===e||"'"===e?h=e:">"===e?(t(),u=1):u&&("="===e?(u=5,s=r,r=""):"/"===e&&(u<5||">"===n[a][o+1])?(t(),3===u&&(p=p[0]),(p=(u=p)[0]).push(2,0,u),u=0):" "===e||"\t"===e||"\n"===e||"\r"===e?(t(),u=2):r+=e),3===u&&"!--"===r&&(u=4,p=p[0])}return t(),p}(n)),t),arguments,[])).length?t:t[0]}var a=function(n,t,e,s){var u;t[0]=0;for(var r=1;r<t.length;r++){var h=t[r++],p=t[r]?(t[0]|=h?1:2,e[t[r++]]):t[++r];3===h?s[0]=p:4===h?s[1]=Object.assign(s[1]||{},p):5===h?(s[1]=s[1]||{})[t[++r]]=p:6===h?s[1][t[++r]]+=p+"":h?(u=n.apply(p,a(n,p,e,["",null])),s.push(u),p[0]?t[0]|=2:(t[r-2]=0,t[r]=u)):s.push(p)}return s},e=new Map;"undefined"!=typeof module?module.exports=n:self.htm=n}();
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

-19
View File
@@ -1,19 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>example</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="bootstrap.min.css" />
<link rel="stylesheet" href="style.css" />
<script src="preact.min.js"></script>
<script src="preact-router.min.js"></script>
<script src="htm.min.js"></script>
<script src="history.min.js"></script>
<script src="linkstate.min.js"></script>
<script src="axios.min.js"></script>
<script src="app.js"></script>
</head>
<body></body>
</html>
-18
View File
@@ -1,18 +0,0 @@
function linkState(component, key, eventPath) {
let path = key.split('.'), cache = component.__lsc || (component.__lsc = {});
return cache[key + eventPath] || (cache[key + eventPath] = function(e) {
let t = e && e.target || this, state = {}, obj = state,
v = typeof eventPath === 'string' ?
delve(e, eventPath) :
t.nodeName ? (t.type.match(/^che|rad/) ? t.checked : t.value) :
e,
i = 0;
for (; i < path.length - 1; i++) {
obj = obj[path[i]] ||
(obj[path[i]] = !i && component.state[path[i]] || {});
}
obj[path[i]] = v;
component.setState(state);
});
}
-1
View File
@@ -1 +0,0 @@
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("preact")):"function"==typeof define&&define.amd?define(["preact"],e):t.preactRouter=e(t.preact)}(this,function(p){function i(t,e){for(var n in e)t[n]=e[n];return t}function u(t,e,n){var r,o=/(?:\?([^#]*))?(#.*)?$/,i=t.match(o),u={};if(i&&i[1])for(var a=i[1].split("&"),p=0;p<a.length;p++){var c=a[p].split("=");u[decodeURIComponent(c[0])]=decodeURIComponent(c.slice(1).join("="))}t=y(t.replace(o,"")),e=y(e||"");for(var f=Math.max(t.length,e.length),l=0;l<f;l++)if(e[l]&&":"===e[l].charAt(0)){var s=e[l].replace(/(^:|[+*?]+$)/g,""),h=(e[l].match(/[+*?]+$/)||v)[0]||"",d=~h.indexOf("+"),g=~h.indexOf("*"),m=t[l]||"";if(!m&&!g&&(h.indexOf("?")<0||d)){r=!1;break}if(u[s]=decodeURIComponent(m),d||g){u[s]=t.slice(l).map(decodeURIComponent).join("/");break}}else if(e[l]!==t[l]){r=!1;break}return(!0===n.default||!1!==r)&&u}function e(t,e){return t.rank<e.rank?1:t.rank>e.rank?-1:t.index-e.index}function n(t,e){return t.index=e,t.rank=(n=t).props.default?0:function(t){return y(t).map(r).join("")}(n.props.path),t.props;var n}function y(t){return t.replace(/(^\/+|\/+$)/g,"").split("/")}function r(t){return":"==t.charAt(0)?1+"*+?".indexOf(t.charAt(t.length-1))||4:5}function o(){var t;return""+((t=g&&g.location?g.location:g&&g.getCurrentLocation?g.getCurrentLocation():"undefined"!=typeof location?location:b).pathname||"")+(t.search||"")}function a(t,e){return void 0===e&&(e=!1),"string"!=typeof t&&t.url&&(e=t.replace,t=t.url),function(t){for(var e=m.length;e--;)if(m[e].canRoute(t))return 1;return}(t)&&(n=t,void 0===(r=e?"replace":"push")&&(r="push"),g&&g[r]?g[r](n):"undefined"!=typeof history&&history[r+"State"]&&history[r+"State"](null,null,n)),c(t);var n,r}function c(t){for(var e=!1,n=0;n<m.length;n++)!0===m[n].routeTo(t)&&(e=!0);for(var r=C.length;r--;)C[r](t);return e}function f(t){if(t&&t.getAttribute){var e=t.getAttribute("href"),n=t.getAttribute("target");if(e&&e.match(/^\//g)&&(!n||n.match(/^_?self$/i)))return a(e)}}function l(t){if(!(t.ctrlKey||t.metaKey||t.altKey||t.shiftKey||0!==t.button))return f(t.currentTarget||t.target||this),s(t)}function s(t){return t&&(t.stopImmediatePropagation&&t.stopImmediatePropagation(),t.stopPropagation&&t.stopPropagation(),t.preventDefault()),!1}function h(t){if(!(t.ctrlKey||t.metaKey||t.altKey||t.shiftKey||0!==t.button)){var e=t.target;do{if("A"===(e.nodeName+"").toUpperCase()&&e.getAttribute("href")){if(e.hasAttribute("native"))return;if(f(e))return s(t)}}while(e=e.parentNode)}}var d,v={},g=null,m=[],C=[],b={},U=!1,t=((d=p.Component)&&(k.__proto__=d),((k.prototype=Object.create(d&&d.prototype)).constructor=k).prototype.shouldComponentUpdate=function(t){return!0!==t.static||t.url!==this.props.url||t.onChange!==this.props.onChange},k.prototype.canRoute=function(t){return 0<this.getMatchingChildren(p.toChildArray(this.props.children),t,!1).length},k.prototype.routeTo=function(t){this.setState({url:t});var e=this.canRoute(t);return this.updating||this.forceUpdate(),e},k.prototype.componentWillMount=function(){m.push(this),this.updating=!0},k.prototype.componentDidMount=function(){var e=this;g&&(this.unlisten=g.listen(function(t){e.routeTo(""+(t.pathname||"")+(t.search||""))})),this.updating=!1},k.prototype.componentWillUnmount=function(){"function"==typeof this.unlisten&&this.unlisten(),m.splice(m.indexOf(this),1)},k.prototype.componentWillUpdate=function(){this.updating=!0},k.prototype.componentDidUpdate=function(){this.updating=!1},k.prototype.getMatchingChildren=function(t,r,o){return t.filter(n).sort(e).map(function(t){var e=u(r,t.props.path,t.props);if(e){if(!1===o)return t;var n={url:r,matches:e};return i(n,e),delete n.ref,delete n.key,p.cloneElement(t,n)}}).filter(Boolean)},k.prototype.render=function(t,e){var n=t.children,r=t.onChange,o=e.url,i=this.getMatchingChildren(p.toChildArray(n),o,!0),u=i[0]||null,a=this.previousUrl;return o!==a&&(this.previousUrl=o,"function"==typeof r&&r({router:this,url:o,previous:a,active:i,current:u})),u},k);function k(t){d.call(this,t),t.history&&(g=t.history),this.state={url:t.url||o()},U||("function"==typeof addEventListener&&(g||addEventListener("popstate",function(){c(o())}),addEventListener("click",h)),U=!0)}return t.subscribers=C,t.getCurrentUrl=o,t.route=a,(t.Router=t).Route=function(t){return p.createElement(t.component,t)},t.Link=function(t){return p.createElement("a",i({onClick:l},t))},t.exec=u,t});
-2
View File
@@ -1,2 +0,0 @@
!function(){var n,l,u,t,i,o,r,e,f={},c=[],a=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;function s(n,l){for(var u in l)n[u]=l[u];return n}function v(n){var l=n.parentNode;l&&l.removeChild(n)}function h(n,l,u){var t,i=arguments,o={};for(t in l)"key"!==t&&"ref"!==t&&(o[t]=l[t]);if(arguments.length>3)for(u=[u],t=3;t<arguments.length;t++)u.push(i[t]);if(null!=u&&(o.children=u),"function"==typeof n&&null!=n.defaultProps)for(t in n.defaultProps)void 0===o[t]&&(o[t]=n.defaultProps[t]);return y(n,o,l&&l.key,l&&l.ref,null)}function y(l,u,t,i,o){var r={type:l,props:u,key:t,ref:i,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,constructor:void 0,__v:o};return null==o&&(r.__v=r),n.vnode&&n.vnode(r),r}function p(n){return n.children}function d(n,l){this.props=n,this.context=l}function _(n,l){if(null==l)return n.__?_(n.__,n.__.__k.indexOf(n)+1):null;for(var u;l<n.__k.length;l++)if(null!=(u=n.__k[l])&&null!=u.__e)return u.__e;return"function"==typeof n.type?_(n):null}function m(n){var l,u;if(null!=(n=n.__)&&null!=n.__c){for(n.__e=n.__c.base=null,l=0;l<n.__k.length;l++)if(null!=(u=n.__k[l])&&null!=u.__e){n.__e=n.__c.base=u.__e;break}return m(n)}}function k(l){(!l.__d&&(l.__d=!0)&&u.push(l)&&!w.__r++||i!==n.debounceRendering)&&((i=n.debounceRendering)||t)(w)}function w(){for(var n;w.__r=u.length;)n=u.sort(function(n,l){return n.__v.__b-l.__v.__b}),u=[],n.some(function(n){var l,u,t,i,o,r,e;n.__d&&(r=(o=(l=n).__v).__e,(e=l.__P)&&(u=[],(t=s({},o)).__v=t,i=N(e,o,t,l.__n,void 0!==e.ownerSVGElement,null,u,null==r?_(o):r),z(u,o),i!=r&&m(o)))})}function g(n,l,u,t,i,o,r,e,a,s){var h,d,m,k,w,g,x,C=t&&t.__k||c,A=C.length;for(a==f&&(a=null!=r?r[0]:A?_(t,0):null),u.__k=[],h=0;h<l.length;h++)if(null!=(k=u.__k[h]=null==(k=l[h])||"boolean"==typeof k?null:"string"==typeof k||"number"==typeof k?y(null,k,null,null,k):Array.isArray(k)?y(p,{children:k},null,null,null):null!=k.__e||null!=k.__c?y(k.type,k.props,k.key,null,k.__v):k)){if(k.__=u,k.__b=u.__b+1,null===(m=C[h])||m&&k.key==m.key&&k.type===m.type)C[h]=void 0;else for(d=0;d<A;d++){if((m=C[d])&&k.key==m.key&&k.type===m.type){C[d]=void 0;break}m=null}w=N(n,k,m=m||f,i,o,r,e,a,s),(d=k.ref)&&m.ref!=d&&(x||(x=[]),m.ref&&x.push(m.ref,null,k),x.push(d,k.__c||w,k)),null!=w?(null==g&&(g=w),a=b(n,k,m,C,r,w,a),"option"==u.type?n.value="":"function"==typeof u.type&&(u.__d=a)):a&&m.__e==a&&a.parentNode!=n&&(a=_(m))}if(u.__e=g,null!=r&&"function"!=typeof u.type)for(h=r.length;h--;)null!=r[h]&&v(r[h]);for(h=A;h--;)null!=C[h]&&j(C[h],C[h]);if(x)for(h=0;h<x.length;h++)$(x[h],x[++h],x[++h])}function b(n,l,u,t,i,o,r){var e,f,c;if(void 0!==l.__d)e=l.__d,l.__d=void 0;else if(i==u||o!=r||null==o.parentNode)n:if(null==r||r.parentNode!==n)n.appendChild(o),e=null;else{for(f=r,c=0;(f=f.nextSibling)&&c<t.length;c+=2)if(f==o)break n;n.insertBefore(o,r),e=r}return void 0!==e?e:o.nextSibling}function x(n,l,u,t,i){var o;for(o in u)"children"===o||"key"===o||o in l||A(n,o,null,u[o],t);for(o in l)i&&"function"!=typeof l[o]||"children"===o||"key"===o||"value"===o||"checked"===o||u[o]===l[o]||A(n,o,l[o],u[o],t)}function C(n,l,u){"-"===l[0]?n.setProperty(l,u):n[l]="number"==typeof u&&!1===a.test(l)?u+"px":null==u?"":u}function A(n,l,u,t,i){var o,r,e,f,c;if(i?"className"===l&&(l="class"):"class"===l&&(l="className"),"style"===l)if(o=n.style,"string"==typeof u)o.cssText=u;else{if("string"==typeof t&&(o.cssText="",t=null),t)for(f in t)u&&f in u||C(o,f,"");if(u)for(c in u)t&&u[c]===t[c]||C(o,c,u[c])}else"o"===l[0]&&"n"===l[1]?(r=l!==(l=l.replace(/Capture$/,"")),e=l.toLowerCase(),l=(e in n?e:l).slice(2),u?(t||n.addEventListener(l,P,r),(n.l||(n.l={}))[l]=u):n.removeEventListener(l,P,r)):"list"!==l&&"tagName"!==l&&"form"!==l&&"type"!==l&&"size"!==l&&!i&&l in n?n[l]=null==u?"":u:"function"!=typeof u&&"dangerouslySetInnerHTML"!==l&&(l!==(l=l.replace(/^xlink:?/,""))?null==u||!1===u?n.removeAttributeNS("http://www.w3.org/1999/xlink",l.toLowerCase()):n.setAttributeNS("http://www.w3.org/1999/xlink",l.toLowerCase(),u):null==u||!1===u&&!/^ar/.test(l)?n.removeAttribute(l):n.setAttribute(l,u))}function P(l){this.l[l.type](n.event?n.event(l):l)}function E(n,l,u){var t,i;for(t=0;t<n.__k.length;t++)(i=n.__k[t])&&(i.__=n,i.__e&&("function"==typeof i.type&&i.__k.length>1&&E(i,l,u),l=b(u,i,i,n.__k,null,i.__e,l),"function"==typeof n.type&&(n.__d=l)))}function N(l,u,t,i,o,r,e,f,c){var a,v,h,y,_,m,k,w,b,x,C,A=u.type;if(void 0!==u.constructor)return null;(a=n.__b)&&a(u);try{n:if("function"==typeof A){if(w=u.props,b=(a=A.contextType)&&i[a.__c],x=a?b?b.props.value:a.__:i,t.__c?k=(v=u.__c=t.__c).__=v.__E:("prototype"in A&&A.prototype.render?u.__c=v=new A(w,x):(u.__c=v=new d(w,x),v.constructor=A,v.render=F),b&&b.sub(v),v.props=w,v.state||(v.state={}),v.context=x,v.__n=i,h=v.__d=!0,v.__h=[]),null==v.__s&&(v.__s=v.state),null!=A.getDerivedStateFromProps&&(v.__s==v.state&&(v.__s=s({},v.__s)),s(v.__s,A.getDerivedStateFromProps(w,v.__s))),y=v.props,_=v.state,h)null==A.getDerivedStateFromProps&&null!=v.componentWillMount&&v.componenLine truncated
//# sourceMappingURL=preact.min.js.map
-7
View File
@@ -1,7 +0,0 @@
html, body { margin: 0; padding: 0; height: 100%; }
select, input, label::before, textarea { outline: none; box-shadow:none !important; border: 1px solid #ccc !important; }
.btn:focus,.btn:active:focus,.btn.active:focus,
.btn.focus,.btn:active.focus,.btn.active.focus { outline: none; box-shadow:none !important; }
.dropdown.autoexpand:hover>.dropdown-menu { display: block; }
.pointer { cursor: pointer; }
.log { max-height: 10em; overflow: auto; height: 100%; }
-10
View File
@@ -1,10 +0,0 @@
PROG ?= example
all: $(PROG)
$(DEBUGGER) ./$(PROG)
$(PROG):
$(CC) ../../mongoose.c -I../.. $(CFLAGS) $(EXTRA) -o $(PROG) main.c mjson.c
clean:
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb log.txt
-82
View File
@@ -1,82 +0,0 @@
// Copyright (c) 2020 Cesanta Software Limited
// All rights reserved
#include "mjson.h" // JSON parsing and printing
#include "mongoose.h"
// This is a configuration structure we're going to show on a dashboard
static struct config {
int value1;
char *value2;
} s_config = {123, NULL};
// Stringifies the config. A caller must free() it.
static char *stringify_config(struct config *cfg) {
char *s = NULL;
mjson_printf(mjson_print_dynamic_buf, &s, "{%Q:%d,%Q:%Q}", "value1",
cfg->value1, "value2", cfg->value2);
return s;
}
// Update config structure. Return true if changed, false otherwise
static bool update_config(struct mg_http_message *hm, struct config *cfg) {
bool changed = false;
char buf[256];
double dv;
if (mjson_get_number(hm->body.ptr, hm->body.len, "$.value1", &dv)) {
s_config.value1 = dv;
changed = true;
}
if (mjson_get_string(hm->body.ptr, hm->body.len, "$.value2", buf,
sizeof(buf)) > 0) {
free(s_config.value2);
s_config.value2 = strdup(buf);
changed = true;
}
return changed;
}
// Notify all config watchers about the config change
static void notify_config_change(struct mg_mgr *mgr) {
struct mg_connection *c;
char *s = stringify_config(&s_config);
for (c = mgr->conns; c != NULL; c = c->next) {
if (c->label[0] == 'W') mg_http_printf_chunk(c, "%s\n", s);
}
free(s);
}
// HTTP request handler function. It implements the following endpoints:
// /api/config/get - returns current config
// /api/config/set - updates current config
// /api/config/watch - does not return. Sends config as it changes in
// chunks all other URI - serves web_root/ directory
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 = (struct mg_http_message *) ev_data;
if (mg_http_match_uri(hm, "/api/config/get")) {
char *s = stringify_config(&s_config);
mg_printf(c, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s\n",
(int) strlen(s) + 1, s);
free(s);
} else if (mg_http_match_uri(hm, "/api/config/set")) {
if (update_config(hm, &s_config)) notify_config_change(fn_data);
mg_printf(c, "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
} else if (mg_http_match_uri(hm, "/api/config/watch")) {
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");
} else {
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
mg_http_serve_dir(c, ev_data, &opts);
}
}
}
int main(void) {
struct mg_mgr mgr;
mg_mgr_init(&mgr);
mg_http_listen(&mgr, "http://localhost:8000", cb, &mgr);
for (;;) mg_mgr_poll(&mgr, 1000);
mg_mgr_free(&mgr);
return 0;
}
-981
View File
@@ -1,981 +0,0 @@
// Copyright (c) 2018-2020 Cesanta Software Limited
// All rights reserved
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "mjson.h"
#if !defined(_MSC_VER) || _MSC_VER >= 1700
#else
#define va_copy(x, y) (x) = (y)
#define snprintf _snprintf
#define alloca _alloca
#endif
static int mjson_esc(int c, int esc) {
const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\"";
for (p = esc ? esc1 : esc2; *p != '\0'; p++) {
if (*p == c) return esc ? esc2[p - esc1] : esc1[p - esc2];
}
return 0;
}
static int mjson_pass_string(const char *s, int len) {
int i;
for (i = 0; i < len; i++) {
if (s[i] == '\\' && i + 1 < len && mjson_esc(s[i + 1], 1)) {
i++;
} else if (s[i] == '\0') {
return MJSON_ERROR_INVALID_INPUT;
} else if (s[i] == '"') {
return i;
}
}
return MJSON_ERROR_INVALID_INPUT;
}
int mjson(const char *s, int len, mjson_cb_t cb, void *ud) {
enum { S_VALUE, S_KEY, S_COLON, S_COMMA_OR_EOO } expecting = S_VALUE;
unsigned char nesting[MJSON_MAX_DEPTH];
int i, depth = 0;
#define MJSONCALL(ev) \
if (cb != NULL && cb(ev, s, start, i - start + 1, ud)) return i + 1;
// In the ascii table, the distance between `[` and `]` is 2.
// Ditto for `{` and `}`. Hence +2 in the code below.
#define MJSONEOO() \
do { \
if (c != nesting[depth - 1] + 2) return MJSON_ERROR_INVALID_INPUT; \
depth--; \
if (depth == 0) { \
MJSONCALL(tok); \
return i + 1; \
} \
} while (0)
for (i = 0; i < len; i++) {
int start = i;
unsigned char c = ((unsigned char *) s)[i];
int tok = c;
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue;
// printf("- %c [%.*s] %d %d\n", c, i, s, depth, expecting);
switch (expecting) {
case S_VALUE:
if (c == '{') {
if (depth >= (int) sizeof(nesting)) return MJSON_ERROR_TOO_DEEP;
nesting[depth++] = c;
expecting = S_KEY;
break;
} else if (c == '[') {
if (depth >= (int) sizeof(nesting)) return MJSON_ERROR_TOO_DEEP;
nesting[depth++] = c;
break;
} else if (c == ']' && depth > 0) { // Empty array
MJSONEOO();
} else if (c == 't' && i + 3 < len && memcmp(&s[i], "true", 4) == 0) {
i += 3;
tok = MJSON_TOK_TRUE;
} else if (c == 'n' && i + 3 < len && memcmp(&s[i], "null", 4) == 0) {
i += 3;
tok = MJSON_TOK_NULL;
} else if (c == 'f' && i + 4 < len && memcmp(&s[i], "false", 5) == 0) {
i += 4;
tok = MJSON_TOK_FALSE;
} else if (c == '-' || ((c >= '0' && c <= '9'))) {
char *end = NULL;
strtod(&s[i], &end);
if (end != NULL) i += end - &s[i] - 1;
tok = MJSON_TOK_NUMBER;
} else if (c == '"') {
int n = mjson_pass_string(&s[i + 1], len - i - 1);
if (n < 0) return n;
i += n + 1;
tok = MJSON_TOK_STRING;
} else {
return MJSON_ERROR_INVALID_INPUT;
}
if (depth == 0) {
MJSONCALL(tok);
return i + 1;
}
expecting = S_COMMA_OR_EOO;
break;
case S_KEY:
if (c == '"') {
int n = mjson_pass_string(&s[i + 1], len - i - 1);
if (n < 0) return n;
i += n + 1;
tok = MJSON_TOK_KEY;
expecting = S_COLON;
} else if (c == '}') { // Empty object
MJSONEOO();
expecting = S_COMMA_OR_EOO;
} else {
return MJSON_ERROR_INVALID_INPUT;
}
break;
case S_COLON:
if (c == ':') {
expecting = S_VALUE;
} else {
return MJSON_ERROR_INVALID_INPUT;
}
break;
case S_COMMA_OR_EOO:
if (depth <= 0) return MJSON_ERROR_INVALID_INPUT;
if (c == ',') {
expecting = (nesting[depth - 1] == '{') ? S_KEY : S_VALUE;
} else if (c == ']' || c == '}') {
MJSONEOO();
} else {
return MJSON_ERROR_INVALID_INPUT;
}
break;
}
MJSONCALL(tok);
}
return MJSON_ERROR_INVALID_INPUT;
}
struct msjon_get_data {
const char *path; // Lookup json path
int pos; // Current path index
int d1; // Current depth of traversal
int d2; // Expected depth of traversal
int i1; // Index in an array
int i2; // Expected index in an array
int obj; // If the value is array/object, offset where it starts
const char **tokptr; // Destination
int *toklen; // Destination length
int tok; // Returned token
};
static int mjson_plen(const char *s) {
int i = 0;
while (s[i] != '\0' && s[i] != '.' && s[i] != '[') i++;
return i;
}
static int mjson_get_cb(int tok, const char *s, int off, int len, void *ud) {
struct msjon_get_data *data = (struct msjon_get_data *) ud;
// printf("--> %2x %2d %2d %2d %2d\t'%s'\t'%.*s'\t\t'%.*s'\n", tok, data->d1,
// data->d2, data->i1, data->i2, data->path + data->pos, off, s, len,
// s + off);
if (data->tok != MJSON_TOK_INVALID) return 1; // Found
if (tok == '{') {
if (!data->path[data->pos] && data->d1 == data->d2) data->obj = off;
data->d1++;
} else if (tok == '[') {
if (data->d1 == data->d2 && data->path[data->pos] == '[') {
data->i1 = 0;
data->i2 = (int) strtod(&data->path[data->pos + 1], NULL);
if (data->i1 == data->i2) {
data->d2++;
data->pos += 3;
}
}
if (!data->path[data->pos] && data->d1 == data->d2) data->obj = off;
data->d1++;
} else if (tok == ',') {
if (data->d1 == data->d2 + 1) {
data->i1++;
if (data->i1 == data->i2) {
while (data->path[data->pos] != ']') data->pos++;
data->pos++;
data->d2++;
}
}
} else if (tok == MJSON_TOK_KEY && data->d1 == data->d2 + 1 &&
data->path[data->pos] == '.' && s[off] == '"' &&
s[off + len - 1] == '"' &&
mjson_plen(&data->path[data->pos + 1]) == len - 2 &&
!memcmp(s + off + 1, &data->path[data->pos + 1], len - 2)) {
data->d2++;
data->pos += len - 1;
} else if (tok == MJSON_TOK_KEY && data->d1 == data->d2) {
return 1; // Exhausted path, not found
} else if (tok == '}' || tok == ']') {
data->d1--;
// data->d2--;
if (!data->path[data->pos] && data->d1 == data->d2 && data->obj != -1) {
data->tok = tok - 2;
if (data->tokptr) *data->tokptr = s + data->obj;
if (data->toklen) *data->toklen = off - data->obj + 1;
return 1;
}
} else if (MJSON_TOK_IS_VALUE(tok)) {
// printf("TOK --> %d\n", tok);
if (data->d1 == data->d2 && !data->path[data->pos]) {
data->tok = tok;
if (data->tokptr) *data->tokptr = s + off;
if (data->toklen) *data->toklen = len;
return 1;
}
}
return 0;
}
enum mjson_tok mjson_find(const char *s, int len, const char *jp,
const char **tokptr, int *toklen) {
struct msjon_get_data data = {jp, 1, 0, 0, 0,
0, -1, tokptr, toklen, MJSON_TOK_INVALID};
if (jp[0] != '$') return MJSON_TOK_INVALID;
if (mjson(s, len, mjson_get_cb, &data) < 0) return MJSON_TOK_INVALID;
return (enum mjson_tok) data.tok;
}
int mjson_get_number(const char *s, int len, const char *path, double *v) {
const char *p;
int tok, n;
if ((tok = mjson_find(s, len, path, &p, &n)) == MJSON_TOK_NUMBER) {
if (v != NULL) *v = strtod(p, NULL);
}
return tok == MJSON_TOK_NUMBER ? 1 : 0;
}
int mjson_get_bool(const char *s, int len, const char *path, int *v) {
int tok = mjson_find(s, len, path, NULL, NULL);
if (tok == MJSON_TOK_TRUE && v != NULL) *v = 1;
if (tok == MJSON_TOK_FALSE && v != NULL) *v = 0;
return tok == MJSON_TOK_TRUE || tok == MJSON_TOK_FALSE ? 1 : 0;
}
static int mjson_unescape(const char *s, int len, char *to, int n) {
int i, j;
for (i = 0, j = 0; i < len && j < n; i++, j++) {
if (s[i] == '\\' && i + 1 < len) {
int c = mjson_esc(s[i + 1], 0);
if (c == 0) return -1;
to[j] = c;
i++;
} else {
to[j] = s[i];
}
}
if (j >= n) return -1;
if (n > 0) to[j] = '\0';
return j;
}
int mjson_get_string(const char *s, int len, const char *path, char *to,
int n) {
const char *p;
int sz;
if (mjson_find(s, len, path, &p, &sz) != MJSON_TOK_STRING) return -1;
return mjson_unescape(p + 1, sz - 2, to, n);
}
int mjson_get_hex(const char *s, int len, const char *x, char *to, int n) {
const char *p;
int i, j, sz;
if (mjson_find(s, len, x, &p, &sz) != MJSON_TOK_STRING) return -1;
for (i = j = 0; i < sz - 3 && j < n; i += 2, j++) {
#define HEXTOI(x) (x >= '0' && x <= '9' ? x - '0' : x - 'W')
unsigned char a = *(const unsigned char *) (p + i + 1);
unsigned char b = *(const unsigned char *) (p + i + 2);
((unsigned char *) to)[j] = (HEXTOI(a) << 4) | HEXTOI(b);
}
if (j < n) to[j] = '\0';
return j;
}
#if MJSON_ENABLE_BASE64
static int mjson_base64rev(int c) {
if (c >= 'A' && c <= 'Z') {
return c - 'A';
} else if (c >= 'a' && c <= 'z') {
return c + 26 - 'a';
} else if (c >= '0' && c <= '9') {
return c + 52 - '0';
} else if (c == '+') {
return 62;
} else if (c == '/') {
return 63;
} else {
return 64;
}
}
int mjson_base64_dec(const char *src, int n, char *dst, int dlen) {
const char *end = src + n;
int len = 0;
while (src + 3 < end && len < dlen) {
int a = mjson_base64rev(src[0]), b = mjson_base64rev(src[1]),
c = mjson_base64rev(src[2]), d = mjson_base64rev(src[3]);
dst[len++] = (a << 2) | (b >> 4);
if (src[2] != '=' && len < dlen) {
dst[len++] = (b << 4) | (c >> 2);
if (src[3] != '=' && len < dlen) {
dst[len++] = (c << 6) | d;
}
}
src += 4;
}
if (len < dlen) dst[len] = '\0';
return len;
}
int mjson_get_base64(const char *s, int len, const char *path, char *to,
int n) {
const char *p;
int sz;
if (mjson_find(s, len, path, &p, &sz) != MJSON_TOK_STRING) return 0;
return mjson_base64_dec(p + 1, sz - 2, to, n);
}
#endif // MJSON_ENABLE_BASE64
#if MJSON_ENABLE_NEXT
struct nextdata {
int off, len, depth, t, vo, arrayindex;
int *koff, *klen, *voff, *vlen, *vtype;
};
static int next_cb(int tok, const char *s, int off, int len, void *ud) {
struct nextdata *d = (struct nextdata *) ud;
// int i;
switch (tok) {
case '{':
case '[':
if (d->depth == 0 && tok == '[') d->arrayindex = 0;
if (d->depth == 1 && off > d->off) {
d->vo = off;
d->t = tok == '{' ? MJSON_TOK_OBJECT : MJSON_TOK_ARRAY;
if (d->voff) *d->voff = off;
if (d->vtype) *d->vtype = d->t;
}
d->depth++;
break;
case '}':
case ']':
d->depth--;
if (d->depth == 1 && d->vo) {
d->len = off + len;
if (d->vlen) *d->vlen = d->len - d->vo;
if (d->arrayindex >= 0) {
if (d->koff) *d->koff = d->arrayindex; // koff holds array index
if (d->klen) *d->klen = 0; // klen holds 0
}
return 1;
}
if (d->depth == 1 && d->arrayindex >= 0) d->arrayindex++;
break;
case ',':
case ':':
break;
case MJSON_TOK_KEY:
if (d->depth == 1 && d->off < off) {
if (d->koff) *d->koff = off; // And report back to the user
if (d->klen) *d->klen = len; // If we have to
}
break;
default:
if (d->depth != 1) break;
// If we're iterating over the array
if (off > d->off) {
d->len = off + len;
if (d->vlen) *d->vlen = len; // value length
if (d->voff) *d->voff = off; // value offset
if (d->vtype) *d->vtype = tok; // value type
if (d->arrayindex >= 0) {
if (d->koff) *d->koff = d->arrayindex; // koff holds array index
if (d->klen) *d->klen = 0; // klen holds 0
}
return 1;
}
if (d->arrayindex >= 0) d->arrayindex++;
break;
}
(void) s;
return 0;
}
int mjson_next(const char *s, int n, int off, int *koff, int *klen, int *voff,
int *vlen, int *vtype) {
struct nextdata d = {off, 0, 0, 0, 0, -1, koff, klen, voff, vlen, vtype};
mjson(s, n, next_cb, &d);
return d.len;
}
#endif
#if MJSON_ENABLE_PRINT
int mjson_print_fixed_buf(const char *ptr, int len, void *fndata) {
struct mjson_fixedbuf *fb = (struct mjson_fixedbuf *) fndata;
int i, left = fb->size - 1 - fb->len;
if (left < len) len = left;
for (i = 0; i < len; i++) fb->ptr[fb->len + i] = ptr[i];
fb->len += len;
fb->ptr[fb->len] = '\0';
return len;
}
int mjson_print_dynamic_buf(const char *ptr, int len, void *fndata) {
char *s, *buf = *(char **) fndata;
int curlen = buf == NULL ? 0 : strlen(buf);
if ((s = (char *) realloc(buf, curlen + len + 1)) == NULL) {
return 0;
} else {
memcpy(s + curlen, ptr, len);
s[curlen + len] = '\0';
*(char **) fndata = s;
return len;
}
}
int mjson_print_null(const char *ptr, int len, void *userdata) {
(void) ptr;
(void) userdata;
return len;
}
int mjson_print_file(const char *ptr, int len, void *userdata) {
return fwrite(ptr, 1, len, (FILE *) userdata);
}
int mjson_print_buf(mjson_print_fn_t fn, void *fndata, const char *buf,
int len) {
return fn(buf, len, fndata);
}
int mjson_print_int(mjson_print_fn_t fn, void *fndata, int value,
int is_signed) {
char buf[20];
int len = snprintf(buf, sizeof(buf), is_signed ? "%d" : "%u", value);
return fn(buf, len, fndata);
}
int mjson_print_long(mjson_print_fn_t fn, void *fndata, long value,
int is_signed) {
char buf[20];
const char *fmt = (is_signed ? "%ld" : "%lu");
int len = snprintf(buf, sizeof(buf), fmt, value);
return fn(buf, len, fndata);
}
int mjson_print_dbl(mjson_print_fn_t fn, void *fndata, double d,
const char *fmt) {
char buf[40];
int n = snprintf(buf, sizeof(buf), fmt, d);
return fn(buf, n, fndata);
}
int mjson_print_str(mjson_print_fn_t fn, void *fndata, const char *s, int len) {
int i, n = fn("\"", 1, fndata);
for (i = 0; i < len; i++) {
char c = mjson_esc(s[i], 1);
if (c) {
n += fn("\\", 1, fndata);
n += fn(&c, 1, fndata);
} else {
n += fn(&s[i], 1, fndata);
}
}
return n + fn("\"", 1, fndata);
}
#if MJSON_ENABLE_BASE64
int mjson_print_b64(mjson_print_fn_t fn, void *fndata, const unsigned char *s,
int n) {
const char *t =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int i, len = fn("\"", 1, fndata);
for (i = 0; i < n; i += 3) {
int a = s[i], b = i + 1 < n ? s[i + 1] : 0, c = i + 2 < n ? s[i + 2] : 0;
char buf[4] = {t[a >> 2], t[(a & 3) << 4 | (b >> 4)], '=', '='};
if (i + 1 < n) buf[2] = t[(b & 15) << 2 | (c >> 6)];
if (i + 2 < n) buf[3] = t[c & 63];
len += fn(buf, sizeof(buf), fndata);
}
return len + fn("\"", 1, fndata);
}
#endif /* MJSON_ENABLE_BASE64 */
int mjson_vprintf(mjson_print_fn_t fn, void *fndata, const char *fmt,
va_list xap) {
int i = 0, n = 0;
va_list ap;
va_copy(ap, xap);
while (fmt[i] != '\0') {
if (fmt[i] == '%') {
char fc = fmt[++i];
int is_long = 0;
if (fc == 'l') {
is_long = 1;
fc = fmt[i + 1];
}
if (fc == 'Q') {
char *buf = va_arg(ap, char *);
n += mjson_print_str(fn, fndata, buf ? buf : "", buf ? strlen(buf) : 0);
} else if (strncmp(&fmt[i], ".*Q", 3) == 0) {
int len = va_arg(ap, int);
char *buf = va_arg(ap, char *);
n += mjson_print_str(fn, fndata, buf, len);
i += 2;
} else if (fc == 'd' || fc == 'u') {
int is_signed = (fc == 'd');
if (is_long) {
long val = va_arg(ap, long);
n += mjson_print_long(fn, fndata, val, is_signed);
i++;
} else {
int val = va_arg(ap, int);
n += mjson_print_int(fn, fndata, val, is_signed);
}
} else if (fc == 'B') {
const char *s = va_arg(ap, int) ? "true" : "false";
n += mjson_print_buf(fn, fndata, s, strlen(s));
} else if (fc == 's') {
char *buf = va_arg(ap, char *);
n += mjson_print_buf(fn, fndata, buf, strlen(buf));
} else if (strncmp(&fmt[i], ".*s", 3) == 0) {
int len = va_arg(ap, int);
char *buf = va_arg(ap, char *);
n += mjson_print_buf(fn, fndata, buf, len);
i += 2;
} else if (fc == 'g') {
n += mjson_print_dbl(fn, fndata, va_arg(ap, double), "%g");
} else if (fc == 'f') {
n += mjson_print_dbl(fn, fndata, va_arg(ap, double), "%f");
#if MJSON_ENABLE_BASE64
} else if (fc == 'V') {
int len = va_arg(ap, int);
const char *buf = va_arg(ap, const char *);
n += mjson_print_b64(fn, fndata, (unsigned char *) buf, len);
#endif
} else if (fc == 'H') {
const char *hex = "0123456789abcdef";
int i, len = va_arg(ap, int);
const unsigned char *p = va_arg(ap, const unsigned char *);
n += fn("\"", 1, fndata);
for (i = 0; i < len; i++) {
n += fn(&hex[(p[i] >> 4) & 15], 1, fndata);
n += fn(&hex[p[i] & 15], 1, fndata);
}
n += fn("\"", 1, fndata);
} else if (fc == 'M') {
mjson_vprint_fn_t vfn = va_arg(ap, mjson_vprint_fn_t);
n += vfn(fn, fndata, &ap);
}
i++;
} else {
n += mjson_print_buf(fn, fndata, &fmt[i++], 1);
}
}
va_end(xap);
va_end(ap);
return n;
}
int mjson_printf(mjson_print_fn_t fn, void *fndata, const char *fmt, ...) {
va_list ap;
int len;
va_start(ap, fmt);
len = mjson_vprintf(fn, fndata, fmt, ap);
va_end(ap);
return len;
}
#endif /* MJSON_ENABLE_PRINT */
#if MJSON_IMPLEMENT_STRTOD
static inline int is_digit(int c) {
return c >= '0' && c <= '9';
}
/* NOTE: strtod() implementation by Yasuhiro Matsumoto. */
double strtod(const char *str, char **end) {
double d = 0.0;
int sign = 1, n = 0;
const char *p = str, *a = str;
/* decimal part */
if (*p == '-') {
sign = -1;
++p;
} else if (*p == '+')
++p;
if (is_digit(*p)) {
d = (double) (*p++ - '0');
while (*p && is_digit(*p)) {
d = d * 10.0 + (double) (*p - '0');
++p;
++n;
}
a = p;
} else if (*p != '.')
goto done;
d *= sign;
/* fraction part */
if (*p == '.') {
double f = 0.0;
double base = 0.1;
++p;
if (is_digit(*p)) {
while (*p && is_digit(*p)) {
f += base * (*p - '0');
base /= 10.0;
++p;
++n;
}
}
d += f * sign;
a = p;
}
/* exponential part */
if ((*p == 'E') || (*p == 'e')) {
int e = 0;
++p;
sign = 1;
if (*p == '-') {
sign = -1;
++p;
} else if (*p == '+')
++p;
if (is_digit(*p)) {
while (*p == '0') ++p;
e = (int) (*p++ - '0');
while (*p && is_digit(*p)) {
e = e * 10 + (int) (*p - '0');
++p;
}
e *= sign;
} else if (!is_digit(*(a - 1))) {
a = str;
goto done;
} else if (*p == 0)
goto done;
if (d == 2.2250738585072011 && e == -308) {
d = 0.0;
a = p;
goto done;
}
if (d == 2.2250738585072012 && e <= -308) {
d *= 1.0e-308;
a = p;
goto done;
}
{
int i;
for (i = 0; i < 10; i++) d *= 10;
}
a = p;
} else if (p > str && !is_digit(*(p - 1))) {
a = str;
goto done;
}
done:
if (end) *end = (char *) a;
return d;
}
#endif
#if MJSON_ENABLE_MERGE
int mjson_merge(const char *s, int n, const char *s2, int n2,
mjson_print_fn_t fn, void *userdata) {
int koff, klen, voff, vlen, t, t2, k, off = 0, len = 0, comma = 0;
if (n < 2) return len;
len += fn("{", 1, userdata);
while ((off = mjson_next(s, n, off, &koff, &klen, &voff, &vlen, &t)) != 0) {
#if !defined(_MSC_VER) || _MSC_VER >= 1700
char path[klen + 1];
#else
char *path = (char *) alloca(klen + 1);
#endif
const char *val;
memcpy(path, "$.", 2);
memcpy(path + 2, s + koff + 1, klen - 2);
path[klen] = '\0';
if ((t2 = mjson_find(s2, n2, path, &val, &k)) != MJSON_TOK_INVALID) {
if (t2 == MJSON_TOK_NULL) continue; // null deletes the key
} else {
val = s + voff; // Key is not found in the update. Copy the old value.
}
if (comma) len += fn(",", 1, userdata);
len += fn(s + koff, klen, userdata);
len += fn(":", 1, userdata);
if (t == MJSON_TOK_OBJECT && t2 == MJSON_TOK_OBJECT) {
len += mjson_merge(s + voff, vlen, val, k, fn, userdata);
} else {
if (t2 != MJSON_TOK_INVALID) vlen = k;
len += fn(val, vlen, userdata);
}
comma = 1;
}
// Add missing keys
off = 0;
while ((off = mjson_next(s2, n2, off, &koff, &klen, &voff, &vlen, &t)) != 0) {
#if !defined(_MSC_VER) || _MSC_VER >= 1700
char path[klen + 1];
#else
char *path = (char *) alloca(klen + 1);
#endif
const char *val;
if (t == MJSON_TOK_NULL) continue;
memcpy(path, "$.", 2);
memcpy(path + 2, s2 + koff + 1, klen - 2);
path[klen] = '\0';
if (mjson_find(s, n, path, &val, &vlen) != MJSON_TOK_INVALID) continue;
if (comma) len += fn(",", 1, userdata);
len += fn(s2 + koff, klen, userdata);
len += fn(":", 1, userdata);
len += fn(s2 + voff, vlen, userdata);
comma = 1;
}
len += fn("}", 1, userdata);
return len;
}
#endif // MJSON_ENABLE_MERGE
#if MJSON_ENABLE_PRETTY
struct prettydata {
int level;
int len;
int prev;
const char *pad;
int padlen;
mjson_print_fn_t fn;
void *userdata;
};
static int pretty_cb(int ev, const char *s, int off, int len, void *ud) {
struct prettydata *d = (struct prettydata *) ud;
int i;
switch (ev) {
case '{':
case '[':
d->level++;
d->len += d->fn(s + off, len, d->userdata);
break;
case '}':
case ']':
d->level--;
if (d->prev != '[' && d->prev != '{' && d->padlen > 0) {
d->len += d->fn("\n", 1, d->userdata);
for (i = 0; i < d->level; i++)
d->len += d->fn(d->pad, d->padlen, d->userdata);
}
d->len += d->fn(s + off, len, d->userdata);
break;
case ',':
d->len += d->fn(s + off, len, d->userdata);
if (d->padlen > 0) {
d->len += d->fn("\n", 1, d->userdata);
for (i = 0; i < d->level; i++)
d->len += d->fn(d->pad, d->padlen, d->userdata);
}
break;
case ':':
d->len += d->fn(s + off, len, d->userdata);
if (d->padlen > 0) d->len += d->fn(" ", 1, d->userdata);
break;
case MJSON_TOK_KEY:
if (d->prev == '{' && d->padlen > 0) {
d->len += d->fn("\n", 1, d->userdata);
for (i = 0; i < d->level; i++)
d->len += d->fn(d->pad, d->padlen, d->userdata);
}
d->len += d->fn(s + off, len, d->userdata);
break;
default:
if (d->prev == '[' && d->padlen > 0) {
d->len += d->fn("\n", 1, d->userdata);
for (i = 0; i < d->level; i++)
d->len += d->fn(d->pad, d->padlen, d->userdata);
}
d->len += d->fn(s + off, len, d->userdata);
break;
}
d->prev = ev;
return 0;
}
int mjson_pretty(const char *s, int n, const char *pad, mjson_print_fn_t fn,
void *userdata) {
struct prettydata d = {0, 0, 0, pad, strlen(pad), fn, userdata};
if (mjson(s, n, pretty_cb, &d) < 0) return -1;
return d.len;
}
#endif // MJSON_ENABLE_PRETTY
#if MJSON_ENABLE_RPC
struct jsonrpc_ctx jsonrpc_default_context;
struct jsonrpc_userdata {
mjson_print_fn_t fn;
void *fndata;
};
int mjson_globmatch(const char *s1, int n1, const char *s2, int n2) {
int i = 0, j = 0, ni = 0, nj = 0;
while (i < n1 || j < n2) {
if (i < n1 && j < n2 && (s1[i] == '?' || s2[j] == s1[i])) {
i++, j++;
} else if (i < n1 && (s1[i] == '*' || s1[i] == '#')) {
ni = i, nj = j + 1, i++;
} else if (nj > 0 && nj <= n2 && (s1[i - 1] == '#' || s2[j] != '/')) {
i = ni, j = nj;
} else {
return 0;
}
}
return 1;
}
static int jsonrpc_printer(const char *buf, int len, void *userdata) {
struct jsonrpc_userdata *u = (struct jsonrpc_userdata *) userdata;
return u->fn(buf, len, u->fndata);
}
void jsonrpc_return_errorv(struct jsonrpc_request *r, int code,
const char *message, const char *data_fmt,
va_list ap) {
if (r->id_len == 0) return;
mjson_printf(r->fn, r->fndata,
"{\"id\":%.*s,\"error\":{\"code\":%d,\"message\":%Q", r->id_len,
r->id, code, message == NULL ? "" : message);
if (data_fmt != NULL) {
mjson_printf(r->fn, r->fndata, ",\"data\":");
mjson_vprintf(r->fn, r->fndata, data_fmt, ap);
}
mjson_printf(r->fn, r->fndata, "}}\n");
}
void jsonrpc_return_error(struct jsonrpc_request *r, int code,
const char *message, const char *data_fmt, ...) {
va_list ap;
va_start(ap, data_fmt);
jsonrpc_return_errorv(r, code, message, data_fmt, ap);
va_end(ap);
}
void jsonrpc_return_successv(struct jsonrpc_request *r, const char *result_fmt,
va_list ap) {
if (r->id_len == 0) return;
mjson_printf(r->fn, r->fndata, "{\"id\":%.*s,\"result\":", r->id_len, r->id);
if (result_fmt != NULL) {
mjson_vprintf(r->fn, r->fndata, result_fmt, ap);
} else {
mjson_printf(r->fn, r->fndata, "%s", "null");
}
mjson_printf(r->fn, r->fndata, "}\n");
}
void jsonrpc_return_success(struct jsonrpc_request *r, const char *result_fmt,
...) {
va_list ap;
va_start(ap, result_fmt);
jsonrpc_return_successv(r, result_fmt, ap);
va_end(ap);
}
void jsonrpc_ctx_process(struct jsonrpc_ctx *ctx, const char *req, int req_sz,
mjson_print_fn_t fn, void *fndata) {
const char *result = NULL, *error = NULL;
int result_sz = 0, error_sz = 0;
struct jsonrpc_method *m = NULL;
struct jsonrpc_userdata d;
struct jsonrpc_request r = {req, req_sz, 0, 0, 0, 0, 0,
0, &jsonrpc_printer, NULL, NULL};
d.fn = fn;
d.fndata = fndata;
r.fndata = &d;
// Is is a response frame?
mjson_find(req, req_sz, "$.result", &result, &result_sz);
if (result == NULL) mjson_find(req, req_sz, "$.error", &error, &error_sz);
if (result_sz > 0 || error_sz > 0) {
if (ctx->response_cb != NULL) ctx->response_cb(req, req_sz, ctx->userdata);
return;
}
// Method must exist and must be a string
if (mjson_find(req, req_sz, "$.method", &r.method, &r.method_len) !=
MJSON_TOK_STRING) {
mjson_printf(fn, fndata, "{\"error\":{\"code\":-32700,\"message\":%.*Q}}\n",
req_sz, req);
ctx->in_len = 0;
return;
}
// id and params are optional
mjson_find(req, req_sz, "$.id", &r.id, &r.id_len);
mjson_find(req, req_sz, "$.params", &r.params, &r.params_len);
for (m = ctx->methods; m != NULL; m = m->next) {
if (mjson_globmatch(m->method, m->method_sz, r.method + 1,
r.method_len - 2) > 0) {
if (r.params == NULL) r.params = "";
r.userdata = m->cbdata;
m->cb(&r);
break;
}
}
if (m == NULL) {
jsonrpc_return_error(&r, JSONRPC_ERROR_NOT_FOUND, "method not found", NULL);
}
}
static int jsonrpc_print_methods(mjson_print_fn_t fn, void *fndata,
va_list *ap) {
struct jsonrpc_ctx *ctx = va_arg(*ap, struct jsonrpc_ctx *);
struct jsonrpc_method *m;
int len = 0;
for (m = ctx->methods; m != NULL; m = m->next) {
if (m != ctx->methods) len += mjson_print_buf(fn, fndata, ",", 1);
len += mjson_print_str(fn, fndata, m->method, strlen(m->method));
}
return len;
}
static void rpclist(struct jsonrpc_request *r) {
jsonrpc_return_success(r, "[%M]", jsonrpc_print_methods, r->userdata);
}
void jsonrpc_ctx_init(struct jsonrpc_ctx *ctx, mjson_print_fn_t response_cb,
void *userdata) {
ctx->response_cb = response_cb;
ctx->userdata = userdata;
jsonrpc_ctx_export(ctx, MJSON_RPC_LIST_NAME, rpclist, ctx);
}
void jsonrpc_ctx_process_byte(struct jsonrpc_ctx *ctx, unsigned char ch,
mjson_print_fn_t fn, void *p) {
if (ctx->in_len >= (int) sizeof(ctx->in)) ctx->in_len = 0; // Overflow
if (ch == '\n') { // If new line, parse frame
if (ctx->in_len > 1) jsonrpc_ctx_process(ctx, ctx->in, ctx->in_len, fn, p);
ctx->in_len = 0;
} else {
ctx->in[ctx->in_len] = ch; // Append to the buffer
ctx->in_len++;
}
}
void jsonrpc_init(mjson_print_fn_t response_cb, void *userdata) {
jsonrpc_ctx_init(&jsonrpc_default_context, response_cb, userdata);
}
#endif // MJSON_ENABLE_RPC
-220
View File
@@ -1,220 +0,0 @@
// Copyright (c) 2018-2020 Cesanta Software Limited
// All rights reserved
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef MJSON_H
#define MJSON_H
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef MJSON_ENABLE_PRINT
#define MJSON_ENABLE_PRINT 1
#endif
#ifndef MJSON_ENABLE_RPC
#define MJSON_ENABLE_RPC 1
#endif
#ifndef MJSON_ENABLE_BASE64
#define MJSON_ENABLE_BASE64 1
#endif
#ifndef MJSON_ENABLE_MERGE
#define MJSON_ENABLE_MERGE 0
#elif MJSON_ENABLE_MERGE
#define MJSON_ENABLE_NEXT 1
#endif
#ifndef MJSON_ENABLE_PRETTY
#define MJSON_ENABLE_PRETTY 0
#elif MJSON_ENABLE_PRETTY
#define MJSON_ENABLE_NEXT 1
#endif
#ifndef MJSON_ENABLE_NEXT
#define MJSON_ENABLE_NEXT 0
#endif
#ifndef MJSON_RPC_IN_BUF_SIZE
#define MJSON_RPC_IN_BUF_SIZE 256
#endif
#ifndef MJSON_RPC_LIST_NAME
#define MJSON_RPC_LIST_NAME "rpc.list"
#endif
#ifdef __cplusplus
extern "C" {
#endif
enum {
MJSON_ERROR_INVALID_INPUT = -1,
MJSON_ERROR_TOO_DEEP = -2,
};
enum mjson_tok {
MJSON_TOK_INVALID = 0,
MJSON_TOK_KEY = 1,
MJSON_TOK_STRING = 11,
MJSON_TOK_NUMBER = 12,
MJSON_TOK_TRUE = 13,
MJSON_TOK_FALSE = 14,
MJSON_TOK_NULL = 15,
MJSON_TOK_ARRAY = 91,
MJSON_TOK_OBJECT = 123,
};
#define MJSON_TOK_IS_VALUE(t) ((t) > 10 && (t) < 20)
typedef int (*mjson_cb_t)(int ev, const char *s, int off, int len, void *ud);
#ifndef MJSON_MAX_DEPTH
#define MJSON_MAX_DEPTH 20
#endif
int mjson(const char *s, int len, mjson_cb_t cb, void *ud);
enum mjson_tok mjson_find(const char *s, int len, const char *jp,
const char **tokptr, int *toklen);
int mjson_get_number(const char *s, int len, const char *path, double *v);
int mjson_get_bool(const char *s, int len, const char *path, int *v);
int mjson_get_string(const char *s, int len, const char *path, char *to, int n);
int mjson_get_hex(const char *s, int len, const char *path, char *to, int n);
#if MJSON_ENABLE_NEXT
int mjson_next(const char *s, int n, int off, int *koff, int *klen, int *voff,
int *vlen, int *vtype);
#endif
#if MJSON_ENABLE_BASE64
int mjson_get_base64(const char *s, int len, const char *path, char *to, int n);
int mjson_base64_dec(const char *src, int n, char *dst, int dlen);
#endif
#if MJSON_ENABLE_PRINT
typedef int (*mjson_print_fn_t)(const char *buf, int len, void *userdata);
typedef int (*mjson_vprint_fn_t)(mjson_print_fn_t, void *, va_list *);
struct mjson_fixedbuf {
char *ptr;
int size, len;
};
int mjson_printf(mjson_print_fn_t, void *, const char *fmt, ...);
int mjson_vprintf(mjson_print_fn_t, void *, const char *fmt, va_list ap);
int mjson_print_str(mjson_print_fn_t, void *, const char *s, int len);
int mjson_print_int(mjson_print_fn_t, void *, int value, int is_signed);
int mjson_print_long(mjson_print_fn_t, void *, long value, int is_signed);
int mjson_print_buf(mjson_print_fn_t fn, void *, const char *buf, int len);
int mjson_print_null(const char *ptr, int len, void *userdata);
int mjson_print_file(const char *ptr, int len, void *userdata);
int mjson_print_fixed_buf(const char *ptr, int len, void *userdata);
int mjson_print_dynamic_buf(const char *ptr, int len, void *userdata);
#if MJSON_ENABLE_PRETTY
int mjson_pretty(const char *, int, const char *, mjson_print_fn_t, void *);
#endif
#if MJSON_ENABLE_MERGE
int mjson_merge(const char *, int, const char *, int, mjson_print_fn_t, void *);
#endif
#endif // MJSON_ENABLE_PRINT
#if MJSON_ENABLE_RPC
void jsonrpc_init(mjson_print_fn_t, void *userdata);
int mjson_globmatch(const char *s1, int n1, const char *s2, int n2);
struct jsonrpc_request {
const char *frame; // Points to the whole frame
int frame_len; // Frame length
const char *params; // Points to the "params" in the request frame
int params_len; // Length of the "params"
const char *id; // Points to the "id" in the request frame
int id_len; // Length of the "id"
const char *method; // Points to the "method" in the request frame
int method_len; // Length of the "method"
mjson_print_fn_t fn; // Printer function
void *fndata; // Printer function data
void *userdata; // Callback's user data as specified at export time
};
struct jsonrpc_method {
const char *method;
int method_sz;
void (*cb)(struct jsonrpc_request *);
void *cbdata;
struct jsonrpc_method *next;
};
// Main RPC context, stores current request information and a list of
// exported RPC methods.
struct jsonrpc_ctx {
struct jsonrpc_method *methods;
void *userdata;
mjson_print_fn_t response_cb;
int in_len;
char in[MJSON_RPC_IN_BUF_SIZE];
};
// Registers function fn under the given name within the given RPC context
#define jsonrpc_ctx_export(ctx, name, fn, ud) \
do { \
static struct jsonrpc_method m = {(name), sizeof(name) - 1, (fn), 0, 0}; \
m.cbdata = (ud); \
m.next = (ctx)->methods; \
(ctx)->methods = &m; \
} while (0)
void jsonrpc_ctx_init(struct jsonrpc_ctx *ctx, mjson_print_fn_t, void *);
void jsonrpc_return_error(struct jsonrpc_request *r, int code,
const char *message, const char *data_fmt, ...);
void jsonrpc_return_success(struct jsonrpc_request *r, const char *result_fmt,
...);
void jsonrpc_ctx_process(struct jsonrpc_ctx *ctx, const char *req, int req_sz,
mjson_print_fn_t fn, void *fndata);
void jsonrpc_ctx_process_byte(struct jsonrpc_ctx *ctx, unsigned char ch,
mjson_print_fn_t fn, void *fndata);
extern struct jsonrpc_ctx jsonrpc_default_context;
#define jsonrpc_export(name, fn, ud) \
jsonrpc_ctx_export(&jsonrpc_default_context, (name), (fn), (ud))
#define jsonrpc_process(buf, len, fn, data) \
jsonrpc_ctx_process(&jsonrpc_default_context, (buf), (len), (fn), (data))
#define jsonrpc_process_byte(x, fn, data) \
jsonrpc_ctx_process_byte(&jsonrpc_default_context, (x), (fn), (data))
#define JSONRPC_ERROR_INVALID -32700 /* Invalid JSON was received */
#define JSONRPC_ERROR_NOT_FOUND -32601 /* The method does not exist */
#define JSONRPC_ERROR_BAD_PARAMS -32602 /* Invalid params passed */
#define JSONRPC_ERROR_INTERNAL -32603 /* Internal JSON-RPC error */
#endif // MJSON_ENABLE_RPC
#ifdef __cplusplus
}
#endif
#endif // MJSON_H
-76
View File
@@ -1,76 +0,0 @@
const {h, render, Component} = preact;
const html = htm.bind(h);
const Info = () => html`<div id="info">
This dashboard shows values kept in server memory. Many clients
can open this page. As soon as any client changes any value,
all clients update automatically.
<br/><br/>
The JS code that watches state changes, reconnects on network failures.
That means if server restarts, dashboard on all connected clients
refresh automatically.
<br/><br/>
You can use <code>curl</code> command-line utility:
<br/><code>curl localhost:8000/api/config/get</code>
<br/><code>curl localhost:8000/api/config/watch</code>
<br/><code>curl localhost:8000/api/config/set -d '{"a":123}'</code>
</div>`;
class Dashboard extends Component {
state = {value1: null, value2: null};
componentDidMount() {
axios.get('/api/config/get')
.then(r => this.setState(r.data))
.catch(e => console.log(e));
var self = this;
var f = function(reader) {
return reader.read().then(function(result) {
var data = String.fromCharCode.apply(null, result.value);
self.setState(JSON.parse(data));
// console.log(JSON.parse(data));
if (!result.done) return f(reader);
});
};
fetch('/api/config/watch')
.then(r => r.body.getReader())
.then(f)
.catch(e => setTimeout(x => self.componentDidMount(), 1000));
}
render(props, state) {
return html
`<div id="dashboard" style="display: flex; justify-content: flex-evenly;">
<div style="width:50%;text-align:center;">Value 1 (number):
<div style="font-size:140%;"><b>${state.value1}</b></div></div>
<div style="width:50%;text-align:center;">Value 2 (string):
<div style="font-size:140%;"><b>${state.value2}</b></div></div>
</div>`
}
};
class Form extends Component {
render(props, state) {
const onclick = ev => axios.post(
'/api/config/set', {value1: +state.value1, value2: state.value2});
// alert(JSON.stringify(state));
return html`<div id="form">
<div><b>Change values</b></div>
<table>
<tr><td>Value 1 (number):</td><td><input value=${state.value1}
onInput=${linkState(this, 'value1')} /></td></tr>
<tr><td>Value 2 (string):</td><td><input value=${state.value2}
onInput=${linkState(this, 'value2')}/></td></tr>
<tr><td></td>
<td><button onClick=${onclick}>Save values</button></td></tr>
</table>
</div>`
}
};
const App = () => html`<div id="container">
<${Info} />
<${Dashboard} />
<${Form} />
</div>`;
window.onload = () => render(h(App), document.body);
-3
View File
@@ -1,3 +0,0 @@
/* 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(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
//# sourceMappingURL=axios.min.map
-1
View File
@@ -1 +0,0 @@
!function(){function n(n){var t=e.get(this);return t||(t=new Map,e.set(this,t)),1<(t=a(this,t.get(n)||(t.set(n,t=function(n){function t(n){1===u&&(n||(r=r.replace(/^\s*\n\s*|\s*\n\s*$/g,"")))?p.push(0,n,r):3===u&&(n||r)?(p.push(3,n,r),u=2):2===u&&"..."===r&&n?p.push(4,n,0):2===u&&r&&!n?p.push(5,0,!0,r):5<=u&&((r||!n&&5===u)&&(p.push(u,0,r,s),u=6),n&&(p.push(u,n,0,s),u=6)),r=""}for(var e,s,u=1,r="",h="",p=[0],a=0;a<n.length;a++){a&&(1===u&&t(),t(a));for(var o=0;o<n[a].length;o++)e=n[a][o],1===u?"<"===e?(t(),p=[p],u=3):r+=e:4===u?r="--"===r&&">"===e?(u=1,""):e+r[0]:h?e===h?h="":r+=e:'"'===e||"'"===e?h=e:">"===e?(t(),u=1):u&&("="===e?(u=5,s=r,r=""):"/"===e&&(u<5||">"===n[a][o+1])?(t(),3===u&&(p=p[0]),(p=(u=p)[0]).push(2,0,u),u=0):" "===e||"\t"===e||"\n"===e||"\r"===e?(t(),u=2):r+=e),3===u&&"!--"===r&&(u=4,p=p[0])}return t(),p}(n)),t),arguments,[])).length?t:t[0]}var a=function(n,t,e,s){var u;t[0]=0;for(var r=1;r<t.length;r++){var h=t[r++],p=t[r]?(t[0]|=h?1:2,e[t[r++]]):t[++r];3===h?s[0]=p:4===h?s[1]=Object.assign(s[1]||{},p):5===h?(s[1]=s[1]||{})[t[++r]]=p:6===h?s[1][t[++r]]+=p+"":h?(u=n.apply(p,a(n,p,e,["",null])),s.push(u),p[0]?t[0]|=2:(t[r-2]=0,t[r]=u)):s.push(p)}return s},e=new Map;"undefined"!=typeof module?module.exports=n:self.htm=n}();
-18
View File
@@ -1,18 +0,0 @@
function linkState(component, key, eventPath) {
let path = key.split('.'), cache = component.__lsc || (component.__lsc = {});
return cache[key + eventPath] || (cache[key + eventPath] = function(e) {
let t = e && e.target || this, state = {}, obj = state,
v = typeof eventPath === 'string' ?
delve(e, eventPath) :
t.nodeName ? (t.type.match(/^che|rad/) ? t.checked : t.value) :
e,
i = 0;
for (; i < path.length - 1; i++) {
obj = obj[path[i]] ||
(obj[path[i]] = !i && component.state[path[i]] || {});
}
obj[path[i]] = v;
component.setState(state);
});
}
-2
View File
@@ -1,2 +0,0 @@
!function(){var n,l,u,t,i,o,r,e,f={},c=[],a=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;function s(n,l){for(var u in l)n[u]=l[u];return n}function v(n){var l=n.parentNode;l&&l.removeChild(n)}function h(n,l,u){var t,i=arguments,o={};for(t in l)"key"!==t&&"ref"!==t&&(o[t]=l[t]);if(arguments.length>3)for(u=[u],t=3;t<arguments.length;t++)u.push(i[t]);if(null!=u&&(o.children=u),"function"==typeof n&&null!=n.defaultProps)for(t in n.defaultProps)void 0===o[t]&&(o[t]=n.defaultProps[t]);return y(n,o,l&&l.key,l&&l.ref,null)}function y(l,u,t,i,o){var r={type:l,props:u,key:t,ref:i,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,constructor:void 0,__v:o};return null==o&&(r.__v=r),n.vnode&&n.vnode(r),r}function p(n){return n.children}function d(n,l){this.props=n,this.context=l}function _(n,l){if(null==l)return n.__?_(n.__,n.__.__k.indexOf(n)+1):null;for(var u;l<n.__k.length;l++)if(null!=(u=n.__k[l])&&null!=u.__e)return u.__e;return"function"==typeof n.type?_(n):null}function m(n){var l,u;if(null!=(n=n.__)&&null!=n.__c){for(n.__e=n.__c.base=null,l=0;l<n.__k.length;l++)if(null!=(u=n.__k[l])&&null!=u.__e){n.__e=n.__c.base=u.__e;break}return m(n)}}function k(l){(!l.__d&&(l.__d=!0)&&u.push(l)&&!w.__r++||i!==n.debounceRendering)&&((i=n.debounceRendering)||t)(w)}function w(){for(var n;w.__r=u.length;)n=u.sort(function(n,l){return n.__v.__b-l.__v.__b}),u=[],n.some(function(n){var l,u,t,i,o,r,e;n.__d&&(r=(o=(l=n).__v).__e,(e=l.__P)&&(u=[],(t=s({},o)).__v=t,i=N(e,o,t,l.__n,void 0!==e.ownerSVGElement,null,u,null==r?_(o):r),z(u,o),i!=r&&m(o)))})}function g(n,l,u,t,i,o,r,e,a,s){var h,d,m,k,w,g,x,C=t&&t.__k||c,A=C.length;for(a==f&&(a=null!=r?r[0]:A?_(t,0):null),u.__k=[],h=0;h<l.length;h++)if(null!=(k=u.__k[h]=null==(k=l[h])||"boolean"==typeof k?null:"string"==typeof k||"number"==typeof k?y(null,k,null,null,k):Array.isArray(k)?y(p,{children:k},null,null,null):null!=k.__e||null!=k.__c?y(k.type,k.props,k.key,null,k.__v):k)){if(k.__=u,k.__b=u.__b+1,null===(m=C[h])||m&&k.key==m.key&&k.type===m.type)C[h]=void 0;else for(d=0;d<A;d++){if((m=C[d])&&k.key==m.key&&k.type===m.type){C[d]=void 0;break}m=null}w=N(n,k,m=m||f,i,o,r,e,a,s),(d=k.ref)&&m.ref!=d&&(x||(x=[]),m.ref&&x.push(m.ref,null,k),x.push(d,k.__c||w,k)),null!=w?(null==g&&(g=w),a=b(n,k,m,C,r,w,a),"option"==u.type?n.value="":"function"==typeof u.type&&(u.__d=a)):a&&m.__e==a&&a.parentNode!=n&&(a=_(m))}if(u.__e=g,null!=r&&"function"!=typeof u.type)for(h=r.length;h--;)null!=r[h]&&v(r[h]);for(h=A;h--;)null!=C[h]&&j(C[h],C[h]);if(x)for(h=0;h<x.length;h++)$(x[h],x[++h],x[++h])}function b(n,l,u,t,i,o,r){var e,f,c;if(void 0!==l.__d)e=l.__d,l.__d=void 0;else if(i==u||o!=r||null==o.parentNode)n:if(null==r||r.parentNode!==n)n.appendChild(o),e=null;else{for(f=r,c=0;(f=f.nextSibling)&&c<t.length;c+=2)if(f==o)break n;n.insertBefore(o,r),e=r}return void 0!==e?e:o.nextSibling}function x(n,l,u,t,i){var o;for(o in u)"children"===o||"key"===o||o in l||A(n,o,null,u[o],t);for(o in l)i&&"function"!=typeof l[o]||"children"===o||"key"===o||"value"===o||"checked"===o||u[o]===l[o]||A(n,o,l[o],u[o],t)}function C(n,l,u){"-"===l[0]?n.setProperty(l,u):n[l]="number"==typeof u&&!1===a.test(l)?u+"px":null==u?"":u}function A(n,l,u,t,i){var o,r,e,f,c;if(i?"className"===l&&(l="class"):"class"===l&&(l="className"),"style"===l)if(o=n.style,"string"==typeof u)o.cssText=u;else{if("string"==typeof t&&(o.cssText="",t=null),t)for(f in t)u&&f in u||C(o,f,"");if(u)for(c in u)t&&u[c]===t[c]||C(o,c,u[c])}else"o"===l[0]&&"n"===l[1]?(r=l!==(l=l.replace(/Capture$/,"")),e=l.toLowerCase(),l=(e in n?e:l).slice(2),u?(t||n.addEventListener(l,P,r),(n.l||(n.l={}))[l]=u):n.removeEventListener(l,P,r)):"list"!==l&&"tagName"!==l&&"form"!==l&&"type"!==l&&"size"!==l&&!i&&l in n?n[l]=null==u?"":u:"function"!=typeof u&&"dangerouslySetInnerHTML"!==l&&(l!==(l=l.replace(/^xlink:?/,""))?null==u||!1===u?n.removeAttributeNS("http://www.w3.org/1999/xlink",l.toLowerCase()):n.setAttributeNS("http://www.w3.org/1999/xlink",l.toLowerCase(),u):null==u||!1===u&&!/^ar/.test(l)?n.removeAttribute(l):n.setAttribute(l,u))}function P(l){this.l[l.type](n.event?n.event(l):l)}function E(n,l,u){var t,i;for(t=0;t<n.__k.length;t++)(i=n.__k[t])&&(i.__=n,i.__e&&("function"==typeof i.type&&i.__k.length>1&&E(i,l,u),l=b(u,i,i,n.__k,null,i.__e,l),"function"==typeof n.type&&(n.__d=l)))}function N(l,u,t,i,o,r,e,f,c){var a,v,h,y,_,m,k,w,b,x,C,A=u.type;if(void 0!==u.constructor)return null;(a=n.__b)&&a(u);try{n:if("function"==typeof A){if(w=u.props,b=(a=A.contextType)&&i[a.__c],x=a?b?b.props.value:a.__:i,t.__c?k=(v=u.__c=t.__c).__=v.__E:("prototype"in A&&A.prototype.render?u.__c=v=new A(w,x):(u.__c=v=new d(w,x),v.constructor=A,v.render=F),b&&b.sub(v),v.props=w,v.state||(v.state={}),v.context=x,v.__n=i,h=v.__d=!0,v.__h=[]),null==v.__s&&(v.__s=v.state),null!=A.getDerivedStateFromProps&&(v.__s==v.state&&(v.__s=s({},v.__s)),s(v.__s,A.getDerivedStateFromProps(w,v.__s))),y=v.props,_=v.state,h)null==A.getDerivedStateFromProps&&null!=v.componentWillMount&&v.componenLine truncated
//# sourceMappingURL=preact.min.js.map
-6
View File
@@ -1,6 +0,0 @@
#container { margin-right: auto; margin-left: auto; max-width: 480px; }
#info { background: #d0f0f0; border-radius: .5em; padding: 2em; }
#dashboard { background: #f0f0f0; border-radius: .5em; padding: 0.5em; max-height: 10em; overflow: auto; height: 100%; margin-top: 1em; }
#form { background: #d0c0f0; border-radius: .5em; padding: 0.5em; max-height: 10em; overflow: auto; height: 100%; margin-top: 1em; }
button { width: 100%; }
button, select, input, label::before, textarea { outline: none; box-shadow:none !important; border: 1px solid #ccc !important; }
+40
View File
@@ -0,0 +1,40 @@
PROG ?= example
SOURCES ?= ../../mongoose.c main.c net.c packed_fs.c
CFLAGS ?= -I../.. -DMG_ENABLE_PACKED_FS=1 -DMG_ENABLE_LINES=1 $(EXTRA)
FILES_TO_EMBED ?= $(wildcard web_root/*)
ROOT ?= $(realpath $(CURDIR)/../../..)
DOCKER ?= docker run --rm -e Tmp=. -e WINEDEBUG=-all -v $(ROOT):$(ROOT) -w $(CURDIR)
VC98 ?= $(DOCKER) mdashnet/vc98 wine
MINGW ?= $(DOCKER) mdashnet/mingw
ifeq "$(SSL)" "MBEDTLS"
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS)/include -L$(MBEDTLS)/lib -lmbedtls -lmbedcrypto -lmbedx509
endif
ifeq "$(SSL)" "OPENSSL"
CFLAGS += -DMG_ENABLE_OPENSSL=1 -I$(OPENSSL)/include -L$(OPENSSL)/lib -lssl -lcrypto
endif
all: $(PROG)
$(RUN) ./$(PROG)
$(PROG): $(SOURCES) $(FILES_TO_EMBED)
$(CC) ../../test/pack.c -o pack
./pack $(FILES_TO_EMBED) > packed_fs.c
$(CC) -W -Wall -Wextra -O0 -g3 $(CFLAGS) -o $(PROG) $(SOURCES)
mingw: $(SOURCES) $(FILES_TO_EMBED)
$(MINGW) i686-w64-mingw32-gcc $(CFLAGS) ../../test/pack.c -o pack.exe
$(MINGW) wine cmd /c 'pack.exe $(FILES_TO_EMBED) > packed_fs.c'
$(MINGW) i686-w64-mingw32-gcc $(CFLAGS) $(SOURCES) -lws2_32 -o $(PROG).exe
$(MINGW) wine $(PROG).exe
vc98: $(SOURCES) $(FILES_TO_EMBED)
$(VC98) cl.exe /nologo $(CFLAGS) ../../test/pack.c /Fepack.exe
$(VC98) cmd /c 'pack.exe $(FILES_TO_EMBED) > packed_fs.c'
$(VC98) cl.exe /nologo /O2 $(CFLAGS) $(SOURCES) /Fe$(PROG).exe
$(VC98) $(PROG).exe
clean:
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb log.txt pack
+27
View File
@@ -0,0 +1,27 @@
# 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 dashboard with the
following features:
- Authentication: login-protected dashboard
- Multiple logins with different permissions (admin and user)
- Web UI is fully embedded into the server/firmware binary, and does not
need a filesystem to serve it. UI is resilient to FS problems
- Administrators can change server settings
- All changes are propagates to all connected clients
- A device is connected to the external MQTT server
- Logged in clients can send/receive messages to a device which get
forwarded to MQTT
# Screenshots
This is a login screen that prompts for user/password
![](screenshots/login.png)
# Main dashboard
A main dashboard page shows and interactive MQTT console
![](screenshots/dashboard.png)
+1
View File
@@ -0,0 +1 @@
../../test/data/ca.pem
+18
View File
@@ -0,0 +1,18 @@
// Copyright (c) 2020-2022 Cesanta Software Limited
// All rights reserved
#include "mongoose.h"
const char *s_listening_url = "http://0.0.0.0:8000";
void device_dashboard_fn(struct mg_connection *, int, void *, void *);
int main(void) {
struct mg_mgr mgr;
mg_log_set(MG_LL_DEBUG); // Set debug log level
mg_mgr_init(&mgr);
mg_http_listen(&mgr, s_listening_url, device_dashboard_fn, &mgr);
MG_INFO(("Listening on %s", s_listening_url));
while (mgr.conns != NULL) mg_mgr_poll(&mgr, 500);
mg_mgr_free(&mgr);
return 0;
}
+217
View File
@@ -0,0 +1,217 @@
// Copyright (c) 2020-2022 Cesanta Software Limited
// All rights reserved
#include "mongoose.h"
#define MQTT_SERVER "mqtt://broker.hivemq.com:1883"
#define MQTT_PUBLISH_TOPIC "mg/my_device"
#define MQTT_SUBSCRIBE_TOPIC "mg/#"
static time_t s_boot_timestamp = 0; // Updated by SNTP
static struct mg_connection *s_sntp_conn = NULL; // SNTP connection
// Define system time()
time_t time(time_t *tp) {
time_t t = s_boot_timestamp + (time_t) (mg_millis() / 1000);
if (tp != NULL) *tp = t;
return t;
}
// Authenticated user.
// A user can be authenticated by:
// - a name:pass pair
// - a token
// When a user is shown a login screen, she enters a user:pass. If successful,
// a server returns user info which includes token. From that point on,
// client can use token for authentication. Tokens could be refreshed/changed
// on a server side, forcing clients to re-login.
struct user {
const char *name, *pass, *token;
};
// This is a configuration structure we're going to show on a dashboard
static struct config {
char *url, *pub, *sub; // MQTT settings
} s_config;
static struct mg_connection *s_mqtt = NULL; // MQTT connection
static bool s_connected = false; // MQTT connection established
// Try to update a single configuration value
static void update_config(struct mg_str *body, const char *name, char **value) {
char buf[256];
if (mg_http_get_var(body, name, buf, sizeof(buf)) > 0) {
free(*value);
*value = strdup(buf);
}
}
// Parse HTTP requests, return authenticated user or NULL
static struct user *getuser(struct mg_http_message *hm) {
// In production, make passwords strong and tokens randomly generated
// In this example, user list is kept in RAM. In production, it can
// be backed by file, database, or some other method.
static struct user users[] = {
{"admin", "pass0", "admin_token"},
{"user1", "pass1", "user1_token"},
{"user2", "pass2", "user2_token"},
{NULL, NULL, NULL},
};
char user[256], pass[256];
struct user *u;
mg_http_creds(hm, user, sizeof(user), pass, sizeof(pass));
if (user[0] != '\0' && pass[0] != '\0') {
// Both user and password is set, search by user/password
for (u = users; u->name != NULL; u++)
if (strcmp(user, u->name) == 0 && strcmp(pass, u->pass) == 0) return u;
} else if (user[0] == '\0') {
// Only password is set, search by token
for (u = users; u->name != NULL; u++)
if (strcmp(pass, u->token) == 0) return u;
}
return NULL;
}
// Notify all config watchers about the config change
static void send_notification(struct mg_mgr *mgr, const char *fmt, ...) {
struct mg_connection *c;
for (c = mgr->conns; c != NULL; c = c->next) {
if (c->label[0] == 'W') {
va_list ap;
va_start(ap, fmt);
mg_ws_vprintf(c, WEBSOCKET_OP_TEXT, fmt, &ap);
va_end(ap);
}
}
}
// Send simulated metrics data to the dashboard, for chart rendering
static void timer_metrics_fn(void *param) {
send_notification(param, "{%Q:%Q,%Q:[%lu, %d]}", "name", "metrics", "data",
(unsigned long) time(NULL),
10 + (int) ((double) rand() * 10 / RAND_MAX));
}
// MQTT event handler function
static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data, void *fnd) {
if (ev == MG_EV_CONNECT && mg_url_is_ssl(s_config.url)) {
struct mg_tls_opts opts = {.ca = "ca.pem",
.srvname = mg_url_host(s_config.url)};
mg_tls_init(c, &opts);
} else if (ev == MG_EV_MQTT_OPEN) {
s_connected = true;
c->is_hexdumping = 1;
mg_mqtt_sub(s_mqtt, mg_str(s_config.sub), 2);
send_notification(c->mgr, "{%Q:%Q,%Q:null}", "name", "config", "data");
} else if (ev == MG_EV_MQTT_MSG) {
struct mg_mqtt_message *mm = ev_data;
send_notification(c->mgr, "{%Q:%Q,%Q:{%Q: %.*Q, %Q: %.*Q, %Q: %d}}", "name",
"message", "data", "topic", (int) mm->topic.len,
mm->topic.ptr, "data", (int) mm->data.len, mm->data.ptr,
"qos", (int) mm->qos);
} else if (ev == MG_EV_MQTT_CMD) {
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
MG_DEBUG(("cmd %d qos %d", mm->cmd, mm->qos));
} else if (ev == MG_EV_CLOSE) {
s_mqtt = NULL;
if (s_connected) {
s_connected = false;
send_notification(c->mgr, "{%Q:%Q,%Q:null}", "name", "config", "data");
}
}
(void) fnd;
}
// Keep MQTT connection open - reconnect if closed
static void timer_mqtt_fn(void *param) {
struct mg_mgr *mgr = (struct mg_mgr *) param;
if (s_mqtt == NULL) {
struct mg_mqtt_opts opts = {0};
s_mqtt = mg_mqtt_connect(mgr, s_config.url, &opts, mqtt_fn, NULL);
}
}
// SNTP connection event handler. When we get a response from an SNTP server,
// adjust s_boot_timestamp. We'll get a valid time from that point on
static void sfn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_SNTP_TIME) {
uint64_t t = *(uint64_t *) ev_data;
MG_INFO(("%lu SNTP: %lld ms from epoch", c->id, t));
s_boot_timestamp = (time_t) ((t - mg_millis()) / 1000);
c->is_closing = 1;
} else if (ev == MG_EV_CLOSE) {
s_sntp_conn = NULL;
}
(void) fn_data;
}
static void timer_sntp_fn(void *param) { // SNTP timer function. Sync up time
struct mg_mgr *mgr = (struct mg_mgr *) param;
if (s_sntp_conn == NULL && s_boot_timestamp == 0) {
s_sntp_conn = mg_sntp_connect(mgr, NULL, sfn, NULL);
}
}
// HTTP request handler function
void device_dashboard_fn(struct mg_connection *c, int ev, void *ev_data,
void *fn_data) {
if (ev == MG_EV_OPEN && c->is_listening) {
mg_timer_add(c->mgr, 1000, MG_TIMER_REPEAT, timer_metrics_fn, c->mgr);
mg_timer_add(c->mgr, 1000, MG_TIMER_REPEAT, timer_mqtt_fn, c->mgr);
mg_timer_add(c->mgr, 1000, MG_TIMER_REPEAT, timer_sntp_fn, c->mgr);
s_config.url = strdup(MQTT_SERVER);
s_config.pub = strdup(MQTT_PUBLISH_TOPIC);
s_config.sub = strdup(MQTT_SUBSCRIBE_TOPIC);
} else if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
struct user *u = getuser(hm);
// MG_INFO(("%p [%.*s] auth %s", c->fd, (int) hm->uri.len, hm->uri.ptr,
// u ? u->name : "NULL"));
if (mg_http_match_uri(hm, "/api/hi")) {
mg_http_reply(c, 200, "", "hi\n"); // Testing endpoint
} else if (u == NULL && mg_http_match_uri(hm, "/api/#")) {
// All URIs starting with /api/ must be authenticated
mg_http_reply(c, 403, "", "Denied\n");
} else if (mg_http_match_uri(hm, "/api/config/get")) {
mg_http_reply(c, 200, NULL, "{%Q:%Q,%Q:%Q,%Q:%Q,%Q:%s}\n", "url",
s_config.url, "pub", s_config.pub, "sub", s_config.sub,
"connected", s_connected ? "true" : "false");
} else if (mg_http_match_uri(hm, "/api/config/set")) {
// Admins only
if (strcmp(u->name, "admin") == 0) {
update_config(&hm->body, "url", &s_config.url);
update_config(&hm->body, "pub", &s_config.pub);
update_config(&hm->body, "sub", &s_config.sub);
if (s_mqtt) s_mqtt->is_closing = 1; // Ask to disconnect from MQTT
send_notification(fn_data, "{%Q:%Q,%Q:null}", "name", "config", "data");
mg_http_reply(c, 200, "", "ok\n");
} else {
mg_http_reply(c, 403, "", "Denied\n");
}
} else if (mg_http_match_uri(hm, "/api/message/send")) {
char buf[256];
if (s_connected &&
mg_http_get_var(&hm->body, "message", buf, sizeof(buf)) > 0) {
mg_mqtt_pub(s_mqtt, mg_str(s_config.pub), mg_str(buf), 1, false);
}
mg_http_reply(c, 200, "", "ok\n");
} else if (mg_http_match_uri(hm, "/api/watch")) {
c->label[0] = 'W'; // Mark ourselves as a event listener
mg_ws_upgrade(c, hm, NULL);
} else if (mg_http_match_uri(hm, "/api/login")) {
mg_http_reply(c, 200, NULL, "{%Q:%Q,%Q:%Q}\n", "user", u->name, "token",
u->token);
} else {
struct mg_http_serve_opts opts = {0};
#if 1
opts.root_dir = "/web_root";
opts.fs = &mg_fs_packed;
#else
opts.root_dir = "web_root";
#endif
mg_http_serve_dir(c, ev_data, &opts);
}
MG_DEBUG(("%.*s %.*s -> %.*s", (int) hm->method.len, hm->method.ptr,
(int) hm->uri.len, hm->uri.ptr, (int) 3, &c->send.buf[9]));
}
}
File diff suppressed because it is too large. Load diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 283 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

@@ -1,16 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<title>example</title> <title>Device Dashboard</title>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="style.css" /> <link rel="stylesheet" href="style.css" />
<script src="preact.min.js"></script>
<script src="htm.min.js"></script>
<script src="linkstate.min.js"></script>
<script src="axios.min.js"></script>
<script src="app.js"></script>
</head> </head>
<body></body> <body></body>
<script type="module" src="main.js"></script>
</html> </html>
+378
View File
@@ -0,0 +1,378 @@
'use strict';
import {Component, h, html, render, useEffect, useState, useRef} from './preact.min.js';
const MaxMetricsDataPoints = 50;
// This simple publish/subscribe is used to pass notifications that were
// received from the server, to all child components of the app.
var PubSub = (function() {
var handlers = {}, id = 0;
return {
subscribe: function(fn) {
handlers[id++] = fn;
},
unsubscribe: function(id) {
delete handlers[id];
},
publish: function(data) {
for (var k in handlers) handlers[k](data);
}
};
})();
const Nav = props => html`
<div style="background: #333; padding: 0.5em; color: #fff;">
<div class="container d-flex">
<div style="flex: 1 1 auto; display: flex; align-items: center;">
<b>Your Product</b>
</div>
<div style="display: flex; align-items: center; flex: 0 0 auto; ">
<span>Logged in as:</span>
<span style="padding: 0 0.5em;"><img src="user.png" height="22" /></span>
<span>${props.user}</span>
<a class="btn" onclick=${props.logout}
style="margin-left: 1em; font-size: 0.8em; background: #8aa;">logout</a>
</div>
</div>
</div>`;
const Hero = props => html`
<div class="section">
<div style="margin-top: 1em; background: #eee; padding: 1em; border-radius: 0.5em; color: #777; ">
<h1 style="margin: 0.2em 0;">Interactive Device Dashboard</h1>
<p>
This device dashboard is developed using the modern and compact Preact framework,
in order to fit on very small devices. This is
a <a href="https://mongoose.ws/tutorials/http-server/">hybrid server</a> which
provides both static and dynamic content. Static files, like CSS/JS/HTML
or images, are compiled into the server binary.
This UI uses the REST API implemented by the device, which you can examine
using <code>curl</code> command-line utility:
</p>
<div><code>curl -u admin:pass0 localhost:8000/api/config/get</code> </div>
<div><code>curl -u admin:pass0 localhost:8000/api/config/set -d 'pub=mg/topic'</code> </div>
<div><code>curl -u admin:pass0 localhost:8000/api/message/send -d 'message=hello'</code> </div>
<p>
The device can send notifications to this dashboard at anytime. Notifications
are sent over WebSocket at URI <code>/api/watch</code> as JSON strings: <code>{"name": "..", "data": ...}</code>
<div>Try <code>wscat --auth user1:pass1 --connect ws://localhost:8000/api/watch</code></div>
</p>
</div>
</div>`;
const Login = function(props) {
const [user, setUser] = useState('');
const [pass, setPass] = useState('');
const login = ev =>
fetch(
'/api/login',
{headers: {Authorization: 'Basic ' + btoa(user + ':' + pass)}})
.then(r => r.json())
.then(r => r && props.login(r))
.catch(err => err);
return html`
<div class="rounded border" style="max-width: 480px; margin: 0 auto; margin-top: 5em; background: #eee; ">
<div style="padding: 2em; ">
<h1 style="color: #666;">Device Dashboard Login </h1>
<div style="margin: 0.5em 0;">
<input type='text' placeholder='Name' style="width: 100%;"
oninput=${ev => setUser(ev.target.value)} value=${user} />
</div>
<div style="margin: 0.5em 0;">
<input type="password" placeholder="Password" style="width: 100%;"
oninput=${ev => setPass(ev.target.value)} value=${pass}
onchange=${login} />
</div>
<div style="margin: 1em 0;">
<button class="btn" style="width: 100%; background: #8aa;"
disabled=${!user || !pass} onclick=${login}> Login </button>
</div>
<div style="color: #777; margin-top: 2em;">
Valid logins: admin:pass0, user1:pass1, user2:pass2
</div>
</div>
</div>`;
};
const Configuration = function(props) {
const [url, setUrl] = useState(props.config.url || '');
const [pub, setPub] = useState(props.config.pub || '');
const [sub, setSub] = useState(props.config.sub || '');
useEffect(() => {
setUrl(props.config.url);
setPub(props.config.pub);
setSub(props.config.sub);
}, [props.config]);
const update = (name, val) => fetch('/api/config/set', {
method: 'post',
body: `${name}=${encodeURIComponent(val)}`
}).catch(err => err);
const updateurl = ev => update('url', url);
const updatepub = ev => update('pub', pub);
const updatesub = ev => update('sub', sub);
// console.log(props, [url, pub, sub]);
return html`
<div class="section">
<h3 style="background: #c03434; color: #fff; padding: 0.4em;">
Device Configuration</h3>
<div style="margin: 0.5em 0; display: flex;">
<span class="addon nowrap">MQTT server:</span>
<input type="text" style="flex: 1 100%;"
value=${url} onchange=${updateurl}
oninput=${ev => setUrl(ev.target.value)} />
<button class="btn" disabled=${!url} onclick=${updateurl}
style="margin-left: 1em; background: #8aa;">Update</button>
</div>
<div style="margin: 0.5em 0; display: flex; ">
<span class="addon nowrap">Subscribe topic:</span>
<input type="text" style="flex: 1 100%;"
value=${sub} onchange=${updatesub}
oninput=${ev => setSub(ev.target.value)} />
<button class="btn" disabled=${!sub} onclick=${updatesub}
style="margin-left: 1em; background: #8aa;">Update</button>
</div>
<div style="margin: 0.5em 0; display: flex;">
<span class="addon nowrap">Publish topic:</span>
<input type="text" style="flex: 1 100%;"
value=${pub} onchange=${updatepub}
oninput=${ev => setPub(ev.target.value)} />
<button class="btn" disabled=${!pub} onclick=${updatepub}
style="margin-left: 1em; background: #8aa;">Update</button>
</div>
<div>
You can use <a href="http://www.hivemq.com/demos/websocket-client/">
HiveMQ Websocket web client</a> to send messages to this console.
</div>
<div class="msg">
The device keeps a persistent connection to the configured MQTT server.
Changes to this configuration are propagated to all dashboards: try
changing them in this dashboard and observe changes in other opened
dashboards.
</div><div class="msg">
Note: administrators can see this section and can change device
configuration, whilst users cannot.
</div>
</div>`;
};
const Message = m => html`<div style="margin: 0.5em 0;">
<span class="qos">qos: ${m.message.qos} </span>
<span class="topic">topic: ${m.message.topic} </span>
<span class="data">data: ${m.message.data}</span>
</div>`;
const Messages = function(props) {
const [messages, setMessages] = useState([]);
const [txt, setTxt] = useState('');
useEffect(() => {
const id = PubSub.subscribe(function(msg) {
if (msg.name == 'message') setMessages(x => x.concat([msg.data]));
});
return PubSub.unsubscribe(id);
}, []);
const sendmessage = ev => fetch('/api/message/send', {
method: 'post',
body: `message=${encodeURIComponent(txt)}`
}).then(r => setTxt(''));
const connstatus = props.config.connected ? 'connected' : 'disconnected';
return html`
<div class="section">
<h3 style="background: #30c040; color: #fff; padding: 0.4em;">MQTT messages</h3>
<div>
MQTT server status: <b>${connstatus}</b>
</div>
<div style="height: 10em; overflow: auto; padding: 0.5em; " class="border">
${messages.map(message => h(Message, {message}))}
</div>
<div style="margin: 0.5em 0; display: flex">
<span class="addon nowrap">Publish message:</span>
<input placeholder="type and press enter..." style="flex: 1 100%;"
value=${txt} onchange=${sendmessage}
oninput=${ev => setTxt(ev.target.value)} />
</div>
<div class="msg">
The message gets passed to the device via REST. Then the device sends it to
the MQTT server over MQTT. All MQTT messages on a subscribed topic
received by the device, are propagated to this dashboard via /api/watch.
</div>
</div>`;
};
// Expected arguments:
// data: timeseries, e.g. [ [1654361352, 19], [1654361353, 18], ... ]
// width, height, yticks, xticks, ymin, ymax, xmin, xmax
const SVG = function(props) {
// w
// +---------------------+
// | h1 |
// | +-----------+ |
// | | | | h
// | w1 | | w2 |
// | +-----------+ |
// | h2 |
// +---------------------+
//
let w = props.width, h = props.height, w1 = 30, w2 = 0, h1 = 8, h2 = 18;
let yticks = props.yticks || 4, xticks = props.xticks || 5;
let data = props.data || [];
let ymin = props.ymin || 0;
let ymax = props.ymax || Math.max.apply(null, data.map(p => p[1]));
let xmin = props.xmin || Math.min.apply(null, data.map(p => p[0]));
let xmax = props.xmax || Math.max.apply(null, data.map(p => p[0]));
// Y-axis tick lines and labels
let yta = (new Array(yticks + 1)).fill(0).map((_, i) => i); // indices
let yti = i => h - h2 - (h - h1 - h2) * i / yticks; // index's Y
let ytv = i => (ymax - ymin) * i / yticks;
let ytl = y => html`<line x1=${w1} y1=${y} x2=${w} y2=${y} class="tick"/>`;
let ytt = (y, v) => html`<text x=0 y=${y + 5} class="label">${v}</text>`;
// X-axis tick lines and labels
let datefmt = unix => (new Date(unix * 1000)).toISOString().substr(14, 5);
let xta = (new Array(xticks + 1)).fill(0).map((_, i) => i); // indices
let xti = i => w1 + (w - w1 - w2) * i / xticks; // index's X
let xtv = i => datefmt(xmin + (xmax - xmin) * i / xticks);
let xtl = x => html`<path d="M ${x},${h1} L ${x},${h - h2}" class="tick"/>`;
let xtt = (x, v) =>
html`<text x=${x - 15} y=${h - 2} class="label">${v}</text>`;
// Transform data points array into coordinate
let dx = v => w1 + (v - xmin) / ((xmax - xmin) || 1) * (w - w1 - w2);
let dy = v => h - h2 - (v - ymin) / ((ymax - ymin) || 1) * (h - h1 - h2);
let dd = data.map(p => [Math.round(dx(p[0])), Math.round(dy(p[1]))]);
let ddl = dd.length;
// And plot the data as <path> element
let begin0 = ddl ? `M ${dd[0][0]},${dd[0][1]}` : `M 0,0`;
let begin = `M ${w1},${h - h2}`; // Initial point
let end = ddl ? `L ${dd[ddl - 1][0]},${h - h2}` : `L ${w1},${h - h2}`;
let series = ddl ? dd.map(p => `L ${p[0]} ${p[1]}`) : [];
return html`
<svg viewBox="0 0 ${w} ${h}">
<style>
.axis { stroke: #aaa; fill: none; }
.label { stroke: #aaa; font-size: 13px; }
.tick { stroke: #ccc; fill: none; stroke-dasharray: 5; }
.seriesbg { stroke: none; fill: rgba(200,225,255, 0.25)}
.series { stroke: #25a; fill: none; }
</style>
${yta.map(i => ytl(yti(i)))}
${yta.map(i => ytt(yti(i), ytv(i)))}
${xta.map(i => xtl(xti(i)))}
${data.length ? xta.map(i => xtt(xti(i), xtv(i))) : ''}
<path d="${begin} ${series.join(' ')} ${end}" class="seriesbg" />
<path d="${begin0} ${series.join(' ')}" class="series" />
</svg>`;
};
const Chart = function(props) {
const [data, setData] = useState([]);
useEffect(() => {
const id = PubSub.subscribe(function(msg) {
if (msg.name != 'metrics') return;
setData(x => x.concat([msg.data]).splice(-MaxMetricsDataPoints));
});
return PubSub.unsubscribe(id);
}, []);
let xmax = 0, missing = MaxMetricsDataPoints - data.length;
if (missing > 0) xmax = Math.round(Date.now() / 1000) + missing;
return html`
<div class="section">
<h3 style="background: #ec3; color: #fff; padding: 0.4em;">Data Chart</h3>
<div style="overflow: auto; padding: 0.5em;" class="">
<${SVG} height=240 width=600 ymin=0 ymax=20 xmax=${xmax} data=${data} />
</div>
<div class="msg">
This chart plots live sensor data, sent by the device via /api/watch.
</div>
</div>`;
};
const App = function(props) {
const [user, setUser] = useState('');
const [config, setConfig] = useState({});
const getconfig = () =>
fetch('/api/config/get', {headers: {Authorization: ''}})
.then(r => r.json())
.then(r => setConfig(r))
.catch(err => console.log(err));
// Watch for notifications. As soon as a notification arrives, pass it on
// to all subscribed components
const watch = function() {
var l = window.location, proto = l.protocol.replace('http', 'ws');
var tid, wsURI = proto + '//' + l.host + '/api/watch'
var reconnect = function() {
var ws = new WebSocket(wsURI);
// ws.onopen = () => console.log('ws connected');
ws.onmessage = function(ev) {
try {
var msg = JSON.parse(ev.data);
PubSub.publish(msg);
// if (msg.name != 'metrics') console.log('ws->', msg);
} catch (e) {
console.log('Invalid ws frame:', ev.data); // eslint-disable-line
}
};
ws.onclose = function() {
clearTimeout(tid);
tid = setTimeout(reconnect, 1000);
console.log('ws disconnected');
};
};
reconnect();
};
const login = function(u) {
document.cookie = `access_token=${u.token}; Secure, HttpOnly; SameSite=Lax; path=/; max-age=3600`;
setUser(u.user);
watch();
return getconfig();
};
const logout = ev => {
document.cookie = `access_token=; Secure, HttpOnly; SameSite=Lax; path=/; max-age=0`;
setUser('');
};
useEffect(() => {
// Called once at init time
PubSub.subscribe(msg => msg.name == 'config' && getconfig());
fetch('/api/login', {headers: {Authorization: ''}})
.then(r => r.json())
.then(r => login(r))
.catch(err => setUser(''));
}, []);
if (!user) return html`<${Login} login=${login} />`;
return html`
<${Nav} user=${user} logout=${logout} />
<div class="container">
<div class="row">
<div class="col col-6"><${Hero} /></div>
<div class="col col-6"><${Chart} /></div>
<div class="col col-6">
${user == 'admin' && h(Configuration, {config})}
</div>
<div class="col col-6"><${Messages} config=${config} /></div>
</div>
</div>`;
};
window.onload = () => render(h(App), document.body);
+1
View File
@@ -0,0 +1 @@
var e,n,_,t,o,r,u,l={},i=[],c=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;function s(e,n){for(var _ in n)e[_]=n[_];return e}function f(e){var n=e.parentNode;n&&n.removeChild(e)}function a(n,_,t){var o,r,u,l={};for(u in _)"key"==u?o=_[u]:"ref"==u?r=_[u]:l[u]=_[u];if(arguments.length>2&&(l.children=arguments.length>3?e.call(arguments,2):t),"function"==typeof n&&null!=n.defaultProps)for(u in n.defaultProps)void 0===l[u]&&(l[u]=n.defaultProps[u]);return p(n,l,o,r,null)}function p(e,t,o,r,u){var l={type:e,props:t,key:o,ref:r,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,__h:null,constructor:void 0,__v:null==u?++_:u};return null!=n.vnode&&n.vnode(l),l}function h(e){return e.children}function d(e,n){this.props=e,this.context=n}function v(e,n){if(null==n)return e.__?v(e.__,e.__.__k.indexOf(e)+1):null;for(var _;n<e.__k.length;n++)if(null!=(_=e.__k[n])&&null!=_.__e)return _.__e;return"function"==typeof e.type?v(e):null}function y(e){var n,_;if(null!=(e=e.__)&&null!=e.__c){for(e.__e=e.__c.base=null,n=0;n<e.__k.length;n++)if(null!=(_=e.__k[n])&&null!=_.__e){e.__e=e.__c.base=_.__e;break}return y(e)}}function m(e){(!e.__d&&(e.__d=!0)&&t.push(e)&&!g.__r++||r!==n.debounceRendering)&&((r=n.debounceRendering)||o)(g)}function g(){for(var e;g.__r=t.length;)e=t.sort(function(e,n){return e.__v.__b-n.__v.__b}),t=[],e.some(function(e){var n,_,t,o,r,u;e.__d&&(r=(o=(n=e).__v).__e,(u=n.__P)&&(_=[],(t=s({},o)).__v=o.__v+1,P(u,o,t,n.__n,void 0!==u.ownerSVGElement,null!=o.__h?[r]:null,_,null==r?v(o):r,o.__h),D(_,o),o.__e!=r&&y(o)))})}function k(e,n,_,t,o,r,u,c,s,f){var a,d,y,m,g,k,x,H=t&&t.__k||i,E=H.length;for(_.__k=[],a=0;a<n.length;a++)if(null!=(m=_.__k[a]=null==(m=n[a])||"boolean"==typeof m?null:"string"==typeof m||"number"==typeof m||"bigint"==typeof m?p(null,m,null,null,m):Array.isArray(m)?p(h,{children:m},null,null,null):m.__b>0?p(m.type,m.props,m.key,null,m.__v):m)){if(m.__=_,m.__b=_.__b+1,null===(y=H[a])||y&&m.key==y.key&&m.type===y.type)H[a]=void 0;else for(d=0;d<E;d++){if((y=H[d])&&m.key==y.key&&m.type===y.type){H[d]=void 0;break}y=null}P(e,m,y=y||l,o,r,u,c,s,f),g=m.__e,(d=m.ref)&&y.ref!=d&&(x||(x=[]),y.ref&&x.push(y.ref,null,m),x.push(d,m.__c||g,m)),null!=g?(null==k&&(k=g),"function"==typeof m.type&&null!=m.__k&&m.__k===y.__k?m.__d=s=b(m,s,e):s=C(e,m,y,H,g,s),f||"option"!==_.type?"function"==typeof _.type&&(_.__d=s):e.value=""):s&&y.__e==s&&s.parentNode!=e&&(s=v(y))}for(_.__e=k,a=E;a--;)null!=H[a]&&("function"==typeof _.type&&null!=H[a].__e&&H[a].__e==_.__d&&(_.__d=v(t,a+1)),U(H[a],H[a]));if(x)for(a=0;a<x.length;a++)T(x[a],x[++a],x[++a])}function b(e,n,_){var t,o;for(t=0;t<e.__k.length;t++)(o=e.__k[t])&&(o.__=e,n="function"==typeof o.type?b(o,n,_):C(_,o,o,e.__k,o.__e,n));return n}function C(e,n,_,t,o,r){var u,l,i;if(void 0!==n.__d)u=n.__d,n.__d=void 0;else if(null==_||o!=r||null==o.parentNode)e:if(null==r||r.parentNode!==e)e.appendChild(o),u=null;else{for(l=r,i=0;(l=l.nextSibling)&&i<t.length;i+=2)if(l==o)break e;e.insertBefore(o,r),u=r}return void 0!==u?u:o.nextSibling}function x(e,n,_){"-"===n[0]?e.setProperty(n,_):e[n]=null==_?"":"number"!=typeof _||c.test(n)?_:_+"px"}function H(e,n,_,t,o){var r;e:if("style"===n)if("string"==typeof _)e.style.cssText=_;else{if("string"==typeof t&&(e.style.cssText=t=""),t)for(n in t)_&&n in _||x(e.style,n,"");if(_)for(n in _)t&&_[n]===t[n]||x(e.style,n,_[n])}else if("o"===n[0]&&"n"===n[1])r=n!==(n=n.replace(/Capture$/,"")),n=n.toLowerCase()in e?n.toLowerCase().slice(2):n.slice(2),e.l||(e.l={}),e.l[n+r]=_,_?t||e.addEventListener(n,r?S:E,r):e.removeEventListener(n,r?S:E,r);else if("dangerouslySetInnerHTML"!==n){if(o)n=n.replace(/xlink[H:h]/,"h").replace(/sName$/,"s");else if("href"!==n&&"list"!==n&&"form"!==n&&"tabIndex"!==n&&"download"!==n&&n in e)try{e[n]=null==_?"":_;break e}catch(e){}"function"==typeof _||(null!=_&&(!1!==_||"a"===n[0]&&"r"===n[1])?e.setAttribute(n,_):e.removeAttribute(n))}}function E(e){this.l[e.type+!1](n.event?n.event(e):e)}function S(e){this.l[e.type+!0](n.event?n.event(e):e)}function P(e,_,t,o,r,u,l,i,c){var f,a,p,v,y,m,g,b,C,x,H,E=_.type;if(void 0!==_.constructor)return null;null!=t.__h&&(c=t.__h,i=_.__e=t.__e,_.__h=null,u=[i]),(f=n.__b)&&f(_);try{e:if("function"==typeof E){if(b=_.props,C=(f=E.contextType)&&o[f.__c],x=f?C?C.props.value:f.__:o,t.__c?g=(a=_.__c=t.__c).__=a.__E:("prototype"in E&&E.prototype.render?_.__c=a=new E(b,x):(_.__c=a=new d(b,x),a.constructor=E,a.render=A),C&&C.sub(a),a.props=b,a.state||(a.state={}),a.context=x,a.__n=o,p=a.__d=!0,a.__h=[]),null==a.__s&&(a.__s=a.state),null!=E.getDerivedStateFromProps&&(a.__s==a.state&&(a.__s=s({},a.__s)),s(a.__s,E.getDerivedStateFromProps(b,a.__s))),v=a.props,y=a.state,p)null==E.getDerivedStateFromProps&&null!=a.componentWillMount&&a.componentWillMount(),null!=a.componentDidMount&&a.__h.push(a.componentDidMount);else{if(null==E.getDerivedStateFromProps&&b!==v&&null!=a.componentWillReceiveProps&&a.componentWillReceiveProps(b,x),!a.__e&&null!=a.shouldComponentUpdate&&!1===a.shouldCompLine truncated
@@ -0,0 +1,43 @@
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: 100%; font: 16px sans-serif; }
select, input, label::before, textarea { outline: none; box-shadow:none !important; border: 1px solid #ccc !important; }
code, pre { color: #373; font-family: monospace; font-weight: bolder; font-size: smaller; background: #ddd; padding: 0.1em 0.3em; border-radius: 0.2em; }
textarea, input, .addon { font-size: 15px; border: 1px solid #ccc; padding: 0.5em; }
a, a:visited, a:active { color: #55f; }
.addon { background: #eee; min-width: 9em;}
.btn {
background: #ccc; border-radius: 0.3em; border: 0; color: #fff; cursor: pointer;
display: inline-block; padding: 0.6em 2em; font-weight: bolder;
}
.btn[disabled] { opacity: 0.5; cursor: auto;}
.smooth { transition: all .2s; }
.container { margin: 0 20px; width: auto; }
.d-flex { display: flex; }
.d-none { display: none; }
.border { border: 1px solid #ddd; }
.rounded { border-radius: 0.5em; }
.nowrap { white-space: nowrap; }
.msg { background: #def; border-left: 5px solid #59d; padding: 0.5em; font-size: 90%; margin: 1em 0; }
.section { margin: 0 1em; }
.topic, .data, .qos { padding: 0.2em 0.5em; border-radius: 0.4em; margin-right: 0.5em; }
.qos { background: #efa; }
.topic { background: #fea; }
.data { background: #aef; }
/* Grid */
.row { display: flex; flex-wrap: wrap; }
.col { margin: 0; padding: 0; overflow: auto; }
.col-12 { width: 100%; }
.col-11 { width: 91.66%; }
.col-10 { width: 83.33%; }
.col-9 { width: 75%; }
.col-8 { width: 66.66%; }
.col-7 { width: 58.33%; }
.col-6 { width: 50%; }
.col-5 { width: 41.66%; }
.col-4 { width: 33.33%; }
.col-3 { width: 25%; }
.col-2 { width: 16.66%; }
.col-1 { width: 8.33%; }
@media (min-width: 1310px) { .container { margin: auto; width: 1270px; } }
@media (max-width: 920px) { .row .col { width: 100%; } }
+51
View File
@@ -0,0 +1,51 @@
PROG ?= example
SOURCES ?= ../../mongoose.c main.c packed_fs.c
CFLAGS ?= -I../.. -DMG_ENABLE_PACKED_FS=1 -DMG_ENABLE_LINES=1 $(EXTRA)
FILES_TO_EMBED ?= $(wildcard web_root/*)
ROOT ?= $(realpath $(CURDIR)/../../..)
DOCKER ?= docker run --rm -e Tmp=. -e WINEDEBUG=-all -v $(ROOT):$(ROOT) -w $(CURDIR)
VC98 ?= $(DOCKER) mdashnet/vc98 wine
MINGW ?= $(DOCKER) mdashnet/mingw
all: $(PROG)
$(RUN) ./$(PROG)
$(PROG): $(SOURCES) $(FILES_TO_EMBED)
$(CC) ../../test/pack.c -o pack
./pack $(FILES_TO_EMBED) > packed_fs.c
$(CC) -W -Wall -Wextra -O0 -g3 $(CFLAGS) -o $(PROG) $(SOURCES)
mingw: $(SOURCES) $(FILES_TO_EMBED)
$(MINGW) i686-w64-mingw32-gcc $(CFLAGS) ../../test/pack.c -o pack.exe
$(MINGW) wine cmd /c 'pack.exe $(FILES_TO_EMBED) > packed_fs.c'
$(MINGW) i686-w64-mingw32-gcc $(CFLAGS) $(SOURCES) -lws2_32 -o $(PROG).exe
$(MINGW) wine $(PROG).exe
vc98: $(SOURCES) $(FILES_TO_EMBED)
$(VC98) cl.exe /nologo $(CFLAGS) ../../test/pack.c /Fepack.exe
$(VC98) cmd /c 'pack.exe $(FILES_TO_EMBED) > packed_fs.c'
$(VC98) cl.exe /nologo /O2 $(CFLAGS) $(SOURCES) /Fe$(PROG).exe
$(VC98) $(PROG).exe
clean:
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb log.txt pack
.PHONY: compress expand gzipped plain all
gzipped: compress
$(MAKE) all
plain: expand
$(MAKE) all
compress:
for file in $(FILES_TO_EMBED) ; do \
gzip -q $$file ; \
done
expand:
for file in $(FILES_TO_EMBED) ; do \
gunzip -q $$file ; \
done
+28
View File
@@ -0,0 +1,28 @@
// Copyright (c) 2022 Cesanta Software Limited
// All rights reserved
#include "mongoose.h"
const char *s_listening_url = "http://0.0.0.0:8000";
// HTTP request handler function
void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_serve_opts opts = {
.root_dir = "/web_root",
.fs = &mg_fs_packed
};
mg_http_serve_dir(c, ev_data, &opts);
}
(void) fn_data;
}
int main(void) {
struct mg_mgr mgr;
mg_log_set(MG_LL_INFO);
mg_mgr_init(&mgr);
mg_http_listen(&mgr, s_listening_url, fn, NULL);
while (true) mg_mgr_poll(&mgr, 500);
mg_mgr_free(&mgr);
return 0;
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="description" content="Mongoose Embedded Filesytem example" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Mongoose Embedded Filesytem example</title>
<link rel="stylesheet" href="style.css" />
</head>
<body></body>
<script type="module" src="main.js"></script>
</html>
@@ -0,0 +1,88 @@
'use strict';
import { h, html, render } from './preact.min.js';
const X = function () {
return html`
<div class="container">
<h2 class="section">ABOUT US</h2>
<div class="row">
<div class="col-7">
<p>
Cesanta Software Ltd. is headquartered in Dublin, Republic of Ireland.
</p>
<p></p>
Our story roots back to 2004, when Mongoose Web Server Library development started. <br>
As Mongoose Web Server grew in popularity and matured over the following years, in 2013 Cesanta was established to continue its development and
provide support to our valued customers.
</p>
<p>We are proud to have among our customers many <i>Fortune 500</i> companies as well as medium and small size businesses.
Security and quality of our solutions is a paramount for us and the fact that Mongoose Web Server is used by NASA aboard the International Space Station is
the best confirmation to it.</p>
<p>Since 2013, Cesanta has expanded its product portfolio. We develop and distribute embedded software and hardware with focus on connected products and the Internet of Things.</p>
</div>
</div>
</div>
`;
};
const Y = function () {
return html`
<div class="container">
<h3 class="section">Among our products are:</h3>
<div class="row">
<div class="col-7">
<ul>
<li>
<a href="https://mongoose.ws/">Mongoose Web Server</a>
- an embedded web server and networking library
</li>
<li>
<a href="https://vcon.io/">VCON.io</a>
- Arduino-compatible boards with built-in firmware OTA updates
and management dashboard
</li>
<li>
<a href="https://mdash.net/">mDash.net</a>
- an all-in-one IoT Platform
</li>
<li>
<a href="https://mongoose-os.com">Mongoose OS</a>
- an operating system for low-power microcontrollers
</li>
<li>
<a href="https://github.com/cesanta/mjs">mJS</a>
- an embedded JavaScript engine for C/C++
</li>
</ul>
</div>
<div class="col-6">
<p><b>Our solutions are:</b></p>
<ul>
<li>integrated into thousands of commercial products</li>
<li>deployed to hundreds of millions devices in production environments</li>
</ul>
</div>
</div>
</div>
`;
};
const App = function (props) {
return html`
<h1>Basic Embedded Filesystem demo</h1>
<div>
${h(X)}
</div>
<div>
${h(Y)}
</div>`;
};
window.onload = () => render(h(App), document.body);
+1
View File
@@ -0,0 +1 @@
var e,n,_,t,o,r,u,l={},i=[],c=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;function s(e,n){for(var _ in n)e[_]=n[_];return e}function f(e){var n=e.parentNode;n&&n.removeChild(e)}function a(n,_,t){var o,r,u,l={};for(u in _)"key"==u?o=_[u]:"ref"==u?r=_[u]:l[u]=_[u];if(arguments.length>2&&(l.children=arguments.length>3?e.call(arguments,2):t),"function"==typeof n&&null!=n.defaultProps)for(u in n.defaultProps)void 0===l[u]&&(l[u]=n.defaultProps[u]);return p(n,l,o,r,null)}function p(e,t,o,r,u){var l={type:e,props:t,key:o,ref:r,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,__h:null,constructor:void 0,__v:null==u?++_:u};return null!=n.vnode&&n.vnode(l),l}function h(e){return e.children}function d(e,n){this.props=e,this.context=n}function v(e,n){if(null==n)return e.__?v(e.__,e.__.__k.indexOf(e)+1):null;for(var _;n<e.__k.length;n++)if(null!=(_=e.__k[n])&&null!=_.__e)return _.__e;return"function"==typeof e.type?v(e):null}function y(e){var n,_;if(null!=(e=e.__)&&null!=e.__c){for(e.__e=e.__c.base=null,n=0;n<e.__k.length;n++)if(null!=(_=e.__k[n])&&null!=_.__e){e.__e=e.__c.base=_.__e;break}return y(e)}}function m(e){(!e.__d&&(e.__d=!0)&&t.push(e)&&!g.__r++||r!==n.debounceRendering)&&((r=n.debounceRendering)||o)(g)}function g(){for(var e;g.__r=t.length;)e=t.sort(function(e,n){return e.__v.__b-n.__v.__b}),t=[],e.some(function(e){var n,_,t,o,r,u;e.__d&&(r=(o=(n=e).__v).__e,(u=n.__P)&&(_=[],(t=s({},o)).__v=o.__v+1,P(u,o,t,n.__n,void 0!==u.ownerSVGElement,null!=o.__h?[r]:null,_,null==r?v(o):r,o.__h),D(_,o),o.__e!=r&&y(o)))})}function k(e,n,_,t,o,r,u,c,s,f){var a,d,y,m,g,k,x,H=t&&t.__k||i,E=H.length;for(_.__k=[],a=0;a<n.length;a++)if(null!=(m=_.__k[a]=null==(m=n[a])||"boolean"==typeof m?null:"string"==typeof m||"number"==typeof m||"bigint"==typeof m?p(null,m,null,null,m):Array.isArray(m)?p(h,{children:m},null,null,null):m.__b>0?p(m.type,m.props,m.key,null,m.__v):m)){if(m.__=_,m.__b=_.__b+1,null===(y=H[a])||y&&m.key==y.key&&m.type===y.type)H[a]=void 0;else for(d=0;d<E;d++){if((y=H[d])&&m.key==y.key&&m.type===y.type){H[d]=void 0;break}y=null}P(e,m,y=y||l,o,r,u,c,s,f),g=m.__e,(d=m.ref)&&y.ref!=d&&(x||(x=[]),y.ref&&x.push(y.ref,null,m),x.push(d,m.__c||g,m)),null!=g?(null==k&&(k=g),"function"==typeof m.type&&null!=m.__k&&m.__k===y.__k?m.__d=s=b(m,s,e):s=C(e,m,y,H,g,s),f||"option"!==_.type?"function"==typeof _.type&&(_.__d=s):e.value=""):s&&y.__e==s&&s.parentNode!=e&&(s=v(y))}for(_.__e=k,a=E;a--;)null!=H[a]&&("function"==typeof _.type&&null!=H[a].__e&&H[a].__e==_.__d&&(_.__d=v(t,a+1)),U(H[a],H[a]));if(x)for(a=0;a<x.length;a++)T(x[a],x[++a],x[++a])}function b(e,n,_){var t,o;for(t=0;t<e.__k.length;t++)(o=e.__k[t])&&(o.__=e,n="function"==typeof o.type?b(o,n,_):C(_,o,o,e.__k,o.__e,n));return n}function C(e,n,_,t,o,r){var u,l,i;if(void 0!==n.__d)u=n.__d,n.__d=void 0;else if(null==_||o!=r||null==o.parentNode)e:if(null==r||r.parentNode!==e)e.appendChild(o),u=null;else{for(l=r,i=0;(l=l.nextSibling)&&i<t.length;i+=2)if(l==o)break e;e.insertBefore(o,r),u=r}return void 0!==u?u:o.nextSibling}function x(e,n,_){"-"===n[0]?e.setProperty(n,_):e[n]=null==_?"":"number"!=typeof _||c.test(n)?_:_+"px"}function H(e,n,_,t,o){var r;e:if("style"===n)if("string"==typeof _)e.style.cssText=_;else{if("string"==typeof t&&(e.style.cssText=t=""),t)for(n in t)_&&n in _||x(e.style,n,"");if(_)for(n in _)t&&_[n]===t[n]||x(e.style,n,_[n])}else if("o"===n[0]&&"n"===n[1])r=n!==(n=n.replace(/Capture$/,"")),n=n.toLowerCase()in e?n.toLowerCase().slice(2):n.slice(2),e.l||(e.l={}),e.l[n+r]=_,_?t||e.addEventListener(n,r?S:E,r):e.removeEventListener(n,r?S:E,r);else if("dangerouslySetInnerHTML"!==n){if(o)n=n.replace(/xlink[H:h]/,"h").replace(/sName$/,"s");else if("href"!==n&&"list"!==n&&"form"!==n&&"tabIndex"!==n&&"download"!==n&&n in e)try{e[n]=null==_?"":_;break e}catch(e){}"function"==typeof _||(null!=_&&(!1!==_||"a"===n[0]&&"r"===n[1])?e.setAttribute(n,_):e.removeAttribute(n))}}function E(e){this.l[e.type+!1](n.event?n.event(e):e)}function S(e){this.l[e.type+!0](n.event?n.event(e):e)}function P(e,_,t,o,r,u,l,i,c){var f,a,p,v,y,m,g,b,C,x,H,E=_.type;if(void 0!==_.constructor)return null;null!=t.__h&&(c=t.__h,i=_.__e=t.__e,_.__h=null,u=[i]),(f=n.__b)&&f(_);try{e:if("function"==typeof E){if(b=_.props,C=(f=E.contextType)&&o[f.__c],x=f?C?C.props.value:f.__:o,t.__c?g=(a=_.__c=t.__c).__=a.__E:("prototype"in E&&E.prototype.render?_.__c=a=new E(b,x):(_.__c=a=new d(b,x),a.constructor=E,a.render=A),C&&C.sub(a),a.props=b,a.state||(a.state={}),a.context=x,a.__n=o,p=a.__d=!0,a.__h=[]),null==a.__s&&(a.__s=a.state),null!=E.getDerivedStateFromProps&&(a.__s==a.state&&(a.__s=s({},a.__s)),s(a.__s,E.getDerivedStateFromProps(b,a.__s))),v=a.props,y=a.state,p)null==E.getDerivedStateFromProps&&null!=a.componentWillMount&&a.componentWillMount(),null!=a.componentDidMount&&a.__h.push(a.componentDidMount);else{if(null==E.getDerivedStateFromProps&&b!==v&&null!=a.componentWillReceiveProps&&a.componentWillReceiveProps(b,x),!a.__e&&null!=a.shouldComponentUpdate&&!1===a.shouldCompLine truncated
@@ -0,0 +1,43 @@
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: 100%; font: 16px sans-serif; }
select, input, label::before, textarea { outline: none; box-shadow:none !important; border: 1px solid #ccc !important; }
code, pre { color: #373; font-family: monospace; font-weight: bolder; font-size: smaller; background: #ddd; padding: 0.1em 0.3em; border-radius: 0.2em; }
textarea, input, .addon { font-size: 15px; border: 1px solid #ccc; padding: 0.5em; }
a, a:visited, a:active { color: #55f; }
.addon { background: #eee; min-width: 9em;}
.btn {
background: #ccc; border-radius: 0.3em; border: 0; color: #fff; cursor: pointer;
display: inline-block; padding: 0.6em 2em; font-weight: bolder;
}
.btn[disabled] { opacity: 0.5; cursor: auto;}
.smooth { transition: all .2s; }
.container { margin: 0 20px; width: auto; }
.d-flex { display: flex; }
.d-none { display: none; }
.border { border: 1px solid #ddd; }
.rounded { border-radius: 0.5em; }
.nowrap { white-space: nowrap; }
.msg { background: #def; border-left: 5px solid #59d; padding: 0.5em; font-size: 90%; margin: 1em 0; }
.section { margin: 0 1em; }
.topic, .data, .qos { padding: 0.2em 0.5em; border-radius: 0.4em; margin-right: 0.5em; }
.qos { background: #efa; }
.topic { background: #fea; }
.data { background: #aef; }
/* Grid */
.row { display: flex; flex-wrap: wrap; }
.col { margin: 0; padding: 0; overflow: auto; }
.col-12 { width: 100%; }
.col-11 { width: 91.66%; }
.col-10 { width: 83.33%; }
.col-9 { width: 75%; }
.col-8 { width: 66.66%; }
.col-7 { width: 58.33%; }
.col-6 { width: 50%; }
.col-5 { width: 41.66%; }
.col-4 { width: 33.33%; }
.col-3 { width: 25%; }
.col-2 { width: 16.66%; }
.col-1 { width: 8.33%; }
@media (min-width: 1310px) { .container { margin: auto; width: 1270px; } }
@media (max-width: 920px) { .row .col { width: 100%; } }
-15
View File
@@ -1,15 +0,0 @@
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
-28
View File
@@ -1,28 +0,0 @@
# 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
```
File renamed without changes.
+38
View File
@@ -0,0 +1,38 @@
THISDIR = $(realpath $(CURDIR))
ROOTDIR = $(realpath $(CURDIR)/../../..)
DOCKER ?= docker run --rm $(DA) -v $(ROOTDIR):$(ROOTDIR) -w $(THISDIR) espressif/idf
CMD ?= idf.py build
PORT ?= /dev/ttyUSB0
all: example
example:
true
build: Makefile $(wildcard main/*)
$(DOCKER) $(CMD)
flash:
flash: CMD = idf.py flash
flash: DA = --device $(PORT)
flash: build
.PHONY: build
dashboard.hex: build
esputil mkhex \
0x8000 build/partition_table/partition-table.bin \
0x1000 build/bootloader/bootloader.bin \
0x100000 build/mongoose-esp32-example.bin > $@
flash2: dashboard.hex
esputil -p $(PORT) -b 921600 -fp 0x220 flash dashboard.hex
esputil -p $(PORT) monitor
ESPTOOL ?= esptool.py
flash3:
cd build && $(ESPTOOL) --chip esp32 -p $(PORT) -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:
$(DOCKER) rm -rf build sdkconfig
@@ -0,0 +1 @@
See detailed tutorial at https://mongoose.ws/tutorials/esp32/device-dashboard
@@ -0,0 +1,7 @@
idf_component_register(SRCS "main.c"
"wifi.c"
"net.c"
"packed_fs.c"
"mongoose.c")
component_compile_options(-DMG_ENABLE_LINES)
component_compile_options(-DMG_ENABLE_PACKED_FS)
@@ -0,0 +1,35 @@
// Copyright (c) 2020 Cesanta Software Limited
// All rights reserved
#include "esp_spiffs.h"
//#include "freertos/FreeRTOS.h"
#include "mongoose.h"
const char *s_listening_url = "http://0.0.0.0:80";
void device_dashboard_fn(struct mg_connection *, int, void *, void *);
#define WIFI_SSID "YOUR_WIFI_NETWORK_NAME" // SET THIS!
#define WIFI_PASS "YOUR_WIFI_PASSWORD" // SET THIS!
#define FS_ROOT "/spiffs"
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);
MG_INFO(("FS %s, %d", conf.base_path, res));
mg_file_printf(&mg_fs_posix, 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(MG_LL_DEBUG); // Set log level
mg_mgr_init(&mgr);
MG_INFO(("Mongoose v%s on %s", MG_VERSION, s_listening_url));
mg_http_listen(&mgr, s_listening_url, device_dashboard_fn, &mgr);
for (;;) mg_mgr_poll(&mgr, 1000); // Infinite event loop
}
+1
View File
@@ -0,0 +1 @@
../../../../mongoose.c
+1
View File
@@ -0,0 +1 @@
../../../../mongoose.h
+1
View File
@@ -0,0 +1 @@
../../../device-dashboard/net.c
+1
View File
@@ -0,0 +1 @@
../../../device-dashboard/packed_fs.c
@@ -35,14 +35,14 @@ static void event_handler(void *arg, esp_event_base_t event_base,
if (s_retry_num < 3) { if (s_retry_num < 3) {
esp_wifi_connect(); esp_wifi_connect();
s_retry_num++; s_retry_num++;
LOG(LL_INFO, ("retry to connect to the AP")); MG_INFO(("retry to connect to the AP"));
} else { } else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
} }
LOG(LL_ERROR, ("connect to the AP fail")); MG_ERROR(("connect to the AP fail"));
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { } 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; ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
LOG(LL_INFO, ("got ip:" IPSTR, IP2STR(&event->ip_info.ip))); MG_INFO(("IP ADDRESS:" IPSTR, IP2STR(&event->ip_info.ip)));
s_retry_num = 0; s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
} }
@@ -81,18 +81,18 @@ void wifi_init(const char *ssid, const char *pass) {
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); 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_set_config(ESP_IF_WIFI_STA, &c));
ESP_ERROR_CHECK(esp_wifi_start()); ESP_ERROR_CHECK(esp_wifi_start());
LOG(LL_DEBUG, ("wifi_init_sta finished.")); MG_DEBUG(("wifi_init_sta finished."));
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE, pdFALSE, portMAX_DELAY); pdFALSE, pdFALSE, portMAX_DELAY);
if (bits & WIFI_CONNECTED_BIT) { if (bits & WIFI_CONNECTED_BIT) {
LOG(LL_INFO, ("connected to ap SSID:%s password:%s", ssid, pass)); MG_INFO(("connected to ap SSID:%s password:%s", ssid, pass));
} else if (bits & WIFI_FAIL_BIT) { } else if (bits & WIFI_FAIL_BIT) {
LOG(LL_ERROR, ("Failed to connect to SSID:%s, password:%s", ssid, pass)); MG_ERROR(("Failed to connect to SSID:%s, password:%s", ssid, pass));
} else { } else {
LOG(LL_ERROR, ("UNEXPECTED EVENT")); MG_ERROR(("UNEXPECTED EVENT"));
} }
/* The event will not be processed after unregister */ /* The event will not be processed after unregister */
File renamed without changes.
Internal Server Error - Gitea: Git with a cup of tea
500 Internal Server Error

An error occurred:

An error occurred

Gitea Version: 28.2.0