Adicionar primeiro
6
components/mongoose/mongoose/.clang-format
Executable file
@@ -0,0 +1,6 @@
|
||||
BasedOnStyle: Google
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
SpaceAfterCStyleCast: true
|
||||
PointerBindsToType: false
|
||||
DerivePointerBinding: false
|
||||
IncludeBlocks: Preserve
|
||||
16
components/mongoose/mongoose/LICENSE
Executable file
@@ -0,0 +1,16 @@
|
||||
Copyright (c) 2004-2013 Sergey Lyubka
|
||||
Copyright (c) 2013-2021 Cesanta Software Limited
|
||||
All rights reserved
|
||||
|
||||
This software is dual-licensed: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation. For the terms of this
|
||||
license, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
You are free to use this software under the terms of the GNU General
|
||||
Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
Alternatively, you can license this software under a commercial
|
||||
license, as set out in <https://mongoose.ws/licensing/>.
|
||||
73
components/mongoose/mongoose/README.md
Executable file
@@ -0,0 +1,73 @@
|
||||
# Mongoose - Embedded Web Server / Embedded Networking Library
|
||||
|
||||
[](https://opensource.org/licenses/gpl-2.0.php)
|
||||
[](https://github.com/cesanta/mongoose/actions)
|
||||
[](https://codecov.io/gh/cesanta/mongoose)
|
||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:mongoose)
|
||||
|
||||
Mongoose is a networking library for C/C++. It implements event-driven
|
||||
non-blocking APIs for TCP, UDP, HTTP, WebSocket, MQTT. It is designed for
|
||||
connecting devices and bringing them online. On the market since 2004, used by
|
||||
vast number of open source and commercial products - it even runs on the
|
||||
International Space Station! Mongoose makes embedded network programming fast,
|
||||
robust, and easy. Features include:
|
||||
|
||||
- Cross-platform: works on Linux/UNIX, MacOS, Windows, Android, FreeRTOS, etc.
|
||||
- Supported embedded architectures: ESP32, NRF52, STM32, NXP, and more
|
||||
- Built-in protocols: plain TCP/UDP, HTTP, MQTT, Websocket
|
||||
- SSL/TLS support: mbedTLS, OpenSSL or custom (via API)
|
||||
- Asynchronous DNS resolver
|
||||
- Tiny static and run-time footprint
|
||||
- Source code is both ISO C and ISO C++ compliant
|
||||
- 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
|
||||
- Detailed [documentation](https://mongoose.ws/documentation/) and
|
||||
[tutorials](https://mongoose.ws/tutorials/)
|
||||
|
||||
|
||||
# Commercial use
|
||||
- Mongoose is used by hundreds of businesses, from Fortune500 giants like
|
||||
Siemens, Schneider Electric, Broadcom, Bosch, Google, Samsung, Qualcomm, Caterpillar to the small businesses
|
||||
- Used to solve a wide range of business needs, like implementing Web UI
|
||||
interface on devices, RESTful API services, telemetry data exchange, remote
|
||||
control for a product, remote software updates, remote monitoring, and others
|
||||
- Deployed to hundreds of millions devices in production environment worldwide
|
||||
- See [Case Studies](https://mongoose.ws/case-studies/) from our respected
|
||||
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
|
||||
- See [Testimonials](https://mongoose.ws/testimonials/) from engineers that integrated Mongoose in their commercial products
|
||||
- We provide [Evaluation and Commercial licensing](https://mongoose.ws/licensing/), [support](https://mongoose.ws/support/), consultancy and integration
|
||||
assistance - don't hesitate to [contact us](https://mongoose.ws/contact/)
|
||||
|
||||
|
||||
# Security
|
||||
|
||||
We take security seriously:
|
||||
1. Mongoose repository runs a
|
||||
[continuous integration test powered by GitHub](https://github.com/cesanta/mongoose/actions),
|
||||
which runs through hundreds of unit tests on every commit to the repository.
|
||||
Our [unit tests](https://github.com/cesanta/mongoose/tree/master/test)
|
||||
are built with modern address sanitizer technologies, which help to find
|
||||
security vulnerabilities early
|
||||
2. Mongoose repository is integrated into Google's
|
||||
[oss-fuzz continuous fuzzer](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:mongoose)
|
||||
which scans for potential vulnerabilities continuously
|
||||
3. We receive periodic vulnerability reports from the independent security
|
||||
groups like
|
||||
[Cisco Talos](https://www.cisco.com/c/en/us/products/security/talos.html),
|
||||
[Microsoft Security Response Center](https://www.microsoft.com/en-us/msrc),
|
||||
[MITRE Corporation](https://www.mitre.org/),
|
||||
[Compass Security](https://www.compass-security.com/en/) and others.
|
||||
In case of the vulnerability found, we act according to the industry best
|
||||
practice: hold on to the publication, fix the software and notify all our
|
||||
customers that have an appropriate subscription
|
||||
4. Some of our customers (for example NASA)
|
||||
have specific security requirements and run independent security audits,
|
||||
of which we get notified and in case of any issue, act similar to (3).
|
||||
|
||||
|
||||
# Contributions
|
||||
|
||||
Contributions are welcome! Please follow the guidelines below:
|
||||
|
||||
- Sign [Cesanta CLA](https://cesanta.com/cla.html) and send GitHub pull request
|
||||
- Make sure that PRs have only one commit, and deal with one issue only
|
||||
4188
components/mongoose/mongoose/docs/README.md
Executable file
97
components/mongoose/mongoose/docs/images/mg_commalist.svg
Executable 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(&s, &k, &v); </text>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<text transform="matrix(1 0 0 1 21.294 197.1485)" class="st1 st2 st3">mg_commalist(&s, &k, &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
components/mongoose/mongoose/docs/images/mg_http_get_request_len.svg
Executable 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
components/mongoose/mongoose/docs/images/mg_http_message.svg
Executable 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&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">{"success": "true"}</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
components/mongoose/mongoose/docs/images/mg_http_next_multipart.svg
Executable 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(&hm->body, pos, &part);</text>
|
||||
<text transform="matrix(1 0 0 1 28.7 171.3107)" class="st3 st4 st5">pos = mg_http_next_multipart(&hm->body, pos, &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="--xyz"</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="foo"; filename="a.txt"</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="bar"; filename="b.txt"</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
components/mongoose/mongoose/docs/images/mg_http_part.svg
Executable 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="--xyz"</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="foo"; filename="a.txt"</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
components/mongoose/mongoose/docs/images/mg_http_reply.svg
Executable 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">"X-Header-1: additional value 1\r\n"</text>
|
||||
<text transform="matrix(1 0 0 1 159.5657 133.8079)" class="st2 st3 st4">"X-Header-2: additional value 2\r\n",</text>
|
||||
<text transform="matrix(1 0 0 1 159.5657 153.9079)" class="st2 st3 st4">"Hello, %s!", "world");</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
components/mongoose/mongoose/docs/images/mg_iobuf.svg
Executable 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
components/mongoose/mongoose/docs/images/mg_iobuf_add1.svg
Executable 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
components/mongoose/mongoose/docs/images/mg_iobuf_add2.svg
Executable 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
components/mongoose/mongoose/docs/images/mg_iobuf_del.svg
Executable 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
components/mongoose/mongoose/docs/images/packed.svg
Executable 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
components/mongoose/mongoose/examples/captive-dns-server/README.md
Executable file
@@ -0,0 +1 @@
|
||||
See detailed tutorial at https://mongoose.ws/tutorials/captive-dns-portal/
|
||||
58
components/mongoose/mongoose/examples/captive-dns-server/main.c
Executable file
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// Example captive DNS server (captive portal).
|
||||
// 1. Run `make`. This builds and starts a server on port 5533
|
||||
// 2. Run `dig -t A www.google.com -4 @localhost -p 5533`
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
static const char *s_listen_url = "udp://0.0.0.0:5533";
|
||||
|
||||
// DNS answer section. We response with IP 1.2.3.4 - you can change it
|
||||
// in the last 4 bytes of this array
|
||||
uint8_t answer[] = {
|
||||
0xc0, 0x0c, // Point to the name in the DNS question
|
||||
0, 1, // 2 bytes - record type, A
|
||||
0, 1, // 2 bytes - address class, INET
|
||||
0, 0, 0, 120, // 4 bytes - TTL
|
||||
0, 4, // 2 bytes - address length
|
||||
1, 2, 3, 4 // 4 bytes - IP address
|
||||
};
|
||||
|
||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_OPEN) {
|
||||
c->is_hexdumping = 1;
|
||||
} else if (ev == MG_EV_READ) {
|
||||
struct mg_dns_rr rr; // Parse first question, offset 12 is header size
|
||||
size_t n = mg_dns_parse_rr(c->recv.buf, c->recv.len, 12, true, &rr);
|
||||
MG_INFO(("DNS request parsed, result=%d", (int) n));
|
||||
if (n > 0) {
|
||||
char buf[512];
|
||||
struct mg_dns_header *h = (struct mg_dns_header *) buf;
|
||||
memset(buf, 0, sizeof(buf)); // Clear the whole datagram
|
||||
h->txnid = ((struct mg_dns_header *) c->recv.buf)->txnid; // Copy tnxid
|
||||
h->num_questions = mg_htons(1); // We use only the 1st question
|
||||
h->num_answers = mg_htons(1); // And only one answer
|
||||
h->flags = mg_htons(0x8400); // Authoritative response
|
||||
memcpy(buf + sizeof(*h), c->recv.buf + sizeof(*h), n); // Copy question
|
||||
memcpy(buf + sizeof(*h) + n, answer, sizeof(answer)); // And answer
|
||||
mg_send(c, buf, 12 + n + sizeof(answer)); // And send it!
|
||||
}
|
||||
mg_iobuf_del(&c->recv, 0, c->recv.len);
|
||||
}
|
||||
(void) fn_data;
|
||||
(void) ev_data;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
|
||||
mg_log_set(MG_LL_DEBUG); // Set log level
|
||||
mg_mgr_init(&mgr); // Initialise event manager
|
||||
mg_listen(&mgr, s_listen_url, fn, NULL); // Start DNS server
|
||||
for (;;) mg_mgr_poll(&mgr, 1000); // Event loop
|
||||
mg_mgr_free(&mgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
27
components/mongoose/mongoose/examples/device-dashboard/README.md
Executable 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
|
||||
|
||||

|
||||
|
||||
# Main dashboard
|
||||
|
||||
A main dashboard page shows and interactive MQTT console
|
||||
|
||||

|
||||
1
components/mongoose/mongoose/examples/device-dashboard/ca.pem
Symbolic link
@@ -0,0 +1 @@
|
||||
../../test/data/ca.pem
|
||||
18
components/mongoose/mongoose/examples/device-dashboard/main.c
Executable 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
components/mongoose/mongoose/examples/device-dashboard/net.c
Executable 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]));
|
||||
}
|
||||
}
|
||||
2830
components/mongoose/mongoose/examples/device-dashboard/packed_fs.c
Executable file
BIN
components/mongoose/mongoose/examples/device-dashboard/screenshots/dashboard.png
Executable file
|
After Width: | Height: | Size: 282 KiB |
BIN
components/mongoose/mongoose/examples/device-dashboard/screenshots/login.png
Executable file
|
After Width: | Height: | Size: 64 KiB |
12
components/mongoose/mongoose/examples/device-dashboard/web_root/index.html
Executable file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Device Dashboard</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="style.css" />
|
||||
</head>
|
||||
<body></body>
|
||||
<script type="module" src="main.js"></script>
|
||||
</html>
|
||||
378
components/mongoose/mongoose/examples/device-dashboard/web_root/main.js
Executable 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
components/mongoose/mongoose/examples/device-dashboard/web_root/preact.min.js
vendored
Executable file
43
components/mongoose/mongoose/examples/device-dashboard/web_root/style.css
Executable file
@@ -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%; } }
|
||||
BIN
components/mongoose/mongoose/examples/device-dashboard/web_root/user.png
Executable file
|
After Width: | Height: | Size: 3.8 KiB |
28
components/mongoose/mongoose/examples/embedded-filesystem/main.c
Executable 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;
|
||||
}
|
||||
1565
components/mongoose/mongoose/examples/embedded-filesystem/packed_fs.c
Executable file
@@ -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>
|
||||
88
components/mongoose/mongoose/examples/embedded-filesystem/web_root/main.js
Executable file
@@ -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
components/mongoose/mongoose/examples/embedded-filesystem/web_root/preact.min.js
vendored
Executable file
43
components/mongoose/mongoose/examples/embedded-filesystem/web_root/style.css
Executable file
@@ -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%; } }
|
||||
@@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(mongoose-esp32-example)
|
||||
1
components/mongoose/mongoose/examples/esp32/device-dashboard/README.md
Executable file
@@ -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)
|
||||
35
components/mongoose/mongoose/examples/esp32/device-dashboard/main/main.c
Executable file
@@ -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
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../../mongoose.c
|
||||
@@ -0,0 +1 @@
|
||||
../../../../mongoose.h
|
||||
@@ -0,0 +1 @@
|
||||
../../../device-dashboard/net.c
|
||||
@@ -0,0 +1 @@
|
||||
../../../device-dashboard/packed_fs.c
|
||||
104
components/mongoose/mongoose/examples/esp32/device-dashboard/main/wifi.c
Executable file
@@ -0,0 +1,104 @@
|
||||
// Code taken from the ESP32 IDF WiFi station Example
|
||||
|
||||
#include <string.h>
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "freertos/task.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
static EventGroupHandle_t s_wifi_event_group;
|
||||
|
||||
/* The event group allows multiple bits for each event, but we only care about
|
||||
* two events:
|
||||
* - we are connected to the AP with an IP
|
||||
* - we failed to connect after the maximum amount of retries */
|
||||
#define WIFI_CONNECTED_BIT BIT0
|
||||
#define WIFI_FAIL_BIT BIT1
|
||||
|
||||
static int s_retry_num = 0;
|
||||
|
||||
static void event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data) {
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||
esp_wifi_connect();
|
||||
} else if (event_base == WIFI_EVENT &&
|
||||
event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
if (s_retry_num < 3) {
|
||||
esp_wifi_connect();
|
||||
s_retry_num++;
|
||||
MG_INFO(("retry to connect to the AP"));
|
||||
} else {
|
||||
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
|
||||
}
|
||||
MG_ERROR(("connect to the AP fail"));
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
|
||||
MG_INFO(("IP ADDRESS:" IPSTR, IP2STR(&event->ip_info.ip)));
|
||||
s_retry_num = 0;
|
||||
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
void wifi_init(const char *ssid, const char *pass) {
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
|
||||
ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
s_wifi_event_group = xEventGroupCreate();
|
||||
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
esp_netif_create_default_wifi_sta();
|
||||
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
|
||||
esp_event_handler_instance_t instance_any_id;
|
||||
esp_event_handler_instance_t instance_got_ip;
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
||||
WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id));
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
||||
IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip));
|
||||
|
||||
wifi_config_t c = {.sta = {.threshold = {.authmode = WIFI_AUTH_WPA2_PSK},
|
||||
.pmf_cfg = {.capable = true, .required = false}}};
|
||||
snprintf((char *) c.sta.ssid, sizeof(c.sta.ssid), "%s", ssid);
|
||||
snprintf((char *) c.sta.password, sizeof(c.sta.password), "%s", pass);
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &c));
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
MG_DEBUG(("wifi_init_sta finished."));
|
||||
|
||||
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
|
||||
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
|
||||
pdFALSE, pdFALSE, portMAX_DELAY);
|
||||
|
||||
if (bits & WIFI_CONNECTED_BIT) {
|
||||
MG_INFO(("connected to ap SSID:%s password:%s", ssid, pass));
|
||||
} else if (bits & WIFI_FAIL_BIT) {
|
||||
MG_ERROR(("Failed to connect to SSID:%s, password:%s", ssid, pass));
|
||||
} else {
|
||||
MG_ERROR(("UNEXPECTED EVENT"));
|
||||
}
|
||||
|
||||
/* The event will not be processed after unregister */
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(
|
||||
IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(
|
||||
WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
|
||||
vEventGroupDelete(s_wifi_event_group);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
storage, data, spiffs, 0x10000, 0x10000,
|
||||
factory, app, factory, 0x100000, 1M,
|
||||
|
6
components/mongoose/mongoose/examples/esp32/uart-bridge/CMakeLists.txt
Executable file
@@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(mongoose-esp32-example)
|
||||
61
components/mongoose/mongoose/examples/esp32/uart-bridge/README.md
Executable file
@@ -0,0 +1,61 @@
|
||||
# A UART to network bridge for ESP32
|
||||
|
||||
This example is a demonstration of how Mongoose Library could be integrated
|
||||
into an embedded device and provide a UART-to-Network bridge capability:
|
||||
|
||||
- A device opens listening TCP port and Websocket port and waits for connections
|
||||
- When a client connects, data is exchanged with the device's UART
|
||||
- Everything that client send, is sent to the UART
|
||||
- Everything that is read from the UART, gets sent to the client
|
||||
- Multiple clients are allowed
|
||||
- Live UART console allows to talk to the UART from the web page
|
||||
- Web UI is hardcoded into the binary and does not need a filesystem
|
||||
|
||||
# Screenshots
|
||||
|
||||

|
||||
|
||||
# Build and flash
|
||||
|
||||
Build requires Docker installed, and uses Espressif's ESP-IDF docker image:
|
||||
|
||||
```sh
|
||||
make build
|
||||
make flash PORT=/dev/YOURSERIAL
|
||||
```
|
||||
|
||||
# Flash pre-built firmware
|
||||
|
||||
You can flash a pre-built firmware to the ESP32 device using the following
|
||||
instructions:
|
||||
|
||||
1. Connect your ESP32 device to the workstation. It should be accessible
|
||||
via a serial port
|
||||
2. Download and unzip ESP32 flashing tool from https://mongoose.ws/downloads/esputil.zip
|
||||
3. Download a prebuilt firmware https://mongoose.ws/downloads/uart-bridge.hex into the unzipped directory
|
||||
4. Start command prompt (or terminal on Mac/Linux). Run `cd
|
||||
PATH/TO/esputil` to go into the unzipped `esputil/` directory. After that, run
|
||||
the following command (change `COMPORT` to the board's serial port):
|
||||
|
||||
| OS | Command |
|
||||
| ------- | ------- |
|
||||
| Windows | <pre><code class="language-bash">.\windows\esputil -p COMPORT flash uart-bridge.hex</code></pre>|
|
||||
| Linux | <pre><code class="language-bash">./linux/esputil -p COMPORT flash uart-bridge.hex</pre> |
|
||||
| MacOS | <pre><code class="language-bash">./macos/esputil -p COMPORT flash uart-bridge.hex</code></pre> |
|
||||
|
||||
Next step is to monitor and follow the instructions.
|
||||
|
||||
```sh
|
||||
esputil -p COMPORT monitor
|
||||
```
|
||||
|
||||
Note: if monitor command shows constant restarts, the flash parameters
|
||||
settings can be wrong. Reflash your device with `-fp ...` flash parameters
|
||||
settings. For example, WROOM-32 based boards use `-fp 0x220`:
|
||||
|
||||
```sh
|
||||
esputil -p COMPORT -fp 0x220 flash uart-bridge.hex
|
||||
```
|
||||
|
||||
For more on possible options for flash parameters, see
|
||||
https://github.com/cpq/esputil#flash-parameters
|
||||
10
components/mongoose/mongoose/examples/esp32/uart-bridge/main/CMakeLists.txt
Executable file
@@ -0,0 +1,10 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
"wifi.c"
|
||||
"uart.c"
|
||||
"cli.c"
|
||||
"net.c"
|
||||
"packed_fs.c"
|
||||
"mongoose.c")
|
||||
component_compile_options(-DMG_ENABLE_LINES=1)
|
||||
component_compile_options(-DMG_ENABLE_PACKED_FS=1)
|
||||
component_compile_options(-DUART_API_IMPLEMENTED=1)
|
||||
93
components/mongoose/mongoose/examples/esp32/uart-bridge/main/cli.c
Executable file
@@ -0,0 +1,93 @@
|
||||
#include "main.h"
|
||||
|
||||
static void cli_wifi(const char *ssid, const char *pass) {
|
||||
if (wifi_init(ssid, pass)) {
|
||||
mg_file_printf(&mg_fs_posix, WIFI_FILE, "{%Q:%Q,%Q:%Q}\n", "ssid", ssid,
|
||||
"pass", pass);
|
||||
MG_INFO(("Reboot now"));
|
||||
}
|
||||
}
|
||||
|
||||
static void cli_ls(void) {
|
||||
DIR *dirp = opendir(FS_ROOT);
|
||||
struct dirent *dp;
|
||||
if (dirp == NULL) {
|
||||
MG_ERROR(("Cannot open FS: %d", errno));
|
||||
} else {
|
||||
while ((dp = readdir(dirp)) != NULL) {
|
||||
/* Do not show current and parent dirs */
|
||||
if (strcmp((const char *) dp->d_name, ".") == 0 ||
|
||||
strcmp((const char *) dp->d_name, "..") == 0) {
|
||||
continue;
|
||||
} else {
|
||||
printf("%s\n", dp->d_name);
|
||||
}
|
||||
}
|
||||
closedir(dirp);
|
||||
}
|
||||
}
|
||||
|
||||
static void cli_cat(const char *fname) {
|
||||
char path[MG_PATH_MAX];
|
||||
snprintf(path, sizeof(path), "%s/%s", FS_ROOT, fname);
|
||||
FILE *fp = fopen(path, "r");
|
||||
if (fp != NULL) {
|
||||
int ch;
|
||||
while ((ch = fgetc(fp)) != EOF) putchar(ch);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
static void cli_rm(const char *fname) {
|
||||
char path[100];
|
||||
snprintf(path, sizeof(path), "%s/%s", FS_ROOT, fname);
|
||||
remove(path);
|
||||
}
|
||||
|
||||
static struct mg_iobuf in;
|
||||
|
||||
void cli(uint8_t input_byte) {
|
||||
if (input_byte == 0 || input_byte == 0xff) return;
|
||||
if (in.len >= 128) in.len = 0;
|
||||
mg_iobuf_add(&in, in.len, &input_byte, sizeof(input_byte));
|
||||
|
||||
if (input_byte == '\n') {
|
||||
const char *arrow = "---";
|
||||
char buf0[10], buf1[50], buf2[250];
|
||||
|
||||
in.buf[in.len] = '\0';
|
||||
buf0[0] = buf1[0] = buf2[0] = '\0';
|
||||
sscanf((char *) in.buf, "%9s %49s %249[^\r\n]", buf0, buf1, buf2);
|
||||
|
||||
printf("%s CLI command: '%s'\n", arrow, buf0);
|
||||
if (strcmp(buf0, "reboot") == 0) {
|
||||
esp_restart();
|
||||
} else if (strcmp(buf0, "ls") == 0) {
|
||||
cli_ls();
|
||||
} else if (strcmp(buf0, "cat") == 0) {
|
||||
cli_cat(buf1);
|
||||
} else if (strcmp(buf0, "rm") == 0) {
|
||||
cli_rm(buf1);
|
||||
} else if (strcmp(buf0, "reboot") == 0) {
|
||||
esp_restart();
|
||||
} else if (strcmp(buf0, "ll") == 0) {
|
||||
mg_log_set(atoi(buf1));
|
||||
} else if (strcmp(buf0, "wifi") == 0) {
|
||||
cli_wifi(buf1, buf2);
|
||||
} else {
|
||||
printf("%s %s\n", arrow, "Unknown command. Usage:");
|
||||
printf("%s %s\n", arrow, " set NAME VALUE");
|
||||
printf("%s %s\n", arrow, " rm FILENAME");
|
||||
printf("%s %s\n", arrow, " cat FILENAME");
|
||||
printf("%s %s\n", arrow, " ls");
|
||||
printf("%s %s\n", arrow, " reboot");
|
||||
printf("%s %s\n", arrow, " wifi WIFI_NET WIFI_PASS");
|
||||
}
|
||||
printf("%s %s\n", arrow, "CLI output end");
|
||||
in.len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void cli_init(void) {
|
||||
mg_iobuf_init(&in, 0, 32);
|
||||
}
|
||||
50
components/mongoose/mongoose/examples/esp32/uart-bridge/main/main.c
Executable file
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#include "main.h"
|
||||
|
||||
const char *s_listening_url = "http://0.0.0.0:80";
|
||||
|
||||
char *config_read(void) {
|
||||
return mg_file_read(&mg_fs_posix, FS_ROOT "/config.json", NULL);
|
||||
}
|
||||
|
||||
void config_write(struct mg_str config) {
|
||||
mg_file_write(&mg_fs_posix, FS_ROOT "/config.json", config.ptr, config.len);
|
||||
}
|
||||
|
||||
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 at %s initialised, status: %d", conf.base_path, res));
|
||||
|
||||
// Try to connect to wifi by using saved WiFi credentials
|
||||
char *json = mg_file_read(&mg_fs_posix, WIFI_FILE, NULL);
|
||||
if (json != NULL) {
|
||||
char *ssid = mg_json_get_str(mg_str(json), "$.ssid");
|
||||
char *pass = mg_json_get_str(mg_str(json), "$.pass");
|
||||
while (!wifi_init(ssid, pass)) (void) 0;
|
||||
free(ssid);
|
||||
free(pass);
|
||||
free(json);
|
||||
} else {
|
||||
// If WiFi is not configured, run CLI until configured
|
||||
MG_INFO(("WiFi is not configured, running CLI. Press enter"));
|
||||
cli_init();
|
||||
for (;;) {
|
||||
uint8_t ch = getchar();
|
||||
cli(ch);
|
||||
usleep(10000);
|
||||
}
|
||||
}
|
||||
|
||||
// Connected to WiFi, now start HTTP server
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_log_set(MG_LL_DEBUG); // Set log level
|
||||
MG_INFO(("Mongoose v%s on %s", MG_VERSION, s_listening_url));
|
||||
mg_http_listen(&mgr, s_listening_url, uart_bridge_fn, &mgr);
|
||||
for (;;) mg_mgr_poll(&mgr, 10); // Infinite event loop
|
||||
}
|
||||
18
components/mongoose/mongoose/examples/esp32/uart-bridge/main/main.h
Executable file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "esp_spiffs.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
|
||||
#define FS_ROOT "/spiffs"
|
||||
#define WIFI_FILE FS_ROOT "/wifi.json"
|
||||
#define UART_NO 1
|
||||
|
||||
void uart_bridge_fn(struct mg_connection *, int, void *, void *);
|
||||
int uart_read(void *buf, size_t len);
|
||||
bool wifi_init(const char *ssid, const char *pass);
|
||||
void cli(uint8_t ch);
|
||||
void cli_init(void);
|
||||
@@ -0,0 +1 @@
|
||||
../../../../mongoose.c
|
||||
@@ -0,0 +1 @@
|
||||
../../../../mongoose.h
|
||||
@@ -0,0 +1 @@
|
||||
../../../uart-bridge/net.c
|
||||
@@ -0,0 +1 @@
|
||||
../../../uart-bridge/packed_fs.c
|
||||
44
components/mongoose/mongoose/examples/esp32/uart-bridge/main/uart.c
Executable file
@@ -0,0 +1,44 @@
|
||||
#include "main.h"
|
||||
|
||||
int uart_close(int no) {
|
||||
return uart_driver_delete(no);
|
||||
}
|
||||
|
||||
int uart_open(int no, int rx, int tx, int cts, int rts, int baud) {
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = baud,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = cts > 0 && rts > 0 ? UART_HW_FLOWCTRL_CTS_RTS
|
||||
: cts > 0 ? UART_HW_FLOWCTRL_CTS
|
||||
: rts > 0 ? UART_HW_FLOWCTRL_RTS
|
||||
: UART_HW_FLOWCTRL_DISABLE,
|
||||
};
|
||||
int e1 = uart_param_config(no, &uart_config);
|
||||
int e2 = uart_set_pin(no, tx, rx, rts, cts);
|
||||
int e3 =
|
||||
uart_driver_install(no, UART_FIFO_LEN * 2, UART_FIFO_LEN * 2, 0, NULL, 0);
|
||||
MG_INFO(("%d: %d/%d/%d, %d %d %d", no, rx, tx, baud, e1, e2, e3));
|
||||
if (e1 != ESP_OK || e2 != ESP_OK || e3 != ESP_OK) return -1;
|
||||
return no;
|
||||
}
|
||||
|
||||
void uart_init(int tx, int rx, int baud) {
|
||||
uart_open(UART_NO, rx, tx, -1, -1, baud);
|
||||
}
|
||||
|
||||
int uart_read(void *buf, size_t len) {
|
||||
size_t x = 0;
|
||||
int no = UART_NO;
|
||||
if (uart_get_buffered_data_len(no, &x) != ESP_OK || x == 0) return 0;
|
||||
int n = uart_read_bytes(no, buf, len, 10 / portTICK_PERIOD_MS);
|
||||
MG_DEBUG(("%d bytes: [%.*s]", n, n, (char *) buf));
|
||||
return n;
|
||||
}
|
||||
|
||||
int uart_write(const void *buf, int len) {
|
||||
int no = UART_NO;
|
||||
MG_DEBUG(("%d bytes: [%.*s]", len, len, (char *) buf));
|
||||
return uart_write_bytes(no, (const char *) buf, len);
|
||||
}
|
||||
108
components/mongoose/mongoose/examples/esp32/uart-bridge/main/wifi.c
Executable file
@@ -0,0 +1,108 @@
|
||||
// Code taken from the ESP32 IDF WiFi station Example
|
||||
|
||||
#include <string.h>
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "freertos/task.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
static EventGroupHandle_t s_wifi_event_group;
|
||||
|
||||
/* The event group allows multiple bits for each event, but we only care about
|
||||
* two events:
|
||||
* - we are connected to the AP with an IP
|
||||
* - we failed to connect after the maximum amount of retries */
|
||||
#define WIFI_CONNECTED_BIT BIT0
|
||||
#define WIFI_FAIL_BIT BIT1
|
||||
|
||||
static int s_retry_num = 0;
|
||||
|
||||
static void event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data) {
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||
esp_wifi_connect();
|
||||
} else if (event_base == WIFI_EVENT &&
|
||||
event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
if (s_retry_num < 3) {
|
||||
esp_wifi_connect();
|
||||
s_retry_num++;
|
||||
MG_INFO(("retry to connect to the AP"));
|
||||
} else {
|
||||
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
|
||||
}
|
||||
MG_ERROR(("connect to the AP fail"));
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
|
||||
MG_INFO(("IP ADDRESS: " IPSTR ". Go to:", IP2STR(&event->ip_info.ip)));
|
||||
MG_INFO(("http://" IPSTR, IP2STR(&event->ip_info.ip)));
|
||||
s_retry_num = 0;
|
||||
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
bool wifi_init(const char *ssid, const char *pass) {
|
||||
bool result = false;
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
|
||||
ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
s_wifi_event_group = xEventGroupCreate();
|
||||
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
esp_netif_create_default_wifi_sta();
|
||||
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
|
||||
esp_event_handler_instance_t instance_any_id;
|
||||
esp_event_handler_instance_t instance_got_ip;
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
||||
WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id));
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
||||
IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip));
|
||||
|
||||
wifi_config_t c = {.sta = {.threshold = {.authmode = WIFI_AUTH_WPA2_PSK},
|
||||
.pmf_cfg = {.capable = true, .required = false}}};
|
||||
snprintf((char *) c.sta.ssid, sizeof(c.sta.ssid), "%s", ssid);
|
||||
snprintf((char *) c.sta.password, sizeof(c.sta.password), "%s", pass);
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &c));
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
MG_DEBUG(("wifi_init_sta finished."));
|
||||
|
||||
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
|
||||
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
|
||||
pdFALSE, pdFALSE, portMAX_DELAY);
|
||||
|
||||
if (bits & WIFI_CONNECTED_BIT) {
|
||||
MG_INFO(("connected to ap SSID:%s", ssid));
|
||||
result = true;
|
||||
} else if (bits & WIFI_FAIL_BIT) {
|
||||
MG_ERROR(("Failed to connect to SSID:%s, password:%s", ssid, pass));
|
||||
} else {
|
||||
MG_ERROR(("UNEXPECTED EVENT"));
|
||||
}
|
||||
|
||||
/* The event will not be processed after unregister */
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(
|
||||
IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(
|
||||
WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
|
||||
vEventGroupDelete(s_wifi_event_group);
|
||||
return result;
|
||||
}
|
||||
0
components/mongoose/mongoose/examples/esp32/uart-bridge/make
Executable file
5
components/mongoose/mongoose/examples/esp32/uart-bridge/partitions.csv
Executable file
@@ -0,0 +1,5 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
storage, data, spiffs, 0x10000, 0x10000,
|
||||
factory, app, factory, 0x100000, 1M,
|
||||
|
22
components/mongoose/mongoose/examples/esp8266/README.md
Executable file
@@ -0,0 +1,22 @@
|
||||
# An example ESP8266 application
|
||||
|
||||
To build this application, follow these steps:
|
||||
|
||||
1. Make sure you have Docker installed
|
||||
2. Clone whole mongoose repository on your machine:
|
||||
```sh
|
||||
git clone https://github.com/cesanta/mongoose.git
|
||||
```
|
||||
3. Start command line or terminal, and go into the example's directory:
|
||||
```sh
|
||||
cd mongoose/examples/esp8266
|
||||
```
|
||||
4. Run `make`. This invokes a Docker-based build. A firmware will be built
|
||||
in the `src/build/` directory:
|
||||
```sh
|
||||
make build
|
||||
```
|
||||
5. Flash your ESP8266. If you have esptool.py installed, the build process will end telling you the command to flash your device. You can just run `make` again to use Docker:
|
||||
```sh
|
||||
make flash PORT=/your/serial
|
||||
```
|
||||
10
components/mongoose/mongoose/examples/esp8266/src/main/component.mk
Executable file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Main component makefile.
|
||||
#
|
||||
# This Makefile can be left empty. By default, it will take the sources in the
|
||||
# src/ directory, compile them and link them into lib(subdirectory_name).a
|
||||
# in the build directory. This behaviour is entirely configurable,
|
||||
# please read the ESP-IDF documents if you need to do this.
|
||||
#
|
||||
|
||||
COMPONENT_INCLUDES += ../../../../..
|
||||
54
components/mongoose/mongoose/examples/esp8266/src/main/main.c
Executable file
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
#define WIFI_SSID "WIFI_NETWORK" // SET THIS!
|
||||
#define WIFI_PASS "WIFI_PASSWORD" // SET THIS!
|
||||
|
||||
#define SERVER_URL "http://0.0.0.0:80"
|
||||
#define CLIENT_URL "http://info.cern.ch"
|
||||
|
||||
// Event handler for an server (accepted) connection
|
||||
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
mg_http_reply(c, 200, "", "Hello from ESP!\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Event handler for a client connection - fetch the first web page in history
|
||||
// To enable TLS for HTTP,
|
||||
// 1. Copy "ca.pem" file to the ESP8266 flash FS
|
||||
// 2. Add TLS init snippet for the connection, see examples/http-client
|
||||
static void cb2(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_CONNECT) {
|
||||
struct mg_str s = mg_url_host(CLIENT_URL);
|
||||
mg_printf(c, "GET / HTTP/1.0\r\nHost: %.*s\r\n\r\n", (int) s.len, s.ptr);
|
||||
} else if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = ev_data; // Print HTTP response
|
||||
MG_INFO(("Fetched:\n%.*s", (int) hm->message.len, hm->message.ptr));
|
||||
c->is_closing = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Called after we're connected to WiFi network
|
||||
static void run_mongoose(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_log_set(MG_LL_DEBUG); // Set log level
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, SERVER_URL, cb, &mgr); // Listening server
|
||||
mg_http_connect(&mgr, CLIENT_URL, cb2, &mgr); // Example client
|
||||
MG_INFO(("Starting Mongoose web server v%s", MG_VERSION));
|
||||
for (;;) mg_mgr_poll(&mgr, 1000);
|
||||
mg_mgr_free(&mgr);
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
// Setup wifi. This function is implemented in wifi.c
|
||||
// It blocks until connected to the configured WiFi network
|
||||
void wifi_init(const char *ssid, const char *pass);
|
||||
wifi_init(WIFI_SSID, WIFI_PASS);
|
||||
|
||||
// Done connecting to WiFi, now start HTTP server
|
||||
run_mongoose();
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../../mongoose.c
|
||||
86
components/mongoose/mongoose/examples/esp8266/src/main/wifi.c
Executable file
@@ -0,0 +1,86 @@
|
||||
#include <string.h>
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "freertos/task.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
static EventGroupHandle_t s_wifi_event_group;
|
||||
|
||||
/* The event group allows multiple bits for each event, but we only care about
|
||||
* two events:
|
||||
* - we are connected to the AP with an IP
|
||||
* - we failed to connect after the maximum amount of retries */
|
||||
#define WIFI_CONNECTED_BIT BIT0
|
||||
#define WIFI_FAIL_BIT BIT1
|
||||
|
||||
static int s_retry_num = 0;
|
||||
|
||||
static void event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data) {
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||
esp_wifi_connect();
|
||||
} else if (event_base == WIFI_EVENT &&
|
||||
event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
if (s_retry_num < 3) {
|
||||
esp_wifi_connect();
|
||||
s_retry_num++;
|
||||
MG_DEBUG(("retry to connect to the AP"));
|
||||
} else {
|
||||
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
|
||||
}
|
||||
MG_ERROR(("connect to the AP fail"));
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
|
||||
MG_INFO(("got ip:%s", ip4addr_ntoa(&event->ip_info.ip)));
|
||||
s_retry_num = 0;
|
||||
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
void wifi_init(const char *ssid, const char *pass) {
|
||||
s_wifi_event_group = xEventGroupCreate();
|
||||
tcpip_adapter_init();
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID,
|
||||
&event_handler, NULL));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP,
|
||||
&event_handler, NULL));
|
||||
|
||||
wifi_config_t c = {};
|
||||
snprintf((char *) c.sta.ssid, sizeof(c.sta.ssid), "%s", ssid);
|
||||
snprintf((char *) c.sta.password, sizeof(c.sta.password), "%s", pass);
|
||||
if (pass != NULL && pass[0] != '\0') {
|
||||
c.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
|
||||
}
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &c));
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
|
||||
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
|
||||
pdFALSE, pdFALSE, portMAX_DELAY);
|
||||
|
||||
if (bits & WIFI_CONNECTED_BIT) {
|
||||
MG_INFO(("connected to ap SSID:%s password:%s", ssid, pass));
|
||||
} else if (bits & WIFI_FAIL_BIT) {
|
||||
MG_ERROR(("Failed to connect to SSID:%s, password:%s", ssid, pass));
|
||||
} else {
|
||||
MG_ERROR(("UNEXPECTED EVENT"));
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP,
|
||||
&event_handler));
|
||||
ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID,
|
||||
&event_handler));
|
||||
vEventGroupDelete(s_wifi_event_group);
|
||||
}
|
||||
1
components/mongoose/mongoose/examples/file-upload-html-form/README.md
Executable file
@@ -0,0 +1 @@
|
||||
See detailed tutorial at https://mongoose.ws/tutorials/file-uploads/
|
||||
51
components/mongoose/mongoose/examples/file-upload-html-form/main.c
Executable file
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2021 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
// HTTP request handler function. It implements the following endpoints:
|
||||
// /upload - prints all submitted form elements
|
||||
// all other URI - serves web_root/ directory
|
||||
//
|
||||
// ///////////////// IMPORTANT //////////////////////////
|
||||
//
|
||||
// Mongoose has a limit on input buffer, which also limits maximum upload size.
|
||||
// It is controlled by the MG_MAX_RECV_SIZE constant, which is set by
|
||||
// default to (3 * 1024 * 1024), i.e. 3 megabytes.
|
||||
// Use -DMG_MAX_BUF_SIZE=NEW_LIMIT to override it.
|
||||
//
|
||||
// Also, consider changing -DMG_IO_SIZE=SOME_BIG_VALUE to increase IO buffer
|
||||
// increment when reading data.
|
||||
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;
|
||||
MG_INFO(("New request to: [%.*s], body size: %lu", (int) hm->uri.len,
|
||||
hm->uri.ptr, (unsigned long) hm->body.len));
|
||||
if (mg_http_match_uri(hm, "/upload")) {
|
||||
struct mg_http_part part;
|
||||
size_t ofs = 0;
|
||||
while ((ofs = mg_http_next_multipart(hm->body, ofs, &part)) > 0) {
|
||||
MG_INFO(("Chunk name: [%.*s] filename: [%.*s] length: %lu bytes",
|
||||
(int) part.name.len, part.name.ptr, (int) part.filename.len,
|
||||
part.filename.ptr, (unsigned long) part.body.len));
|
||||
}
|
||||
mg_http_reply(c, 200, "", "Thank you!");
|
||||
} 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_log_set(MG_LL_DEBUG); // Set log level
|
||||
mg_http_listen(&mgr, "http://localhost:8000", cb, NULL);
|
||||
|
||||
for (;;) mg_mgr_poll(&mgr, 50);
|
||||
mg_mgr_free(&mgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<!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" />
|
||||
<style>
|
||||
#container { margin-right: auto; margin-left: auto; max-width: 480px; }
|
||||
#info { background: #e0f0f0; border-radius: .5em; padding: 2em; }
|
||||
#wrapper { margin-top: 1em; }
|
||||
form * { margin: 0.2em 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="info">
|
||||
Mongoose always buffers a full HTTP message before invoking
|
||||
MG_EV_HTTP_MSG event. Big POST request require of lot
|
||||
of RAM to buffer everything. Therefore, standard form uploads
|
||||
should be used only when Mongoose runs on a system with lots of RAM.
|
||||
Otherwise, please see <code>file-updload</code> example, how
|
||||
a big file could be uploaded to a device with little RAM.
|
||||
<br/><br/>
|
||||
In this example, a standard HTML form upload is used, which uses
|
||||
<code>multipart-form-data</code> encoding with
|
||||
several variables and file upload. On a server side, a
|
||||
<code>mg_http_next_multipart()</code> API is used to iterate over
|
||||
all submitted form elements and print their payload.
|
||||
</div>
|
||||
<div id="wrapper">
|
||||
<form action="/upload" method="post" enctype="multipart/form-data">
|
||||
<input type="text" name="field1" value="type some text here" /> <br/>
|
||||
<input type="file" name="file1" /> </br>
|
||||
<button type="submit">submit form</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
See detailed tutorial at https://mongoose.ws/tutorials/file-uploads/
|
||||
40
components/mongoose/mongoose/examples/file-upload-multiple-posts/main.c
Executable file
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
// HTTP request handler function. It implements the following endpoints:
|
||||
// /upload - Saves the next file chunk
|
||||
// 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, "/upload")) {
|
||||
char path[80], name[64];
|
||||
mg_http_get_var(&hm->query, "name", name, sizeof(name));
|
||||
if (name[0] == '\0') {
|
||||
mg_http_reply(c, 400, "", "%s", "name required");
|
||||
} else {
|
||||
mg_snprintf(path, sizeof(path), "/tmp/%s", name);
|
||||
mg_http_upload(c, hm, &mg_fs_posix, mg_remove_double_dots(path), 99999);
|
||||
}
|
||||
} 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;
|
||||
struct mg_timer t1;
|
||||
|
||||
mg_mgr_init(&mgr);
|
||||
mg_log_set(MG_LL_DEBUG); // Set log level
|
||||
mg_http_listen(&mgr, "http://localhost:8000", cb, NULL);
|
||||
|
||||
for (;;) mg_mgr_poll(&mgr, 50);
|
||||
mg_mgr_free(&mgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
// Helper function to display upload status
|
||||
var setStatus = function(text) {
|
||||
document.getElementById('el3').innerText = text;
|
||||
};
|
||||
|
||||
// When user clicks on a button, trigger file selection dialog
|
||||
var button = document.getElementById('el2');
|
||||
button.onclick = function(ev) {
|
||||
input.click();
|
||||
};
|
||||
|
||||
// Send a large blob of data chunk by chunk
|
||||
var sendFileData = function(name, data, chunkSize) {
|
||||
var sendChunk = function(offset) {
|
||||
var chunk = data.subarray(offset, offset + chunkSize) || '';
|
||||
var opts = {method: 'POST', body: chunk};
|
||||
var url = '/upload?offset=' + offset + '&name=' + encodeURIComponent(name);
|
||||
var ok;
|
||||
setStatus(
|
||||
'Uploading ' + name + ', bytes ' + offset + '..' +
|
||||
(offset + chunk.length) + ' of ' + data.length);
|
||||
fetch(url, opts)
|
||||
.then(function(res) {
|
||||
if (res.ok && chunk.length > 0) sendChunk(offset + chunk.length);
|
||||
ok = res.ok;
|
||||
return res.text();
|
||||
})
|
||||
.then(function(text) {
|
||||
if (!ok) setStatus('Error: ' + text);
|
||||
});
|
||||
};
|
||||
sendChunk(0);
|
||||
};
|
||||
|
||||
// If user selected a file, read it into memory and trigger sendFileData()
|
||||
var input = document.getElementById('el1');
|
||||
input.onchange = function(ev) {
|
||||
if (!ev.target.files[0]) return;
|
||||
var f = ev.target.files[0], r = new FileReader();
|
||||
r.readAsArrayBuffer(f);
|
||||
r.onload = function() {
|
||||
ev.target.value = '';
|
||||
sendFileData(f.name, new Uint8Array(r.result), 2048);
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
<!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" />
|
||||
<style>
|
||||
#container { margin-right: auto; margin-left: auto; max-width: 480px; }
|
||||
#info { background: #e0f0f0; border-radius: .5em; padding: 2em; }
|
||||
#wrapper { margin-top: 1em; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="info">
|
||||
Mongoose always buffers a full HTTP message before invoking
|
||||
the MG_EV_HTTP_MSG event. A big POST request would require a lot
|
||||
of RAM to buffer everything. Therefore, in order to upload large
|
||||
files on memory-constrained systems, a large file should be sent
|
||||
in small chunks.
|
||||
<br/><br/>
|
||||
In this example, the JavaScript code on this page sends the chosen
|
||||
file in 2Kb chunks using the <code>/upload</code> endpoint.
|
||||
The uploaded file is stored in the <code>/tmp</code> directory by
|
||||
the helper API function <code>mg_http_upload()</code>
|
||||
</div>
|
||||
<div id="wrapper">
|
||||
<input type="file" id="el1" style="display: none"/>
|
||||
<button id="el2">choose file...</button>
|
||||
<div id="el3"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="app.js"></script>
|
||||
</html>
|
||||
1
components/mongoose/mongoose/examples/file-upload-single-post/README.md
Executable file
@@ -0,0 +1 @@
|
||||
See detailed tutorial at https://mongoose.ws/tutorials/file-uploads/
|
||||
47
components/mongoose/mongoose/examples/file-upload-single-post/main.c
Executable file
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// Streaming upload example. Demonstrates how to use chunked encoding
|
||||
// to send large payload in smaller chunks. To test, use curl utility:
|
||||
//
|
||||
// curl http://localhost:8000/upload?name=a.txt --data-binary @large_file.txt
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
// HTTP request handler function. It implements the following endpoints:
|
||||
// /upload - Saves the next file chunk
|
||||
// all other URI - serves web_root/ directory
|
||||
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (ev == MG_EV_HTTP_CHUNK && mg_http_match_uri(hm, "/upload")) {
|
||||
MG_INFO(("Got chunk len %lu", (unsigned long) hm->chunk.len));
|
||||
MG_INFO(("Query string: [%.*s]", (int) hm->query.len, hm->query.ptr));
|
||||
// MG_INFO(("Chunk data:\n%.*s", (int) hm->chunk.len, hm->chunk.ptr));
|
||||
mg_http_delete_chunk(c, hm);
|
||||
if (hm->chunk.len == 0) {
|
||||
MG_INFO(("Last chunk received, sending response"));
|
||||
mg_http_reply(c, 200, "", "ok (chunked)\n");
|
||||
}
|
||||
} else if (ev == MG_EV_HTTP_MSG && mg_http_match_uri(hm, "/upload")) {
|
||||
MG_INFO(("Got all %lu bytes!", (unsigned long) hm->body.len));
|
||||
MG_INFO(("Query string: [%.*s]", (int) hm->query.len, hm->query.ptr));
|
||||
// MG_INFO(("Body:\n%.*s", (int) hm->body.len, hm->body.ptr));
|
||||
mg_http_reply(c, 200, "", "ok (%lu)\n", (unsigned long) hm->body.len);
|
||||
} else if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
|
||||
mg_http_serve_dir(c, hm, &opts);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
|
||||
mg_mgr_init(&mgr);
|
||||
mg_log_set(MG_LL_DEBUG); // Set debug log level
|
||||
mg_http_listen(&mgr, "http://localhost:8000", cb, NULL);
|
||||
|
||||
for (;;) mg_mgr_poll(&mgr, 50);
|
||||
mg_mgr_free(&mgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<!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" />
|
||||
<style>
|
||||
#container { margin-right: auto; margin-left: auto; max-width: 480px; }
|
||||
#info { background: #e0f0f0; border-radius: .5em; padding: 2em; }
|
||||
#wrapper { margin-top: 1em; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="info">
|
||||
Mongoose always buffers a full HTTP message before invoking
|
||||
MG_EV_HTTP_MSG event. Big POST request require of lot
|
||||
of RAM to buffer everything.
|
||||
<br><br>
|
||||
In order to upload large files to a memory-constrained system, use
|
||||
<code>MG_EV_HTTP_CHUNK</code> on a server side. It fires when
|
||||
a partial HTTP message has been received (or a chunk-encoded chunk).
|
||||
Use <code>mg_http_delete_chunk()</code> to release chunk memory.
|
||||
When 0-sized chunk is received, that's the end of the message.
|
||||
Use <code>MG_MAX_RECV_SIZE</code> build constant to limit
|
||||
maximum chunk size on a server side.
|
||||
<br><br>
|
||||
In this example, JavaScript code uses "fetch()" browser API.
|
||||
Uploaded file is not saved, but rather printed by server side.
|
||||
</div>
|
||||
<div id="wrapper">
|
||||
<input type="file" id="el1" style="display: none"/>
|
||||
<button id="el2">choose file...</button>
|
||||
<div id="el3" style="margin-top: 1em;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
|
||||
// When user clicks on a button, trigger file selection dialog
|
||||
document.getElementById('el2').onclick = function(ev) {
|
||||
document.getElementById('el1').click();
|
||||
};
|
||||
|
||||
// If user selected a file, read it into memory and trigger sendFileData()
|
||||
document.getElementById('el1').onchange = function(ev) {
|
||||
if (!ev.target.files[0]) return;
|
||||
var f = ev.target.files[0], r = new FileReader();
|
||||
r.readAsArrayBuffer(f);
|
||||
r.onload = function() {
|
||||
ev.target.value = '';
|
||||
document.getElementById('el3').innerText = 'Uploading...';
|
||||
fetch('/upload?name=' + encodeURIComponent(f.name), {
|
||||
method: 'POST',
|
||||
body: r.result,
|
||||
}).then(function(res) {
|
||||
document.getElementById('el3').innerText = 'Uploaded ' + r.result.byteLength + ' bytes';
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
</script>
|
||||
</html>
|
||||
1
components/mongoose/mongoose/examples/http-client/README.md
Executable file
@@ -0,0 +1 @@
|
||||
See detailed tutorial at https://mongoose.ws/tutorials/http-client/
|
||||
1
components/mongoose/mongoose/examples/http-client/ca.pem
Symbolic link
@@ -0,0 +1 @@
|
||||
../../test/data/ca.pem
|
||||
72
components/mongoose/mongoose/examples/http-client/main.c
Executable file
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2021 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// Example HTTP client. Connect to `s_url`, send request, wait for a response,
|
||||
// print the response and exit.
|
||||
// You can change `s_url` from the command line by executing: ./example YOUR_URL
|
||||
//
|
||||
// To enable SSL/TLS, make SSL=OPENSSL or make SSL=MBEDTLS
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
// The very first web page in history. You can replace it from command line
|
||||
static const char *s_url = "http://info.cern.ch/";
|
||||
static const char *s_post_data = NULL; // POST data
|
||||
static const uint64_t s_timeout_ms = 1500; // Connect timeout in milliseconds
|
||||
|
||||
// Print HTTP response and signal that we're done
|
||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_OPEN) {
|
||||
// Connection created. Store connect expiration time in c->label
|
||||
*(uint64_t *) c->label = mg_millis() + s_timeout_ms;
|
||||
} else if (ev == MG_EV_POLL) {
|
||||
if (mg_millis() > *(uint64_t *) c->label &&
|
||||
(c->is_connecting || c->is_resolving)) {
|
||||
mg_error(c, "Connect timeout");
|
||||
}
|
||||
} else if (ev == MG_EV_CONNECT) {
|
||||
// Connected to server. Extract host name from URL
|
||||
struct mg_str host = mg_url_host(s_url);
|
||||
|
||||
// If s_url is https://, tell client connection to use TLS
|
||||
if (mg_url_is_ssl(s_url)) {
|
||||
struct mg_tls_opts opts = {.ca = "ca.pem", .srvname = host};
|
||||
mg_tls_init(c, &opts);
|
||||
}
|
||||
|
||||
// Send request
|
||||
int content_length = s_post_data ? strlen(s_post_data) : 0;
|
||||
mg_printf(c,
|
||||
"%s %s HTTP/1.0\r\n"
|
||||
"Host: %.*s\r\n"
|
||||
"Content-Type: octet-stream\r\n"
|
||||
"Content-Length: %d\r\n"
|
||||
"\r\n",
|
||||
s_post_data ? "POST" : "GET", mg_url_uri(s_url), (int) host.len,
|
||||
host.ptr, content_length);
|
||||
mg_send(c, s_post_data, content_length);
|
||||
} else if (ev == MG_EV_HTTP_MSG) {
|
||||
// Response is received. Print it
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
printf("%.*s", (int) hm->message.len, hm->message.ptr);
|
||||
c->is_closing = 1; // Tell mongoose to close this connection
|
||||
*(bool *) fn_data = true; // Tell event loop to stop
|
||||
} else if (ev == MG_EV_ERROR) {
|
||||
*(bool *) fn_data = true; // Error, tell event loop to stop
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *log_level = getenv("LOG_LEVEL"); // Allow user to set log level
|
||||
if (log_level == NULL) log_level = "4"; // Default is verbose
|
||||
|
||||
struct mg_mgr mgr; // Event manager
|
||||
bool done = false; // Event handler flips it to true
|
||||
if (argc > 1) s_url = argv[1]; // Use URL provided in the command line
|
||||
mg_log_set(atoi(log_level)); // Set to 0 to disable debug
|
||||
mg_mgr_init(&mgr); // Initialise event manager
|
||||
mg_http_connect(&mgr, s_url, fn, &done); // Create client connection
|
||||
while (!done) mg_mgr_poll(&mgr, 50); // Event manager loops until 'done'
|
||||
mg_mgr_free(&mgr); // Free resources
|
||||
return 0;
|
||||
}
|
||||
1
components/mongoose/mongoose/examples/http-proxy-client/ca.pem
Symbolic link
@@ -0,0 +1 @@
|
||||
../../test/data/ca.pem
|
||||
65
components/mongoose/mongoose/examples/http-proxy-client/main.c
Executable file
@@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// Example HTTP client that uses a proxy server. Usage:
|
||||
// make
|
||||
// ./example PROXY:PORT http://www.ladyada.net
|
||||
//
|
||||
// To enable SSL/TLS, make SSL=OPENSSL or make SSL=MBEDTLS
|
||||
//
|
||||
#include "mongoose.h"
|
||||
|
||||
// Print HTTP response and signal that we're done
|
||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
const char *url = fn_data;
|
||||
static bool connected;
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
printf("%.*s", (int) hm->message.len, hm->message.ptr);
|
||||
exit(EXIT_SUCCESS);
|
||||
} else if (ev == MG_EV_CONNECT) {
|
||||
// Proxy TCP connection established. Send CONNECT request
|
||||
struct mg_str host = mg_url_host(url);
|
||||
// c->is_hexdumping = 1;
|
||||
mg_printf(c, "CONNECT %.*s:%hu HTTP/1.1\r\nHost: %.*s:%hu\r\n\r\n",
|
||||
(int) host.len, host.ptr, mg_url_port(url), (int) host.len,
|
||||
host.ptr, mg_url_port(url));
|
||||
// If target URL is SSL/TLS, command client connection to use TLS
|
||||
if (mg_url_is_ssl(url)) {
|
||||
struct mg_tls_opts opts = {.ca = "ca.pem"};
|
||||
mg_tls_init(c, &opts);
|
||||
}
|
||||
} else if (!connected && ev == MG_EV_READ) {
|
||||
struct mg_http_message hm;
|
||||
int n = mg_http_parse((char *) c->recv.buf, c->recv.len, &hm);
|
||||
if (n > 0) {
|
||||
struct mg_str host = mg_url_host(url);
|
||||
// CONNECT response - tunnel is established
|
||||
connected = true;
|
||||
MG_DEBUG(
|
||||
("Connected to proxy, status: %.*s", (int) hm.uri.len, hm.uri.ptr));
|
||||
mg_iobuf_del(&c->recv, 0, n);
|
||||
// Send request to the target server
|
||||
mg_printf(c, "GET %s HTTP/1.0\r\n"
|
||||
"Host: %.*s\r\n"
|
||||
"\r\n",
|
||||
mg_url_uri(url), (int) host.len, host.ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct mg_mgr mgr;
|
||||
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: %s PROXY_URL URL\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
mg_mgr_init(&mgr); // Initialise event manager
|
||||
mg_http_connect(&mgr, argv[1], fn, argv[2]); // Connect to the proxy
|
||||
for (;;) mg_mgr_poll(&mgr, 1000); // Event loop
|
||||
mg_mgr_free(&mgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
1
components/mongoose/mongoose/examples/http-restful-server/ca.pem
Symbolic link
@@ -0,0 +1 @@
|
||||
../../test/data/ca.pem
|
||||
68
components/mongoose/mongoose/examples/http-restful-server/main.c
Executable file
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// HTTP server example. This server serves both static and dynamic content.
|
||||
// It opens two ports: plain HTTP on port 8000 and HTTP on port 8443.
|
||||
// It implements the following endpoints:
|
||||
// /api/stats - respond with free-formatted stats on current connections
|
||||
// /api/f2/:id - wildcard example, respond with JSON string {"result": "URI"}
|
||||
// any other URI serves static files from s_root_dir
|
||||
//
|
||||
// To enable SSL/TLS (using self-signed certificates in PEM files),
|
||||
// 1. make SSL=OPENSSL or make SSL=MBEDTLS
|
||||
// 2. curl -k https://127.0.0.1:8443
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
static const char *s_http_addr = "http://0.0.0.0:8000"; // HTTP port
|
||||
static const char *s_https_addr = "https://0.0.0.0:8443"; // HTTPS port
|
||||
static const char *s_root_dir = ".";
|
||||
|
||||
// We use the same event handler function for HTTP and HTTPS connections
|
||||
// fn_data is NULL for plain HTTP, and non-NULL for HTTPS
|
||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_ACCEPT && fn_data != NULL) {
|
||||
struct mg_tls_opts opts = {
|
||||
//.ca = "ca.pem", // Uncomment to enable two-way SSL
|
||||
.cert = "server.pem", // Certificate PEM file
|
||||
.certkey = "server.pem", // This pem contains both cert and key
|
||||
};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_http_match_uri(hm, "/api/stats")) {
|
||||
// Print some statistics about currently established connections
|
||||
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||
mg_http_printf_chunk(c, "ID PROTO TYPE LOCAL REMOTE\n");
|
||||
for (struct mg_connection *t = c->mgr->conns; t != NULL; t = t->next) {
|
||||
char loc[40], rem[40];
|
||||
mg_http_printf_chunk(c, "%-3lu %4s %s %-15s %s\n", t->id,
|
||||
t->is_udp ? "UDP" : "TCP",
|
||||
t->is_listening ? "LISTENING"
|
||||
: t->is_accepted ? "ACCEPTED "
|
||||
: "CONNECTED",
|
||||
mg_straddr(&t->loc, loc, sizeof(loc)),
|
||||
mg_straddr(&t->rem, rem, sizeof(rem)));
|
||||
}
|
||||
mg_http_printf_chunk(c, ""); // Don't forget the last empty chunk
|
||||
} else if (mg_http_match_uri(hm, "/api/f2/*")) {
|
||||
mg_http_reply(c, 200, "", "{\"result\": \"%.*s\"}\n", (int) hm->uri.len,
|
||||
hm->uri.ptr);
|
||||
} else {
|
||||
struct mg_http_serve_opts opts = {.root_dir = s_root_dir};
|
||||
mg_http_serve_dir(c, ev_data, &opts);
|
||||
}
|
||||
}
|
||||
(void) fn_data;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
struct mg_mgr mgr; // Event manager
|
||||
mg_log_set(MG_LL_DEBUG); // Set log level
|
||||
mg_mgr_init(&mgr); // Initialise event manager
|
||||
mg_http_listen(&mgr, s_http_addr, fn, NULL); // Create HTTP listener
|
||||
mg_http_listen(&mgr, s_https_addr, fn, (void *) 1); // HTTPS listener
|
||||
for (;;) mg_mgr_poll(&mgr, 1000); // Infinite event loop
|
||||
mg_mgr_free(&mgr);
|
||||
return 0;
|
||||
}
|
||||
50
components/mongoose/mongoose/examples/http-restful-server/server.pem
Executable file
@@ -0,0 +1,50 @@
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number:
|
||||
6e:73:28:55:df:13:b5:61:f5:4f:4f:5d:00:d9:0a:d8:b5:3a:21:4b
|
||||
Signature Algorithm: ecdsa-with-SHA256
|
||||
Issuer: C = IE, L = Dublin, O = Cesanta, CN = Test Root
|
||||
Validity
|
||||
Not Before: May 9 21:51:49 2020 GMT
|
||||
Not After : May 9 21:51:49 2030 GMT
|
||||
Subject: CN = server
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: id-ecPublicKey
|
||||
Public-Key: (256 bit)
|
||||
pub:
|
||||
04:92:e0:46:9c:89:c3:37:a9:74:eb:35:55:43:55:
|
||||
5c:ac:eb:c7:e4:50:ee:f4:c0:ba:17:02:5c:d9:ed:
|
||||
b4:d4:ff:21:12:9a:b4:43:f4:89:4b:69:e4:6d:2b:
|
||||
96:1f:fc:01:4d:30:5a:79:73:76:ba:19:41:cc:c5:
|
||||
16:2b:bf:74:28
|
||||
ASN1 OID: prime256v1
|
||||
NIST CURVE: P-256
|
||||
X509v3 extensions:
|
||||
X509v3 Basic Constraints:
|
||||
CA:FALSE
|
||||
X509v3 Key Usage:
|
||||
Digital Signature, Key Encipherment, Key Agreement
|
||||
X509v3 Extended Key Usage:
|
||||
TLS Web Server Authentication
|
||||
Signature Algorithm: ecdsa-with-SHA256
|
||||
30:46:02:21:00:fa:3a:c7:1e:cb:8c:27:59:41:8d:77:dd:7b:
|
||||
cb:8c:08:15:16:b9:6e:70:e6:47:38:d1:55:42:e0:d7:66:c8:
|
||||
f0:02:21:00:cc:70:4d:96:28:00:d3:c7:39:53:74:b2:49:87:
|
||||
27:92:1b:ab:1a:0e:74:06:59:42:23:47:98:43:d8:20:a7:fa
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBhzCCASygAwIBAgIUbnMoVd8TtWH1T09dANkK2LU6IUswCgYIKoZIzj0EAwIw
|
||||
RDELMAkGA1UEBhMCSUUxDzANBgNVBAcMBkR1YmxpbjEQMA4GA1UECgwHQ2VzYW50
|
||||
YTESMBAGA1UEAwwJVGVzdCBSb290MB4XDTIwMDUwOTIxNTE0OVoXDTMwMDUwOTIx
|
||||
NTE0OVowETEPMA0GA1UEAwwGc2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD
|
||||
QgAEkuBGnInDN6l06zVVQ1VcrOvH5FDu9MC6FwJc2e201P8hEpq0Q/SJS2nkbSuW
|
||||
H/wBTTBaeXN2uhlBzMUWK790KKMvMC0wCQYDVR0TBAIwADALBgNVHQ8EBAMCA6gw
|
||||
EwYDVR0lBAwwCgYIKwYBBQUHAwEwCgYIKoZIzj0EAwIDSQAwRgIhAPo6xx7LjCdZ
|
||||
QY133XvLjAgVFrlucOZHONFVQuDXZsjwAiEAzHBNligA08c5U3SySYcnkhurGg50
|
||||
BllCI0eYQ9ggp/o=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQglNni0t9Dg9icgG8w
|
||||
kbfxWSS+TuNgbtNybIQXcm3NHpmhRANCAASS4EacicM3qXTrNVVDVVys68fkUO70
|
||||
wLoXAlzZ7bTU/yESmrRD9IlLaeRtK5Yf/AFNMFp5c3a6GUHMxRYrv3Qo
|
||||
-----END PRIVATE KEY-----
|
||||
1
components/mongoose/mongoose/examples/http-reverse-proxy/ca.pem
Symbolic link
@@ -0,0 +1 @@
|
||||
../../test/data/ca.pem
|
||||
85
components/mongoose/mongoose/examples/http-reverse-proxy/main.c
Executable file
@@ -0,0 +1,85 @@
|
||||
// Copyright (c) 2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// Example HTTP reverse proxy
|
||||
// 1. Run `make`. This builds and starts a proxy on port 8000
|
||||
// 2. Start your browser, go to https://localhost:8000
|
||||
//
|
||||
// To enable SSL/TLS, add SSL=OPENSSL or SSL=MBEDTLS
|
||||
|
||||
static const char *s_backend_url =
|
||||
#if defined(MG_ENABLE_MBEDTLS) || defined(MG_ENABLE_OPENSSL)
|
||||
"https://cesanta.com";
|
||||
#else
|
||||
"http://info.cern.ch";
|
||||
#endif
|
||||
static const char *s_listen_url = "http://localhost:8000";
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
// Forward client request to the backend connection, rewriting the Host header
|
||||
static void forward_request(struct mg_http_message *hm,
|
||||
struct mg_connection *c) {
|
||||
size_t i, max = sizeof(hm->headers) / sizeof(hm->headers[0]);
|
||||
struct mg_str host = mg_url_host(s_backend_url);
|
||||
mg_printf(c, "%.*s\r\n",
|
||||
(int) (hm->proto.ptr + hm->proto.len - hm->message.ptr),
|
||||
hm->message.ptr);
|
||||
for (i = 0; i < max && hm->headers[i].name.len > 0; i++) {
|
||||
struct mg_str *k = &hm->headers[i].name, *v = &hm->headers[i].value;
|
||||
if (mg_strcmp(*k, mg_str("Host")) == 0) v = &host;
|
||||
mg_printf(c, "%.*s: %.*s\r\n", (int) k->len, k->ptr, (int) v->len, v->ptr);
|
||||
}
|
||||
mg_send(c, "\r\n", 2);
|
||||
mg_send(c, hm->body.ptr, hm->body.len);
|
||||
MG_DEBUG(("FORWARDING: %.*s %.*s", (int) hm->method.len, hm->method.ptr,
|
||||
(int) hm->uri.len, hm->uri.ptr));
|
||||
}
|
||||
|
||||
static void fn2(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
struct mg_connection *c2 = fn_data;
|
||||
if (ev == MG_EV_READ) {
|
||||
// All incoming data from the backend, forward to the client
|
||||
if (c2 != NULL) mg_send(c2, c->recv.buf, c->recv.len);
|
||||
mg_iobuf_del(&c->recv, 0, c->recv.len);
|
||||
} else if (ev == MG_EV_CLOSE) {
|
||||
if (c2 != NULL) c2->fn_data = NULL;
|
||||
}
|
||||
(void) ev_data;
|
||||
}
|
||||
|
||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
struct mg_connection *c2 = fn_data;
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
// Client request, create backend connection Note that we're passing
|
||||
// client connection `c` as fn_data for the created backend connection.
|
||||
c2 = mg_connect(c->mgr, s_backend_url, fn2, c);
|
||||
if (c2 == NULL) {
|
||||
mg_error(c, "Cannot create backend connection");
|
||||
} else {
|
||||
if (mg_url_is_ssl(s_backend_url)) {
|
||||
struct mg_tls_opts opts = {.ca = "ca.pem"};
|
||||
mg_tls_init(c2, &opts);
|
||||
}
|
||||
c->fn_data = c2;
|
||||
forward_request(hm, c2);
|
||||
c2->is_hexdumping = 1;
|
||||
}
|
||||
} else if (ev == MG_EV_CLOSE) {
|
||||
if (c2 != NULL) c2->is_closing = 1;
|
||||
if (c2 != NULL) c2->fn_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
|
||||
mg_log_set(MG_LL_DEBUG); // Set log level
|
||||
mg_mgr_init(&mgr); // Initialise event manager
|
||||
mg_http_listen(&mgr, s_listen_url, fn, NULL); // Start proxy
|
||||
for (;;) mg_mgr_poll(&mgr, 1000); // Event loop
|
||||
mg_mgr_free(&mgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
1
components/mongoose/mongoose/examples/http-server/README.md
Executable file
@@ -0,0 +1 @@
|
||||
See detailed tutorial at https://mongoose.ws/tutorials/http-server/
|
||||
103
components/mongoose/mongoose/examples/http-server/main.c
Executable file
@@ -0,0 +1,103 @@
|
||||
// Copyright (c) 2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#include <signal.h>
|
||||
#include "mongoose.h"
|
||||
|
||||
static int s_debug_level = MG_LL_INFO;
|
||||
static const char *s_root_dir = ".";
|
||||
static const char *s_listening_address = "http://0.0.0.0:8000";
|
||||
static const char *s_enable_hexdump = "no";
|
||||
static const char *s_ssi_pattern = "#.html";
|
||||
|
||||
// Handle interrupts, like Ctrl-C
|
||||
static int s_signo;
|
||||
static void signal_handler(int signo) {
|
||||
s_signo = signo;
|
||||
}
|
||||
|
||||
// Event handler for the listening connection.
|
||||
// Simply serve static files from `s_root_dir`
|
||||
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = ev_data, tmp = {0};
|
||||
struct mg_str unknown = mg_str_n("?", 1), *cl;
|
||||
struct mg_http_serve_opts opts = {0};
|
||||
opts.root_dir = s_root_dir;
|
||||
opts.ssi_pattern = s_ssi_pattern;
|
||||
mg_http_serve_dir(c, hm, &opts);
|
||||
mg_http_parse((char *) c->send.buf, c->send.len, &tmp);
|
||||
cl = mg_http_get_header(&tmp, "Content-Length");
|
||||
if (cl == NULL) cl = &unknown;
|
||||
MG_INFO(("%.*s %.*s %.*s %.*s", (int) hm->method.len, hm->method.ptr,
|
||||
(int) hm->uri.len, hm->uri.ptr, (int) tmp.uri.len, tmp.uri.ptr,
|
||||
(int) cl->len, cl->ptr));
|
||||
}
|
||||
(void) fn_data;
|
||||
}
|
||||
|
||||
static void usage(const char *prog) {
|
||||
fprintf(stderr,
|
||||
"Mongoose v.%s\n"
|
||||
"Usage: %s OPTIONS\n"
|
||||
" -H yes|no - enable traffic hexdump, default: '%s'\n"
|
||||
" -S PAT - SSI filename pattern, default: '%s'\n"
|
||||
" -d DIR - directory to serve, default: '%s'\n"
|
||||
" -l ADDR - listening address, default: '%s'\n"
|
||||
" -v LEVEL - debug level, from 0 to 4, default: %d\n",
|
||||
MG_VERSION, prog, s_enable_hexdump, s_ssi_pattern, s_root_dir,
|
||||
s_listening_address, s_debug_level);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char path[MG_PATH_MAX] = ".";
|
||||
struct mg_mgr mgr;
|
||||
struct mg_connection *c;
|
||||
int i;
|
||||
|
||||
// Parse command-line flags
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-d") == 0) {
|
||||
s_root_dir = argv[++i];
|
||||
} else if (strcmp(argv[i], "-H") == 0) {
|
||||
s_enable_hexdump = argv[++i];
|
||||
} else if (strcmp(argv[i], "-S") == 0) {
|
||||
s_ssi_pattern = argv[++i];
|
||||
} else if (strcmp(argv[i], "-l") == 0) {
|
||||
s_listening_address = argv[++i];
|
||||
} else if (strcmp(argv[i], "-v") == 0) {
|
||||
s_debug_level = atoi(argv[++i]);
|
||||
} else {
|
||||
usage(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Root directory must not contain double dots. Make it absolute
|
||||
// Do the conversion only if the root dir spec does not contain overrides
|
||||
if (strchr(s_root_dir, ',') == NULL) {
|
||||
realpath(s_root_dir, path);
|
||||
s_root_dir = path;
|
||||
}
|
||||
|
||||
// Initialise stuff
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
mg_log_set(s_debug_level);
|
||||
mg_mgr_init(&mgr);
|
||||
if ((c = mg_http_listen(&mgr, s_listening_address, cb, &mgr)) == NULL) {
|
||||
MG_ERROR(("Cannot listen on %s. Use http://ADDR:PORT or :PORT",
|
||||
s_listening_address));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mg_casecmp(s_enable_hexdump, "yes") == 0) c->is_hexdumping = 1;
|
||||
|
||||
// Start infinite event loop
|
||||
MG_INFO(("Mongoose version : v%s", MG_VERSION));
|
||||
MG_INFO(("Listening on : %s", s_listening_address));
|
||||
MG_INFO(("Web root : [%s]", s_root_dir));
|
||||
while (s_signo == 0) mg_mgr_poll(&mgr, 1000);
|
||||
mg_mgr_free(&mgr);
|
||||
MG_INFO(("Exiting on signal %d", s_signo));
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../test/data/ca.pem
|
||||
70
components/mongoose/mongoose/examples/http-streaming-client/main.c
Executable file
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) 2021 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// Example HTTP client.
|
||||
// Instead of buffering the whole HTTP response in memory and wait for the
|
||||
// MG_EV_HTTP_MSG event, this client catches MG_EV_HTTP_CHUNK events and
|
||||
// prints them. This is useful to download large content without spooling
|
||||
// everything to memory, or catch chunked content.
|
||||
//
|
||||
// You can change `s_url` from the command line by executing: ./example YOUR_URL
|
||||
//
|
||||
// To enable SSL/TLS for this client, build it like this:
|
||||
// make MBEDTLS=/path/to/your/mbedtls/installation
|
||||
// make OPENSSL=/path/to/your/openssl/installation
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
// The very first web page in history. You can replace it from command line
|
||||
static const char *s_url = "http://info.cern.ch";
|
||||
|
||||
// Print HTTP response and signal that we're done
|
||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_CONNECT) {
|
||||
// Connected to server. Extract host name from URL
|
||||
struct mg_str host = mg_url_host(s_url);
|
||||
|
||||
// If s_url is https://, tell client connection to use TLS
|
||||
if (mg_url_is_ssl(s_url)) {
|
||||
struct mg_tls_opts opts = {.ca = "ca.pem", .srvname = host};
|
||||
mg_tls_init(c, &opts);
|
||||
}
|
||||
|
||||
// Send request
|
||||
mg_printf(c,
|
||||
"GET %s HTTP/1.1\r\n"
|
||||
"Connection: keep-alive\r\n"
|
||||
"Keep-Alive: timeout=60\r\n"
|
||||
"Host: %.*s\r\n"
|
||||
"\r\n",
|
||||
mg_url_uri(s_url), (int) host.len, host.ptr);
|
||||
} else if (ev == MG_EV_HTTP_CHUNK) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
fwrite(hm->chunk.ptr, 1, hm->chunk.len, stdout);
|
||||
// fprintf(stderr, "c %u\n", (unsigned) hm->chunk.len);
|
||||
mg_http_delete_chunk(c, hm);
|
||||
if (hm->chunk.len == 0) *(bool *) fn_data = true; // Last chunk
|
||||
} else if (ev == MG_EV_HTTP_MSG) {
|
||||
// Response is received. Print it
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
fwrite(hm->body.ptr, 1, hm->body.len, stdout);
|
||||
c->is_closing = 1; // Tell mongoose to close this connection
|
||||
*(bool *) fn_data = true; // Tell event loop to stop
|
||||
} else if (ev == MG_EV_ERROR) {
|
||||
*(bool *) fn_data = true; // Error, tell event loop to stop
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct mg_mgr mgr; // Event manager
|
||||
bool done = false; // Event handler flips it to true
|
||||
const char *log_level = getenv("V"); // Log level
|
||||
if (log_level == NULL) log_level = "3"; // If not set, set to DEBUG
|
||||
mg_log_set(atoi(log_level)); // Set to 0 to disable debug log
|
||||
if (argc > 1) s_url = argv[1]; // Use URL from command line
|
||||
mg_mgr_init(&mgr); // Initialise event manager
|
||||
mg_http_connect(&mgr, s_url, fn, &done); // Create client connection
|
||||
while (!done) mg_mgr_poll(&mgr, 1000); // Infinite event loop
|
||||
mg_mgr_free(&mgr); // Free resources
|
||||
return 0;
|
||||
}
|
||||
89
components/mongoose/mongoose/examples/huge-response/main.c
Executable file
@@ -0,0 +1,89 @@
|
||||
// Copyright (c) 2021 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// Example that demonstrates how to send a large responses with limited memory.
|
||||
// We're going to send a JSON array of many integer values, s_data.
|
||||
// The idea is to send a response in small chunks, and let the client request
|
||||
// the next chunk.
|
||||
// Periodically, s_data changes, which is tracked by s_version.
|
||||
// Client requests a range and a version, to ensure data integrity.
|
||||
//
|
||||
// 1. Start this server, type `make`
|
||||
// 2. Open http://localhost:8000 in your browser
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
static const char *s_listen_on = "http://localhost:8000";
|
||||
static const char *s_root_dir = "web_root";
|
||||
|
||||
#define DATA_SIZE 10000 // Total number of elements
|
||||
#define CHUNK_SIZE 100 // Max number returned in one API call
|
||||
static int s_data[DATA_SIZE]; // Simulate some complex big data
|
||||
static long s_version = 0; // Data "version"
|
||||
|
||||
static long getparam(struct mg_http_message *hm, const char *json_path) {
|
||||
double dv = 0;
|
||||
mg_json_get_num(hm->body, json_path, &dv);
|
||||
return dv;
|
||||
}
|
||||
|
||||
static size_t printdata(mg_pfn_t out, void *ptr, va_list *ap) {
|
||||
unsigned start = va_arg(*ap, unsigned);
|
||||
unsigned max = start + CHUNK_SIZE;
|
||||
const char *comma = "";
|
||||
size_t n = 0;
|
||||
if (max > DATA_SIZE) max = DATA_SIZE;
|
||||
while (start < max) {
|
||||
n += mg_xprintf(out, ptr, "%s%d", comma, s_data[start]);
|
||||
comma = ",";
|
||||
start++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = ev_data;
|
||||
if (mg_http_match_uri(hm, "/api/data")) {
|
||||
const char *headers = "content-type: text/json\r\n";
|
||||
long start = getparam(hm, "$.start");
|
||||
long version = getparam(hm, "$.version");
|
||||
MG_DEBUG(("%.*s", (int) hm->body.len, hm->body.ptr));
|
||||
if (version > 0 && version != s_version) {
|
||||
// Version mismatch: s_data has changed while client fetches it
|
||||
// Tell client to restart
|
||||
mg_http_reply(c, 200, headers, "{%Q:%Q, %Q:%ld}", "error",
|
||||
"wrong version", "version", version);
|
||||
} else {
|
||||
// Return data, up to CHUNK_SIZE elements
|
||||
mg_http_reply(c, 200, headers, "{%Q:%ld,%Q:%ld,%Q:[%M]}", "version",
|
||||
s_version, "start", start, "data", printdata, start);
|
||||
}
|
||||
} else {
|
||||
struct mg_http_serve_opts opts = {0};
|
||||
opts.root_dir = s_root_dir;
|
||||
mg_http_serve_dir(c, hm, &opts);
|
||||
}
|
||||
}
|
||||
(void) fn_data;
|
||||
}
|
||||
|
||||
static void timer_fn(void *arg) {
|
||||
for (int i = 0; i < DATA_SIZE; i++) {
|
||||
s_data[i] = rand();
|
||||
}
|
||||
s_version++;
|
||||
(void) arg;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
srand(time(NULL));
|
||||
mg_timer_add(&mgr, 5000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, NULL);
|
||||
mg_http_listen(&mgr, s_listen_on, fn, NULL);
|
||||
MG_INFO(("Listening on %s", s_listen_on));
|
||||
for (;;) mg_mgr_poll(&mgr, 1000);
|
||||
mg_mgr_free(&mgr);
|
||||
return 0;
|
||||
}
|
||||
59
components/mongoose/mongoose/examples/huge-response/web_root/index.html
Executable file
@@ -0,0 +1,59 @@
|
||||
<!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" />
|
||||
<style>
|
||||
#container { margin-right: auto; margin-left: auto; max-width: 480px; }
|
||||
#info { background: #e0f0f0; border-radius: .5em; padding: 2em; margin-bottom: 1em; }
|
||||
#result { margin-top: 1em; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="info">
|
||||
On devices with limited RAM, it is important to limit the response size
|
||||
of API calls. This example demonstrates how to fetch a large
|
||||
data in smaller chunks, and guarantee its integrity.
|
||||
Data gets returned in a series of request/response transactions,
|
||||
where each response is small enough to fit into available device RAM.
|
||||
<br/><br/>
|
||||
Data integrity is implemented by versioning.
|
||||
The idea is that the first response includes the current "version" of the
|
||||
data, and that version is passed to all subsequent requests.
|
||||
If data version changes in the middle of the request series,
|
||||
client fails with 'wrong version' error.
|
||||
</div>
|
||||
<button id="btn">fetch data</button>
|
||||
<div id="result"></div>
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
const getchunk = (start, version) =>
|
||||
fetch('/api/data', {method: 'POST', body:JSON.stringify({start, version})})
|
||||
.then(r => r.json());
|
||||
document.getElementById('btn').onclick = function() {
|
||||
var data = [], version = 0;
|
||||
const load = offset => getchunk(offset, version)
|
||||
.then(r => {
|
||||
// console.log(r);
|
||||
if (r.error) {
|
||||
document.getElementById('result').innerText = 'Error: ' + r.error;
|
||||
} else {
|
||||
version = r.version;
|
||||
data = data.concat(r.data);
|
||||
if (r.data.length == 0) {
|
||||
document.getElementById('result').innerText = 'Version: ' +
|
||||
version + ', data: \n' +
|
||||
JSON.stringify(data, null, 2);
|
||||
} else {
|
||||
load(offset + r.data.length, version);
|
||||
}
|
||||
}
|
||||
});
|
||||
load(0);
|
||||
};
|
||||
</script>
|
||||
</html>
|
||||
1
components/mongoose/mongoose/examples/json-rpc-over-websocket/README.md
Executable file
@@ -0,0 +1 @@
|
||||
See detailed tutorial at https://mongoose.ws/tutorials/json-rpc-over-websocket/
|
||||
84
components/mongoose/mongoose/examples/json-rpc-over-websocket/main.c
Executable file
@@ -0,0 +1,84 @@
|
||||
// Copyright (c) 2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// See https://mongoose.ws/tutorials/json-rpc-over-websocket/
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
static const char *s_listen_on = "ws://localhost:8000";
|
||||
static const char *s_web_root = "web_root";
|
||||
static struct mg_rpc *s_rpc_head = NULL;
|
||||
|
||||
static void rpc_sum(struct mg_rpc_req *r) {
|
||||
double a = 0.0, b = 0.0;
|
||||
mg_json_get_num(r->frame, "$.params[0]", &a);
|
||||
mg_json_get_num(r->frame, "$.params[1]", &b);
|
||||
mg_rpc_ok(r, "%g", a + b);
|
||||
}
|
||||
|
||||
static void rpc_mul(struct mg_rpc_req *r) {
|
||||
double a = 0.0, b = 0.0;
|
||||
mg_json_get_num(r->frame, "$.params[0]", &a);
|
||||
mg_json_get_num(r->frame, "$.params[1]", &b);
|
||||
mg_rpc_ok(r, "%g", a * b);
|
||||
}
|
||||
|
||||
// This RESTful server implements the following endpoints:
|
||||
// /websocket - upgrade to Websocket, and implement websocket echo server
|
||||
// any other URI serves static files from s_web_root
|
||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_OPEN) {
|
||||
// c->is_hexdumping = 1;
|
||||
} else if (ev == MG_EV_WS_OPEN) {
|
||||
c->label[0] = 'W'; // Mark this connection as an established WS client
|
||||
} else if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
if (mg_http_match_uri(hm, "/websocket")) {
|
||||
// Upgrade to websocket. From now on, a connection is a full-duplex
|
||||
// Websocket connection, which will receive MG_EV_WS_MSG events.
|
||||
mg_ws_upgrade(c, hm, NULL);
|
||||
} else {
|
||||
// Serve static files
|
||||
struct mg_http_serve_opts opts = {.root_dir = s_web_root};
|
||||
mg_http_serve_dir(c, ev_data, &opts);
|
||||
}
|
||||
} else if (ev == MG_EV_WS_MSG) {
|
||||
// Got websocket frame. Received data is wm->data
|
||||
struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
|
||||
struct mg_iobuf io = {0, 0, 0, 512};
|
||||
struct mg_rpc_req r = {&s_rpc_head, 0, mg_pfn_iobuf, &io, 0, wm->data};
|
||||
mg_rpc_process(&r);
|
||||
if (io.buf) mg_ws_send(c, (char *) io.buf, io.len, WEBSOCKET_OP_TEXT);
|
||||
mg_iobuf_free(&io);
|
||||
}
|
||||
(void) fn_data;
|
||||
}
|
||||
|
||||
static void timer_fn(void *arg) {
|
||||
struct mg_mgr *mgr = (struct mg_mgr *) arg;
|
||||
// Broadcast message to all connected websocket clients.
|
||||
for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) {
|
||||
if (c->label[0] != 'W') continue;
|
||||
mg_ws_printf(c, WEBSOCKET_OP_TEXT, "{%Q:%Q,%Q:[%d,%d,%d]}", "method",
|
||||
"notification1", "params", 1, 2, 3);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
struct mg_mgr mgr; // Event manager
|
||||
mg_mgr_init(&mgr); // Init event manager
|
||||
mg_log_set(MG_LL_DEBUG); // Set log level
|
||||
mg_timer_add(&mgr, 5000, MG_TIMER_REPEAT, timer_fn, &mgr); // Init timer
|
||||
|
||||
// Configure JSON-RPC functions we're going to handle
|
||||
mg_rpc_add(&s_rpc_head, mg_str("sum"), rpc_sum, NULL);
|
||||
mg_rpc_add(&s_rpc_head, mg_str("mul"), rpc_mul, NULL);
|
||||
mg_rpc_add(&s_rpc_head, mg_str("rpc.list"), mg_rpc_list, &s_rpc_head);
|
||||
|
||||
printf("Starting WS listener on %s/websocket\n", s_listen_on);
|
||||
mg_http_listen(&mgr, s_listen_on, fn, NULL); // Create HTTP listener
|
||||
for (;;) mg_mgr_poll(&mgr, 1000); // Infinite event loop
|
||||
mg_mgr_free(&mgr); // Deallocate event manager
|
||||
mg_rpc_del(&s_rpc_head, NULL); // Deallocate RPC handlers
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<h1>JSON-RPC over Websocket demo</h1>
|
||||
<input id="url" type="text" placeholder="Type URL" value="ws://localhost:8000/websocket" style="width:20em;" />
|
||||
<button id="connect">connect</button>
|
||||
<div style="height: 0.3em;"> </div>
|
||||
<button id="btn1">Calculate 1 + 2</button>
|
||||
<button id="btn2">Calculate 2 * 3</button>
|
||||
<div style="margin-top: 1em;">Event log:</div>
|
||||
<div id="log" style="background: #eee; height: 10em; padding: 0.5em; overflow:auto;"><div>
|
||||
</body>
|
||||
<script src="rpc-over-websocket.js"></script>
|
||||
<script>
|
||||
var rpc, E = function(id) { return document.getElementById(id); };
|
||||
var url = E('url'), connect = E('connect'), btn1 = E('btn1'), btn2 = E('btn2'), msglog = E('log');
|
||||
var enable = function(en) { btn1.disabled = btn2.disabled = !en; url.disabled = en; connect.innerHTML = en ? 'disconnect' : 'connect'; };
|
||||
var log = text => msglog.innerHTML += text + '<br/>\n';
|
||||
enable(false);
|
||||
connect.onclick = function() {
|
||||
console.log(rpc);
|
||||
if (rpc) { rpc.close(); rpc = null; return; }
|
||||
rpc = jsonrpc(url.value,
|
||||
() => enable(true),
|
||||
() => enable(false),
|
||||
msg => log('NOTIFICATION: ' + JSON.stringify(msg)));
|
||||
};
|
||||
btn1.onclick = ev => rpc.call('sum', [1, 2]).then(res => log('SUM:' + JSON.stringify(res)));
|
||||
btn2.onclick = ev => rpc.call('mul', [2, 3]).then(res => log('MUL:' + JSON.stringify(res)));
|
||||
</script>
|
||||
</html>
|
||||
@@ -0,0 +1,36 @@
|
||||
// JSON-RPC over Websocket implementation
|
||||
var JSONRPC_TIMEOUT_MS = 1000;
|
||||
|
||||
var jsonrpc = function(url, onopen, onclose, onnotification) {
|
||||
var rpcid = 0, pending = {}, ws = new WebSocket(url);
|
||||
if (!ws) return null;
|
||||
ws.onclose = onclose;
|
||||
ws.onmessage = function(ev) {
|
||||
const frame = JSON.parse(ev.data);
|
||||
console.log('rcvd', frame, 'pending:', pending);
|
||||
if (frame.id !== undefined) {
|
||||
if (pending[frame.id] !== undefined) pending[frame.id](frame); // Resolve
|
||||
delete (pending[frame.id]);
|
||||
} else {
|
||||
if (onnotification) onnotification(frame);
|
||||
}
|
||||
};
|
||||
if (onopen) onopen();
|
||||
return {
|
||||
close: () => ws.close(),
|
||||
call: function(method, params) {
|
||||
const id = rpcid++, request = {id, method, params};
|
||||
ws.send(JSON.stringify(request));
|
||||
console.log('sent', request);
|
||||
return new Promise(function(resolve, reject) {
|
||||
setTimeout(JSONRPC_TIMEOUT_MS, function() {
|
||||
if (pending[id] === undefined) return;
|
||||
log('Timing out frame ', JSON.stringify(request));
|
||||
delete (pending[id]);
|
||||
reject();
|
||||
});
|
||||
pending[id] = x => resolve(x);
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
61
components/mongoose/mongoose/examples/live-log/main.c
Executable file
@@ -0,0 +1,61 @@
|
||||
// Copyright (c) 2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
// HTTP request handler function. It implements the following endpoints:
|
||||
// /api/log/static - returns contents of log.txt file
|
||||
// /api/log/live - hangs forever, and returns live log messages
|
||||
// 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/log/static")) {
|
||||
struct mg_http_serve_opts opts = {.root_dir = NULL};
|
||||
mg_http_serve_file(c, hm, "log.txt", &opts);
|
||||
} 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 {
|
||||
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
|
||||
mg_http_serve_dir(c, ev_data, &opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 timer_fn(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;
|
||||
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://localhost:8000", cb, NULL);
|
||||
mg_timer_add(&mgr, 1000, MG_TIMER_REPEAT, timer_fn, &mgr);
|
||||
|
||||
for (;;) mg_mgr_poll(&mgr, 50);
|
||||
mg_mgr_free(&mgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
51
components/mongoose/mongoose/examples/live-log/web_root/index.html
Executable file
@@ -0,0 +1,51 @@
|
||||
<!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" />
|
||||
<style>
|
||||
#container { margin-right: auto; margin-left: auto; max-width: 480px; }
|
||||
#info { background: #e0f0f0; border-radius: .5em; padding: 2em; }
|
||||
#static, #live { background: #f0f0f0; border-radius: .5em; padding: 0.5em; max-height: 10em; overflow: auto; height: 100%; }
|
||||
#wrapper { display: flex; justify-content: flex-evenly; margin-top: 1em; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="info">
|
||||
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 id="wrapper">
|
||||
<div style="width: 50%"><b>Static</b><pre id="static"></pre></div>
|
||||
<div style="width: 1em;"></div>
|
||||
<div style="width: 50%"><b>Live</b><pre id="live"></pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
var f = function(r) {
|
||||
return r.read().then(function(result) {
|
||||
var data = String.fromCharCode.apply(null, result.value);
|
||||
document.getElementById('live').innerText += data; // Append live log
|
||||
if (!result.done) f(r); // Read next chunk
|
||||
});
|
||||
};
|
||||
window.onload = ev => fetch('/api/log/static')
|
||||
.then(r => r.text())
|
||||
.then(r => { document.getElementById('static').innerText = r; })
|
||||
.then(r => fetch('/api/log/live'))
|
||||
.then(r => r.body.getReader())
|
||||
.then(f);
|
||||
</script>
|
||||
</html>
|
||||
132
components/mongoose/mongoose/examples/mip-pcap/main.c
Executable file
@@ -0,0 +1,132 @@
|
||||
// Copyright (c) 2022 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// SNTP example using MIP and pcap driver
|
||||
|
||||
#include <pcap.h>
|
||||
#include "mongoose.h"
|
||||
|
||||
static struct mg_connection *s_sntp_conn = NULL;
|
||||
|
||||
static int s_signo;
|
||||
void signal_handler(int signo) {
|
||||
s_signo = signo;
|
||||
}
|
||||
|
||||
// SNTP client callback
|
||||
static void sfn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_SNTP_TIME) {
|
||||
int64_t t = *(int64_t *) ev_data;
|
||||
MG_INFO(("Got SNTP time: %lld ms from epoch", t));
|
||||
} else if (ev == MG_EV_CLOSE) {
|
||||
s_sntp_conn = NULL;
|
||||
}
|
||||
(void) fn_data, (void) c;
|
||||
}
|
||||
|
||||
// Called every 5 seconds. Increase that for production case.
|
||||
static void timer_fn(void *arg) {
|
||||
struct mg_mgr *mgr = (struct mg_mgr *) arg;
|
||||
if (s_sntp_conn == NULL) s_sntp_conn = mg_sntp_connect(mgr, NULL, sfn, NULL);
|
||||
if (s_sntp_conn != NULL) mg_sntp_request(s_sntp_conn);
|
||||
}
|
||||
|
||||
static int fail(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static size_t pcap_tx(const void *data, size_t len, void *userdata) {
|
||||
int res = pcap_inject((pcap_t *) userdata, data, len);
|
||||
if (res == PCAP_ERROR) {
|
||||
MG_ERROR(("pcap_inject: %d", res));
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static bool pcap_status(void *userdata) {
|
||||
return userdata ? true : false;
|
||||
}
|
||||
|
||||
static size_t pcap_rx(void *buf, size_t len, void *userdata) {
|
||||
size_t received = 0;
|
||||
struct pcap_pkthdr *hdr = NULL;
|
||||
const unsigned char *pkt = NULL;
|
||||
if (pcap_next_ex((pcap_t *) userdata, &hdr, &pkt) == 1) {
|
||||
received = hdr->len < len ? hdr->len : len;
|
||||
memcpy(buf, pkt, received);
|
||||
}
|
||||
return received;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *iface = "lo0"; // Network iface
|
||||
const char *mac = "aa:bb:cc:01:02:03"; // MAC address
|
||||
const char *bpf = NULL; // "host x.x.x.x or ether host ff:ff:ff:ff:ff:ff";
|
||||
char errbuf[PCAP_ERRBUF_SIZE] = "";
|
||||
|
||||
struct mg_mgr mgr; // Event manager
|
||||
mg_mgr_init(&mgr); // Initialise event manager
|
||||
mg_log_set(MG_LL_DEBUG); // Set debug log level
|
||||
mg_timer_add(&mgr, 3000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, &mgr);
|
||||
|
||||
// Parse options
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-i") == 0 && i + 1 < argc) {
|
||||
iface = argv[++i];
|
||||
} else if (strcmp(argv[i], "-mac") == 0 && i + 1 < argc) {
|
||||
mac = argv[++i];
|
||||
} else if (strcmp(argv[i], "-bpf") == 0 && i + 1 < argc) {
|
||||
bpf = argv[++i];
|
||||
} else {
|
||||
return fail("unknown option %s", argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Open network interface
|
||||
pcap_t *ph = pcap_open_live(iface, 0xffff, 1, 1, errbuf);
|
||||
if (ph == NULL) {
|
||||
pcap_if_t *devs, *d;
|
||||
MG_ERROR(("Failed to open interface %s. Available interfaces:", iface));
|
||||
if (pcap_findalldevs(&devs, errbuf) == 0) {
|
||||
for (d = devs; d != NULL; d = d->next) {
|
||||
MG_ERROR(("%s (%s)", d->name, d->description ? d->description : ""));
|
||||
}
|
||||
pcap_freealldevs(devs);
|
||||
}
|
||||
fail("pcap_open_live: %s\n", errbuf);
|
||||
}
|
||||
pcap_setnonblock(ph, 1, errbuf);
|
||||
// Apply BPF to reduce noise. Let in only broadcasts and our own traffic
|
||||
if (bpf != NULL) {
|
||||
struct bpf_program bpfp;
|
||||
if (pcap_compile(ph, &bpfp, bpf, 1, 0)) fail("compile \n");
|
||||
pcap_setfilter(ph, &bpfp);
|
||||
pcap_freecode(&bpfp);
|
||||
}
|
||||
MG_INFO(("Opened interface %s\n", iface));
|
||||
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
|
||||
struct mip_ipcfg ipcfg = {.ip = 0, .mask = 0, .gw = 0};
|
||||
sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &ipcfg.mac[0], &ipcfg.mac[1],
|
||||
&ipcfg.mac[2], &ipcfg.mac[3], &ipcfg.mac[4], &ipcfg.mac[5]);
|
||||
|
||||
struct mip_driver driver = {
|
||||
.tx = pcap_tx, .status = pcap_status, .rx = pcap_rx};
|
||||
|
||||
mip_init(&mgr, &ipcfg, &driver, ph);
|
||||
MG_INFO(("Init done, starting main loop"));
|
||||
|
||||
while (s_signo == 0) mg_mgr_poll(&mgr, 1); // Infinite event loop
|
||||
|
||||
mg_mgr_free(&mgr);
|
||||
pcap_close(ph);
|
||||
printf("Exiting on signal %d\n", s_signo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
1
components/mongoose/mongoose/examples/mqtt-client-aws-iot/README.md
Executable file
@@ -0,0 +1 @@
|
||||
See detailed tutorial at https://mongoose.ws/tutorials/aws-iot/
|
||||
1
components/mongoose/mongoose/examples/mqtt-client-aws-iot/ca.pem
Symbolic link
@@ -0,0 +1 @@
|
||||
../../test/data/ca.pem
|
||||
91
components/mongoose/mongoose/examples/mqtt-client-aws-iot/main.c
Executable file
@@ -0,0 +1,91 @@
|
||||
// Copyright (c) 2020 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// Example MQTT client. It performs the following steps:
|
||||
// 1. Connects to the AWS IoT MQTT server
|
||||
// 2. When connected, subscribes to the topic `s_rx_topic`
|
||||
// 3. Publishes message `hello` to the `s_tx_topic` periodically
|
||||
//
|
||||
// This example requires TLS support. By default, it is built with mbedTLS,
|
||||
// therefore make sure mbedTLS is installed. To build with OpenSSL, execute:
|
||||
// make clean all CFLAGS="-W -Wall -DMG_ENABLE_OPENSSL=1 -lssl"
|
||||
|
||||
// In order to get MQTT URL, login to AWS IoT, click on "Settings" on the left
|
||||
// bar, copy the "Endpoint" URL.
|
||||
static const char *s_url =
|
||||
"mqtts://a1pjwh2bop1ojt-ats.iot.eu-west-1.amazonaws.com";
|
||||
|
||||
// To create certificates:
|
||||
// 1. Click Policies -> Create, fill fields:
|
||||
// Name : Policy1
|
||||
// Action : iot:*
|
||||
// Resource ARN: *
|
||||
// Effect : allow
|
||||
// then, click "Create"
|
||||
// 2. Click Manage -> Things -> Create things -> Create single thing -> Next
|
||||
// Thing name: t1, no shadow, Next
|
||||
// Auto-generate new certificate, Next
|
||||
// Select policy Policy1, Create thing
|
||||
// 3. From the dialog box that appears, download:
|
||||
// xxx-certificate.pem.crt as cert.pem to the example directory
|
||||
// xxx-private.pem.key as key.pem to the example directory
|
||||
static const char *s_cert = "cert.pem";
|
||||
static const char *s_key = "key.pem";
|
||||
|
||||
static const char *s_rx_topic = "d/rx";
|
||||
static const char *s_tx_topic = "d/tx";
|
||||
static int s_qos = 1;
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_OPEN) {
|
||||
// c->is_hexdumping = 1;
|
||||
} else if (ev == MG_EV_ERROR) {
|
||||
// On error, log error message
|
||||
MG_ERROR(("%p %s", c->fd, (char *) ev_data));
|
||||
} else if (ev == MG_EV_CONNECT) {
|
||||
// Set up 2-way TLS that is required by AWS IoT
|
||||
struct mg_tls_opts opts = {
|
||||
.ca = "ca.pem", .cert = s_cert, .certkey = s_key};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_MQTT_OPEN) {
|
||||
// MQTT connect is successful
|
||||
struct mg_str topic = mg_str(s_rx_topic);
|
||||
MG_INFO(("Connected to %s", s_url));
|
||||
MG_INFO(("Subscribing to %s", s_rx_topic));
|
||||
mg_mqtt_sub(c, topic, s_qos);
|
||||
c->label[0] = 'X'; // Set a label that we're logged in
|
||||
} else if (ev == MG_EV_MQTT_MSG) {
|
||||
// When we receive MQTT message, print it
|
||||
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
|
||||
MG_INFO(("Received on %.*s : %.*s", (int) mm->topic.len, mm->topic.ptr,
|
||||
(int) mm->data.len, mm->data.ptr));
|
||||
} else if (ev == MG_EV_POLL && c->label[0] == 'X') {
|
||||
static unsigned long prev_second;
|
||||
unsigned long now_second = (*(unsigned long *) ev_data) / 1000;
|
||||
if (now_second != prev_second) {
|
||||
struct mg_str topic = mg_str(s_tx_topic), data = mg_str("{\"a\":123}");
|
||||
MG_INFO(("Publishing to %s", s_tx_topic));
|
||||
mg_mqtt_pub(c, topic, data, s_qos, false);
|
||||
prev_second = now_second;
|
||||
}
|
||||
}
|
||||
|
||||
if (ev == MG_EV_ERROR || ev == MG_EV_CLOSE) {
|
||||
MG_INFO(("Got event %d, stopping...", ev));
|
||||
*(bool *) fn_data = true; // Signal that we're done
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
struct mg_mqtt_opts opts = {.clean = true};
|
||||
bool done = false;
|
||||
mg_mgr_init(&mgr); // Initialise event manager
|
||||
MG_INFO(("Connecting to %s", s_url)); // Inform that we're starting
|
||||
mg_mqtt_connect(&mgr, s_url, &opts, fn, &done); // Create client connection
|
||||
while (!done) mg_mgr_poll(&mgr, 1000); // Loop until done
|
||||
mg_mgr_free(&mgr); // Finished, cleanup
|
||||
return 0;
|
||||
}
|
||||