mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-26 12:14:56 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
409c12a851 | ||
|
|
bcdcbf20ee | ||
|
|
8fc5b5a55f | ||
|
|
faeedb2930 | ||
|
|
c8e8f94ffe | ||
|
|
22aeb6111b | ||
|
|
2d1d2e6534 | ||
|
|
05c88a98fc | ||
|
|
5224afb946 | ||
|
|
3bd79c7cd5 | ||
|
|
c52e0744cb | ||
|
|
6c09c303d0 | ||
|
|
b6fde06990 | ||
|
|
af892c9726 | ||
|
|
df7ad13680 | ||
|
|
057c2d4b42 | ||
|
|
6c9b43bcf5 | ||
|
|
a91438acae | ||
|
|
a6fa51dbc2 | ||
|
|
6ceac6c84c | ||
|
|
288efe3c23 | ||
|
|
5207545a8b | ||
|
|
716d524f9b | ||
|
|
a434bab767 | ||
|
|
e9633a8d2d | ||
|
|
c7b6a6f0ea | ||
|
|
6cdb9f7ed3 | ||
|
|
4502dd0c86 | ||
|
|
95055f6048 | ||
|
|
2c36532ec4 | ||
|
|
f2b0b9c737 | ||
|
|
b3866439a0 | ||
|
|
4f2205a667 | ||
|
|
6cec1d36a8 | ||
|
|
4238370ae1 | ||
|
|
b4924b715e | ||
|
|
7a0385dcac | ||
|
|
44a146faf6 | ||
|
|
53a55da7bc | ||
|
|
bf44277764 | ||
|
|
a2e1da6e30 | ||
|
|
bef3f85ba8 | ||
|
|
eb72a63cca | ||
|
|
f19bbc73cc | ||
|
|
25326b3b12 | ||
|
|
10ee430bfd | ||
|
|
10d0bfdab4 | ||
|
|
6b6637c337 | ||
|
|
878acca213 | ||
|
|
ace9285966 | ||
|
|
cdc167b0cc | ||
|
|
a0dd396b95 | ||
|
|
8082501b9c | ||
|
|
e4ad3010be | ||
|
|
03a82ef848 | ||
|
|
9459d69dcc | ||
|
|
b28662362d | ||
|
|
66450bf3d1 | ||
|
|
478ca05e7a | ||
|
|
8cad0a72f9 | ||
|
|
31178f4d48 | ||
|
|
7a5485493e | ||
|
|
d3cbb160f5 | ||
|
|
45ff2c2c19 | ||
|
|
c3db7b141b | ||
|
|
0a0ea36ace | ||
|
|
72ed954721 | ||
|
|
33e035273a | ||
|
|
223f36c130 | ||
|
|
4c0bc5bd03 | ||
|
|
808a5f6f53 | ||
|
|
404e635665 | ||
|
|
9d7a60a63f | ||
|
|
ba9c74187b | ||
|
|
e9d4847cbb | ||
|
|
ea76de07ee | ||
|
|
5a8c468ff7 | ||
|
|
5b143a6237 | ||
|
|
d244a7fdfd | ||
|
|
300a27de99 | ||
|
|
04a15a0c10 | ||
|
|
f0f6ae05aa | ||
|
|
8a7d535d92 | ||
|
|
e7ac6024de | ||
|
|
9981b99ac8 | ||
|
|
87a36c0c30 | ||
|
|
f2b13761c0 | ||
|
|
9786478a31 | ||
|
|
7d236d7f33 | ||
|
|
e098a7292d | ||
|
|
632b3a38a9 | ||
|
|
23141c2fef | ||
|
|
c8ba652f1c | ||
|
|
6ac2fa2ae6 | ||
|
|
0322ec5647 | ||
|
|
a5223a9850 | ||
|
|
016968ada1 | ||
|
|
710b888122 | ||
|
|
cf53959f34 | ||
|
|
30d29fb77f | ||
|
|
c05b51bbfc | ||
|
|
1ab704ac92 | ||
|
|
2bc77e065c | ||
|
|
790daabf7d | ||
|
|
a6598a1278 | ||
|
|
0af5502b74 | ||
|
|
f059e41cac | ||
|
|
2cce91de9a | ||
|
|
0ff5b5b044 | ||
|
|
0c5d9a98c2 | ||
|
|
c9fbdfc1b5 | ||
|
|
6193b5171c | ||
|
|
911115ccc0 | ||
|
|
2f3ddeccc5 | ||
|
|
ca3f5a3257 | ||
|
|
df206bc05a | ||
|
|
531fec34fd | ||
|
|
4c10d1f356 | ||
|
|
94dccdd6f4 | ||
|
|
544352b7d3 | ||
|
|
29c2ae4886 | ||
|
|
1a2e2ec2fd | ||
|
|
3e780d21fc | ||
|
|
63fcea0159 | ||
|
|
e5d21225be | ||
|
|
0c9caf3120 | ||
|
|
54ba36c1c9 | ||
|
|
5077350589 | ||
|
|
2d880c4f5c | ||
|
|
4ca4c862a5 | ||
|
|
0918df1566 | ||
|
|
aa2583cc26 | ||
|
|
e1b1d39635 | ||
|
|
3bf82dd541 | ||
|
|
2896965c97 | ||
|
|
53b784b143 | ||
|
|
8e91e3a305 | ||
|
|
dbc07c8b00 | ||
|
|
ce953575e2 | ||
|
|
80db048578 | ||
|
|
382d165574 | ||
|
|
0fb2f38cb7 | ||
|
|
aa007f1285 | ||
|
|
8752910330 | ||
|
|
2a5a8eec49 | ||
|
|
ceca52de30 | ||
|
|
8a3691055c | ||
|
|
56d12c89da | ||
|
|
2cfce4d8b2 | ||
|
|
f372faf614 | ||
|
|
882f3b3ac3 | ||
|
|
fac0e9b0ac | ||
|
|
a3cf67c380 | ||
|
|
2987cbdb5c | ||
|
|
6083b9c5c5 | ||
|
|
83237a02d9 | ||
|
|
965188bac9 | ||
|
|
66da41d401 | ||
|
|
cfd334ac6c | ||
|
|
b5f6254c1e | ||
|
|
dcbd1cbbd1 | ||
|
|
a3b568f460 | ||
|
|
75770aec80 | ||
|
|
3a8ae7ac17 | ||
|
|
b116b2fa82 | ||
|
|
7806609773 | ||
|
|
72f45aa7e2 | ||
|
|
5e3e6a6dce | ||
|
|
1388bb1db4 | ||
|
|
3cc0d16f65 | ||
|
|
b50095fa61 | ||
|
|
7ad85219d8 | ||
|
|
347a249d10 | ||
|
|
07d982129a | ||
|
|
73f2602ba0 | ||
|
|
44561d163a | ||
|
|
c941a1a39a | ||
|
|
bee22312bc | ||
|
|
bdb16c624c | ||
|
|
e389e70d05 | ||
|
|
695559f691 | ||
|
|
13be74b4c6 | ||
|
|
02a1032fd4 | ||
|
|
788f35b19c | ||
|
|
3721efe1e9 | ||
|
|
e0822ffb78 | ||
|
|
ae7d5a8f94 | ||
|
|
ced7a2e0b5 | ||
|
|
5ed6708468 | ||
|
|
9fe53f307b | ||
|
|
c64d30e1f6 | ||
|
|
b4c25fc7ba | ||
|
|
b67b618811 | ||
|
|
5a19438f70 | ||
|
|
860addf1e3 | ||
|
|
03d571a119 | ||
|
|
0d9ecffc53 | ||
|
|
d4c8384b85 | ||
|
|
bd40145301 | ||
|
|
9b42494316 | ||
|
|
2daff6959f | ||
|
|
e9c434a6a1 | ||
|
|
d6fba7e45d | ||
|
|
0a0130b90c | ||
|
|
facf2af66e | ||
|
|
cc54195f59 | ||
|
|
e2fb707d9f | ||
|
|
7dfff935d6 | ||
|
|
5727a5c0ed | ||
|
|
268d2e9cbe | ||
|
|
1e7da874a4 | ||
|
|
7875a8c2bd | ||
|
|
b0355d45ae | ||
|
|
91136d7731 | ||
|
|
01a058d29b | ||
|
|
e6eca1738f | ||
|
|
2108ec5a0c | ||
|
|
bc4e47630a | ||
|
|
f41c9a2a1f | ||
|
|
6c77208236 | ||
|
|
386d2e5cd4 | ||
|
|
b738fdbffa | ||
|
|
b5704850db | ||
|
|
9c67e8960e | ||
|
|
d3dff4e1d5 | ||
|
|
82872e86fd | ||
|
|
ac229b6606 | ||
|
|
a6bf2bcbf4 | ||
|
|
b0cf8304cb | ||
|
|
0d9fe39dbb | ||
|
|
708af6d9c5 | ||
|
|
e4c71425c9 | ||
|
|
6e07215c1c | ||
|
|
ca9603301e | ||
|
|
d6c388042c | ||
|
|
6f66d794e8 | ||
|
|
1389eec784 | ||
|
|
6ef795e082 | ||
|
|
1e5d258e9e | ||
|
|
70eb4c4bbc | ||
|
|
a639e10a4d | ||
|
|
48750e67f6 | ||
|
|
ce60379af6 | ||
|
|
e0b9e4abfd | ||
|
|
665f205527 | ||
|
|
030daaf5d5 | ||
|
|
760511ec49 | ||
|
|
203688a34b | ||
|
|
29f4703e4f | ||
|
|
3cec6f6745 | ||
|
|
abcea07641 | ||
|
|
6a54704b29 | ||
|
|
8a2fbac4c0 | ||
|
|
96ce6bac69 | ||
|
|
50c0b958ff | ||
|
|
44416902d6 | ||
|
|
25e646c1a1 | ||
|
|
bd723bdc38 | ||
|
|
5e57031724 | ||
|
|
c583913290 | ||
|
|
870ca615de | ||
|
|
64b51699f8 | ||
|
|
50a889dac0 | ||
|
|
0ff0788458 | ||
|
|
fec6009edb | ||
|
|
c4f172a120 | ||
|
|
464c77314d | ||
|
|
f51ca8d5d1 | ||
|
|
7b37e0cb8b | ||
|
|
c7925353e7 | ||
|
|
bd23ec4323 | ||
|
|
3671b2632d | ||
|
|
25115a694c | ||
|
|
2436f9d6c3 | ||
|
|
2238951c18 | ||
|
|
f266dd2c94 | ||
|
|
b03358cb03 | ||
|
|
1bede7e28b | ||
|
|
3536670b82 | ||
|
|
3235c05fd6 | ||
|
|
63db54e7b5 | ||
|
|
1db51eb788 | ||
|
|
0e640ae885 | ||
|
|
1bff6df2a7 | ||
|
|
d0e66de225 | ||
|
|
f537670ce2 | ||
|
|
4cb3341a15 | ||
|
|
d52d9a4a6f | ||
|
|
4a076c7ea4 | ||
|
|
db6e883c22 | ||
|
|
804da054b5 | ||
|
|
fb4e701545 | ||
|
|
ccff4abf13 | ||
|
|
24a7936907 | ||
|
|
0993994139 | ||
|
|
8b740536de | ||
|
|
e851aac853 | ||
|
|
a39861b7bf | ||
|
|
63490249ba | ||
|
|
704f057384 | ||
|
|
40968bc496 | ||
|
|
6873f3c5f6 | ||
|
|
ba5cd7267a | ||
|
|
1bb98e5e8e | ||
|
|
a7774d0f1a | ||
|
|
f52c756fbb | ||
|
|
cc586c6ba2 | ||
|
|
606eab7f4f | ||
|
|
872b85b5f2 | ||
|
|
35bd2b6032 | ||
|
|
c5287b9044 | ||
|
|
223f6d960e | ||
|
|
464b895116 | ||
|
|
05d7b7c8bc | ||
|
|
d8b4db37a0 | ||
|
|
6bb49c780c | ||
|
|
3a60c5764d | ||
|
|
a8b38e4ab9 | ||
|
|
8750f8af1f | ||
|
|
e94a02dc12 | ||
|
|
5680b0fcc5 | ||
|
|
33c56b0edc | ||
|
|
e62e48397d | ||
|
|
8be30350be | ||
|
|
2609a2ab72 | ||
|
|
5a04ab2c56 | ||
|
|
4739de6c28 | ||
|
|
639d7a2fd8 | ||
|
|
8115ce1d82 | ||
|
|
3558b587b7 | ||
|
|
e21ec58ea8 | ||
|
|
74135bca7d | ||
|
|
d369f31608 | ||
|
|
d4b14ca3c1 | ||
|
|
f0994896d5 | ||
|
|
cfdd430b98 | ||
|
|
a6c05a9e83 | ||
|
|
94f63787bb | ||
|
|
367f5df328 | ||
|
|
f096138d6e | ||
|
|
0d00cd51e6 | ||
|
|
b216210a13 | ||
|
|
166833f330 | ||
|
|
4d6bedfd4e | ||
|
|
ace8c1736c | ||
|
|
c658a54d18 | ||
|
|
781a1dc25e | ||
|
|
3ea3b8dfa4 | ||
|
|
a514e143ff | ||
|
|
e1486a79e3 | ||
|
|
ee615248e3 | ||
|
|
687e0e2ee8 | ||
|
|
19aefcb7dd | ||
|
|
6a46244a21 | ||
|
|
60674c11c9 | ||
|
|
91c9ab807b | ||
|
|
9231c7346c | ||
|
|
20cb3a823a | ||
|
|
cbd8d69e6d | ||
|
|
f7fcfa6a42 | ||
|
|
293c5e5852 | ||
|
|
ceb866b4ee | ||
|
|
2f9166e96e | ||
|
|
fe0e0e69e5 | ||
|
|
db96641c10 | ||
|
|
fe83928ca4 | ||
|
|
014414f17f | ||
|
|
6ffe2d7f7a | ||
|
|
30c82d7efe | ||
|
|
999c4ad26c | ||
|
|
30a7965135 | ||
|
|
a8a017a048 | ||
|
|
eac8ffabc4 | ||
|
|
a7a17711ec | ||
|
|
18e28ef879 | ||
|
|
ce7515fca9 | ||
|
|
d5a78fb664 | ||
|
|
1b3a1b74ac | ||
|
|
8dd76e6ef4 | ||
|
|
976b5f37c1 | ||
|
|
31489ab7b1 | ||
|
|
1eb59940a4 | ||
|
|
576d769b56 | ||
|
|
afaba7ee17 | ||
|
|
40f257ef2b | ||
|
|
5840dc8153 | ||
|
|
5ed3dafb56 | ||
|
|
b99bf306ec | ||
|
|
89fae72aa7 | ||
|
|
ab147e8f19 | ||
|
|
81a78f9c8b | ||
|
|
370aeefdde | ||
|
|
c5407a75f4 | ||
|
|
7217aa22f1 | ||
|
|
69bd5f7aa2 | ||
|
|
41b3c1b23e | ||
|
|
f639409533 | ||
|
|
67c44799c8 | ||
|
|
4646e2ad55 | ||
|
|
b77532ea3f | ||
|
|
ed8168e8a1 | ||
|
|
39e2d2ad55 | ||
|
|
27c6656398 | ||
|
|
ffe83051fe | ||
|
|
93cd77ffad | ||
|
|
279c06c64c | ||
|
|
570c8213b6 | ||
|
|
f521999ea6 | ||
|
|
e41df3cf9c | ||
|
|
65f484291f | ||
|
|
77db89961b | ||
|
|
ad50310bb6 | ||
|
|
66ec3d1f1e | ||
|
|
a9da86d05c | ||
|
|
5f25a88821 | ||
|
|
fd7dc33645 | ||
|
|
9c22771a43 | ||
|
|
11640cc3c6 | ||
|
|
2264520a2f | ||
|
|
2f0b411ddd | ||
|
|
e0aceb4f3a | ||
|
|
ea9a60a59a | ||
|
|
458320cffb | ||
|
|
e0214af422 | ||
|
|
df5e997ea7 | ||
|
|
0a3cb63c73 | ||
|
|
37f7f3fb12 | ||
|
|
2ac970fa16 | ||
|
|
de35a353d4 | ||
|
|
dbbda02f70 | ||
|
|
725c30446c | ||
|
|
60473ae41a | ||
|
|
951d20f904 | ||
|
|
85a6abd58b | ||
|
|
2fbe09ad7c | ||
|
|
23325efab2 | ||
|
|
107902bae4 | ||
|
|
9bbf4c8384 | ||
|
|
c39a712540 | ||
|
|
e9f6111ba1 | ||
|
|
ba267a32fd | ||
|
|
f64ebbe0b1 | ||
|
|
8865dd5e84 | ||
|
|
ce57f47de0 | ||
|
|
48be2dbc2a | ||
|
|
8905522a94 | ||
|
|
eea1680cf9 | ||
|
|
d5004cb7eb | ||
|
|
1d1a05bf39 | ||
|
|
2009069037 | ||
|
|
8f7703c2a9 | ||
|
|
8e87c4f013 | ||
|
|
639a6dc2a8 | ||
|
|
cead9a04ca | ||
|
|
e528093027 | ||
|
|
c432b783fb | ||
|
|
e06976836f | ||
|
|
c9f7407573 | ||
|
|
a40e59dbe6 | ||
|
|
61ee3d36d0 | ||
|
|
94dbf21ffb | ||
|
|
998425b14b | ||
|
|
6900dd733a | ||
|
|
9e4cd054c8 | ||
|
|
5dc317fcb0 | ||
|
|
fbd5d77ce8 | ||
|
|
6f8751b479 | ||
|
|
877c4dc698 | ||
|
|
2dfc79129a | ||
|
|
416f4bf10f | ||
|
|
f9a99530ff | ||
|
|
940b65e4db | ||
|
|
b22f7d3a49 | ||
|
|
eaa0e26a85 | ||
|
|
a3a63f7e56 | ||
|
|
c9036f3ac0 | ||
|
|
60858d7fe5 | ||
|
|
1c914bde1d | ||
|
|
a487332aa0 | ||
|
|
3987d4d560 | ||
|
|
8d3181e0bf | ||
|
|
0f1a59aeb4 | ||
|
|
2cdf259940 | ||
|
|
0187fe943a | ||
|
|
a34d1ec00a | ||
|
|
e70d98b7b0 | ||
|
|
bea012a3c1 | ||
|
|
eb2d470f65 | ||
|
|
652c352394 | ||
|
|
f1b37b3101 | ||
|
|
81b9876af8 | ||
|
|
9e118c8a31 |
No files matched your search
@@ -1,11 +1,11 @@
|
|||||||
Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
|
Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
|
||||||
Copyright (c) 2013 Cesanta Software Limited
|
Copyright (c) 2013-2015 Cesanta Software Limited
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
This code is dual-licensed: you can redistribute it and/or modify
|
This code is dual-licensed: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License version 2 as
|
it under the terms of the GNU General Public License version 2 as
|
||||||
published by the Free Software Foundation. For the terms of this
|
published by the Free Software Foundation. For the terms of this
|
||||||
license, see http://www.gnu.org/licenses.
|
license, see <http://www.gnu.org/licenses>.
|
||||||
|
|
||||||
You are free to use this code under the terms of the GNU General
|
You are free to use this code under the terms of the GNU General
|
||||||
Public License, but WITHOUT ANY WARRANTY; without even the implied
|
Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||||
@@ -13,4 +13,4 @@ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|||||||
See the GNU General Public License for more details.
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
Alternatively, you can license this code under a commercial
|
Alternatively, you can license this code under a commercial
|
||||||
license, as set out in http://cesanta.com/products.html.
|
license, as set out in <http://cesanta.com/>.
|
||||||
@@ -1,60 +1,76 @@
|
|||||||
# Mongoose Web Server
|
# <img src="http://cesanta.com/images/mongoose_logo.png" width="64" height="64"> Mongoose Web Server
|
||||||
|
|
||||||
|
Mongoose is the most easy to use web server on the planet. A web server of choice for Web developers (PHP, Ruby, Python, etc) and Web designers.
|
||||||
|
|
||||||
|
Mongoose is built on top of Libmongoose embedded library, which can turn
|
||||||
|
anything into a web server in 5 minutes worth of effort and few lines of code.
|
||||||
|
Libmongoose is used to serve Web GUI on embedded devices, implement RESTful
|
||||||
|
services, RPC frameworks (e.g. JSON-RPC), handle telemetry data exchange, and
|
||||||
|
perform many other tasks in various different industries including aerospace,
|
||||||
|
manufacturing, finance, research, automotive, gaming, IT.
|
||||||
|
|
||||||
|
|
||||||
Mongoose is easy to use, powerful, embeddable web server.
|
|
||||||
* [Downloads](http://cesanta.com/downloads.html)
|
|
||||||
* [Documentation](http://cesanta.com/docs.html)
|
|
||||||
* [Mailing list](http://groups.google.com/group/mongoose-users)
|
* [Mailing list](http://groups.google.com/group/mongoose-users)
|
||||||
|
* [Downloads](http://cesanta.com/products.shtml)
|
||||||
|
* [Documentation](http://cesanta.com/docs.shtml)
|
||||||
|
|
||||||
|
Check out Fossa - our [embedded multi-protocol library](https://github.com/cesanta/fossa) with TCP,UDP,HTTP,Websocket,MQTT,DNS support, designed for Internet Of Things!
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
|
|
||||||
- Works on Windows, Mac, UNIX/Linux, iPhone, Android, and many other platforms
|
- Works on Windows, Mac, UNIX/Linux, iPhone, Android eCos, QNX
|
||||||
- CGI, SSL, Digest auth, Websocket, WEbDAV, Resumed download, URL rewrite, file blacklist, IP-based ACL, Windows service
|
and many other platforms
|
||||||
- Scripting and database support ([Lua](http://lua.org) +
|
- CGI, SSI, SSL, Digest auth, Websocket, WEbDAV, Resumed download,
|
||||||
[Sqlite](http://sqlite.org), see
|
URL rewrite, file blacklist
|
||||||
[dirscan.lp](https://github.com/cesanta/mongoose/blob/master/examples/lua/dirscan.lp) ),
|
- Custom error pages, Virtual hosts, IP-based ACL, Windows service,
|
||||||
which provides ready to go, powerful web development platform in
|
HTTP/HTTPS client
|
||||||
one single-click executable with no dependencies
|
|
||||||
- Simple and clean
|
- Simple and clean
|
||||||
[embedding API](https://github.com/cesanta/mongoose/blob/master/mongoose.h).
|
[embedding API](https://github.com/cesanta/mongoose/blob/master/mongoose.h).
|
||||||
The source is in single
|
The source is in single
|
||||||
[mongoose.c](https://github.com/cesanta/mongoose/blob/master/mongoose.c) file
|
[mongoose.c](https://github.com/cesanta/mongoose/blob/master/mongoose.c) file
|
||||||
to make embedding easy
|
to make embedding easy
|
||||||
- Extremely lightweight, has a core of under 40kB and tiny runtime footprint
|
- Extremely lightweight, has a core of under 40kB and tiny runtime footprint
|
||||||
- Asyncronouns, non-blocking core supporting single- or multi-threaded usage
|
- Asynchronous, non-blocking core supporting single- or multi-threaded usage
|
||||||
- On the market since 2004, stable, mature and tested,
|
- On the market since 2004 with over 1 million cumulative downloads
|
||||||
has several man-years invested in continuous improvement and refinement
|
- Stable, mature and tested, has several man-years invested
|
||||||
- Professional support and consultancy available from
|
in continuous improvement and refinement
|
||||||
[Cesanta Software](http://cesanta.com), developer of Mongoose
|
|
||||||
|
|
||||||
# Acknowledgements
|
# Screenshots
|
||||||
|
|
||||||
Mongoose made better thanks to the contribution of following people:
|
Download, double-click to start, run browser -- that's all!
|
||||||
|
|
||||||
Arnout Vandecappelle, Benoît Amiaux, Boris Pek, Cody Hanson, Colin Leitner,
|

|
||||||
Daniel Oaks, Eric Bakan, Erik Oomen, Filipp Kovalev, Ger Hobbelt,
|

|
||||||
Hendrik Polczynski, Igor Okulist, Jay, Joe Mucchiello, John Safranek,
|
|
||||||
José Miguel Gonçalves, Shueng Chuan, Katerina Blinova, Konstantin Sorokin,
|

|
||||||
Marin Atanasov, Matt Healy, Mitch Hendrickson, Nigel Stewart, Pavel Khlebovich,
|

|
||||||
Sebastian Reinhard, Stefan Doehla, abadc0de, nullable.type,
|
|
||||||
T.Barmann, D.Hughes, J.C.Sloan, R.Romeo, L.E.Spencer, S.Kotay, R.M.Shorter,
|
# Contributions
|
||||||
W.Mar, J.Wilander, Santa from Memphis, S.Davies, C.Beck,
|
|
||||||
O.M.Vilhunen, C.Radik, G.Woodcock, M.Szczepkowski,
|
People who have agreed to the
|
||||||
Eternal Lands Dev Team, T.Tollet, C.Tangerino, G.Karsai, A.Bourgett,
|
[Cesanta CLA](http://cesanta.com/contributors_la.html)
|
||||||
C.Blakemore, D.Fonaryov, T.Andrle, O.IJsselmuiden, R.Womack, M.Tomlinson,
|
can make contributions. Note that the CLA isn't a copyright
|
||||||
A.Slåttå, L.Farrell, J.D.P.Ballestero, V.Albaev, B.Harker, T.Scheffel, H.Klein,
|
_assigment_ but rather a copyright _license_.
|
||||||
R.Merit, T.Bennett, H.Solis, A.Zincenko, M.S., S.Krul, K.Cooke, S.McCallum,
|
You retain the copyright on your contributions.
|
||||||
F.Morenius, and 10 others.
|
|
||||||
|
|
||||||
# Licensing
|
# Licensing
|
||||||
|
|
||||||
Mongoose is released under
|
Mongoose is released under commercial and
|
||||||
[GNU GPL v.2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html).
|
[GNU GPL v.2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) open
|
||||||
Businesses have an option to get non-restrictive, royalty-free commercial
|
source licenses. The GPLv2 open source License does not generally permit
|
||||||
license and professional support from
|
incorporating this software into non-open source programs.
|
||||||
[Cesanta Software](http://cesanta.com).
|
For those customers who do not wish to comply with the GPLv2 open
|
||||||
|
source license requirements,
|
||||||
|
[Cesanta](http://cesanta.com) offers a full,
|
||||||
|
royalty-free commercial license and professional support
|
||||||
|
without any of the GPL restrictions.
|
||||||
|
|
||||||
[Frozen JSON parser](https://github.com/cesanta/frozen),
|
# Other products by Cesanta
|
||||||
[Super Light Regular Expression library](https://github.com/cesanta/slre),
|
|
||||||
[Super Light DNS Resolver](https://github.com/cesanta/sldr)
|
- [Fossa](http://github.com/cesanta/fossa) - Multi-protocol networking library
|
||||||
are other projects by Cesanta Software, developed with the same philosophy
|
- [SSL Wrapper](https://github.com/cesanta/ssl_wrapper) - application to
|
||||||
of functionality and simplicity.
|
secure network communications
|
||||||
|
- [Frozen](https://github.com/cesanta/frozen) - JSON parser and generator
|
||||||
|
- [SLRE](https://github.com/cesanta/slre) - Super Light Regular Expression
|
||||||
|
library
|
||||||
|
- [V7](https://github.com/cesanta/v7) - Embedded JavaScript engine
|
||||||
+105
-64
@@ -1,14 +1,13 @@
|
|||||||
# Mongoose API Reference
|
# Mongoose API Reference
|
||||||
|
|
||||||
struct mg_server *mg_create_server(void *server_param);
|
struct mg_server *mg_create_server(void *server_param, mg_handler_t handler);
|
||||||
|
|
||||||
Creates web server instance. Returns opaque instance pointer, or NULL if
|
Creates web server instance. Returns opaque instance pointer, or NULL if
|
||||||
there is not enough memory. `server_param`: Could be any pointer, or NULL.
|
there is not enough memory. `server_param`: Could be any pointer, or NULL.
|
||||||
This pointer will be passed
|
This pointer will be passed
|
||||||
to the callback functions as `struct mg_connection::server_param` field.
|
to the callback functions as `struct mg_connection::server_param` field.
|
||||||
A common use case is to pass `this` pointer of the C++ wrapper class
|
A common use case is to pass `this` pointer of the C++ wrapper class
|
||||||
as `user_param`, to let the callback get the pointer to the C++
|
as `user_param`, to let the callback get the pointer to the C++ object.
|
||||||
object.
|
|
||||||
|
|
||||||
Note that this function doesn't make the
|
Note that this function doesn't make the
|
||||||
server instance to serve. Serving is done by `mg_poll_server()` function.
|
server instance to serve. Serving is done by `mg_poll_server()` function.
|
||||||
@@ -17,10 +16,7 @@ When server instance is created, it contains an information about
|
|||||||
the configuration and the state of each connection.
|
the configuration and the state of each connection.
|
||||||
Server instance is capable on listening on only one port. After creation,
|
Server instance is capable on listening on only one port. After creation,
|
||||||
`struct mg_server` has a list
|
`struct mg_server` has a list
|
||||||
of active connections, initially empty. It has a list of URI handlers,
|
of active connections and configuration parameters.
|
||||||
initially empty, and configuration parameters. Configuration can be
|
|
||||||
altered by `mg_set_option()`, and new URI handlers could be added by
|
|
||||||
`mg_add_uri_handler()`.
|
|
||||||
|
|
||||||
Side-effect: on UNIX, `mg_create_server()` ignores SIGPIPE signals. If custom
|
Side-effect: on UNIX, `mg_create_server()` ignores SIGPIPE signals. If custom
|
||||||
processing is required SIGPIPE, signal handler must be set up after
|
processing is required SIGPIPE, signal handler must be set up after
|
||||||
@@ -38,57 +34,84 @@ server pointer a NULL pointer.
|
|||||||
const char mg_set_option(struct mg_server *server, const char *name,
|
const char mg_set_option(struct mg_server *server, const char *name,
|
||||||
const char *value);
|
const char *value);
|
||||||
|
|
||||||
Sets a particular server option. Please refer to a separate documentation page
|
Sets a particular server option. Note that at least one option,
|
||||||
that lists all available option names. Note that at least one option,
|
|
||||||
`listening_port`, must be specified. To serve static files, `document_root`
|
`listening_port`, must be specified. To serve static files, `document_root`
|
||||||
must be specified too. If `document_root` option is left unset, Mongoose
|
must be specified too. If `document_root` option is left unset, Mongoose
|
||||||
will not access filesystem at all. This function returns NULL if option was
|
will not access filesystem at all. `mg_set_option()` returns NULL if option was
|
||||||
set successfully, otherwise it returns human-readable error string. It is
|
set successfully, otherwise it returns human-readable error string. It is
|
||||||
allowed to call `mg_set_option()` by the same thread that does
|
allowed to call `mg_set_option()` by the same thread that does
|
||||||
`mg_poll_server()` (an IO thread) and change server configuration while it
|
`mg_poll_server()` (Mongoose thread) and change server configuration while it
|
||||||
is serving, in between `mg_poll_server()` calls.
|
is serving, in between `mg_poll_server()` calls.
|
||||||
|
|
||||||
void mg_poll_server(struct mg_server *server, int milliseconds);
|
int mg_poll_server(struct mg_server *server, int milliseconds);
|
||||||
|
|
||||||
This function performs one iteration of IO loop by iterating over all
|
Performs one iteration of IO loop by iterating over all
|
||||||
active connections, performing `select()` syscall on all sockets with a timeout
|
active connections, performing `select()` syscall on all sockets with a timeout
|
||||||
of `milliseconds` number of milliseconds. When `select()` returns, Mongoose
|
of `milliseconds`. When `select()` returns, Mongoose
|
||||||
does an IO for each socket that has data to be sent or received. Application
|
does an IO for each socket that has data to be sent or received. Application
|
||||||
code must call `mg_poll_server()` in a loop. It is an error to have more then
|
code must call `mg_poll_server()` in a loop. It is an error to have more then
|
||||||
one thread calling `mg_poll_server()`, `mg_set_option()` or any other function
|
one thread calling `mg_poll_server()`, `mg_set_option()` or any other function
|
||||||
that take `struct mg_server *` parameter. Mongoose does not
|
that take `struct mg_server *` parameter. Mongoose does not
|
||||||
mutex-protect `struct mg_server *`, therefore the best practice is
|
mutex-protect `struct mg_server *`, therefore only single thread
|
||||||
to call server management functions from the same thread (an IO thread).
|
(Mongoose thread) should make Mongoose calls.
|
||||||
|
|
||||||
void mg_set_auth_handler(struct mg_server *, mg_handler_t handler);
|
`mg_poll_server()` calls user-specified event handler when certain events
|
||||||
|
occur. Sequence of events for the accepted connection is this:
|
||||||
|
|
||||||
Sets authorization handler. Called by Mongoose on each request, before
|
* `MG_AUTH` - Mongoose asks whether this connection is authorized. If event
|
||||||
performing any other action. Handler can return either `MG_AUTH_OK` or
|
handler returns `MG_FALSE`, then Mongoose does not serve the request but
|
||||||
`MG_AUTH_FAIL`. If `handler` returns `MG_AUTH_FAIL`, then Mongoose sends
|
sends authorization request to the client. If `MG_TRUE` is returned,
|
||||||
digest authorization request to the client. If `handler returns `MG_AUTH_OK`,
|
then Mongoose continues on with the request.
|
||||||
then mongoose proceeds with handling the request. Handler function can use
|
* `MG_REQUEST` - Mongoose asks event handler to serve the request. If
|
||||||
`mg_authorize_digest()` function to verify authorization, or implement any other
|
event handler serves the request by sending a reply,
|
||||||
custom authorization mechanism.
|
it should return `MG_TRUE`. Otherwise,
|
||||||
|
it should return `MG_FALSE` which tells Mongoose that request is not
|
||||||
|
served and Mongoose should serve it. For example, event handler might
|
||||||
|
choose to serve only RESTful API requests with URIs that start with
|
||||||
|
certain prefix, and let Mongoose serve all static files.
|
||||||
|
If event handler decides to serve the request, but doesn't have
|
||||||
|
all the data at the moment, it should return `MG_MORE`. That tells
|
||||||
|
Mongoose to keep the connection open after callback returns.
|
||||||
|
|
||||||
void mg_set_request_handler(struct mg_server *, mg_handler_t handler);
|
`mg_connection::connection_param` pointer is a placeholder to keep
|
||||||
|
user-specific data. For example, handler could decide to open a DB
|
||||||
|
connection and store DB connection handle in `connection_param`.
|
||||||
|
* `MG_POLL` is sent to every connection on every iteration of
|
||||||
|
`mg_poll_server()`. Event handler should return `MG_FALSE` to ignore
|
||||||
|
this event. If event handler returns `MG_TRUE`, then Mongoose assumes
|
||||||
|
that event handler has finished sending data, and Mongoose will
|
||||||
|
close the connection.
|
||||||
|
* `MG_HTTP_ERROR` sent when Mongoose is about to send HTTP error back
|
||||||
|
to the client. Event handler can choose to send a reply itself, in which
|
||||||
|
case event handler must return `MG_TRUE`. Otherwise, event handler must
|
||||||
|
return `MG_FALSE`.
|
||||||
|
* `MG_CLOSE` is sent when the connection is closed. This event is used
|
||||||
|
to cleanup per-connection state stored in `connection_param`
|
||||||
|
if it was allocated. Event handler return value is ignored.
|
||||||
|
|
||||||
Sets a request handler. When set, `handler` will be called for each request.
|
Sequence of events for the client connection is this:
|
||||||
Possible return values from a handler function are `MG_REQUEST_NOT_PROCESSED`,
|
|
||||||
`MG_REQUEST_PROCESSED` and `MG_REQUEST_CALL_AGAIN`. If handler returns
|
|
||||||
`MG_REQUEST_NOT_PROCESSED`, mongoose will proceed with handling the request.
|
|
||||||
If handler returns `MG_REQUEST_PROCESSED`, that signals mongoose that handler
|
|
||||||
has already processed the connection, and mongoose will skip to the next
|
|
||||||
request. `MG_REQUEST_CALL_AGAIN` tells mongoose to call request handler
|
|
||||||
again and again on each `mg_poll_server()` iteration.
|
|
||||||
|
|
||||||
When mongoose buffers in HTTP request and successfully parses it, it calls
|
* `MG_CONNECT` sent when Mongoose has connected to the remote host.
|
||||||
appropriate URI handler immediately for GET requests. For POST requests,
|
This event is sent to the connection initiated by `mg_connect()` call.
|
||||||
|
Connection status is held in `mg_connection::status_code`: if zero,
|
||||||
|
then connection was successful, otherwise connection was not established.
|
||||||
|
User should send a request upon successful connection.
|
||||||
|
Event handler should return `MG_TRUE` if connection was successful and
|
||||||
|
HTTP request has been sent. Otherwise, it should send `MG_FALSE`.
|
||||||
|
* `MG_REPLY` is sent when response has been received from the remote host.
|
||||||
|
If event handler sends another request, then it should return `MG_TRUE`.
|
||||||
|
Otherwise it should return `MG_FALSE` and Mongoose will close the connection.
|
||||||
|
* `MG_CLOSE` same as for the accepted connection.
|
||||||
|
|
||||||
|
|
||||||
|
When mongoose buffers in HTTP request and successfully parses it, it sends
|
||||||
|
`MG_REQUEST` event for GET requests immediately. For POST requests,
|
||||||
Mongoose delays the call until the whole POST request is buffered in memory.
|
Mongoose delays the call until the whole POST request is buffered in memory.
|
||||||
POST data is available to the callback as `struct mg_connection::content`,
|
POST data is available to the callback as `struct mg_connection::content`,
|
||||||
and POST data length is in `struct mg_connection::content_len`.
|
and POST data length is in `struct mg_connection::content_len`.
|
||||||
|
|
||||||
Note that websocket connections are treated the same way. Mongoose buffers
|
Note that websocket connections are treated the same way. Mongoose buffers
|
||||||
websocket frame in memory, and calls URI handler when frame is fully
|
websocket frame in memory, and calls event handler when frame is fully
|
||||||
buffered. Frame data is available `struct mg_connection::content`, and
|
buffered. Frame data is available `struct mg_connection::content`, and
|
||||||
data length is in `struct mg_connection::content_len`, i.e. very similar to
|
data length is in `struct mg_connection::content_len`, i.e. very similar to
|
||||||
the POST request. `struct mg_connection::is_websocket` flag indicates
|
the POST request. `struct mg_connection::is_websocket` flag indicates
|
||||||
@@ -96,18 +119,10 @@ whether the request is websocket or not. Also, for websocket requests,
|
|||||||
there is `struct mg_connection::wsbits` field which contains first byte
|
there is `struct mg_connection::wsbits` field which contains first byte
|
||||||
of the websocket frame which URI handler can examine. Note that to
|
of the websocket frame which URI handler can examine. Note that to
|
||||||
reply to the websocket client, `mg_websocket_write()` should be used.
|
reply to the websocket client, `mg_websocket_write()` should be used.
|
||||||
To reply to the plain HTTP client, `mg_write_data()` should be used. Note that
|
To reply to the plain HTTP client, `mg_write_data()` should be used.
|
||||||
websocket handler must return either `MG_CLIENT_CLOSE` or `MG_CLIENT_CONTINUE`
|
|
||||||
value.
|
|
||||||
|
|
||||||
void mg_set_http_error_handler(struct mg_server *, mg_handler_t);
|
Return value: number of active connections.
|
||||||
|
|
||||||
Adds HTTP error handler. An actual HTTP error is passed as
|
|
||||||
`struct mg_connection::status_code` parameter.
|
|
||||||
Hanlder should return either `MG_ERROR_PROCESSED` or `MG_ERROR_NOT_PROCESSED`.
|
|
||||||
If handler returns `MG_ERROR_NOT_PROCESSED`, it
|
|
||||||
means a handler has not processed the connection, and mongoose proceeds
|
|
||||||
with sending HTTP error to the client. Otherwise, mongoose does nothing.
|
|
||||||
|
|
||||||
const char **mg_get_valid_option_names(void);
|
const char **mg_get_valid_option_names(void);
|
||||||
|
|
||||||
@@ -123,17 +138,14 @@ given parameter name is not valid, NULL is returned. For valid names, return
|
|||||||
value is guaranteed to be non-NULL. If parameter is not set, zero-length string
|
value is guaranteed to be non-NULL. If parameter is not set, zero-length string
|
||||||
is returned.
|
is returned.
|
||||||
|
|
||||||
|
void mg_wakeup_server_ex(struct mg_server *, mg_handler_t func,
|
||||||
|
const char *fmt, ...);
|
||||||
|
|
||||||
int mg_iterate_over_connections(struct mg_server *,
|
Sends string message to a server. Function `func` is called for every active
|
||||||
void (*func)(struct mg_connection *, void *),
|
connection. String message is passed in `struct mg_connection::callback_param`.
|
||||||
void *param);
|
This function is designed to push data to the connected clients, and
|
||||||
|
can be called from any thread. There is a limitation on the length of
|
||||||
This is an interface primarily designed to push arbitrary data to websocket
|
the message, currently at 8 kilobytes.
|
||||||
connections at any time. This function could be called from any thread. When
|
|
||||||
it returns, an IO thread called `func()` on each active connection,
|
|
||||||
passing `param` as an extra parameter. It is allowed to call `mg_send_data()` or
|
|
||||||
`mg_websocket_write()` within a callback, cause `func` is executed in the
|
|
||||||
context of the IO thread.
|
|
||||||
|
|
||||||
void mg_send_status(struct mg_connection *, int status_code);
|
void mg_send_status(struct mg_connection *, int status_code);
|
||||||
void mg_send_header(struct mg_connection *, const char *name,
|
void mg_send_header(struct mg_connection *, const char *name,
|
||||||
@@ -162,11 +174,23 @@ a response body. Mongoose provides functions for all three parts:
|
|||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
int mg_websocket_write(struct mg_connection* conn, int opcode,
|
void mg_send_file(struct mg_connection *, const char *path);
|
||||||
const char *data, size_t data_len);
|
|
||||||
|
|
||||||
Similar to `mg_write()`, but wraps the data into a websocket frame with a
|
Tells Mongoose to serve given file. Mongoose handles file according to
|
||||||
given websocket `opcode`.
|
it's extensions, i.e. Mongoose will invoke CGI script if `path` has CGI
|
||||||
|
extension, it'll render SSI file if `path` has SSI extension, etc. If `path`
|
||||||
|
points to a directory, Mongoose will show directory listing. If this function
|
||||||
|
is used, no calls to `mg_send*` or `mg_printf*` functions must be made, and
|
||||||
|
event handler must return `MG_MORE`.
|
||||||
|
|
||||||
|
size_t mg_websocket_write(struct mg_connection* conn, int opcode,
|
||||||
|
const char *data, size_t data_len);
|
||||||
|
size_t mg_websocket_printf(struct mg_connection* conn, int opcode,
|
||||||
|
const char *fmt, ...);
|
||||||
|
|
||||||
|
|
||||||
|
Similar to `mg_write()` and `mg_printf()`, but wraps the data into a
|
||||||
|
websocket frame with a given websocket `opcode`.
|
||||||
|
|
||||||
const char *mg_get_header(const struct mg_connection *, const char *name);
|
const char *mg_get_header(const struct mg_connection *, const char *name);
|
||||||
|
|
||||||
@@ -198,11 +222,28 @@ the length of the fetched value, or 0 if variable not found.
|
|||||||
const char *user,
|
const char *user,
|
||||||
const char *password);
|
const char *password);
|
||||||
|
|
||||||
Add, edit or delete the entry in the passwords file.
|
Add, edit or delete the entry in the passwords file.
|
||||||
This function allows an application to manipulate .htpasswd files on the
|
This function allows an application to manipulate .htpasswd files on the
|
||||||
fly by adding, deleting and changing user records. This is one of the
|
fly by adding, deleting and changing user records. This is one of the
|
||||||
several ways of implementing authentication on the server side. For another,
|
several ways of implementing authentication on the server side.
|
||||||
cookie-based way please refer to the examples/chat.c in the source tree.
|
|
||||||
If password is not NULL, entry is added (or modified if already exists).
|
If password is not NULL, entry is added (or modified if already exists).
|
||||||
If password is NULL, entry is deleted.
|
If password is NULL, entry is deleted.
|
||||||
Return: 1 on success, 0 on error.
|
Return: 1 on success, 0 on error.
|
||||||
|
|
||||||
|
|
||||||
|
int mg_parse_multipart(const char *buf, int buf_len,
|
||||||
|
char *var_name, int var_name_len,
|
||||||
|
char *file_name, int file_name_len,
|
||||||
|
const char **data, int *data_len);
|
||||||
|
|
||||||
|
Parses a buffer that contains multipart form data. Stores chunk name
|
||||||
|
in a `var_name` buffer. If chunk is an uploaded file, then `file_name`
|
||||||
|
will have a file name. `data` and `data_len` will point to the chunk data.
|
||||||
|
Returns number of bytes to skip to the next chunk.
|
||||||
|
|
||||||
|
struct mg_connection *mg_connect(struct mg_server *server,
|
||||||
|
const char *host, int port, int use_ssl);
|
||||||
|
|
||||||
|
Create connection to the remote host. Returns `NULL` on error, non-null
|
||||||
|
if the connection has been scheduled for connection. Upon a connection,
|
||||||
|
Mongoose will send `MG_CONNECT` event to the event handler.
|
||||||
@@ -7,7 +7,7 @@ Note : You dont need root access to run mongoose on Android.
|
|||||||
|
|
||||||
- Clone Mongoose Git repo
|
- Clone Mongoose Git repo
|
||||||
- Download the Android NDK from [http://developer.android.com/tools/sdk/ndk/index.html](http://developer.android.com/tools/sdk/ndk/index.html)
|
- Download the Android NDK from [http://developer.android.com/tools/sdk/ndk/index.html](http://developer.android.com/tools/sdk/ndk/index.html)
|
||||||
- Run `/path-to-ndk/ndk-build -C /path-to-mongoose/build`
|
- Run `/path-to-ndk/ndk-build -C /path/to/mongoose`
|
||||||
That should generate mongoose/lib/armeabi/mongoose
|
That should generate mongoose/lib/armeabi/mongoose
|
||||||
- Using the adb tool (you need to have Android SDK installed for that),
|
- Using the adb tool (you need to have Android SDK installed for that),
|
||||||
push the generated mongoose binary to `/data/local` folder on device.
|
push the generated mongoose binary to `/data/local` folder on device.
|
||||||
@@ -15,7 +15,7 @@ Note : You dont need root access to run mongoose on Android.
|
|||||||
- To test if the server is running fine, visit your web-browser and
|
- To test if the server is running fine, visit your web-browser and
|
||||||
navigate to `http://127.0.0.1:8080` You should see the `Index of /` page.
|
navigate to `http://127.0.0.1:8080` You should see the `Index of /` page.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
How To Create Basic Website With Mongoose
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
## 1. Create a directory which will contain your website files. For example, on drive `C:\`, create a directory called `my_website`:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 2. Inside `my_website` directory, create a new file called "index". This will be the default web page shown when the website is visited.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 3. Open index file with your favorite editor (for example, Notepad) and enter some HTML code:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 4. Save this file as `index.html`:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
## 5. Download Mongoose executable from http://cesanta.com/mongoose.shtml and copy the executable inside `my_website` directory:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 6. Double-click mongoose executable. An icon will appear on a system tray in the bottom right corner of the desktop:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 7. Click on the mongoose icon and choose "Go to my address" menu:
|
||||||
|

|
||||||
|
|
||||||
|
## 8. A browser will popup displaying `index.html` file. Now, you can expand your website by adding more content.
|
||||||
|
|
||||||
|

|
||||||
+103
-38
@@ -13,34 +13,81 @@ Embedding Mongoose is done in two steps:
|
|||||||
Here's a minimal application `app.c` that embeds mongoose:
|
Here's a minimal application `app.c` that embeds mongoose:
|
||||||
|
|
||||||
#include "mongoose.h"
|
#include "mongoose.h"
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
struct mg_server *server = mg_create_server(NULL);
|
struct mg_server *server = mg_create_server(NULL, NULL);
|
||||||
mg_set_option(server, "document_root", ".");
|
mg_set_option(server, "document_root", "."); // Serve current directory
|
||||||
mg_set_option(server, "listening_port", "8080");
|
mg_set_option(server, "listening_port", "8080"); // Open port 8080
|
||||||
for (;;) mg_poll_server(server, 1000); // Infinite loop, Ctrl-C to stop
|
|
||||||
|
for (;;) {
|
||||||
|
mg_poll_server(server, 1000); // Infinite loop, Ctrl-C to stop
|
||||||
|
}
|
||||||
mg_destroy_server(&server);
|
mg_destroy_server(&server);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
To compile it, put `mongoose.c`, `mongoose.h` and `minimal.c` into one
|
To compile it, put `mongoose.c`, `mongoose.h` and `app.c` into one
|
||||||
folder, start terminal on UNIX or Visual Studio command line prompt on Windows,
|
folder, start terminal on UNIX or Visual Studio command line prompt on Windows,
|
||||||
and run the following command:
|
and run the following command:
|
||||||
|
|
||||||
cc app.c mongoose.c -o app # on Unix
|
cc app.c mongoose.c -pthread -o app # on Unix
|
||||||
cl app.c mongoose.c /TC /MD # on Windows
|
cl.exe app.c mongoose.c /TC /MD # on Windows
|
||||||
|
|
||||||
When run, this simple application opens port 8080 and serves static files,
|
When run, this simple application opens port 8080 and serves static files,
|
||||||
CGI files and lists directory content in the current working directory.
|
CGI files and lists directory content in the current working directory.
|
||||||
|
|
||||||
Mongoose can call user-defined functions when certain URIs are requested.
|
It is possible to generate HTML page content. Mongoose can call user-defined
|
||||||
These functions are _called uri handlers_. `mg_add_uri_handler()` registers
|
function when certain events occur.
|
||||||
an URI handler, and there is no restriction exist on the number of URI handlers.
|
That function is called _an event handler_, and it is the second parameter
|
||||||
Also, mongoose can call a user-defined function when it is about to send
|
to `mg_create_server()` function. Here is the example event handler function:
|
||||||
HTTP error back to client. That function is called _http error handler_ and
|
|
||||||
can be registered by `mg_set_http_error_handler()`. Handlers are called
|
int event_handler(struct mg_connection *conn, enum mg_event ev) {
|
||||||
by Mongoose with `struct mg_connection *` pointer as a parameter, which
|
switch (ev) {
|
||||||
|
case MG_AUTH: return MG_TRUE;
|
||||||
|
default: return MG_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Event handler is called by Mongoose with `struct mg_connection *`
|
||||||
|
pointer and an event number. `struct mg_connection *conn`
|
||||||
has all information about the request: HTTP headers, POST or websocket
|
has all information about the request: HTTP headers, POST or websocket
|
||||||
data buffer, etcetera.
|
data buffer, etcetera. `enum mg_event ev` tells which exactly event is sent.
|
||||||
|
For each event, an event handler returns a value which tells Mongoose how
|
||||||
|
to behave.
|
||||||
|
|
||||||
|
The sequence of events for every connection is this:
|
||||||
|
|
||||||
|
* `MG_AUTH` - Mongoose asks whether this connection is authorized. If event
|
||||||
|
handler returns `MG_FALSE`, then Mongoose does not serve the request but
|
||||||
|
sends authorization request to the client. If `MG_TRUE` is returned,
|
||||||
|
then Mongoose continues on with the request.
|
||||||
|
* `MG_REQUEST` - Mongoose asks event handler to serve the request. If
|
||||||
|
event handler serves the request by sending a reply,
|
||||||
|
it should return `MG_TRUE`. Otherwise,
|
||||||
|
it should return `MG_FALSE` which tells Mongoose that request is not
|
||||||
|
served and Mongoose should serve it. For example, event handler might
|
||||||
|
choose to serve only RESTful API requests with URIs that start with
|
||||||
|
certain prefix, and let Mongoose serve all static files.
|
||||||
|
If event handler decides to serve the request, but doesn't have
|
||||||
|
all the data at the moment, it should return `MG_MORE`. That tells
|
||||||
|
Mongoose to keep the connection open after callback returns.
|
||||||
|
|
||||||
|
`mg_connection::connection_param` pointer is a placeholder to keep
|
||||||
|
user-specific data. For example, handler could decide to open a DB
|
||||||
|
connection and store DB connection handle in `connection_param`.
|
||||||
|
* `MG_POLL` is sent to every connection on every iteration of
|
||||||
|
`mg_poll_server()`. Event handler should return `MG_FALSE` to ignore
|
||||||
|
this event. If event handler returns `MG_TRUE`, then Mongoose assumes
|
||||||
|
that event handler has finished sending data, and Mongoose will
|
||||||
|
close the connection.
|
||||||
|
* `MG_HTTP_ERROR` sent when Mongoose is about to send HTTP error back
|
||||||
|
to the client. Event handler can choose to send a reply itself, in which
|
||||||
|
case event handler must return `MG_TRUE`. Otherwise, event handler must
|
||||||
|
return `MG_FALSE`
|
||||||
|
* `MG_CLOSE` is sent when the connection is closed. This event is used
|
||||||
|
to cleanup per-connection state stored in `connection_param`
|
||||||
|
if it was allocated.
|
||||||
|
|
||||||
Let's extend our minimal application example and
|
Let's extend our minimal application example and
|
||||||
create an URI that will be served by user's C code. The app will handle
|
create an URI that will be served by user's C code. The app will handle
|
||||||
@@ -50,22 +97,38 @@ http://127.0.0.1:8080/hello will say hello, and here's the code:
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "mongoose.h"
|
#include "mongoose.h"
|
||||||
|
|
||||||
static int handle_hello(struct mg_connection *conn) {
|
static int event_handler(struct mg_connection *conn, enum mg_event ev) {
|
||||||
static const char *reply = "Hello world!\n";
|
if (ev == MG_AUTH) {
|
||||||
mg_write_data(conn, reply, strlen(reply));
|
return MG_TRUE; // Authorize all requests
|
||||||
return 1;
|
} else if (ev == MG_REQUEST && !strcmp(conn->uri, "/hello")) {
|
||||||
|
mg_printf_data(conn, "%s", "Hello world");
|
||||||
|
return MG_TRUE; // Mark as processed
|
||||||
|
} else {
|
||||||
|
return MG_FALSE; // Rest of the events are not processed
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
struct mg_server *server = mg_create_server(NULL);
|
struct mg_server *server = mg_create_server(NULL, event_handler);
|
||||||
mg_set_option(server, "document_root", ".");
|
mg_set_option(server, "document_root", ".");
|
||||||
mg_set_option(server, "listening_port", "8080");
|
mg_set_option(server, "listening_port", "8080");
|
||||||
mg_add_uri_handler(server, "/hello", &handle_hello);
|
|
||||||
for (;;) mg_poll_server(server, 1000); // Infinite loop, Ctrl-C to stop
|
for (;;) {
|
||||||
|
mg_poll_server(server, 1000); // Infinite loop, Ctrl-C to stop
|
||||||
|
}
|
||||||
mg_destroy_server(&server);
|
mg_destroy_server(&server);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
## Example code
|
||||||
|
|
||||||
|
Mongoose source code contains number of examples, located in the
|
||||||
|
[examples](https://github.com/cesanta/mongoose/blob/master/examples/) directory.
|
||||||
|
To build any example, go to the respective directory and run `make`.
|
||||||
|
|
||||||
|
## Compilation flags
|
||||||
|
|
||||||
Below is the list of compilation flags that enable or disable certain
|
Below is the list of compilation flags that enable or disable certain
|
||||||
features. By default, some features are enabled, and could be disabled
|
features. By default, some features are enabled, and could be disabled
|
||||||
by setting appropriate `NO_*` flag. Features that are disabled by default
|
by setting appropriate `NO_*` flag. Features that are disabled by default
|
||||||
@@ -73,6 +136,12 @@ could be enabled by setting appropriate `USE_*` flag. Bare bones Mongoose
|
|||||||
is quite small, about 30 kilobytes of compiled x86 code. Each feature adds
|
is quite small, about 30 kilobytes of compiled x86 code. Each feature adds
|
||||||
a couple of kilobytes to the executable size, and also has some runtime penalty.
|
a couple of kilobytes to the executable size, and also has some runtime penalty.
|
||||||
|
|
||||||
|
Note that some flags start with `NS_` prefix. This is because Mongoose uses
|
||||||
|
[Net Skeleton](http://github.com/cesanta/net_skeleton) as a low-level
|
||||||
|
networking engine. If user code has `#include <net_skeleton.h>`, then
|
||||||
|
all Net Skeleton functions will be available too.
|
||||||
|
|
||||||
|
|
||||||
-DMONGOOSE_NO_AUTH Disable MD5 authorization support
|
-DMONGOOSE_NO_AUTH Disable MD5 authorization support
|
||||||
-DMONGOOSE_NO_CGI Disable CGI support
|
-DMONGOOSE_NO_CGI Disable CGI support
|
||||||
-DMONGOOSE_NO_DAV Disable WebDAV support
|
-DMONGOOSE_NO_DAV Disable WebDAV support
|
||||||
@@ -80,29 +149,25 @@ a couple of kilobytes to the executable size, and also has some runtime penalty.
|
|||||||
-DMONGOOSE_NO_DIRECTORY_LISTING Disable directory listing
|
-DMONGOOSE_NO_DIRECTORY_LISTING Disable directory listing
|
||||||
-DMONGOOSE_NO_FILESYSTEM Disables all file IO, serving from memory only
|
-DMONGOOSE_NO_FILESYSTEM Disables all file IO, serving from memory only
|
||||||
-DMONGOOSE_NO_LOGGING Disable access/error logging
|
-DMONGOOSE_NO_LOGGING Disable access/error logging
|
||||||
-DMONGOOSE_NO_THREADS
|
-DMONGOOSE_ENABLE_THREADS Enable mg_start_thread() function
|
||||||
-DMONGOOSE_NO_WEBSOCKET Disable WebSocket support
|
-DMONGOOSE_NO_WEBSOCKET Disable WebSocket support
|
||||||
|
-DMONGOOSE_NO_USER No concept of a user on used platform.
|
||||||
|
(Platform does not provide getpwnam, setgid or setuid)
|
||||||
|
|
||||||
-DMONGOOSE_USE_IDLE_TIMEOUT_SECONDS=X Idle connection timeout, default is 30
|
-DMONGOOSE_USE_IDLE_TIMEOUT_SECONDS=X Idle connection timeout, default is 30
|
||||||
-DMONGOOSE_USE_IPV6 Enable IPv6 support
|
|
||||||
-DMONGOOSE_USE_LUA Enable Lua scripting
|
-DMONGOOSE_USE_LUA Enable Lua scripting
|
||||||
-DMONGOOSE_USE_LUA_SQLITE3 Enable sqlite3 binding for Lua
|
-DMONGOOSE_USE_LUA_SQLITE3 Enable sqlite3 binding for Lua
|
||||||
-DMONGOOSE_USE_SSL Enable SSL
|
|
||||||
-DMONGOOSE_USE_POST_SIZE_LIMIT=X POST requests larger than X will be
|
-DMONGOOSE_USE_POST_SIZE_LIMIT=X POST requests larger than X will be
|
||||||
rejected, not set by default
|
rejected, not set by default
|
||||||
-DMONGOOSE_USE_EXTRA_HTTP_HEADERS=X Append X to the HTTP headers
|
-DMONGOOSE_USE_EXTRA_HTTP_HEADERS=X Append X to the HTTP headers
|
||||||
for static files, empty by default
|
for static files, empty by default
|
||||||
-DMONGOOSE_USE_STACK_SIZE=X Let mg_start_thread() use stack
|
|
||||||
size X, default is OS default
|
|
||||||
-DMONGOOSE_ENABLE_DEBUG Enables debug messages on stdout, very noisy
|
|
||||||
|
|
||||||
Mongoose source code contains a well-commented example code, listed below:
|
-DNS_ENABLE_DEBUG Enables debug messages on stdout, very noisy
|
||||||
|
-DNS_ENABLE_SSL Enable SSL
|
||||||
* [hello.c](https://github.com/cesanta/mongoose/blob/master/examples/hello.c)
|
-DNS_ENABLE_IPV6 Enable IPv6 support
|
||||||
a minimalistic hello world example
|
-DNS_ENABLE_HEXDUMP Enables hexdump of sent and received traffic
|
||||||
* [post.c](https://github.com/cesanta/mongoose/blob/master/examples/post.c)
|
-DNS_STACK_SIZE=X Sets stack size to X for ns_start_thread()
|
||||||
shows how to handle form input
|
-DNS_DISABLE_THREADS Disable threads support
|
||||||
* [upload.c](https://github.com/cesanta/mongoose/blob/master/examples/post.c)
|
-DNS_DISABLE_SOCKETPAIR For systems without loopback interface
|
||||||
shows how to upload files
|
-DMONGOOSE_SEND_NS_EVENTS Send Net Skeleton events to the event handler
|
||||||
* [websocket.c](https://github.com/cesanta/mongoose/blob/master/examples/websocket.c) demonstrates websocket usage
|
in addition to the Mongoose events
|
||||||
* [auth.c](https://github.com/cesanta/mongoose/blob/master/examples/websocket.c) demonstrates API-controlled Digest authorization
|
|
||||||
+24
-2
@@ -1,6 +1,28 @@
|
|||||||
# Mongoose FAQ
|
# Mongoose FAQ
|
||||||
|
|
||||||
### PHP doesn't work: getting empty page, or 'File not found' error
|
## My Antivirus Software reports Mongoose as a security threat
|
||||||
|
|
||||||
|
Mongoose doesn't contain any malicious logic. Antivirus reports a
|
||||||
|
[false positive](http://en.wikipedia.org/wiki/Type_I_and_type_II_errors#False_positive_error).
|
||||||
|
This is when certain byte sequence in Mongoose accidentally matches
|
||||||
|
virus signature in the Antivirus database.
|
||||||
|
|
||||||
|
## Download page doesn't work
|
||||||
|
|
||||||
|
Please make sure Javascript is enabled in your browser, and that the
|
||||||
|
antivirus software is not blocking the download.
|
||||||
|
|
||||||
|
|
||||||
|
## MacOS message: "Mongoose.app is damaged and can’t be opened. You should move it to the Trash"
|
||||||
|
|
||||||
|
This happens on newer MacOS systems. The reason for the message
|
||||||
|
is the fact Mongoose.app is not digitally signed.
|
||||||
|
Mongoose download procedure changes the app on the fly by injecting
|
||||||
|
user information in the binary, making any prior digital signature void.
|
||||||
|
Open "System Preferences" -> "Security" and set "Allow apps downloaded from"
|
||||||
|
to "Anywhere". Revert the settings once Mongoose is installed.
|
||||||
|
|
||||||
|
## PHP doesn't work: getting empty page, or 'File not found' error
|
||||||
|
|
||||||
The reason for that is wrong paths to the interpreter. Remember that with PHP,
|
The reason for that is wrong paths to the interpreter. Remember that with PHP,
|
||||||
correct interpreter is `php-cgi.exe` (`php-cgi` on UNIX). Solution: specify
|
correct interpreter is `php-cgi.exe` (`php-cgi` on UNIX). Solution: specify
|
||||||
@@ -8,7 +30,7 @@ full path to the PHP interpreter, e.g.:
|
|||||||
|
|
||||||
mongoose -cgi_interpreter /full/path/to/php-cgi
|
mongoose -cgi_interpreter /full/path/to/php-cgi
|
||||||
|
|
||||||
### Mongoose fails to start
|
## Mongoose fails to start
|
||||||
|
|
||||||
If Mongoose exits immediately when run, this
|
If Mongoose exits immediately when run, this
|
||||||
usually indicates a syntax error in the configuration file
|
usually indicates a syntax error in the configuration file
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
How To Share Files With Mongoose
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
## 1. Download Mongoose executable from http://cesanta.com/mongoose.shtml and copy the executable inside the directory you want to share:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 2. Double-click mongoose executable. A browser will start automatically, an icon will appear on a system tray in the bottom right corner of the desktop:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 3. Click on the mongoose icon
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
## 4. Click on "Go to my address" to launch a browser locally. Or, to access a folder from another machine, launch a browser and type in the URL:
|
||||||
|
|
||||||
|

|
||||||
@@ -1,59 +0,0 @@
|
|||||||
# Mongoose Lua Server Pages
|
|
||||||
|
|
||||||
Pre-built Windows and Mac mongoose binaries support Lua Server Pages
|
|
||||||
functionality.
|
|
||||||
That means it is possible to write PHP-like scripts with mongoose
|
|
||||||
using Lua programming language instead of PHP. Lua is known
|
|
||||||
for it's speed and small size. Mongoose uses Lua version 5.2.1, the
|
|
||||||
documentation for it can be found at
|
|
||||||
[Lua 5.2 reference manual](http://www.lua.org/manual/5.2/).
|
|
||||||
|
|
||||||
To create a Lua Page, make a file that is called `<something>.lp`. For example,
|
|
||||||
let's say it is going to be `my_page.lp`. It is important to have a file
|
|
||||||
name that ends up with `.lp`, cause this is the way mongoose recognises
|
|
||||||
Lua Page file. The contents of the file, just like
|
|
||||||
with PHP, is HTML with embedded Lua code. Lua code must be enclosed within
|
|
||||||
`<? ?>` blocks, and can appear anywhere on the page.
|
|
||||||
|
|
||||||
Mongoose does not send HTTP headers for Lua pages. Therefore,
|
|
||||||
every Lua Page must begin with HTTP status line and headers, like this:
|
|
||||||
|
|
||||||
<? mg.write('HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n') ?>
|
|
||||||
<html><body>
|
|
||||||
<span>Today is:</span> <? mg.write(os.date("%A")) ?>
|
|
||||||
</body></html>
|
|
||||||
|
|
||||||
Note that this example uses function `mg.write()`, which prints data to the
|
|
||||||
web page. Using function `mg.write()` is the way to generate web content from
|
|
||||||
inside Lua code. In addition to `mg.write()`, all standard library functions
|
|
||||||
are accessible from the Lua code (please check reference manual for details).
|
|
||||||
Information about the request is available in `mg.request_info` object.
|
|
||||||
I contains request method, all headers, etcetera. Please refer to
|
|
||||||
`struct mg_request_info` definition in
|
|
||||||
[mongoose.h](https://github.com/cesanta/mongoose/blob/master/mongoose.h)
|
|
||||||
to see what is available in `mg.request_info`. Also,
|
|
||||||
[page.lp](https://github.com/cesanta/mongoose/blob/master/test/page.lp) and
|
|
||||||
[prime_numbers.lp](https://github.com/cesanta/mongoose/blob/master/examples/lua/prime_numbers.lp)
|
|
||||||
contain some example code that uses `request_info` and other functions,
|
|
||||||
like form submission.
|
|
||||||
|
|
||||||
Mongoose exports the following to the Lua server page:
|
|
||||||
|
|
||||||
mg.write(str) -- writes string to the client
|
|
||||||
mg.onerror(msg) -- error handler, can be overridden
|
|
||||||
mg.request_info -- a table with request information
|
|
||||||
sqlite3 -- Sqlite3 interface
|
|
||||||
|
|
||||||
slite3 functions are documented at [lua.sqlite.org](http://lua.sqlite.org/),
|
|
||||||
and usage example is at
|
|
||||||
[page.lp](https://github.com/cesanta/mongoose/blob/master/test/page.lp).
|
|
||||||
|
|
||||||
Using Lua scripting it is easy to emulate SSI functionality. For example,
|
|
||||||
to include the content of another file, one can write:
|
|
||||||
|
|
||||||
<? mg.write(io.open('MY_FILE.TXT'):read('*all')) ?>
|
|
||||||
|
|
||||||
To serve a Lua Page, mongoose creates Lua context. That context is used for
|
|
||||||
all Lua blocks within the page. That means, all Lua blocks on the same page
|
|
||||||
share the same context. If one block defines a variable, for example, that
|
|
||||||
variable is visible in the block that follows.
|
|
||||||
+44
-30
@@ -10,8 +10,12 @@ this means to deny only that single IP address.
|
|||||||
|
|
||||||
Subnet masks may vary from 0 to 32, inclusive. The default setting is to allow
|
Subnet masks may vary from 0 to 32, inclusive. The default setting is to allow
|
||||||
all accesses. On each request the full list is traversed, and
|
all accesses. On each request the full list is traversed, and
|
||||||
the last match wins. Example: `$ mongoose -access_control_list -0.0.0.0/0,+192.168/16` to deny all acccesses except from 192.168/16 subnet. To learn
|
the last match wins. Example: `$ mongoose -access_control_list -0.0.0.0/0,+192.168/16` to deny all acccesses except those from `192.168/16` subnet. Note that if the option is set, then all accesses are forbidden
|
||||||
more about subnet masks, see the
|
by default. Thus in a previous example, `-0.0.0.0` part is not necessary.
|
||||||
|
For example, `$mongoose access_control_list +10.0.0.0/8`
|
||||||
|
means disallow all, allow subnet 10/8 only.
|
||||||
|
|
||||||
|
To learn more about subnet masks, see the
|
||||||
[Wikipedia page on Subnetwork](http://en.wikipedia.org/wiki/Subnetwork)
|
[Wikipedia page on Subnetwork](http://en.wikipedia.org/wiki/Subnetwork)
|
||||||
|
|
||||||
Default: not set, all accesses are allowed.
|
Default: not set, all accesses are allowed.
|
||||||
@@ -24,27 +28,32 @@ mongoose executable. Default: not set, no query logging is done.
|
|||||||
Authorization realm used in `.htpasswd` authorization. Default: `mydomain.com`
|
Authorization realm used in `.htpasswd` authorization. Default: `mydomain.com`
|
||||||
|
|
||||||
### cgi_interpreter
|
### cgi_interpreter
|
||||||
Path to an executable to use as CGI interpreter for __all__ CGI scripts
|
Path to an executable to be used use as an interpreter for __all__ CGI scripts
|
||||||
regardless script extension.
|
regardless script extension. Default: not set, Mongoose looks at
|
||||||
for an interpreter. Default: not set, Mongoose looks at
|
|
||||||
[shebang line](http://en.wikipedia.org/wiki/Shebang_(Unix\).
|
[shebang line](http://en.wikipedia.org/wiki/Shebang_(Unix\).
|
||||||
|
|
||||||
For example, if both PHP and perl CGIs are used, then
|
For example, if both PHP and perl CGIs are used, then
|
||||||
`#!/path/to/php-cgi.exe` and `#!/path/to/perl.exe` must be first lines of the
|
`#!/path/to/php-cgi.exe` and `#!/path/to/perl.exe` must be first lines of the
|
||||||
respective CGI scripts. Note that paths should be either full file paths,
|
respective CGI scripts. Note that paths should be either full file paths,
|
||||||
or file paths relative to the directory where mongoose server is located.
|
or file paths relative to the directory where mongoose executable is located.
|
||||||
|
|
||||||
If all CGIs use the same interpreter, for example they are all PHP, then
|
If all CGIs use the same interpreter, for example they are all PHP, then
|
||||||
`cgi_interpreter` option can be set to the path to `php-cgi.exe` executable and
|
`cgi_interpreter` option can be set to the path to `php-cgi.exe` executable and
|
||||||
shebang line in the CGI scripts can be omitted.
|
shebang line in the CGI scripts can be omitted.
|
||||||
Note that PHP scripts must use `php-cgi.exe` executable, not `php.exe`.
|
**Note**: PHP scripts must use `php-cgi.exe`, not `php.exe`.
|
||||||
|
|
||||||
### cgi_pattern
|
### cgi_pattern
|
||||||
All files that match `cgi_pattern` are treated as CGI files. Default pattern
|
All files that match `cgi_pattern` are treated as CGI files. Default pattern
|
||||||
allows CGI files be anywhere. To restrict CGIs to a certain directory,
|
allows CGI files be anywhere. To restrict CGIs to a certain directory,
|
||||||
use `/path/to/cgi-bin/**.cgi` as pattern. Note that full file path is
|
use `/path/to/cgi-bin/**.cgi` as a pattern. Note that **full file path** is
|
||||||
matched against the pattern, not the URI. Note: if `MONGOOSE_CGI` environment
|
matched against the pattern, not the URI.
|
||||||
variable is set, then Mongoose passes it to the CGI script.
|
|
||||||
|
When Mongoose starts CGI program, it creates new environment for it (in
|
||||||
|
contrast, usually child program inherits the environment from parent). Several
|
||||||
|
environment variables however are inherited from Mongoose's environment,
|
||||||
|
they are: `PATH`, `TMP`, `TEMP`, `TMPDIR`, `PERLLIB`, `MONGOOSE_CGI`. On UNIX
|
||||||
|
it is also `LD_LIBRARY_PATH`. On Windows it is also `COMSPEC`, `SYSTEMROOT`,
|
||||||
|
`SystemDrive`, `ProgramFiles`, `ProgramFiles(x86)`, `CommonProgramFiles(x86)`.
|
||||||
|
|
||||||
Default: `**.cgi$|**.pl$|**.php$`
|
Default: `**.cgi$|**.pl$|**.php$`
|
||||||
|
|
||||||
@@ -60,9 +69,10 @@ A directory to serve. Default: current working directory.
|
|||||||
### enable\_directory\_listing
|
### enable\_directory\_listing
|
||||||
Enable directory listing, either `yes` or `no`. Default: `yes`.
|
Enable directory listing, either `yes` or `no`. Default: `yes`.
|
||||||
|
|
||||||
### error\_log\_file
|
### enable\_proxy
|
||||||
Path to a file for error logs. Either full path, or relative to the
|
Enable proxy functionality, either `yes` or `no`. If set to `yes`, then
|
||||||
mongoose executable. Default: not set, no errors are logged.
|
browsers can be configured to use Mongoose as a proxy. Default: `no`.
|
||||||
|
|
||||||
|
|
||||||
### extra\_mime\_types
|
### extra\_mime\_types
|
||||||
Extra mime types to recognize, in form `extension1=type1,extension2=type2,...`.
|
Extra mime types to recognize, in form `extension1=type1,extension2=type2,...`.
|
||||||
@@ -85,29 +95,27 @@ must be for a file name only, not including directory name, e.g.
|
|||||||
`mongoose -hide_files_patterns secret.txt|even_more_secret.txt`. Default:
|
`mongoose -hide_files_patterns secret.txt|even_more_secret.txt`. Default:
|
||||||
not set.
|
not set.
|
||||||
|
|
||||||
### idle\_timeout\_ms
|
|
||||||
Timeout for idle connections. Default: 30000 (30 seconds)
|
|
||||||
|
|
||||||
### index_files
|
### index_files
|
||||||
Comma-separated list of files to be treated as directory index
|
Comma-separated list of files to be treated as directory index
|
||||||
files. Default: `index.html,index.htm,index.cgi,index.shtml,index.php`
|
files. Default: `index.html,index.htm,index.cgi,index.shtml,index.php`
|
||||||
|
|
||||||
### ssl_certificate
|
|
||||||
Path to SSL certificate file. The file must be in PEM format,
|
|
||||||
and it must have both private key and certificate, see for example
|
|
||||||
[ssl_cert.pem](https://github.com/cesanta/mongoose/blob/master/build/ssl_cert.pem). If this option is set, then Mongoose serves SSL connections on
|
|
||||||
`listening_port`. Default: not set.
|
|
||||||
|
|
||||||
### listening_port
|
### listening_port
|
||||||
Port to listen on. Port could be prepended by the specific IP address to bind
|
Port to listen on. Port could be prepended by the specific IP address to bind
|
||||||
to, e.g. `mongoose -listening_port 127.0.0.1:8080`. Otherwise Mongoose
|
to, e.g. `mongoose -listening_port 127.0.0.1:8080`. Otherwise Mongoose
|
||||||
will bind to all addresses. Default: 8080.
|
will bind to all addresses. To enable SSL, build Mongoose with
|
||||||
|
`-DNS_ENABLE_SSL` compilation option, and specify `listening_port` as
|
||||||
|
`ssl://PORT:SSL_CERTIFICATE.PEM`. Example SSL listener:
|
||||||
|
`mongoose -listening_port ssl://8043:ssl_cert.pem`. Note that PEM file should
|
||||||
|
be in PEM format, and must have both certificate and private key in it,
|
||||||
|
concatenated together. More than one listening port can be specified,
|
||||||
|
separated by comma,
|
||||||
|
for example `mongoose -listening_port 8080,8000`. Default: 8080.
|
||||||
|
|
||||||
### run\_as\_user
|
### run\_as\_user
|
||||||
Switch to given user credentials after startup. UNIX-only. This option is
|
Switch to given user credentials after startup. UNIX-only. This option is
|
||||||
required when mongoose needs to bind on privileged port on UNIX, e.g.
|
required when mongoose needs to bind on privileged port on UNIX, e.g.
|
||||||
|
|
||||||
$ sudo mongoose -listening_ports 80 -run_as_user nobody
|
$ sudo mongoose -listening_port 80 -run_as_user nobody
|
||||||
|
|
||||||
Default: not set.
|
Default: not set.
|
||||||
|
|
||||||
@@ -116,17 +124,20 @@ Comma-separated list of URL rewrites in the form of
|
|||||||
`uri_pattern=file_or_directory_path`. When Mongoose receives the request,
|
`uri_pattern=file_or_directory_path`. When Mongoose receives the request,
|
||||||
it constructs the file name to show by combining `document_root` and the URI.
|
it constructs the file name to show by combining `document_root` and the URI.
|
||||||
However, if the rewrite option is used and `uri_pattern` matches the
|
However, if the rewrite option is used and `uri_pattern` matches the
|
||||||
requested URI, then `document_root` is ignored. Insted,
|
requested URI, then `document_root` is ignored. Instead,
|
||||||
`file_or_directory_path` is used, which should be a full path name or
|
`file_or_directory_path` is used, which should be a full path name or
|
||||||
a path relative to the web server's current working directory. Note that
|
a path relative to the web server's current working directory. Note that
|
||||||
`uri_pattern`, as all mongoose patterns, is a prefix pattern. If `uri_patters`
|
`uri_pattern`, as all mongoose patterns, is a prefix pattern. If `uri_pattern`
|
||||||
is a number, then it is treated as HTTP error code, and `file_or_directory_path`
|
is a number, then it is treated as HTTP error code, and `file_or_directory_path`
|
||||||
should be an URI to redirect to. Mongoose will issue `302` temporary redirect
|
should be an URI to redirect to. Mongoose will issue `302` temporary redirect
|
||||||
to the specified URI, appending two parameters:
|
to the specified URI with following parameters:
|
||||||
`?code=<http_error_code&orig_uri=<original_uri>`.
|
`?code=HTTP_ERROR_CODE&orig_uri=ORIGINAL_URI&query_string=QUERY_STRING`.
|
||||||
|
|
||||||
This makes it possible to serve many directories outside from `document_root`,
|
If `uri_pattern` starts with `@` symbol, then Mongoose compares
|
||||||
redirect all requests to scripts, and do other tricky things. Examples:
|
it with the `HOST` header of the request. If they are equal, Mongoose sets
|
||||||
|
document root to `file_or_directory_path`, implementing virtual hosts support.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
# Redirect all accesses to `.doc` files to a special script
|
# Redirect all accesses to `.doc` files to a special script
|
||||||
mongoose -url_rewrites **.doc$=/path/to/cgi-bin/handle_doc.cgi
|
mongoose -url_rewrites **.doc$=/path/to/cgi-bin/handle_doc.cgi
|
||||||
@@ -137,4 +148,7 @@ redirect all requests to scripts, and do other tricky things. Examples:
|
|||||||
# Redirect 404 errors to a specific error page
|
# Redirect 404 errors to a specific error page
|
||||||
mongoose -url_rewrites 404=/cgi-bin/error.cgi
|
mongoose -url_rewrites 404=/cgi-bin/error.cgi
|
||||||
|
|
||||||
|
# Virtual hosts example: serve foo.com domain from different directory
|
||||||
|
mongoose -url_rewrites @foo.com=/var/www/foo.com
|
||||||
|
|
||||||
Default: not set.
|
Default: not set.
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
How To Create A PHP Website With Mongoose
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
## 1. Create a directory which will contain your website files. For example, on drive `C:\`, create a directory called `my_website`:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 2. Inside `my_website` directory, create a new file called "index". This will be the default web page shown when the website is visited.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 3. Open index file with your favorite editor (for example, Notepad) and enter some HTML / PHP code:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 4. Save this file as `index.php`:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
## 5. Download Mongoose executable from http://cesanta.com/mongoose.shtml and copy the executable inside `my_website` directory:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 6. Double-click mongoose executable. An icon will appear on a system tray in the bottom right corner of the desktop:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 7. Download PHP 5.3 zip (do NOT download PHP 5.5 cause you might have missing DLLs problem) from http://windows.php.net/download and extract it to `C:\php5` directory:
|
||||||
|

|
||||||
|
|
||||||
|
## 8. Click on the mongoose icon and choose "Edit Settings" menu.:
|
||||||
|

|
||||||
|
|
||||||
|
## 9. A settings dialog will appear. Click on `cgi_interpreter` button:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 10. Choose `C:\php5\php-cgi.exe` and click "Save Settings":
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 11. Click on the mongoose icon and choose "Go to my address" menu:
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
## 12. A browser will popup displaying `index.php`.
|
||||||
|
|
||||||
|

|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
# Mongoose Release Notes
|
||||||
|
|
||||||
|
## Release 5.6, 2015-03-17
|
||||||
|
|
||||||
|
Changes in Libmongoose library:
|
||||||
|
|
||||||
|
- Added `-dav_root` configuration option that gives an ability to mount
|
||||||
|
a different root directory (not document_root)
|
||||||
|
- Fixes for build under Win23 and MinGW
|
||||||
|
- Bugfix: Double dots removal
|
||||||
|
- Bugfix: final chunked response double-send
|
||||||
|
- Fixed compilation in 64-bit environments
|
||||||
|
- Added OS/2 compatibility
|
||||||
|
- Added `getaddrinfo()` call and `NS_ENABLE_GETADDRINFO`
|
||||||
|
- Various SSL-related fixes
|
||||||
|
- Added integer overflow protection in `iobuf_append()` and `deliver_websocket_frame()`
|
||||||
|
- Fixed NetBSD build
|
||||||
|
- Enabled `NS_ENABLE_IPV6` build for Visual Studio 2008+
|
||||||
|
- Enhanced comma detection in `parse_header()`
|
||||||
|
- Fixed unchanged memory accesses on ARM
|
||||||
|
- Added ability to use custom memory allocator through NS_MALLOC, NS_FREE, NS_REALLOC
|
||||||
|
|
||||||
|
Changes in Mongoose binary:
|
||||||
|
|
||||||
|
- Added `-start_browser` option to disable automatic browser launch
|
||||||
|
- Added experimental SSL support. To listen on HTTPS port, use `ssl://PORT:SSL_CERT` format. For example, to listen on HTTP port 8080 and HTTPS port 8043, use `-listening_port 8080,ssl://8043:ssl_cert.pem`
|
||||||
|
|
||||||
|
## Release 5.5, October 28 2014
|
||||||
|
|
||||||
|
Changes in Libmongoose library:
|
||||||
|
|
||||||
|
- Added new API function: `mg_forward()` for proxying functionality
|
||||||
|
- Added new API function: `mg_send_file_data()` for sending file data
|
||||||
|
- Added new utility API functions: `mg_mmap() and mg_munmap()`
|
||||||
|
- Changed the way SSL settings are handled: removed `ssl_certificate` and
|
||||||
|
`ssl_ca_certificate` options, and instead made `listening_port` accept
|
||||||
|
`ssl://PORT:SSL_CERT:CA_CERT` notation
|
||||||
|
- Added ability to listen on multiple ports, see `listening_port` documentation
|
||||||
|
- Added `enable_proxy` option
|
||||||
|
- Added [cookie_authentication](https://github.com/cesanta/mongoose/tree/master/examples/cookie_authentication) example
|
||||||
|
- Added [websocket\_ssl\_proxy](https://github.com/cesanta/mongoose/tree/master/examples/websocket_ssl_proxy) example
|
||||||
|
- Added [http_client](https://github.com/cesanta/mongoose/tree/master/examples/http_client) example
|
||||||
|
- Increased default 'idle connection' timeout from 30 to 300 seconds
|
||||||
|
- Fixed MinGW build
|
||||||
|
- Refactored all examples, put each in it's own directory with dedicated build
|
||||||
|
- Many smaller bugfixed, including SSL, CGI, API, proxy, etc
|
||||||
|
|
||||||
|
Changes in pre-compiled binaries:
|
||||||
|
|
||||||
|
- Support for multiple listening ports
|
||||||
|
- Fixed CGI handling for scripts that specify interpreter in the hashbang line
|
||||||
|
|
||||||
|
## Release 5.4, July 28 2014
|
||||||
|
|
||||||
|
Changes in Libmongoose library:
|
||||||
|
|
||||||
|
- Added `hexdump_file` option for low-level request/reply debugging
|
||||||
|
- Added `mg_template()` API function for generating HTML pages from
|
||||||
|
templates with expansions
|
||||||
|
- Fixed `struct mg_connection::local_ip` handling, `mg_set_option()`
|
||||||
|
behavior with NULL values
|
||||||
|
- Added `mg_send_file()` call to send arbitrary file to the client
|
||||||
|
- Added `mg_terminate_ssl()` for SSL termination functionality
|
||||||
|
- Added HTTP proxy support, `enable_proxy` config option
|
||||||
|
- Added `mg_next()` for iterating over existing active connections
|
||||||
|
- Added client-side SSL auth, `ssl_ca_certificate` option
|
||||||
|
- Added `mg_wakeup_server_ex()` for pushing messages to existing connections
|
||||||
|
- Added `MG_WS_HANDSHAKE` and `MG_WS_CONNECT` events that are sent on
|
||||||
|
Websocket handshake is connection establishment, respectively
|
||||||
|
- Removed server-side Lua support
|
||||||
|
- Filesystem access, reading from socket/SSL performance improvements
|
||||||
|
- DAV PROPFIND memory leak fixed
|
||||||
|
- Added `big_upload.c` and enhanced `upload.c` example
|
||||||
|
- Added `proxy.c` example that demonstrates proxy functionality and SSE pushes
|
||||||
|
- Added `websocket2.c` example that shows simple web chat implementation
|
||||||
|
over websockets
|
||||||
|
- Various minor fixes
|
||||||
|
|
||||||
|
|
||||||
|
Changes in pre-compiled binaries:
|
||||||
|
|
||||||
|
- Created HTML administration console
|
||||||
|
- When server is started, browser is started automatically
|
||||||
|
- Fixed directory listing bug when directory contains `#` character
|
||||||
|
- Removed built-in Lua Server Pages in the binary, and instead
|
||||||
|
added Mongoose + Lua developer bundle which has Lua Server Pages support.
|
||||||
|
That also solves external Lua modules loading problem.
|
||||||
|
|
||||||
|
|
||||||
|
## Release 5.3, March 10 2014
|
||||||
|
|
||||||
|
Changes in Libmongoose library:
|
||||||
|
|
||||||
|
* Moved to the evented API. Updated API documentation is at
|
||||||
|
http://cesanta.com/docs/Embed.shtml
|
||||||
|
http://cesanta.com/docs/API.shtml
|
||||||
|
* Added `MG_LUA` event for exporting custom variables to the Lua environment
|
||||||
|
* Added virtual hosts capability, see `url_rewrites` option description at
|
||||||
|
http://cesanta.com/docs/Options.shtml
|
||||||
|
* Added mjpg serving example
|
||||||
|
* Cleaned up and documented HTTP client API, with unit tests
|
||||||
|
* Added `mg_wakeup_server()` to awaken `mg_poll_server()`
|
||||||
|
from another thread
|
||||||
|
* Moved Mongoose IO core to [https://github.com/cesanta/net_skeleton](Net Skeleton)
|
||||||
|
* Added connection hexdump functionality for developers
|
||||||
|
* Bug fixes
|
||||||
|
|
||||||
|
Changes in pre-compiled binaries:
|
||||||
|
|
||||||
|
* New awesome Mongoose logos by our designer Katrin - thanks Katrin!
|
||||||
|
Check them out at http://cesanta.com/products.shtml
|
||||||
|
* Added Lua Server Pages support to the free version, quick intro is at
|
||||||
|
http://cesanta.com/docs/Lua.shtml
|
||||||
|
* Added quick "Set shared directory" menu item to set `document_root`
|
||||||
|
* Added SSI support to the Pro version
|
||||||
|
* Removed SSL support from the Pro version
|
||||||
|
|
||||||
|
## Release 5.2, Feb 1 2014
|
||||||
|
|
||||||
|
* Windows binary made fully UNICODE aware. In previous versions,
|
||||||
|
the presence of non-ASCII chars in document root, CGI script name,
|
||||||
|
or directory name might have broken Mongoose as stand-alone
|
||||||
|
or as Windows service. Now Mongoose works with non-ASCII paths properly.
|
||||||
|
Internally, Mongoose uses UTF8 encoding. When making WinAPI calls,
|
||||||
|
mongoose converts UTF8 strings to wide chars and calls UNICODE API.
|
||||||
|
* Enhanced authorization API by providing `mg_set_auth_handler()` and
|
||||||
|
`mg_authorize_digest()`
|
||||||
|
* Removed `mg_add_uri_handler()`, added `mg_set_request_handler()`.
|
||||||
|
There is only oneURI handler that handles all requests, just like in 4.x.
|
||||||
|
The reason for this change is to provide an ability to catch all URIs,
|
||||||
|
and at the same time signal Mongoose to continue handling specific URIs.
|
||||||
|
* Added `mg_parse_multipart()` API for file uploads.
|
||||||
|
Note that the restriction on uploading huge files still exists,
|
||||||
|
and will be eliminated in the next release.
|
||||||
|
* Allowing mongoose to bind to port 0, in which case it'll bind to any
|
||||||
|
random unused port.
|
||||||
|
* Moved `idle_timeout_ms` run-time option to compile-time flag
|
||||||
|
* Added asynchronous HTTP client, not documented yet. Documentation and
|
||||||
|
examples are coming in the next couple of weeks. Async Websocket client
|
||||||
|
is scheduled for the next release. See usage examples at `unit_test.c`
|
||||||
|
* Windows and MacOS pre-built binaries are now split to free and paid ones,
|
||||||
|
paid binaries include CGI, SSL, Lua, Sqlite, support and updates.
|
||||||
|
Linux pre-built binary includes all functionality and is free, and will
|
||||||
|
continue to be free. Source code for Windows and MacOS GUI is closed.
|
||||||
|
Disclaimer: source code for the command line stand-alone server,
|
||||||
|
as well as Mongoose library itself, will never be closed.
|
||||||
|
* Multiple bug fixes and minor enhancements
|
||||||
|
|
||||||
|
## Release 5.1, Jan 10 2014
|
||||||
|
|
||||||
|
* CGI-related bugs where fixed, primarily for Windows platform
|
||||||
|
* Bugs on Windows related to UNICODE support were fixed
|
||||||
|
* Added a feature to support "error pages" through redirect.
|
||||||
|
Done using `-url_redirects` option, details are on
|
||||||
|
http://cesanta.com/docs/Options.shtml
|
||||||
|
|
||||||
|
## Release 5.0, Jan 6 2014
|
||||||
|
|
||||||
|
* Internal core has been changed from blocking, thread-per-connection to
|
||||||
|
non-blocking, asynchronous, one thread for all.
|
||||||
|
* API modification for server creation and response creation. That allowed
|
||||||
|
keep-alive support for dynamic requests, boosting the embedded performance
|
||||||
|
to 100+ thousands requests per second on a single core
|
||||||
|
(as measured on my development MacBook laptop)
|
||||||
|
* Unified handling of POST requests and Websocket requests by putting a
|
||||||
|
payload into `conn->content`, `conn->content_len` attributes.
|
||||||
|
That simplified user code and eliminated the need of `mg_read()`,
|
||||||
|
since mongoose buffers all data prior to calling the callback
|
||||||
|
* keep-alive support is the default
|
||||||
|
* Dropped SSI support and throttling support
|
||||||
|
* Several configuraition parameters are gone:
|
||||||
|
* `cgi_environment` (replaced with MONGOOSE_CGI),
|
||||||
|
* `protect_uri` (not useful)
|
||||||
|
* `ssi_pattern` (SSI support is gone)
|
||||||
|
* `throttle` (throttling support is gone)
|
||||||
|
* `error_log_file` (not used)
|
||||||
|
* `enable_keep_alive` (enabled by default)
|
||||||
|
* `listening_ports` (renamed to listening_port)
|
||||||
|
* `num_threads` (core has changed to single thread)
|
||||||
|
* `put_delete_auth_file` (renamed to dav_auth_file)
|
||||||
|
* `authentication_domain` (renamed to auth_domain)
|
||||||
|
* Due to the async, non-blocking nature of the core, few restrictions
|
||||||
|
are now in place:
|
||||||
|
* user callbacks must not block
|
||||||
|
* POST and Websocket data are now buffered, and cannot be huge
|
||||||
|
* mongoose is now capable on listening on only one port
|
||||||
|
|
||||||
|
## Release 4.1, Oct 2013
|
||||||
|
## Release 4.0, Oct 2013
|
||||||
|
## Release 3.8, Sep 2013
|
||||||
|
|
||||||
|
## Release 3.7, Feb 2 2013
|
||||||
|
|
||||||
|
* Added "redirect to SSL port" functionality, e.g. if you specify
|
||||||
|
`-listening_ports 8080r,8043s`
|
||||||
|
then all requests to HTTP port 8080 will be redirected to HTTPS port 8043
|
||||||
|
* Added `mg_download()` API, an HTTP client interface!
|
||||||
|
* Lua server pages now must output HTTP headers -- full control for Lua
|
||||||
|
* Added pre-built binary for MacOS, with initial GUI support
|
||||||
|
* API change: got rid of events, moved to struct `mg_callbacks`
|
||||||
|
* Bugfixes, thanks to contributors
|
||||||
|
|
||||||
|
|
||||||
|
## Release 3.7, Jan 18 2013
|
||||||
|
* Fixed source code archive (main.c was missing)
|
||||||
|
* Extended Windows GUI functionality:
|
||||||
|
* Added "Start browser" systray popup menu item
|
||||||
|
* Enhanced configuration editor
|
||||||
|
* Renamed config options:
|
||||||
|
* `put_delete_passwords_file` -> `put_delete_auth_file`
|
||||||
|
* `global_passwords_file` -> `global_auth_file`
|
||||||
|
* `select()` changed to `poll()`, to avoid big file descriptor
|
||||||
|
`FD_SET` problem on UNIX
|
||||||
|
* Couple of bugfixes, thanks to contributors
|
||||||
|
|
||||||
|
|
||||||
|
Eearlier release notes could be found by searching
|
||||||
|
[Mongoose mailing list](https://groups.google.com/forum/#!forum/mongoose-users)
|
||||||
+5
-10
@@ -1,20 +1,15 @@
|
|||||||
# Mongoose SSL guide
|
# Mongoose SSL guide
|
||||||
|
|
||||||
SSL is a protocol that makes web communication secure. To enable SSL
|
SSL is a protocol that makes web communication secure. To enable SSL
|
||||||
in mongoose, 3 steps are required:
|
in mongoose, 2 steps are required:
|
||||||
|
|
||||||
1. Valid certificate file must be created
|
1. Create valid SSL certificate file
|
||||||
2. `ssl_certificate` options must be set to contain path to the
|
2. Append SSL certificate file path to the `listening_ports` option
|
||||||
certificate file.
|
|
||||||
3. `listening_ports` option must contain a port number with letter `s`
|
|
||||||
appended to it, which instructs Mongoose to use SSL for all connections
|
|
||||||
made to that port.
|
|
||||||
|
|
||||||
Below is the `mongoose.conf` file snippet for typical SSL setup:
|
Below is the `mongoose.conf` file snippet for typical SSL setup:
|
||||||
|
|
||||||
document_root www_root # Serve files in www_root directory
|
document_root www_root # Serve files in www_root directory
|
||||||
listening_ports 80r,443s # Redirect all HTTP requests to HTTPS
|
listening_ports 80,443:cert.pem # Listen on ports 80 and 443
|
||||||
ssl_certificate ssl_cert.pem # Location of certificate file
|
|
||||||
|
|
||||||
## How to create SSL certificate file
|
## How to create SSL certificate file
|
||||||
|
|
||||||
|
|||||||
+11
-10
@@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
Mongoose is small and easy to use web server built on top of
|
Mongoose is small and easy to use web server built on top of
|
||||||
mongoose library. It is designed with maximum simplicity in mind. For example,
|
mongoose library. It is designed with maximum simplicity in mind. For example,
|
||||||
to share any directory, just drop mongoose executable file in that directory,
|
to share any directory, just drop mongoose executable in that directory,
|
||||||
double-click it (on UNIX, run it from shell) and launch a browser at
|
double-click it (on UNIX, run it from shell) and launch a browser at
|
||||||
[http://localhost:8080](http://localhost:8080) Note that 'localhost' should
|
[http://localhost:8080](http://localhost:8080) Note that 'localhost' should
|
||||||
be changed to a machine's name if a folder is accessed from other computer.
|
be changed to a machine's name if a folder is accessed from other computer.
|
||||||
|
|
||||||
On Windows and Mac, Mongoose iconifies itself to the system tray when started.
|
On Windows and Mac, Mongoose iconifies itself to the system tray when started.
|
||||||
Right-click on the icon pops up a menu, where it is possible to stop
|
Right-click on the icon to pop up a menu, where it is possible to stop
|
||||||
mongoose, or configure it.
|
mongoose, or configure it.
|
||||||
|
|
||||||
On UNIX, `mongoose` is a command line utility. Running `mongoose` in
|
On UNIX, `mongoose` is a command line utility. Running `mongoose` in
|
||||||
@@ -68,17 +68,18 @@ recognized by the file name pattern. Mongoose uses shell-like glob
|
|||||||
patterns. Pattern match starts at the beginning of the string, so essentially
|
patterns. Pattern match starts at the beginning of the string, so essentially
|
||||||
patterns are prefix patterns. Syntax is as follows:
|
patterns are prefix patterns. Syntax is as follows:
|
||||||
|
|
||||||
** Matches everything
|
** Matches everything
|
||||||
* Matches everything but slash character, '/'
|
* Matches everything but slash character, '/'
|
||||||
? Matches any character
|
? Matches any character
|
||||||
$ Matches the end of the string
|
$ Matches the end of the string
|
||||||
| Matches if pattern on the left side or the right side matches.
|
| Matches if pattern on the left side or the right side matches.
|
||||||
|
|
||||||
All other characters in the pattern match themselves. Examples:
|
All other characters in the pattern match themselves. Examples:
|
||||||
|
|
||||||
**.cgi$ Any string that ends with .cgi
|
# Pattern Meaning
|
||||||
/foo Any string that begins with /foo
|
**.cgi$ Any string that ends with .cgi
|
||||||
**a$|**b$ Any string that ends with a or b
|
/foo Any string that begins with /foo
|
||||||
|
**a$|**b$ Any string that ends with a or b
|
||||||
|
|
||||||
To restrict CGI files only to `/cgi-bin/` directory, use this setting:
|
To restrict CGI files only to `/cgi-bin/` directory, use this setting:
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
*.exe
|
||||||
+13
-47
@@ -1,54 +1,20 @@
|
|||||||
CFLAGS = -W -Wall -I.. -pthread -g -pipe $(CFLAGS_EXTRA)
|
# Copyright (c) 2014 Cesanta Software
|
||||||
DLL_FLAGS = -DLUA_COMPAT_ALL -I../build
|
# All rights reserved
|
||||||
RM = rm -rf
|
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT)
|
SUBDIRS = $(sort $(filter-out csharp/, $(dir $(wildcard */))))
|
||||||
RM = del /q /f
|
X = $(SUBDIRS)
|
||||||
else
|
ifdef WINDIR
|
||||||
UNAME_S := $(shell uname -s)
|
# appending the Winsock2 library at the end of the compiler
|
||||||
DLL_FLAGS += -shared
|
# invocation
|
||||||
|
CFLAGS_EXTRA += -lws2_32
|
||||||
ifeq ($(UNAME_S),Linux)
|
|
||||||
CFLAGS += -ldl
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(UNAME_S),Darwin)
|
|
||||||
# DLL_FLAGS += -bundle -undefined dynamic_lookup -dynamiclib
|
|
||||||
DLL_FLAGS += -flat_namespace -undefined suppress -dynamiclib
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: websocket_html.c
|
.PHONY: $(SUBDIRS)
|
||||||
$(CC) hello.c ../mongoose.c -o hello $(CFLAGS)
|
|
||||||
$(CC) websocket.c websocket_html.c ../mongoose.c -o websocket $(CFLAGS)
|
|
||||||
$(CC) post.c ../mongoose.c -o post $(CFLAGS)
|
|
||||||
$(CC) multi_threaded.c ../mongoose.c -o multi_threaded $(CFLAGS)
|
|
||||||
$(CC) upload.c ../mongoose.c -o upload $(CFLAGS)
|
|
||||||
$(CC) auth.c ../mongoose.c -o auth $(CFLAGS)
|
|
||||||
$(CC) server.c ../mongoose.c -o server $(CFLAGS)
|
|
||||||
|
|
||||||
# $(CC) chat.c ../mongoose.c -o chat $(CFLAGS)
|
all: $(SUBDIRS)
|
||||||
# $(CC) lua_dll.c ../build/lua_5.2.1.c -o $@.so $(CFLAGS) $(DLL_FLAGS)
|
|
||||||
|
|
||||||
websocket_html.c: websocket.html
|
$(SUBDIRS):
|
||||||
perl mkdata.pl $< > $@
|
@$(MAKE) CFLAGS_EXTRA="$(CFLAGS_EXTRA)" -C $@
|
||||||
|
|
||||||
MSVC = ../../vc6
|
|
||||||
CL = $(MSVC)/bin/cl
|
|
||||||
CLFLAGS = /MD /TC /nologo $(DBG) /W3 \
|
|
||||||
/I$(MSVC)/include /I.. /Dsnprintf=_snprintf
|
|
||||||
LFLAGS = /link /incremental:no /libpath:$(MSVC)/lib /machine:IX86
|
|
||||||
|
|
||||||
windows: websocket_html.c
|
|
||||||
$(CL) hello.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
|
|
||||||
$(CL) websocket.c websocket_html.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
|
|
||||||
$(CL) post.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
|
|
||||||
$(CL) multi_threaded.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
|
|
||||||
$(CL) upload.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
|
|
||||||
$(CL) auth.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
|
|
||||||
$(CL) server.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
|
|
||||||
|
|
||||||
#$(CL) lua_dll.c $(CLFLAGS) $(DLL_FLAGS) /DLL $(LFLAGS) /SUBSYSTEM:WINDOWS /ENTRY:luaopen_lua_dll /EXPORT:luaopen_lua_dll /out:lua_dll.dll
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
-@$(RM) hello upload post websocket chat *.exe *.dSYM *.obj .*o
|
for d in $(SUBDIRS) ; do $(MAKE) -C $$d clean ; done
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "mongoose.h"
|
|
||||||
|
|
||||||
static int auth_handler(struct mg_connection *conn) {
|
|
||||||
int result = MG_AUTH_FAIL; // Not authorized
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
// To populate passwords file, do
|
|
||||||
// mongoose -A my_passwords.txt mydomain.com admin admin
|
|
||||||
if ((fp = fopen("my_passwords.txt", "r")) != NULL) {
|
|
||||||
result = mg_authorize_digest(conn, fp);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
struct mg_server *server = mg_create_server(NULL);
|
|
||||||
mg_set_option(server, "listening_port", "8080");
|
|
||||||
mg_set_option(server, "document_root", ".");
|
|
||||||
mg_set_auth_handler(server, auth_handler);
|
|
||||||
|
|
||||||
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
|
|
||||||
for (;;) {
|
|
||||||
mg_poll_server(server, 1000);
|
|
||||||
}
|
|
||||||
mg_destroy_server(&server);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Copyright (c) 2014 Cesanta Software
|
||||||
|
# All rights reserved
|
||||||
|
|
||||||
|
PROG = big_upload
|
||||||
|
CFLAGS = -W -Wall -pthread -I../.. -g -O0 $(CFLAGS_EXTRA)
|
||||||
|
SOURCES = $(PROG).c ../../mongoose.c
|
||||||
|
|
||||||
|
$(PROG): $(SOURCES)
|
||||||
|
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static int handle_request(struct mg_connection *conn) {
|
||||||
|
if (strcmp(conn->uri, "/upload") == 0) {
|
||||||
|
FILE *fp = (FILE *) conn->connection_param;
|
||||||
|
if (fp != NULL) {
|
||||||
|
fwrite(conn->content, 1, conn->content_len, fp); // Write last bits
|
||||||
|
mg_printf(conn, "HTTP/1.1 200 OK\r\n"
|
||||||
|
"Content-Type: text/plain\r\n"
|
||||||
|
"Connection: close\r\n\r\n"
|
||||||
|
"Written %ld of POST data to a temp file:\n\n",
|
||||||
|
(long) ftell(fp));
|
||||||
|
|
||||||
|
// Temp file will be destroyed after fclose(), do something with the
|
||||||
|
// data here -- for example, parse it and extract uploaded files.
|
||||||
|
// As an example, we just echo the whole POST buffer back to the client.
|
||||||
|
rewind(fp);
|
||||||
|
mg_send_file_data(conn, fileno(fp));
|
||||||
|
return MG_MORE; // Tell Mongoose reply is not completed yet
|
||||||
|
} else {
|
||||||
|
mg_printf_data(conn, "%s", "Had no data to write...");
|
||||||
|
return MG_TRUE; // Tell Mongoose we're done with this request
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mg_printf_data(conn, "%s",
|
||||||
|
"<html><body>Upload example."
|
||||||
|
"<form method=\"POST\" action=\"/upload\" "
|
||||||
|
" enctype=\"multipart/form-data\">"
|
||||||
|
"<input type=\"file\" name=\"file\" /> <br/>"
|
||||||
|
"<input type=\"submit\" value=\"Upload\" />"
|
||||||
|
"</form></body></html>");
|
||||||
|
return MG_TRUE; // Tell mongoose to close this connection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mongoose sends MG_RECV for every received POST chunk.
|
||||||
|
// When last POST chunk is received, Mongoose sends MG_REQUEST, then MG_CLOSE.
|
||||||
|
static int handle_recv(struct mg_connection *conn) {
|
||||||
|
FILE *fp = (FILE *) conn->connection_param;
|
||||||
|
|
||||||
|
// Open temporary file where we going to write data
|
||||||
|
if (fp == NULL && ((conn->connection_param = fp = tmpfile())) == NULL) {
|
||||||
|
return -1; // Close connection on error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return number of bytes written to a temporary file: that is how many
|
||||||
|
// bytes we want to discard from the receive buffer
|
||||||
|
return fwrite(conn->content, 1, conn->content_len, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we free all allocated resources
|
||||||
|
static int handle_close(struct mg_connection *conn) {
|
||||||
|
if (conn->connection_param != NULL) {
|
||||||
|
fclose((FILE *) conn->connection_param);
|
||||||
|
conn->connection_param = NULL;
|
||||||
|
}
|
||||||
|
return MG_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
||||||
|
switch (ev) {
|
||||||
|
case MG_AUTH: return MG_TRUE;
|
||||||
|
case MG_REQUEST: return handle_request(conn);
|
||||||
|
case MG_RECV: return handle_recv(conn);
|
||||||
|
case MG_CLOSE: return handle_close(conn);
|
||||||
|
default: return MG_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_server *server = mg_create_server(NULL, ev_handler);
|
||||||
|
mg_set_option(server, "listening_port", "8080");
|
||||||
|
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
mg_poll_server(server, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
mg_destroy_server(&server);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
// This file is part of mongoose web server project,
|
|
||||||
// https://github.com/cesanta/mongoose
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
public class Program {
|
|
||||||
static private int EventHandler(MongooseEvent ev) {
|
|
||||||
if (ev.type != 1) {
|
|
||||||
return 0; // Mark as unhandled
|
|
||||||
}
|
|
||||||
|
|
||||||
MongooseRequestInfo request_info = (MongooseRequestInfo)
|
|
||||||
Marshal.PtrToStructure(ev.request_info, typeof(MongooseRequestInfo));
|
|
||||||
|
|
||||||
if (request_info.uri != "/test") {
|
|
||||||
return 0; // Mark as unhandled
|
|
||||||
}
|
|
||||||
|
|
||||||
Mongoose.write(ev.conn, "HTTP/1.1 200 OK\r\n\r\n");
|
|
||||||
Mongoose.write(ev.conn, "Hello from C#!\n");
|
|
||||||
|
|
||||||
return 1; // Mark as handled
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Main() {
|
|
||||||
Mongoose web_server = new Mongoose(".", "9000",
|
|
||||||
new MongooseEventHandler(EventHandler));
|
|
||||||
|
|
||||||
Console.WriteLine("Mongoose v." + web_server.version_ + " started.");
|
|
||||||
Console.WriteLine("Press enter to exit program.");
|
|
||||||
|
|
||||||
// Serve requests until user presses "enter" on a keyboard
|
|
||||||
Console.ReadLine();
|
|
||||||
web_server.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
// This file is part of mongoose web server project,
|
|
||||||
// https://github.com/cesanta/mongoose
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)] public struct MongooseHeader {
|
|
||||||
[MarshalAs(UnmanagedType.LPTStr)] public IntPtr name;
|
|
||||||
[MarshalAs(UnmanagedType.LPTStr)] public IntPtr value;
|
|
||||||
};
|
|
||||||
|
|
||||||
// mongoose.h :: struct mg_request_info
|
|
||||||
[StructLayout(LayoutKind.Sequential)] public struct MongooseRequestInfo {
|
|
||||||
[MarshalAs(UnmanagedType.LPTStr)] public string request_method;
|
|
||||||
[MarshalAs(UnmanagedType.LPTStr)] public string uri;
|
|
||||||
[MarshalAs(UnmanagedType.LPTStr)] public string http_version;
|
|
||||||
[MarshalAs(UnmanagedType.LPTStr)] public string query_string;
|
|
||||||
[MarshalAs(UnmanagedType.LPTStr)] public string remote_user;
|
|
||||||
public int remote_ip;
|
|
||||||
public int remote_port;
|
|
||||||
public int is_ssl;
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray,SizeConst=64)]
|
|
||||||
public MongooseHeader[] http_headers;
|
|
||||||
};
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)] public struct MongooseEvent {
|
|
||||||
public int type;
|
|
||||||
public IntPtr user_data;
|
|
||||||
public IntPtr conn_data;
|
|
||||||
public IntPtr event_param;
|
|
||||||
public IntPtr conn;
|
|
||||||
public IntPtr request_info;
|
|
||||||
};
|
|
||||||
|
|
||||||
public delegate int MongooseEventHandlerN(ref MongooseEvent ev);
|
|
||||||
public delegate int MongooseEventHandler(MongooseEvent ev);
|
|
||||||
|
|
||||||
public class Mongoose {
|
|
||||||
public const string dll_name_ = "mongoose";
|
|
||||||
public string version_ = "??";
|
|
||||||
|
|
||||||
// These are here to store a ref to the callbacks
|
|
||||||
// while they are over in unmanaged code, to prevent garbage collection.
|
|
||||||
private event MongooseEventHandlerN delegates;
|
|
||||||
|
|
||||||
private IntPtr ctx_;
|
|
||||||
|
|
||||||
[DllImport(dll_name_)] private static extern
|
|
||||||
IntPtr mg_start([MarshalAs(UnmanagedType.LPArray,
|
|
||||||
ArraySubType=UnmanagedType.LPTStr)] string[] options,
|
|
||||||
MongooseEventHandlerN callback,
|
|
||||||
IntPtr user_data);
|
|
||||||
[DllImport(dll_name_)] private static extern void mg_stop(IntPtr ctx);
|
|
||||||
[DllImport(dll_name_)] private static extern IntPtr mg_version();
|
|
||||||
[DllImport(dll_name_)] public static extern int mg_write(IntPtr conn,
|
|
||||||
string data, int length);
|
|
||||||
|
|
||||||
public Mongoose(string document_root,
|
|
||||||
string listening_ports,
|
|
||||||
MongooseEventHandler event_handler) {
|
|
||||||
version_ = Marshal.PtrToStringAnsi(mg_version());
|
|
||||||
|
|
||||||
string[] options = {
|
|
||||||
"document_root", document_root,
|
|
||||||
"listening_ports", listening_ports,
|
|
||||||
null
|
|
||||||
};
|
|
||||||
|
|
||||||
MongooseEventHandlerN cb = delegate(ref MongooseEvent ev) {
|
|
||||||
return event_handler(ev);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Prevent garbage collection
|
|
||||||
delegates += cb;
|
|
||||||
|
|
||||||
ctx_ = mg_start(options, cb, IntPtr.Zero);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int write(IntPtr conn, string data) {
|
|
||||||
return mg_write(conn, data, data.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
if (this.ctx_ != IntPtr.Zero) {
|
|
||||||
mg_stop(this.ctx_);
|
|
||||||
}
|
|
||||||
this.ctx_ = IntPtr.Zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Mongoose() {
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-386
@@ -1,386 +0,0 @@
|
|||||||
// This file is part of the Mongoose project, http://code.google.com/p/mongoose
|
|
||||||
// It implements an online chat server. For more details,
|
|
||||||
// see the documentation on the project web site.
|
|
||||||
// To test the application,
|
|
||||||
// 1. type "make" in the directory where this file lives
|
|
||||||
// 2. point your browser to http://127.0.0.1:8081
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#include "mongoose.h"
|
|
||||||
|
|
||||||
#define MAX_USER_LEN 20
|
|
||||||
#define MAX_MESSAGE_LEN 100
|
|
||||||
#define MAX_MESSAGES 5
|
|
||||||
#define MAX_SESSIONS 2
|
|
||||||
#define SESSION_TTL 120
|
|
||||||
|
|
||||||
static const char *authorize_url = "/authorize";
|
|
||||||
static const char *login_url = "/login.html";
|
|
||||||
static const char *ajax_reply_start =
|
|
||||||
"HTTP/1.1 200 OK\r\n"
|
|
||||||
"Cache: no-cache\r\n"
|
|
||||||
"Content-Type: application/x-javascript\r\n"
|
|
||||||
"\r\n";
|
|
||||||
|
|
||||||
// Describes single message sent to a chat. If user is empty (0 length),
|
|
||||||
// the message is then originated from the server itself.
|
|
||||||
struct message {
|
|
||||||
long id; // Message ID
|
|
||||||
char user[MAX_USER_LEN]; // User that have sent the message
|
|
||||||
char text[MAX_MESSAGE_LEN]; // Message text
|
|
||||||
time_t timestamp; // Message timestamp, UTC
|
|
||||||
};
|
|
||||||
|
|
||||||
// Describes web session.
|
|
||||||
struct session {
|
|
||||||
char session_id[33]; // Session ID, must be unique
|
|
||||||
char random[20]; // Random data used for extra user validation
|
|
||||||
char user[MAX_USER_LEN]; // Authenticated user
|
|
||||||
time_t expire; // Expiration timestamp, UTC
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct message messages[MAX_MESSAGES]; // Ringbuffer for messages
|
|
||||||
static struct session sessions[MAX_SESSIONS]; // Current sessions
|
|
||||||
static long last_message_id;
|
|
||||||
|
|
||||||
// Protects messages, sessions, last_message_id
|
|
||||||
static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
|
|
||||||
|
|
||||||
// Get session object for the connection. Caller must hold the lock.
|
|
||||||
static struct session *get_session(const struct mg_connection *conn) {
|
|
||||||
int i;
|
|
||||||
const char *cookie = mg_get_header(conn, "Cookie");
|
|
||||||
char session_id[33];
|
|
||||||
time_t now = time(NULL);
|
|
||||||
mg_get_cookie(cookie, "session", session_id, sizeof(session_id));
|
|
||||||
for (i = 0; i < MAX_SESSIONS; i++) {
|
|
||||||
if (sessions[i].expire != 0 &&
|
|
||||||
sessions[i].expire > now &&
|
|
||||||
strcmp(sessions[i].session_id, session_id) == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i == MAX_SESSIONS ? NULL : &sessions[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void get_qsvar(const struct mg_request_info *request_info,
|
|
||||||
const char *name, char *dst, size_t dst_len) {
|
|
||||||
const char *qs = request_info->query_string;
|
|
||||||
mg_get_var(qs, strlen(qs == NULL ? "" : qs), name, dst, dst_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a get of messages with IDs greater than last_id and transform them
|
|
||||||
// into a JSON string. Return that string to the caller. The string is
|
|
||||||
// dynamically allocated, caller must free it. If there are no messages,
|
|
||||||
// NULL is returned.
|
|
||||||
static char *messages_to_json(long last_id) {
|
|
||||||
const struct message *message;
|
|
||||||
int max_msgs, len;
|
|
||||||
char buf[sizeof(messages)]; // Large enough to hold all messages
|
|
||||||
|
|
||||||
// Read-lock the ringbuffer. Loop over all messages, making a JSON string.
|
|
||||||
pthread_rwlock_rdlock(&rwlock);
|
|
||||||
len = 0;
|
|
||||||
max_msgs = sizeof(messages) / sizeof(messages[0]);
|
|
||||||
// If client is too far behind, return all messages.
|
|
||||||
if (last_message_id - last_id > max_msgs) {
|
|
||||||
last_id = last_message_id - max_msgs;
|
|
||||||
}
|
|
||||||
for (; last_id < last_message_id; last_id++) {
|
|
||||||
message = &messages[last_id % max_msgs];
|
|
||||||
if (message->timestamp == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// buf is allocated on stack and hopefully is large enough to hold all
|
|
||||||
// messages (it may be too small if the ringbuffer is full and all
|
|
||||||
// messages are large. in this case asserts will trigger).
|
|
||||||
len += snprintf(buf + len, sizeof(buf) - len,
|
|
||||||
"{user: '%s', text: '%s', timestamp: %lu, id: %lu},",
|
|
||||||
message->user, message->text, message->timestamp, message->id);
|
|
||||||
assert(len > 0);
|
|
||||||
assert((size_t) len < sizeof(buf));
|
|
||||||
}
|
|
||||||
pthread_rwlock_unlock(&rwlock);
|
|
||||||
|
|
||||||
return len == 0 ? NULL : strdup(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If "callback" param is present in query string, this is JSONP call.
|
|
||||||
// Return 1 in this case, or 0 if "callback" is not specified.
|
|
||||||
// Wrap an output in Javascript function call.
|
|
||||||
static int handle_jsonp(struct mg_connection *conn,
|
|
||||||
const struct mg_request_info *request_info) {
|
|
||||||
char cb[64];
|
|
||||||
|
|
||||||
get_qsvar(request_info, "callback", cb, sizeof(cb));
|
|
||||||
if (cb[0] != '\0') {
|
|
||||||
mg_printf(conn, "%s(", cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cb[0] == '\0' ? 0 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A handler for the /ajax/get_messages endpoint.
|
|
||||||
// Return a list of messages with ID greater than requested.
|
|
||||||
static void ajax_get_messages(struct mg_connection *conn,
|
|
||||||
const struct mg_request_info *request_info) {
|
|
||||||
char last_id[32], *json;
|
|
||||||
int is_jsonp;
|
|
||||||
|
|
||||||
mg_printf(conn, "%s", ajax_reply_start);
|
|
||||||
is_jsonp = handle_jsonp(conn, request_info);
|
|
||||||
|
|
||||||
get_qsvar(request_info, "last_id", last_id, sizeof(last_id));
|
|
||||||
if ((json = messages_to_json(strtoul(last_id, NULL, 10))) != NULL) {
|
|
||||||
mg_printf(conn, "[%s]", json);
|
|
||||||
free(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_jsonp) {
|
|
||||||
mg_printf(conn, "%s", ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate new message. Caller must hold the lock.
|
|
||||||
static struct message *new_message(void) {
|
|
||||||
static int size = sizeof(messages) / sizeof(messages[0]);
|
|
||||||
struct message *message = &messages[last_message_id % size];
|
|
||||||
message->id = last_message_id++;
|
|
||||||
message->timestamp = time(0);
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void my_strlcpy(char *dst, const char *src, size_t len) {
|
|
||||||
strncpy(dst, src, len);
|
|
||||||
dst[len - 1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
// A handler for the /ajax/send_message endpoint.
|
|
||||||
static void ajax_send_message(struct mg_connection *conn,
|
|
||||||
const struct mg_request_info *request_info) {
|
|
||||||
struct message *message;
|
|
||||||
struct session *session;
|
|
||||||
char text[sizeof(message->text) - 1];
|
|
||||||
int is_jsonp;
|
|
||||||
|
|
||||||
mg_printf(conn, "%s", ajax_reply_start);
|
|
||||||
is_jsonp = handle_jsonp(conn, request_info);
|
|
||||||
|
|
||||||
get_qsvar(request_info, "text", text, sizeof(text));
|
|
||||||
if (text[0] != '\0') {
|
|
||||||
// We have a message to store. Write-lock the ringbuffer,
|
|
||||||
// grab the next message and copy data into it.
|
|
||||||
pthread_rwlock_wrlock(&rwlock);
|
|
||||||
message = new_message();
|
|
||||||
// TODO(lsm): JSON-encode all text strings
|
|
||||||
session = get_session(conn);
|
|
||||||
assert(session != NULL);
|
|
||||||
my_strlcpy(message->text, text, sizeof(text));
|
|
||||||
my_strlcpy(message->user, session->user, sizeof(message->user));
|
|
||||||
pthread_rwlock_unlock(&rwlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
mg_printf(conn, "%s", text[0] == '\0' ? "false" : "true");
|
|
||||||
|
|
||||||
if (is_jsonp) {
|
|
||||||
mg_printf(conn, "%s", ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Redirect user to the login form. In the cookie, store the original URL
|
|
||||||
// we came from, so that after the authorization we could redirect back.
|
|
||||||
static void redirect_to_login(struct mg_connection *conn,
|
|
||||||
const struct mg_request_info *request_info) {
|
|
||||||
mg_printf(conn, "HTTP/1.1 302 Found\r\n"
|
|
||||||
"Set-Cookie: original_url=%s\r\n"
|
|
||||||
"Location: %s\r\n\r\n",
|
|
||||||
request_info->uri, login_url);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return 1 if username/password is allowed, 0 otherwise.
|
|
||||||
static int check_password(const char *user, const char *password) {
|
|
||||||
// In production environment we should ask an authentication system
|
|
||||||
// to authenticate the user.
|
|
||||||
// Here however we do trivial check that user and password are not empty
|
|
||||||
return (user[0] && password[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate new session object
|
|
||||||
static struct session *new_session(void) {
|
|
||||||
int i;
|
|
||||||
time_t now = time(NULL);
|
|
||||||
pthread_rwlock_wrlock(&rwlock);
|
|
||||||
for (i = 0; i < MAX_SESSIONS; i++) {
|
|
||||||
if (sessions[i].expire == 0 || sessions[i].expire < now) {
|
|
||||||
sessions[i].expire = time(0) + SESSION_TTL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pthread_rwlock_unlock(&rwlock);
|
|
||||||
return i == MAX_SESSIONS ? NULL : &sessions[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate session ID. buf must be 33 bytes in size.
|
|
||||||
// Note that it is easy to steal session cookies by sniffing traffic.
|
|
||||||
// This is why all communication must be SSL-ed.
|
|
||||||
static void generate_session_id(char *buf, const char *random,
|
|
||||||
const char *user) {
|
|
||||||
mg_md5(buf, random, user, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void send_server_message(const char *fmt, ...) {
|
|
||||||
va_list ap;
|
|
||||||
struct message *message;
|
|
||||||
|
|
||||||
pthread_rwlock_wrlock(&rwlock);
|
|
||||||
message = new_message();
|
|
||||||
message->user[0] = '\0'; // Empty user indicates server message
|
|
||||||
va_start(ap, fmt);
|
|
||||||
vsnprintf(message->text, sizeof(message->text), fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
pthread_rwlock_unlock(&rwlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A handler for the /authorize endpoint.
|
|
||||||
// Login page form sends user name and password to this endpoint.
|
|
||||||
static void authorize(struct mg_connection *conn,
|
|
||||||
const struct mg_request_info *request_info) {
|
|
||||||
char user[MAX_USER_LEN], password[MAX_USER_LEN];
|
|
||||||
struct session *session;
|
|
||||||
|
|
||||||
// Fetch user name and password.
|
|
||||||
get_qsvar(request_info, "user", user, sizeof(user));
|
|
||||||
get_qsvar(request_info, "password", password, sizeof(password));
|
|
||||||
|
|
||||||
if (check_password(user, password) && (session = new_session()) != NULL) {
|
|
||||||
// Authentication success:
|
|
||||||
// 1. create new session
|
|
||||||
// 2. set session ID token in the cookie
|
|
||||||
// 3. remove original_url from the cookie - not needed anymore
|
|
||||||
// 4. redirect client back to the original URL
|
|
||||||
//
|
|
||||||
// The most secure way is to stay HTTPS all the time. However, just to
|
|
||||||
// show the technique, we redirect to HTTP after the successful
|
|
||||||
// authentication. The danger of doing this is that session cookie can
|
|
||||||
// be stolen and an attacker may impersonate the user.
|
|
||||||
// Secure application must use HTTPS all the time.
|
|
||||||
my_strlcpy(session->user, user, sizeof(session->user));
|
|
||||||
snprintf(session->random, sizeof(session->random), "%d", rand());
|
|
||||||
generate_session_id(session->session_id, session->random, session->user);
|
|
||||||
send_server_message("<%s> joined", session->user);
|
|
||||||
mg_printf(conn, "HTTP/1.1 302 Found\r\n"
|
|
||||||
"Set-Cookie: session=%s; max-age=3600; http-only\r\n" // Session ID
|
|
||||||
"Set-Cookie: user=%s\r\n" // Set user, needed by Javascript code
|
|
||||||
"Set-Cookie: original_url=/; max-age=0\r\n" // Delete original_url
|
|
||||||
"Location: /\r\n\r\n",
|
|
||||||
session->session_id, session->user);
|
|
||||||
} else {
|
|
||||||
// Authentication failure, redirect to login.
|
|
||||||
redirect_to_login(conn, request_info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return 1 if request is authorized, 0 otherwise.
|
|
||||||
static int is_authorized(const struct mg_connection *conn,
|
|
||||||
const struct mg_request_info *request_info) {
|
|
||||||
struct session *session;
|
|
||||||
char valid_id[33];
|
|
||||||
int authorized = 0;
|
|
||||||
|
|
||||||
// Always authorize accesses to login page and to authorize URI
|
|
||||||
if (!strcmp(request_info->uri, login_url) ||
|
|
||||||
!strcmp(request_info->uri, authorize_url)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_rwlock_rdlock(&rwlock);
|
|
||||||
if ((session = get_session(conn)) != NULL) {
|
|
||||||
generate_session_id(valid_id, session->random, session->user);
|
|
||||||
if (strcmp(valid_id, session->session_id) == 0) {
|
|
||||||
session->expire = time(0) + SESSION_TTL;
|
|
||||||
authorized = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pthread_rwlock_unlock(&rwlock);
|
|
||||||
|
|
||||||
return authorized;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void redirect_to_ssl(struct mg_connection *conn,
|
|
||||||
const struct mg_request_info *request_info) {
|
|
||||||
const char *p, *host = mg_get_header(conn, "Host");
|
|
||||||
if (host != NULL && (p = strchr(host, ':')) != NULL) {
|
|
||||||
mg_printf(conn, "HTTP/1.1 302 Found\r\n"
|
|
||||||
"Location: https://%.*s:8082/%s:8082\r\n\r\n",
|
|
||||||
(int) (p - host), host, request_info->uri);
|
|
||||||
} else {
|
|
||||||
mg_printf(conn, "%s", "HTTP/1.1 500 Error\r\n\r\nHost: header is not set");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int event_handler(struct mg_event *event) {
|
|
||||||
struct mg_request_info *request_info = event->request_info;
|
|
||||||
struct mg_connection *conn = event->conn;
|
|
||||||
int result = 1;
|
|
||||||
|
|
||||||
if (event->type != MG_REQUEST_BEGIN) return 0;
|
|
||||||
|
|
||||||
if (!request_info->is_ssl) {
|
|
||||||
redirect_to_ssl(conn, request_info);
|
|
||||||
} else if (!is_authorized(conn, request_info)) {
|
|
||||||
redirect_to_login(conn, request_info);
|
|
||||||
} else if (strcmp(request_info->uri, authorize_url) == 0) {
|
|
||||||
authorize(conn, request_info);
|
|
||||||
} else if (strcmp(request_info->uri, "/ajax/get_messages") == 0) {
|
|
||||||
ajax_get_messages(conn, request_info);
|
|
||||||
} else if (strcmp(request_info->uri, "/ajax/send_message") == 0) {
|
|
||||||
ajax_send_message(conn, request_info);
|
|
||||||
} else {
|
|
||||||
// No suitable handler found, mark as not processed. Mongoose will
|
|
||||||
// try to serve the request.
|
|
||||||
result = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *options[] = {
|
|
||||||
"document_root", "html",
|
|
||||||
"listening_ports", "8081,8082s",
|
|
||||||
"ssl_certificate", "ssl_cert.pem",
|
|
||||||
"num_threads", "5",
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
struct mg_context *ctx;
|
|
||||||
|
|
||||||
// Initialize random number generator. It will be used later on for
|
|
||||||
// the session identifier creation.
|
|
||||||
srand((unsigned) time(0));
|
|
||||||
|
|
||||||
// Setup and start Mongoose
|
|
||||||
if ((ctx = mg_start(options, event_handler, NULL)) == NULL) {
|
|
||||||
printf("%s\n", "Cannot start chat server, fatal exit");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait until enter is pressed, then exit
|
|
||||||
printf("Chat server started on ports %s, press enter to quit.\n",
|
|
||||||
mg_get_option(ctx, "listening_ports"));
|
|
||||||
getchar();
|
|
||||||
mg_stop(ctx);
|
|
||||||
printf("%s\n", "Chat server stopped.");
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// vim:ts=2:sw=2:et
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Copyright (c) 2014 Cesanta Software
|
||||||
|
# All rights reserved
|
||||||
|
|
||||||
|
PROG = cookie_auth
|
||||||
|
CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
|
||||||
|
SOURCES = $(PROG).c ../../mongoose.c
|
||||||
|
|
||||||
|
$(PROG): $(SOURCES)
|
||||||
|
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
// Copyright (c) 2014 Cesanta Software
|
||||||
|
// All rights reserved
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static const char *s_login_uri = "/login.html";
|
||||||
|
static const char *s_secret = ":-)"; // Must be known only to server
|
||||||
|
|
||||||
|
static void generate_ssid(const char *user_name, const char *expiration_date,
|
||||||
|
char *ssid, size_t ssid_size) {
|
||||||
|
char hash[33];
|
||||||
|
mg_md5(hash, user_name, ":", expiration_date, ":", s_secret, NULL);
|
||||||
|
snprintf(ssid, ssid_size, "%s|%s|%s", user_name, expiration_date, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_auth(struct mg_connection *conn) {
|
||||||
|
char ssid[100], calculated_ssid[100], name[100], expire[100];
|
||||||
|
|
||||||
|
// Always authenticate requests to login page
|
||||||
|
if (strcmp(conn->uri, s_login_uri) == 0) {
|
||||||
|
return MG_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for session ID in the Cookie.
|
||||||
|
// That session ID can be validated against the database that stores
|
||||||
|
// current active sessions.
|
||||||
|
mg_parse_header(mg_get_header(conn, "Cookie"), "ssid", ssid, sizeof(ssid));
|
||||||
|
if (sscanf(ssid, "%[^|]|%[^|]|", name, expire) == 2) {
|
||||||
|
generate_ssid(name, expire, calculated_ssid, sizeof(calculated_ssid));
|
||||||
|
if (strcmp(ssid, calculated_ssid) == 0) {
|
||||||
|
return MG_TRUE; // Authenticate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auth failed, do NOT authenticate, redirect to login page
|
||||||
|
mg_printf(conn, "HTTP/1.1 302 Moved\r\nLocation: %s\r\n\r\n", s_login_uri);
|
||||||
|
return MG_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_login_form_submission(struct mg_connection *conn) {
|
||||||
|
char name[100], password[100], ssid[100], expire[100], expire_epoch[100];
|
||||||
|
|
||||||
|
mg_get_var(conn, "name", name, sizeof(name));
|
||||||
|
mg_get_var(conn, "password", password, sizeof(password));
|
||||||
|
|
||||||
|
// A real authentication mechanism should be employed here.
|
||||||
|
// Also, the whole site should be served through HTTPS.
|
||||||
|
if (strcmp(name, "Joe") == 0 && strcmp(password, "Doe") == 0) {
|
||||||
|
// Generate expiry date
|
||||||
|
time_t t = time(NULL) + 3600; // Valid for 1 hour
|
||||||
|
snprintf(expire_epoch, sizeof(expire_epoch), "%lu", (unsigned long) t);
|
||||||
|
strftime(expire, sizeof(expire), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t));
|
||||||
|
generate_ssid(name, expire_epoch, ssid, sizeof(ssid));
|
||||||
|
// Set "session id" cookie, there could be some data encoded in it.
|
||||||
|
mg_printf(conn,
|
||||||
|
"HTTP/1.1 302 Moved\r\n"
|
||||||
|
"Set-Cookie: ssid=%s; expire=\"%s\"; http-only; HttpOnly;\r\n"
|
||||||
|
"Location: /\r\n\r\n",
|
||||||
|
ssid, expire);
|
||||||
|
return MG_TRUE;
|
||||||
|
}
|
||||||
|
return MG_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serve_request(struct mg_connection *conn) {
|
||||||
|
if (strcmp(conn->uri, s_login_uri) == 0 &&
|
||||||
|
strcmp(conn->request_method, "POST") == 0) {
|
||||||
|
return check_login_form_submission(conn);
|
||||||
|
}
|
||||||
|
return MG_FALSE; // Serve files in the document_root
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
||||||
|
switch (ev) {
|
||||||
|
case MG_AUTH: return check_auth(conn);
|
||||||
|
case MG_REQUEST: return serve_request(conn);
|
||||||
|
default: return MG_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_server *server = mg_create_server(NULL, ev_handler);
|
||||||
|
mg_set_option(server, "listening_port", "8080");
|
||||||
|
mg_set_option(server, "document_root", ".");
|
||||||
|
|
||||||
|
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
|
||||||
|
for (;;) {
|
||||||
|
mg_poll_server(server, 1000);
|
||||||
|
}
|
||||||
|
mg_destroy_server(&server);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>WebSocket Test</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<style type="text/css">
|
||||||
|
body {
|
||||||
|
background-color: #cde; margin: 0;
|
||||||
|
padding: 0; font: 14px Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
* { outline: none; }
|
||||||
|
div.content {
|
||||||
|
width: 800px; margin: 2em auto; padding: 20px 50px;
|
||||||
|
background-color: #fff; border-radius: 1em;
|
||||||
|
}
|
||||||
|
label { display: inline-block; min-width: 7em; }
|
||||||
|
input { border: 1px solid #ccc; padding: 0.4em; margin: 0 0 10px 0; }
|
||||||
|
a:link, a:visited { color: #69c; text-decoration: none; }
|
||||||
|
@media (max-width: 700px) {
|
||||||
|
body { background-color: #fff; }
|
||||||
|
div.content {
|
||||||
|
width: auto; margin: 0 auto; border-radius: 0; padding: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="content">
|
||||||
|
<h1>Mongoose Cookie Base Authentication</h1>
|
||||||
|
<p>This is an index page. Authentication succeeded.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>WebSocket Test</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<style type="text/css">
|
||||||
|
body {
|
||||||
|
background-color: #cde; margin: 0;
|
||||||
|
padding: 0; font: 14px Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
* { outline: none; }
|
||||||
|
div.content {
|
||||||
|
width: 800px; margin: 2em auto; padding: 20px 50px;
|
||||||
|
background-color: #fff; border-radius: 1em;
|
||||||
|
}
|
||||||
|
label { display: inline-block; min-width: 7em; }
|
||||||
|
input { border: 1px solid #ccc; padding: 0.4em; margin: 0 0 10px 0; }
|
||||||
|
a:link, a:visited { color: #69c; text-decoration: none; }
|
||||||
|
@media (max-width: 700px) {
|
||||||
|
body { background-color: #fff; }
|
||||||
|
div.content {
|
||||||
|
width: auto; margin: 0 auto; border-radius: 0; padding: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="content">
|
||||||
|
<h1>Mongoose Cookie Based Authentication</h1>
|
||||||
|
<p>Use name "Joe", password "Doe" to login.</p>
|
||||||
|
<form method="POST">
|
||||||
|
<div>
|
||||||
|
<label>Name:</label>
|
||||||
|
<input type="text" name="name"/>
|
||||||
|
</div><div>
|
||||||
|
<label>Password:</label>
|
||||||
|
<input type="password" name="password"/>
|
||||||
|
</div><div>
|
||||||
|
<input type="submit" value="Login"/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
// This file is part of mongoose web server project,
|
||||||
|
// https://github.com/cesanta/mongoose
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
public class Program {
|
||||||
|
static private int EventHandler(IntPtr conn_ptr, int ev) {
|
||||||
|
MongooseConnection conn = (MongooseConnection)
|
||||||
|
System.Runtime.InteropServices.Marshal.PtrToStructure(
|
||||||
|
conn_ptr , typeof(MongooseConnection));
|
||||||
|
|
||||||
|
if (ev == 102) {
|
||||||
|
// MG_AUTH
|
||||||
|
return 1;
|
||||||
|
} else if (ev == 103) {
|
||||||
|
// MG_REQUEST
|
||||||
|
Mongoose.send_data(conn_ptr, "Hello from C#!\n");
|
||||||
|
Mongoose.send_data(conn_ptr, "URI: " + conn.uri + "\n");
|
||||||
|
Mongoose.send_data(conn_ptr, "HTTP Headers:\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < conn.num_headers; i++) {
|
||||||
|
IntPtr name = conn.http_headers[i].name;
|
||||||
|
IntPtr val = conn.http_headers[i].value;
|
||||||
|
System.Runtime.InteropServices.Marshal.PtrToStringAnsi(name);
|
||||||
|
Mongoose.send_data(conn_ptr, " " +
|
||||||
|
System.Runtime.InteropServices.Marshal.PtrToStringAnsi(name) + ": " +
|
||||||
|
System.Runtime.InteropServices.Marshal.PtrToStringAnsi(val) + "\n");
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Main() {
|
||||||
|
Mongoose web_server = new Mongoose(".", "9001",
|
||||||
|
new MongooseEventHandler(EventHandler));
|
||||||
|
|
||||||
|
Console.WriteLine("Mongoose started, press Ctrl-C to exit.");
|
||||||
|
for (;;) {
|
||||||
|
web_server.poll(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
// This file is part of mongoose web server project,
|
||||||
|
// https://github.com/cesanta/mongoose
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)] public struct MongooseHeader {
|
||||||
|
[MarshalAs(UnmanagedType.LPTStr)] public IntPtr name;
|
||||||
|
[MarshalAs(UnmanagedType.LPTStr)] public IntPtr value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// mongoose.h :: struct mg_connection
|
||||||
|
[StructLayout(LayoutKind.Sequential)] public struct MongooseConnection {
|
||||||
|
[MarshalAs(UnmanagedType.LPTStr)] public string request_method;
|
||||||
|
[MarshalAs(UnmanagedType.LPTStr)] public string uri;
|
||||||
|
[MarshalAs(UnmanagedType.LPTStr)] public string http_version;
|
||||||
|
[MarshalAs(UnmanagedType.LPTStr)] public string query_string;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray,SizeConst=48)] public char[] remote_ip;
|
||||||
|
[MarshalAs(UnmanagedType.LPTStr)] public string local_ip;
|
||||||
|
[MarshalAs(UnmanagedType.U2)] public short remote_port;
|
||||||
|
[MarshalAs(UnmanagedType.U2)] public short local_port;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.SysInt)] public int num_headers;
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray,SizeConst=30)]
|
||||||
|
public MongooseHeader[] http_headers;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.LPTStr)] public IntPtr content;
|
||||||
|
[MarshalAs(UnmanagedType.SysInt)] public int content_len;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.SysInt)] public int is_websocket;
|
||||||
|
[MarshalAs(UnmanagedType.SysInt)] public int status_code;
|
||||||
|
[MarshalAs(UnmanagedType.SysInt)] public int wsbits;
|
||||||
|
};
|
||||||
|
|
||||||
|
public delegate int MongooseEventHandler(IntPtr c, int ev);
|
||||||
|
|
||||||
|
public class Mongoose {
|
||||||
|
public const string dll_ = "mongoose";
|
||||||
|
private IntPtr server_;
|
||||||
|
|
||||||
|
[DllImport(dll_)] private static extern IntPtr
|
||||||
|
mg_create_server(IntPtr user_data, MongooseEventHandler eh);
|
||||||
|
[DllImport(dll_)] private static extern int
|
||||||
|
mg_poll_server(IntPtr server, int milli);
|
||||||
|
[DllImport(dll_)] private static extern IntPtr
|
||||||
|
mg_set_option(IntPtr server, string name, string value);
|
||||||
|
[DllImport(dll_)] public static extern int
|
||||||
|
mg_send_data(IntPtr conn, string data, int length);
|
||||||
|
|
||||||
|
public Mongoose(string document_root,
|
||||||
|
string listening_port,
|
||||||
|
MongooseEventHandler event_handler) {
|
||||||
|
server_ = mg_create_server(IntPtr.Zero, event_handler);
|
||||||
|
mg_set_option(server_, "document_root", document_root);
|
||||||
|
mg_set_option(server_, "listening_port", listening_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int send_data(IntPtr conn, string data) {
|
||||||
|
return mg_send_data(conn, data, data.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void poll(int milli) {
|
||||||
|
mg_poll_server(server_, milli);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add destructor and call mg_destroy_server()
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Copyright (c) 2014 Cesanta Software
|
||||||
|
# All rights reserved
|
||||||
|
|
||||||
|
PROG = digest_auth
|
||||||
|
CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
|
||||||
|
SOURCES = $(PROG).c ../../mongoose.c
|
||||||
|
|
||||||
|
$(PROG): $(SOURCES)
|
||||||
|
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
||||||
|
|
||||||
|
if (ev == MG_AUTH) {
|
||||||
|
int result = MG_FALSE; // Not authorized
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
// To populate passwords file, do
|
||||||
|
// mongoose -A my_passwords.txt mydomain.com admin admin
|
||||||
|
if ((fp = fopen("my_passwords.txt", "r")) != NULL) {
|
||||||
|
result = mg_authorize_digest(conn, fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MG_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_server *server = mg_create_server(NULL, ev_handler);
|
||||||
|
mg_set_option(server, "listening_port", "8080");
|
||||||
|
mg_set_option(server, "document_root", ".");
|
||||||
|
|
||||||
|
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
|
||||||
|
for (;;) {
|
||||||
|
mg_poll_server(server, 1000);
|
||||||
|
}
|
||||||
|
mg_destroy_server(&server);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "mongoose.h"
|
|
||||||
|
|
||||||
|
|
||||||
static int index_html(struct mg_connection *conn) {
|
|
||||||
FILE *fp = (FILE *) conn->connection_param;
|
|
||||||
char buf[200];
|
|
||||||
size_t n = 0;
|
|
||||||
|
|
||||||
if (fp == NULL) {
|
|
||||||
fp = fopen("../mongoose.c", "r");
|
|
||||||
conn->connection_param = (void *) fp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fp != NULL) {
|
|
||||||
n = fread(buf, 1, sizeof(buf), fp);
|
|
||||||
mg_send_data(conn, buf, n);
|
|
||||||
|
|
||||||
if (n < sizeof(buf) || conn->wsbits != 0) {
|
|
||||||
fclose(fp);
|
|
||||||
conn->connection_param = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return n < sizeof(buf) ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
struct mg_server *server;
|
|
||||||
|
|
||||||
// Create and configure the server
|
|
||||||
server = mg_create_server(NULL);
|
|
||||||
mg_set_option(server, "listening_port", "8080");
|
|
||||||
mg_add_uri_handler(server, "/", index_html);
|
|
||||||
|
|
||||||
// Serve request. Hit Ctrl-C to terminate the program
|
|
||||||
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
|
|
||||||
for (;;) {
|
|
||||||
mg_poll_server(server, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup, and free server instance
|
|
||||||
mg_destroy_server(&server);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Copyright (c) 2014 Cesanta Software
|
||||||
|
# All rights reserved
|
||||||
|
|
||||||
|
PROG = file_upload
|
||||||
|
CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
|
||||||
|
SOURCES = $(PROG).c ../../mongoose.c
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
|
||||||
|
run: $(PROG)
|
||||||
|
./$(PROG)
|
||||||
|
|
||||||
|
$(PROG): $(SOURCES) Makefile
|
||||||
|
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
|
||||||
|
|
||||||
|
win:
|
||||||
|
wine cl $(SOURCES) /MD /nologo /DNDEBUG /O1 /I../.. /Fe$(PROG).exe
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib *.gc*
|
||||||
@@ -5,9 +5,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "mongoose.h"
|
#include "mongoose.h"
|
||||||
|
|
||||||
static int index_html(struct mg_connection *conn) {
|
static int send_index_page(struct mg_connection *conn) {
|
||||||
const char *data;
|
const char *data;
|
||||||
int data_len;
|
int data_len, ofs = 0;
|
||||||
char var_name[100], file_name[100];
|
char var_name[100], file_name[100];
|
||||||
|
|
||||||
mg_printf_data(conn, "%s",
|
mg_printf_data(conn, "%s",
|
||||||
@@ -18,28 +18,33 @@ static int index_html(struct mg_connection *conn) {
|
|||||||
"<input type=\"submit\" value=\"Upload\" />"
|
"<input type=\"submit\" value=\"Upload\" />"
|
||||||
"</form>");
|
"</form>");
|
||||||
|
|
||||||
if (mg_parse_multipart(conn->content, conn->content_len,
|
while ((ofs = mg_parse_multipart(conn->content + ofs, conn->content_len - ofs,
|
||||||
var_name, sizeof(var_name),
|
var_name, sizeof(var_name),
|
||||||
file_name, sizeof(file_name),
|
file_name, sizeof(file_name),
|
||||||
&data, &data_len) > 0) {
|
&data, &data_len)) > 0) {
|
||||||
|
mg_printf_data(conn, "var: %s, file_name: %s, size: %d bytes<br>",
|
||||||
mg_printf_data(conn, "%s", "Uploaded file:<pre>");
|
var_name, file_name, data_len);
|
||||||
mg_send_data(conn, data, data_len);
|
|
||||||
mg_printf_data(conn, "%s", "/pre>");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mg_printf_data(conn, "%s", "</body></html>");
|
mg_printf_data(conn, "%s", "</body></html>");
|
||||||
|
|
||||||
return MG_REQUEST_PROCESSED;
|
return MG_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
||||||
|
switch (ev) {
|
||||||
|
case MG_AUTH: return MG_TRUE;
|
||||||
|
case MG_REQUEST: return send_index_page(conn);
|
||||||
|
default: return MG_FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
struct mg_server *server;
|
struct mg_server *server;
|
||||||
|
|
||||||
// Create and configure the server
|
// Create and configure the server
|
||||||
server = mg_create_server(NULL);
|
server = mg_create_server(NULL, ev_handler);
|
||||||
mg_set_option(server, "listening_port", "8080");
|
mg_set_option(server, "listening_port", "8080");
|
||||||
mg_set_request_handler(server, index_html);
|
|
||||||
|
|
||||||
// Serve request. Hit Ctrl-C to terminate the program
|
// Serve request. Hit Ctrl-C to terminate the program
|
||||||
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
|
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Copyright (c) 2014 Cesanta Software
|
||||||
|
# All rights reserved
|
||||||
|
|
||||||
|
PROG = form_submit
|
||||||
|
CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
|
||||||
|
SOURCES = $(PROG).c ../../mongoose.c
|
||||||
|
|
||||||
|
$(PROG): $(SOURCES)
|
||||||
|
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
|
||||||
@@ -10,7 +10,7 @@ static const char *html_form =
|
|||||||
"<input type=\"submit\" />"
|
"<input type=\"submit\" />"
|
||||||
"</form></body></html>";
|
"</form></body></html>";
|
||||||
|
|
||||||
static int handler(struct mg_connection *conn) {
|
static void send_reply(struct mg_connection *conn) {
|
||||||
char var1[500], var2[500];
|
char var1[500], var2[500];
|
||||||
|
|
||||||
if (strcmp(conn->uri, "/handle_post_request") == 0) {
|
if (strcmp(conn->uri, "/handle_post_request") == 0) {
|
||||||
@@ -33,18 +33,30 @@ static int handler(struct mg_connection *conn) {
|
|||||||
// Show HTML form.
|
// Show HTML form.
|
||||||
mg_send_data(conn, html_form, strlen(html_form));
|
mg_send_data(conn, html_form, strlen(html_form));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return MG_REQUEST_PROCESSED;
|
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
||||||
|
if (ev == MG_REQUEST) {
|
||||||
|
send_reply(conn);
|
||||||
|
return MG_TRUE;
|
||||||
|
} else if (ev == MG_AUTH) {
|
||||||
|
return MG_TRUE;
|
||||||
|
} else {
|
||||||
|
return MG_FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
struct mg_server *server = mg_create_server(NULL);
|
struct mg_server *server = mg_create_server(NULL, ev_handler);
|
||||||
|
|
||||||
mg_set_option(server, "listening_port", "8080");
|
mg_set_option(server, "listening_port", "8080");
|
||||||
mg_set_request_handler(server, handler);
|
|
||||||
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
|
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
|
||||||
for (;;) {
|
for (;;) {
|
||||||
mg_poll_server(server, 1000);
|
mg_poll_server(server, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
mg_destroy_server(&server);
|
mg_destroy_server(&server);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "mongoose.h"
|
|
||||||
|
|
||||||
// This function will be called by mongoose on every new request
|
|
||||||
static int index_html(struct mg_connection *conn) {
|
|
||||||
mg_printf_data(conn, "Hello! Requested URI is [%s]", conn->uri);
|
|
||||||
return MG_REQUEST_PROCESSED;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
struct mg_server *server;
|
|
||||||
|
|
||||||
// Create and configure the server
|
|
||||||
server = mg_create_server(NULL);
|
|
||||||
mg_set_option(server, "listening_port", "8080");
|
|
||||||
mg_set_request_handler(server, index_html);
|
|
||||||
|
|
||||||
// Serve request. Hit Ctrl-C to terminate the program
|
|
||||||
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
|
|
||||||
for (;;) {
|
|
||||||
mg_poll_server(server, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup, and free server instance
|
|
||||||
mg_destroy_server(&server);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Copyright (c) 2014 Cesanta Software
|
||||||
|
# All rights reserved
|
||||||
|
|
||||||
|
PROG = hello_world
|
||||||
|
CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
|
||||||
|
SOURCES = $(PROG).c ../../mongoose.c
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
|
||||||
|
run: $(PROG)
|
||||||
|
./$(PROG)
|
||||||
|
|
||||||
|
$(PROG): $(SOURCES) Makefile
|
||||||
|
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
|
||||||
|
|
||||||
|
win:
|
||||||
|
wine cl $(SOURCES) /MD /nologo /DNDEBUG /O1 /I../.. /Fe$(PROG).exe
|
||||||
|
wine $(PROG).exe
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib *.gc*
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (c) 2014 Cesanta Software
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// This example demostrates basic use of Mongoose embedded web server.
|
||||||
|
// $Date: 2014-09-09 22:20:23 UTC $
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
||||||
|
switch (ev) {
|
||||||
|
case MG_AUTH: return MG_TRUE;
|
||||||
|
case MG_REQUEST:
|
||||||
|
mg_printf_data(conn, "Hello! Requested URI is [%s]", conn->uri);
|
||||||
|
return MG_TRUE;
|
||||||
|
default: return MG_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_server *server;
|
||||||
|
|
||||||
|
// Create and configure the server
|
||||||
|
server = mg_create_server(NULL, ev_handler);
|
||||||
|
mg_set_option(server, "listening_port", "8080");
|
||||||
|
|
||||||
|
// Serve request. Hit Ctrl-C to terminate the program
|
||||||
|
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
|
||||||
|
for (;;) {
|
||||||
|
mg_poll_server(server, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup, and free server instance
|
||||||
|
mg_destroy_server(&server);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,73 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" dir="ltr">
|
|
||||||
<!-- This file is part of the Mongoose project,
|
|
||||||
http://code.google.com/p/mongoose -->
|
|
||||||
<head>
|
|
||||||
<title>Mongoose chat server</title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
|
|
||||||
<link type="text/css" rel="stylesheet" href="style.css"/>
|
|
||||||
<script src="jquery.js"></script>
|
|
||||||
<script src="main.js"></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="header">
|
|
||||||
<div id="logo"></div>
|
|
||||||
<div class="rounded infobox help-message" id="motd">
|
|
||||||
Chat room implemented using
|
|
||||||
<a href="http://code.google.com/p/mongoose" target="_blank">Mongoose</a>
|
|
||||||
embeddable web server.
|
|
||||||
This application was written for educational purposes demonstrating
|
|
||||||
how web interface could be decoupled from the business logic. Not a
|
|
||||||
single line of HTML is generated by the server, instead, server
|
|
||||||
gives data to the client in JSON format.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
|
|
||||||
<div id="middle">
|
|
||||||
<div><center><span id="error" class="rounded"></span><center></div>
|
|
||||||
|
|
||||||
<div id="menu">
|
|
||||||
<div class="menu-item left-rounded menu-item-selected"
|
|
||||||
name="chat">Chat</div>
|
|
||||||
<div class="menu-item left-rounded" name="settings">Settings</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="content" class="rounded">
|
|
||||||
|
|
||||||
<div id="chat" class="main">
|
|
||||||
<div class="chat-window">
|
|
||||||
<span class="top-rounded chat-title">Main room</span>
|
|
||||||
<div class="bottom-rounded chat-content">
|
|
||||||
<div class="message-list" id="mml">
|
|
||||||
</div>
|
|
||||||
<input type="text" size="40" class="message-input"></input>
|
|
||||||
<span class="help-message">
|
|
||||||
Type your message here and press enter</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="settings" class="hidden main">
|
|
||||||
<div>
|
|
||||||
<span class="top-rounded chat-title">Settings</span>
|
|
||||||
<div class="bottom-rounded chat-content">
|
|
||||||
<table>
|
|
||||||
<tr><td>Max messages to display:</td><td>blah blah</td></tr>
|
|
||||||
<tr><td>Text color:</td><td>blah blah</td></tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="footer">
|
|
||||||
Copyright © 2004-2010 by Sergey Lyubka
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
Vendored
-154
@@ -1,154 +0,0 @@
|
|||||||
/*!
|
|
||||||
* jQuery JavaScript Library v1.4.2
|
|
||||||
* http://jquery.com/
|
|
||||||
*
|
|
||||||
* Copyright 2010, John Resig
|
|
||||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
||||||
* http://jquery.org/license
|
|
||||||
*
|
|
||||||
* Includes Sizzle.js
|
|
||||||
* http://sizzlejs.com/
|
|
||||||
* Copyright 2010, The Dojo Foundation
|
|
||||||
* Released under the MIT, BSD, and GPL Licenses.
|
|
||||||
*
|
|
||||||
* Date: Sat Feb 13 22:33:48 2010 -0500
|
|
||||||
*/
|
|
||||||
(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
|
|
||||||
e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
|
|
||||||
j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
|
|
||||||
"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
|
|
||||||
true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
|
|
||||||
Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
|
|
||||||
(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
|
|
||||||
a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
|
|
||||||
"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
|
|
||||||
function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
|
|
||||||
c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
|
|
||||||
L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
|
|
||||||
"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
|
|
||||||
a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
|
|
||||||
d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
|
|
||||||
a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
|
|
||||||
!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
|
|
||||||
true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
|
|
||||||
var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
|
|
||||||
parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
|
|
||||||
false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
|
|
||||||
s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
|
|
||||||
applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
|
|
||||||
else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
|
|
||||||
a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
|
|
||||||
w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
|
|
||||||
cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
|
|
||||||
i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
|
|
||||||
" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
|
|
||||||
this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
|
|
||||||
e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
|
|
||||||
c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
|
|
||||||
a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
|
|
||||||
function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
|
|
||||||
k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
|
|
||||||
C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
|
|
||||||
null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
|
|
||||||
e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
|
|
||||||
f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
|
|
||||||
if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
|
|
||||||
fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
|
|
||||||
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
|
|
||||||
"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
|
|
||||||
a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
|
|
||||||
isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
|
|
||||||
{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
|
|
||||||
if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
|
|
||||||
e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
|
|
||||||
"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
|
|
||||||
d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
|
|
||||||
!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
|
|
||||||
toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
|
|
||||||
u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
|
|
||||||
function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
|
|
||||||
if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
|
|
||||||
e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
|
|
||||||
t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
|
|
||||||
g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
|
|
||||||
for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
|
|
||||||
1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
|
|
||||||
CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
|
|
||||||
relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
|
|
||||||
l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
|
|
||||||
h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
|
|
||||||
CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
|
|
||||||
g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
|
|
||||||
text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
|
|
||||||
setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
|
|
||||||
h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
|
|
||||||
m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
|
|
||||||
"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
|
|
||||||
h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
|
|
||||||
!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
|
|
||||||
h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
|
|
||||||
q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
|
|
||||||
if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
|
|
||||||
(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
|
|
||||||
function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
|
|
||||||
gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
|
|
||||||
c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
|
|
||||||
{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
|
|
||||||
"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
|
|
||||||
d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
|
|
||||||
a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
|
|
||||||
1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
|
|
||||||
a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
|
|
||||||
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
|
|
||||||
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
|
|
||||||
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
|
|
||||||
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
|
|
||||||
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
|
|
||||||
""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
|
|
||||||
this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
|
|
||||||
u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
|
|
||||||
1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
|
|
||||||
return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
|
|
||||||
""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
|
|
||||||
c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
|
|
||||||
c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
|
|
||||||
function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
|
|
||||||
Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
|
|
||||||
"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
|
|
||||||
a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
|
|
||||||
a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
|
|
||||||
"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
|
|
||||||
serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
|
|
||||||
function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
|
|
||||||
global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
|
|
||||||
e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
|
|
||||||
"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
|
|
||||||
false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
|
|
||||||
false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
|
|
||||||
c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
|
|
||||||
d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
|
|
||||||
g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
|
|
||||||
1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
|
|
||||||
"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
|
|
||||||
if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
|
|
||||||
this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
|
|
||||||
"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
|
|
||||||
animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
|
|
||||||
j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
|
|
||||||
this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
|
|
||||||
"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
|
|
||||||
c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
|
|
||||||
this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
|
|
||||||
this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
|
|
||||||
e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
|
|
||||||
c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
|
|
||||||
function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
|
|
||||||
this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
|
|
||||||
k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
|
|
||||||
f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
|
|
||||||
a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
|
|
||||||
c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
|
|
||||||
d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
|
|
||||||
f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
|
|
||||||
"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
|
|
||||||
e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" dir="ltr">
|
|
||||||
<!-- This file is part of the Mongoose project,
|
|
||||||
http://code.google.com/p/mongoose -->
|
|
||||||
<head>
|
|
||||||
<title>Mongoose chat: login</title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
|
|
||||||
<!--
|
|
||||||
Note that this page is self-sufficient, it does not load any other
|
|
||||||
CSS or Javascript file. This is done so because only this page is
|
|
||||||
allowed for non-authorized users. If we want to load other files
|
|
||||||
from the frontend, we need to change backend code to allow those
|
|
||||||
for non-authorized users. See chat.c :: must_authorize() function.
|
|
||||||
-->
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.onload = function() {
|
|
||||||
// Set correct action for the login form. We assume that the SSL port
|
|
||||||
// is the next one to insecure one.
|
|
||||||
var httpsPort = location.protocol.match(/https/) ? location.port :
|
|
||||||
parseInt(location.port) + 1;
|
|
||||||
document.forms[0].action = 'https://' + location.hostname + ':' +
|
|
||||||
httpsPort + '/authorize';
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<center>
|
|
||||||
<h2>Mongoose chat server login</h2>
|
|
||||||
<div style="max-width: 30em;">
|
|
||||||
Username and password can be any non-empty strings.
|
|
||||||
</div>
|
|
||||||
<br/>
|
|
||||||
<form>
|
|
||||||
<input type="text" name="user"></input><br/>
|
|
||||||
<input type="text" name="password"></input><br/>
|
|
||||||
<input type="submit" value="Login"></input>
|
|
||||||
</form>
|
|
||||||
</center>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 KiB |
@@ -1,106 +0,0 @@
|
|||||||
// This file is part of Mongoose project, http://code.google.com/p/mongoose
|
|
||||||
|
|
||||||
var chat = {
|
|
||||||
// Backend URL, string.
|
|
||||||
// 'http://backend.address.com' or '' if backend is the same as frontend
|
|
||||||
backendUrl: '',
|
|
||||||
maxVisibleMessages: 10,
|
|
||||||
errorMessageFadeOutTimeoutMs: 2000,
|
|
||||||
errorMessageFadeOutTimer: null,
|
|
||||||
lastMessageId: 0,
|
|
||||||
getMessagesIntervalMs: 1000,
|
|
||||||
};
|
|
||||||
|
|
||||||
chat.normalizeText = function(text) {
|
|
||||||
return text.replace('<', '<').replace('>', '>');
|
|
||||||
};
|
|
||||||
|
|
||||||
chat.refresh = function(data) {
|
|
||||||
|
|
||||||
if (data === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$.each(data, function(index, entry) {
|
|
||||||
var row = $('<div>').addClass('message-row').appendTo('#mml');
|
|
||||||
var timestamp = (new Date(entry.timestamp * 1000)).toLocaleTimeString();
|
|
||||||
$('<span>')
|
|
||||||
.addClass('message-timestamp')
|
|
||||||
.html('[' + timestamp + ']')
|
|
||||||
.prependTo(row);
|
|
||||||
$('<span>')
|
|
||||||
.addClass('message-user')
|
|
||||||
.addClass(entry.user ? '' : 'message-user-server')
|
|
||||||
.html(chat.normalizeText((entry.user || '[server]') + ':'))
|
|
||||||
.appendTo(row);
|
|
||||||
$('<span>')
|
|
||||||
.addClass('message-text')
|
|
||||||
.addClass(entry.user ? '' : 'message-text-server')
|
|
||||||
.html(chat.normalizeText(entry.text))
|
|
||||||
.appendTo(row);
|
|
||||||
chat.lastMessageId = Math.max(chat.lastMessageId, entry.id) + 1;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Keep only chat.maxVisibleMessages, delete older ones.
|
|
||||||
while ($('#mml').children().length > chat.maxVisibleMessages) {
|
|
||||||
$('#mml div:first-child').remove();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
chat.getMessages = function(enter_loop) {
|
|
||||||
$.ajax({
|
|
||||||
dataType: 'jsonp',
|
|
||||||
url: chat.backendUrl + '/ajax/get_messages',
|
|
||||||
data: {last_id: chat.lastMessageId},
|
|
||||||
success: chat.refresh,
|
|
||||||
error: function() {
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (enter_loop) {
|
|
||||||
window.setTimeout('chat.getMessages(true)', chat.getMessagesIntervalMs);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
chat.handleMenuItemClick = function(ev) {
|
|
||||||
$('.menu-item').removeClass('menu-item-selected'); // Deselect menu buttons
|
|
||||||
$(this).addClass('menu-item-selected'); // Select clicked button
|
|
||||||
$('.main').addClass('hidden'); // Hide all main windows
|
|
||||||
$('#' + $(this).attr('name')).removeClass('hidden'); // Show main window
|
|
||||||
};
|
|
||||||
|
|
||||||
chat.showError = function(message) {
|
|
||||||
$('#error').html(message).fadeIn('fast');
|
|
||||||
window.clearTimeout(chat.errorMessageFadeOutTimer);
|
|
||||||
chat.errorMessageFadeOutTimer = window.setTimeout(function() {
|
|
||||||
$('#error').fadeOut('slow');
|
|
||||||
}, chat.errorMessageFadeOutTimeoutMs);
|
|
||||||
};
|
|
||||||
|
|
||||||
chat.handleMessageInput = function(ev) {
|
|
||||||
var input = ev.target;
|
|
||||||
if (ev.keyCode != 13 || !input.value)
|
|
||||||
return;
|
|
||||||
//input.disabled = true;
|
|
||||||
$.ajax({
|
|
||||||
dataType: 'jsonp',
|
|
||||||
url: chat.backendUrl + '/ajax/send_message',
|
|
||||||
data: {text: input.value},
|
|
||||||
success: function(ev) {
|
|
||||||
input.value = '';
|
|
||||||
input.disabled = false;
|
|
||||||
chat.getMessages(false);
|
|
||||||
},
|
|
||||||
error: function(ev) {
|
|
||||||
chat.showError('Error sending message');
|
|
||||||
input.disabled = false;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
$('.menu-item').click(chat.handleMenuItemClick);
|
|
||||||
$('.message-input').keypress(chat.handleMessageInput);
|
|
||||||
chat.getMessages(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
// vim:ts=2:sw=2:et
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
/*
|
|
||||||
* vim:ts=2:sw=2:et:ai
|
|
||||||
*/
|
|
||||||
|
|
||||||
body {
|
|
||||||
font: 13px Arial; margin: 0.5em 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#logo {
|
|
||||||
background: url('logo.png') no-repeat ;
|
|
||||||
width: 160px;
|
|
||||||
height: 40px;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
#motd {
|
|
||||||
margin-left: 170px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.infobox {
|
|
||||||
background: #eed;
|
|
||||||
padding: 1px 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.help-message {
|
|
||||||
color: #aaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
#middle {
|
|
||||||
margin: 0.5em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#error {
|
|
||||||
background: #c44;
|
|
||||||
color: white;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content, .menu-item-selected, .chat-title, .chat-content {
|
|
||||||
background: #c3d9ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content {
|
|
||||||
overflow: hidden;
|
|
||||||
min-height: 7em;
|
|
||||||
padding: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-title {
|
|
||||||
padding: 1px 1ex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-content {
|
|
||||||
padding: 1ex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-window {
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-row {
|
|
||||||
margin: 2px;
|
|
||||||
border-bottom: 1px solid #bbb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-timestamp {
|
|
||||||
color: #484;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-user {
|
|
||||||
margin-left: 0.5em;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-text {
|
|
||||||
margin-left: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-user-server {
|
|
||||||
color: purple;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-text-server {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main {
|
|
||||||
padding: 0.5em;
|
|
||||||
background: #f0fcff;
|
|
||||||
}
|
|
||||||
|
|
||||||
#menu {
|
|
||||||
margin-top: 1em;
|
|
||||||
min-width: 7em;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
#footer {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
color: #ccc;
|
|
||||||
padding: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section {
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-item {
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0.1em 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-item-selected {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-list {
|
|
||||||
min-height: 1em;
|
|
||||||
background: white;
|
|
||||||
margin: 0.5em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rounded {
|
|
||||||
border-radius: 6px;
|
|
||||||
-moz-border-radius: 6px;
|
|
||||||
-webkit-border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left-rounded {
|
|
||||||
border-radius: 6px 0 0 6px;
|
|
||||||
-moz-border-radius: 6px 0 0 6px;
|
|
||||||
-webkit-border-radius: 6px 0 0 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottom-rounded {
|
|
||||||
border-radius: 0 0 6px 6px;
|
|
||||||
-moz-border-radius: 0 0 6px 6px;
|
|
||||||
-webkit-border-radius: 0 0 6px 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-rounded {
|
|
||||||
border-radius: 6px 6px 0 0;
|
|
||||||
-moz-border-radius: 6px 6px 0 0;
|
|
||||||
-webkit-border-radius: 6px 6px 0 0;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Copyright (c) 2014 Cesanta Software
|
||||||
|
# All rights reserved
|
||||||
|
|
||||||
|
PROG = http_client
|
||||||
|
CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
|
||||||
|
SOURCES = $(PROG).c ../../mongoose.c
|
||||||
|
|
||||||
|
unix: $(SOURCES)
|
||||||
|
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp *.o *.lib
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
// Copyright (c) 2014 Cesanta Software
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// This example demostrates how to connect to the remote Web server,
|
||||||
|
// download data, process it and send back a reply.
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static int s_received_signal = 0;
|
||||||
|
static struct mg_server *s_server = NULL;
|
||||||
|
static const char *s_remote_addr = "glosbe.com:80";
|
||||||
|
|
||||||
|
static void signal_handler(int sig_num) {
|
||||||
|
signal(sig_num, signal_handler);
|
||||||
|
s_received_signal = sig_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
||||||
|
struct mg_connection *client, *orig;
|
||||||
|
|
||||||
|
switch (ev) {
|
||||||
|
case MG_AUTH:
|
||||||
|
return MG_TRUE;
|
||||||
|
|
||||||
|
case MG_CONNECT:
|
||||||
|
// Send request to the remote host.
|
||||||
|
// TODO(lsm): handle connect error here.
|
||||||
|
mg_printf(conn, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n",
|
||||||
|
"/gapi/translate?from=eng&dest=fra&format=json&phrase=cat",
|
||||||
|
s_remote_addr);
|
||||||
|
return MG_TRUE;
|
||||||
|
|
||||||
|
case MG_REPLY:
|
||||||
|
// Send reply to the original connection
|
||||||
|
orig = (struct mg_connection *) conn->connection_param;
|
||||||
|
mg_send_status(orig, conn->status_code);
|
||||||
|
mg_send_header(orig, "Content-Type", "text/plain");
|
||||||
|
mg_send_data(orig, conn->content, conn->content_len);
|
||||||
|
mg_send_data(orig, "", 0); // Last chunk: mark the end of reply
|
||||||
|
|
||||||
|
// Disconnect connections
|
||||||
|
orig->connection_param = NULL;
|
||||||
|
conn->connection_param = NULL;
|
||||||
|
return MG_TRUE;
|
||||||
|
|
||||||
|
case MG_REQUEST:
|
||||||
|
if ((client = mg_connect(s_server, s_remote_addr)) != NULL) {
|
||||||
|
// Interconnect requests
|
||||||
|
client->connection_param = conn;
|
||||||
|
conn->connection_param = client;
|
||||||
|
return MG_MORE;
|
||||||
|
} else {
|
||||||
|
mg_printf_data(conn, "%s", "cannot send API request");
|
||||||
|
return MG_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return MG_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
s_server = mg_create_server(NULL, ev_handler);
|
||||||
|
|
||||||
|
mg_set_option(s_server, "listening_port", "8080");
|
||||||
|
|
||||||
|
// Setup signal handlers
|
||||||
|
signal(SIGTERM, signal_handler);
|
||||||
|
signal(SIGINT, signal_handler);
|
||||||
|
|
||||||
|
printf("Listening on port %s\n", mg_get_option(s_server, "listening_port"));
|
||||||
|
while (s_received_signal == 0) {
|
||||||
|
mg_poll_server(s_server, 1000);
|
||||||
|
}
|
||||||
|
mg_destroy_server(&s_server);
|
||||||
|
printf("Existing on signal %d\n", s_received_signal);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
HTTP/1.0 200 OK
|
|
||||||
Content-Type: text/plain
|
|
||||||
|
|
||||||
<?
|
|
||||||
-- Directory scanning example
|
|
||||||
|
|
||||||
function scandir(dir)
|
|
||||||
local t = {}
|
|
||||||
for f in io.popen('dir ' .. dir):lines() do table.insert(t, f) end
|
|
||||||
return t
|
|
||||||
end
|
|
||||||
|
|
||||||
local tab = scandir('C:\\')
|
|
||||||
for k,v in pairs(tab) do mg.write(v, '\n') end
|
|
||||||
?>
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
HTTP/1.0 200 OK
|
|
||||||
Content-Type: text/html
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<p>Prime numbers from 0 to 100, calculated by Lua:</p>
|
|
||||||
<?
|
|
||||||
function is_prime(n)
|
|
||||||
if n <= 0 then return false end
|
|
||||||
if n <= 2 then return true end
|
|
||||||
if (n % 2 == 0) then return false end
|
|
||||||
for i = 3, n / 2, 2 do
|
|
||||||
if (n % i == 0) then return false end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
for i = 1, 100 do
|
|
||||||
if is_prime(i) then mg.write('<span>' .. i .. '</span> ') end
|
|
||||||
end
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
||||||
<p>Reading POST data from Lua (click submit):</p>
|
|
||||||
<form method="POST" ><input type="text" name="t1"/><input type="submit"></form>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
POST data: [<? mg.write(mg.request_info.content) ?>]
|
|
||||||
request method: [<? mg.write(mg.request_info.request_method) ?>]
|
|
||||||
IP/port: [<?mg.write(mg.request_info.remote_ip, ':',
|
|
||||||
mg.request_info.remote_port) ?>]
|
|
||||||
URI: [<? mg.write(mg.request_info.uri) ?>]
|
|
||||||
HTTP version [<? mg.write(mg.request_info.http_version) ?>]
|
|
||||||
Content Len: [<? mg.write(mg.request_info.content_len) ?>]
|
|
||||||
HEADERS:
|
|
||||||
<?
|
|
||||||
for name, value in pairs(mg.request_info.http_headers) do
|
|
||||||
mg.write(name, ':', value, '\n')
|
|
||||||
end
|
|
||||||
?>
|
|
||||||
|
|
||||||
</pre>
|
|
||||||
</html>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include "lua_5.2.1.h"
|
|
||||||
|
|
||||||
static int smile(lua_State *L) {
|
|
||||||
(void) L; // Unused
|
|
||||||
printf("%s\n", ":-)");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int LUA_API luaopen_lua_dll(lua_State *L) {
|
|
||||||
static const struct luaL_Reg api[] = {
|
|
||||||
{"smile", smile},
|
|
||||||
{NULL, NULL},
|
|
||||||
};
|
|
||||||
luaL_openlib(L, "lua_dll", api, 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Copyright (c) 2014 Cesanta Software
|
||||||
|
# All rights reserved
|
||||||
|
|
||||||
|
PROG = mjpg_streamer
|
||||||
|
CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
|
||||||
|
SOURCES = $(PROG).c ../../mongoose.c
|
||||||
|
|
||||||
|
$(PROG): $(SOURCES)
|
||||||
|
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static void send_file(struct mg_connection *conn, const char *path) {
|
||||||
|
char buf[1024];
|
||||||
|
struct stat st;
|
||||||
|
int n;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
if (stat(path, &st) == 0 && (fp = fopen(path, "rb")) != NULL) {
|
||||||
|
mg_printf(conn, "--w00t\r\nContent-Type: image/jpeg\r\n"
|
||||||
|
"Content-Length: %lu\r\n\r\n", (unsigned long) st.st_size);
|
||||||
|
while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
|
||||||
|
mg_write(conn, buf, n);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
mg_write(conn, "\r\n", 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct conn_state {
|
||||||
|
int file_index;
|
||||||
|
time_t last_poll;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
||||||
|
const char **file_names = (const char **) conn->server_param;
|
||||||
|
struct conn_state *state;
|
||||||
|
time_t now = time(NULL);
|
||||||
|
|
||||||
|
switch (ev) {
|
||||||
|
|
||||||
|
case MG_AUTH:
|
||||||
|
return MG_TRUE;
|
||||||
|
|
||||||
|
case MG_REQUEST:
|
||||||
|
if (strcmp(conn->uri, "/stream") != 0) {
|
||||||
|
mg_send_header(conn, "Content-Type", "text/html");
|
||||||
|
mg_printf_data(conn, "%s",
|
||||||
|
"Go to <a href=/stream>/stream</a> for MJPG stream");
|
||||||
|
return MG_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mg_printf(conn, "%s",
|
||||||
|
"HTTP/1.0 200 OK\r\n" "Cache-Control: no-cache\r\n"
|
||||||
|
"Pragma: no-cache\r\nExpires: Thu, 01 Dec 1994 16:00:00 GMT\r\n"
|
||||||
|
"Connection: close\r\nContent-Type: multipart/x-mixed-replace; "
|
||||||
|
"boundary=--w00t\r\n\r\n");
|
||||||
|
|
||||||
|
send_file(conn, file_names[0]);
|
||||||
|
|
||||||
|
state = (struct conn_state *) malloc(sizeof(*state));
|
||||||
|
conn->connection_param = state;
|
||||||
|
state->file_index = 1; // First file is already sent
|
||||||
|
state->last_poll = time(NULL);
|
||||||
|
return MG_MORE;
|
||||||
|
|
||||||
|
case MG_POLL:
|
||||||
|
state = (struct conn_state *) conn->connection_param;
|
||||||
|
|
||||||
|
if (state != NULL && now > state->last_poll) {
|
||||||
|
if (file_names[state->file_index] != NULL) {
|
||||||
|
send_file(conn, file_names[state->file_index]);
|
||||||
|
state->file_index++;
|
||||||
|
if (file_names[state->file_index] == NULL) {
|
||||||
|
return MG_TRUE; // No more images, close connection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state->last_poll = now;
|
||||||
|
}
|
||||||
|
return MG_FALSE;
|
||||||
|
|
||||||
|
case MG_CLOSE:
|
||||||
|
free(conn->connection_param);
|
||||||
|
conn->connection_param = NULL;
|
||||||
|
return MG_FALSE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return MG_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
struct mg_server *server;
|
||||||
|
|
||||||
|
if (argc < 3) {
|
||||||
|
printf("Usage: %s image1.jpg image2.jpg ...\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
server = mg_create_server(&argv[1], ev_handler);
|
||||||
|
mg_set_option(server, "listening_port", "8080");
|
||||||
|
|
||||||
|
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
|
||||||
|
for (;;) {
|
||||||
|
mg_poll_server(server, 1000);
|
||||||
|
}
|
||||||
|
mg_destroy_server(&server);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Copyright (c) 2014 Cesanta Software
|
||||||
|
# All rights reserved
|
||||||
|
|
||||||
|
PROG = multi_threaded_server
|
||||||
|
CFLAGS = -W -Wall -I../.. -pthread -g -O0 -DMONGOOSE_ENABLE_THREADS $(CFLAGS_EXTRA)
|
||||||
|
SOURCES = $(PROG).c ../../mongoose.c
|
||||||
|
|
||||||
|
$(PROG): $(SOURCES)
|
||||||
|
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
|
||||||
+15
-12
@@ -2,11 +2,17 @@
|
|||||||
|
|
||||||
// Start a browser and hit refresh couple of times. The replies will
|
// Start a browser and hit refresh couple of times. The replies will
|
||||||
// come from both server instances.
|
// come from both server instances.
|
||||||
static int request_handler(struct mg_connection *conn) {
|
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
||||||
mg_send_header(conn, "Content-Type", "text/plain");
|
if (ev == MG_REQUEST) {
|
||||||
mg_printf_data(conn, "This is a reply from server instance # %s",
|
mg_send_header(conn, "Content-Type", "text/plain");
|
||||||
(char *) conn->server_param);
|
mg_printf_data(conn, "This is a reply from server instance # %s",
|
||||||
return MG_REQUEST_PROCESSED;
|
(char *) conn->server_param);
|
||||||
|
return MG_TRUE;
|
||||||
|
} else if (ev == MG_AUTH) {
|
||||||
|
return MG_TRUE;
|
||||||
|
} else {
|
||||||
|
return MG_FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *serve(void *server) {
|
static void *serve(void *server) {
|
||||||
@@ -17,15 +23,12 @@ static void *serve(void *server) {
|
|||||||
int main(void) {
|
int main(void) {
|
||||||
struct mg_server *server1, *server2;
|
struct mg_server *server1, *server2;
|
||||||
|
|
||||||
server1 = mg_create_server((void *) "1");
|
server1 = mg_create_server((void *) "1", ev_handler);
|
||||||
server2 = mg_create_server((void *) "2");
|
server2 = mg_create_server((void *) "2", ev_handler);
|
||||||
|
|
||||||
mg_set_request_handler(server1, request_handler);
|
// Make both server1 and server2 listen on the same sockets
|
||||||
mg_set_request_handler(server2, request_handler);
|
|
||||||
|
|
||||||
// Make both server1 and server2 listen on the same socket
|
|
||||||
mg_set_option(server1, "listening_port", "8080");
|
mg_set_option(server1, "listening_port", "8080");
|
||||||
mg_set_listening_socket(server2, mg_get_listening_socket(server1));
|
mg_copy_listeners(server1, server2);
|
||||||
|
|
||||||
// server1 goes to separate thread, server 2 runs in main thread.
|
// server1 goes to separate thread, server 2 runs in main thread.
|
||||||
// IMPORTANT: NEVER LET DIFFERENT THREADS HANDLE THE SAME SERVER.
|
// IMPORTANT: NEVER LET DIFFERENT THREADS HANDLE THE SAME SERVER.
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Copyright (c) 2014 Cesanta Software
|
||||||
|
# All rights reserved
|
||||||
|
|
||||||
|
PROG = proxy_server
|
||||||
|
FLAGS = -I../.. -DNS_ENABLE_SSL
|
||||||
|
CFLAGS = -W -Wall -g -O0 -pthread -lssl -DMONGOOSE_ENABLE_THREADS $(FLAGS) $(CFLAGS_EXTRA)
|
||||||
|
SOURCES = $(PROG).c ../../mongoose.c
|
||||||
|
|
||||||
|
unix: $(SOURCES)
|
||||||
|
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
// Copyright (c) 2014 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// To build and run this example:
|
||||||
|
// git clone https://github.com/cesanta/net_skeleton.git
|
||||||
|
// git clone https://github.com/cesanta/mongoose.git
|
||||||
|
// cd mongoose/examples
|
||||||
|
// make proxy
|
||||||
|
// ./proxy
|
||||||
|
//
|
||||||
|
// Configure your browser to use localhost:2014 as a proxy for all protocols
|
||||||
|
// Then, navigate to https://cesanta.com
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define sleep(x) Sleep((x) * 1000)
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static int s_received_signal = 0;
|
||||||
|
static struct mg_server *s_server = NULL;
|
||||||
|
|
||||||
|
#define SSE_CONNECTION ((void *) 1)
|
||||||
|
|
||||||
|
static void elog(int do_exit, const char *fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
fputc('\n', stderr);
|
||||||
|
if (do_exit) exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void signal_handler(int sig_num) {
|
||||||
|
signal(sig_num, signal_handler);
|
||||||
|
s_received_signal = sig_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sse_push(struct mg_connection *conn, enum mg_event ev) {
|
||||||
|
if (ev == MG_POLL && conn->connection_param == SSE_CONNECTION) {
|
||||||
|
mg_printf(conn, "data: %s\r\n\r\n", (const char *) conn->callback_param);
|
||||||
|
}
|
||||||
|
return MG_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *sse_pusher_thread_func(void *param) {
|
||||||
|
while (s_received_signal == 0) {
|
||||||
|
mg_wakeup_server_ex(s_server, sse_push, "%lu %s",
|
||||||
|
(unsigned long) time(NULL), (const char *) param);
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return: 1 if regular file, 2 if directory, 0 if not found
|
||||||
|
static int exists(const char *path) {
|
||||||
|
struct stat st;
|
||||||
|
return stat(path, &st) != 0 ? 0 : S_ISDIR(st.st_mode) == 0 ? 1 : 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return: 1 if regular file, 2 if directory, 0 if not found
|
||||||
|
static int is_local_file(const char *uri, char *path, size_t path_len) {
|
||||||
|
snprintf(path, path_len, "%s/%s",
|
||||||
|
mg_get_option(s_server, "document_root"), uri);
|
||||||
|
return exists(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int try_to_serve_locally(struct mg_connection *conn) {
|
||||||
|
char path[500], buf[2000];
|
||||||
|
int n, res;
|
||||||
|
FILE *fp = NULL;
|
||||||
|
|
||||||
|
if ((res = is_local_file(conn->uri, path, sizeof(path))) == 2) {
|
||||||
|
strncat(path, "/index.html", sizeof(path) - strlen(path) - 1);
|
||||||
|
res = exists(path);
|
||||||
|
printf("PATH: [%s]\n", path);
|
||||||
|
}
|
||||||
|
if (res == 0) return MG_FALSE;
|
||||||
|
|
||||||
|
if ((fp = fopen(path, "rb")) != NULL) {
|
||||||
|
printf("Serving [%s] locally \n", path);
|
||||||
|
mg_send_header(conn, "Connection", "close");
|
||||||
|
mg_send_header(conn, "Content-Type", mg_get_mime_type(path, "text/plain"));
|
||||||
|
while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
|
||||||
|
mg_send_data(conn, buf, n);
|
||||||
|
}
|
||||||
|
mg_send_data(conn, "", 0);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
return fp == NULL ? MG_FALSE : MG_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int is_resource_present_locally(const char *uri) {
|
||||||
|
char path[500];
|
||||||
|
return is_local_file(uri, path, sizeof(path)) || strcmp(uri, "/api/sse") == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int proxy_event_handler(struct mg_connection *conn, enum mg_event ev) {
|
||||||
|
static const char target_url[] = "http://cesanta.com";
|
||||||
|
static int target_url_size = sizeof(target_url) - 1;
|
||||||
|
const char *host;
|
||||||
|
|
||||||
|
switch (ev) {
|
||||||
|
case MG_REQUEST:
|
||||||
|
host = mg_get_header(conn, "Host");
|
||||||
|
printf("[%s] [%s] [%s]\n", conn->request_method, conn->uri,
|
||||||
|
host == NULL ? "" : host);
|
||||||
|
if (strstr(conn->uri, "/qqq") != NULL) s_received_signal = SIGTERM;
|
||||||
|
|
||||||
|
// Proxied HTTPS requests use "CONNECT foo.com:443"
|
||||||
|
// Proxied HTTP requests use "GET http://..... "
|
||||||
|
// Serve requests for target_url from the local FS.
|
||||||
|
if (memcmp(conn->uri, target_url, target_url_size) == 0 &&
|
||||||
|
is_resource_present_locally(conn->uri + target_url_size)) {
|
||||||
|
conn->uri += target_url_size; // Leave only path in the URI
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(conn->uri, "/api/sse") == 0) {
|
||||||
|
conn->connection_param = SSE_CONNECTION;
|
||||||
|
mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n"
|
||||||
|
"Content-Type: text/event-stream\r\n"
|
||||||
|
"Cache-Control: no-cache\r\n\r\n");
|
||||||
|
return MG_MORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (host != NULL && strstr(host, "cesanta") != NULL) {
|
||||||
|
return try_to_serve_locally(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable man-in-the-middle SSL mode for oracle.com
|
||||||
|
if (!strcmp(conn->request_method, "CONNECT") &&
|
||||||
|
!strcmp(host, "oracle.com")) {
|
||||||
|
mg_terminate_ssl(conn, "ssl_cert.pem"); // MUST return MG_MORE after
|
||||||
|
return MG_MORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MG_FALSE;
|
||||||
|
case MG_AUTH:
|
||||||
|
return MG_TRUE;
|
||||||
|
default:
|
||||||
|
return MG_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setopt(struct mg_server *s, const char *opt, const char *val) {
|
||||||
|
const char *err_msg = mg_set_option(s, opt, val);
|
||||||
|
if (err_msg != NULL) {
|
||||||
|
elog(1, "Error setting [%s]: [%s]", opt, err_msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
const char *port = "2014", *dump = NULL, *root = "proxy_web_root";
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Parse command line options
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
if (strcmp(argv[i], "-port") == 0 && i + 1 < argc) {
|
||||||
|
port = argv[++i];
|
||||||
|
} else if (strcmp(argv[i], "-root") == 0 && i + 1 < argc) {
|
||||||
|
root = argv[++i];
|
||||||
|
} else if (strcmp(argv[i], "-dump") == 0 && i + 1 < argc) {
|
||||||
|
dump = argv[++i];
|
||||||
|
} else {
|
||||||
|
elog(1, "Usage: %s [-cert FILE] [-ca_cert FILE] [-port PORT]", argv[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signal(SIGTERM, signal_handler);
|
||||||
|
signal(SIGINT, signal_handler);
|
||||||
|
|
||||||
|
// Create and configure proxy server
|
||||||
|
s_server = mg_create_server(NULL, &proxy_event_handler);
|
||||||
|
setopt(s_server, "enable_proxy", "yes");
|
||||||
|
setopt(s_server, "document_root", root);
|
||||||
|
setopt(s_server, "listening_port", port);
|
||||||
|
setopt(s_server, "hexdump_file", dump);
|
||||||
|
|
||||||
|
// Start two SSE pushing threads
|
||||||
|
mg_start_thread(sse_pusher_thread_func, (void *) "sse_pusher_thread_1");
|
||||||
|
mg_start_thread(sse_pusher_thread_func, (void *) "sse_pusher_thread_2");
|
||||||
|
|
||||||
|
// Start serving in the main thread
|
||||||
|
printf("Starting on port %s\n", mg_get_option(s_server, "listening_port"));
|
||||||
|
while (s_received_signal == 0) {
|
||||||
|
mg_poll_server(s_server, 1000);
|
||||||
|
}
|
||||||
|
printf("Existing on signal %d\n", s_received_signal);
|
||||||
|
mg_destroy_server(&s_server);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>App1 Index</title>
|
||||||
|
<style>
|
||||||
|
img { height: 40px; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>App1 index page. Served locally from the the proxy server filesystem</h1>
|
||||||
|
|
||||||
|
<p>image that references non-existent local resource. Forwarded to
|
||||||
|
the 'real' proxy target:</p>
|
||||||
|
<img src="http://cesanta.com/images/logo.png" />
|
||||||
|
|
||||||
|
<p>Google logo via HTTPS (external resource, served by remote host):</p>
|
||||||
|
<img src="https://www.google.ie/images/srpr/logo11w.png" />
|
||||||
|
|
||||||
|
<p>Same image via HTTP:</p>
|
||||||
|
<img src="http://www.google.ie/images/srpr/logo11w.png" />
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>App2 Index</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
// Using secure websocket connection, wss://
|
||||||
|
var ws = new WebSocket('wss://echo.websocket.org');
|
||||||
|
var div = document.getElementById('events');
|
||||||
|
ws.onmessage = function(ev) {
|
||||||
|
var el = document.createElement('div');
|
||||||
|
el.innerHTML = 'websocket message: ' + ev.data;
|
||||||
|
div.appendChild(el);
|
||||||
|
// Keep only last 5 messages in the list
|
||||||
|
while (div.childNodes.length > 5) div.removeChild(div.firstChild);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send random stuff to the websocket connection periodically.
|
||||||
|
// websocket server much echo that stuff back.
|
||||||
|
window.setInterval(function() {
|
||||||
|
var d = new Date();
|
||||||
|
ws.send(d.toString());
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>App2 index page. Served locally from the
|
||||||
|
the proxy's filesystem.</h1>
|
||||||
|
<p>
|
||||||
|
Following div shows proxy forwarding of websocket connection, served by
|
||||||
|
ws://echo.websocket.org:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div id="events"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title> proxy index </title>
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.onload = function() {
|
||||||
|
var es = new EventSource("/api/sse");
|
||||||
|
var div = document.getElementById('events');
|
||||||
|
es.onmessage = function(ev) {
|
||||||
|
var el = document.createElement('div');
|
||||||
|
el.innerHTML = 'sse message: ' + ev.data;
|
||||||
|
div.appendChild(el);
|
||||||
|
// Keep only last 5 messages in the list
|
||||||
|
while (div.childNodes.length > 5) div.removeChild(div.firstChild);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1> proxy index page.</h1>
|
||||||
|
<ul>
|
||||||
|
<li><a href="app1">App1</a> - App1 root</li>
|
||||||
|
<li><a href="app2">App2</a> - App2 root</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>SSE pushes, done by separate threads at random times:</h2>
|
||||||
|
<div id="events"></div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
File renamed without changes.
@@ -0,0 +1,12 @@
|
|||||||
|
# Copyright (c) 2014 Cesanta Software
|
||||||
|
# All rights reserved
|
||||||
|
|
||||||
|
PROG = restful_api
|
||||||
|
CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
|
||||||
|
SOURCES = $(PROG).c ../../mongoose.c
|
||||||
|
|
||||||
|
$(PROG): $(SOURCES)
|
||||||
|
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>RESTful API demo</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<style type="text/css">
|
||||||
|
* { outline: none; font: 16px/1.4 Helvetica, Arial, sans-serif; }
|
||||||
|
body {
|
||||||
|
background-color: #cde; margin: 0;
|
||||||
|
padding: 0; font: 16px/1.4 Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
div.content {
|
||||||
|
width: 800px; margin: 2em auto; padding: 20px 50px;
|
||||||
|
background-color: #fff; border-radius: 1em;
|
||||||
|
}
|
||||||
|
label { display: inline-block; min-width: 7em; }
|
||||||
|
input { border: 1px solid #ccc; padding: 0.2em; }
|
||||||
|
a:link, a:visited { color: #69c; text-decoration: none; }
|
||||||
|
@media (max-width: 700px) {
|
||||||
|
body { background-color: #fff; }
|
||||||
|
div.content { width: auto; margin: 0 auto; padding: 1em; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
|
||||||
|
<script language="javascript" type="text/javascript">
|
||||||
|
jQuery(function() {
|
||||||
|
|
||||||
|
$(document).on('keyup', '#n1, #n2', function() {
|
||||||
|
$.ajax({
|
||||||
|
url: '/api/sum',
|
||||||
|
method: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
data: { n1: $('#n1').val(), n2: $('#n2').val() },
|
||||||
|
success: function(json) {
|
||||||
|
$('#result').html(json.result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="content">
|
||||||
|
<h1>RESTful API demo.</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This page demonstrates how Mongoose web server could be used to implement
|
||||||
|
RESTful APIs. Enter numbers below, and press Submit. Browser will send
|
||||||
|
two numbers to <tt>/api/sum</tt> URI, Mongoose calclulates the sum of
|
||||||
|
two and returns the result.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label>Number 1:</label> <input type="text" id="n1" />
|
||||||
|
</div><div>
|
||||||
|
<label>Number 2:</label> <input type="text" id="n2" />
|
||||||
|
</div><div>
|
||||||
|
<label>Result:</label> <span id="result"> </span>
|
||||||
|
</div><div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static const char *s_no_cache_header =
|
||||||
|
"Cache-Control: max-age=0, post-check=0, "
|
||||||
|
"pre-check=0, no-store, no-cache, must-revalidate\r\n";
|
||||||
|
|
||||||
|
static void handle_restful_call(struct mg_connection *conn) {
|
||||||
|
char n1[100], n2[100];
|
||||||
|
|
||||||
|
// Get form variables
|
||||||
|
mg_get_var(conn, "n1", n1, sizeof(n1));
|
||||||
|
mg_get_var(conn, "n2", n2, sizeof(n2));
|
||||||
|
|
||||||
|
mg_printf_data(conn, "{ \"result\": %lf }", strtod(n1, NULL) + strtod(n2, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
||||||
|
switch (ev) {
|
||||||
|
case MG_AUTH: return MG_TRUE;
|
||||||
|
case MG_REQUEST:
|
||||||
|
if (!strcmp(conn->uri, "/api/sum")) {
|
||||||
|
handle_restful_call(conn);
|
||||||
|
return MG_TRUE;
|
||||||
|
}
|
||||||
|
mg_send_file(conn, "index.html", s_no_cache_header);
|
||||||
|
return MG_MORE;
|
||||||
|
default: return MG_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_server *server;
|
||||||
|
|
||||||
|
// Create and configure the server
|
||||||
|
server = mg_create_server(NULL, ev_handler);
|
||||||
|
mg_set_option(server, "listening_port", "8000");
|
||||||
|
|
||||||
|
// Serve request. Hit Ctrl-C to terminate the program
|
||||||
|
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
|
||||||
|
for (;;) {
|
||||||
|
mg_poll_server(server, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup, and free server instance
|
||||||
|
mg_destroy_server(&server);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Copyright (c) 2014 Cesanta Software
|
||||||
|
# All rights reserved
|
||||||
|
|
||||||
|
PROG = send_file
|
||||||
|
CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
|
||||||
|
SOURCES = $(PROG).c ../../mongoose.c
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
|
||||||
|
run: $(PROG)
|
||||||
|
./$(PROG)
|
||||||
|
|
||||||
|
$(PROG): $(SOURCES) Makefile
|
||||||
|
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
|
||||||
|
|
||||||
|
win:
|
||||||
|
wine cl $(SOURCES) /MD /nologo /DNDEBUG /O1 /I../.. /Fe$(PROG).exe
|
||||||
|
wine $(PROG).exe
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib *.gc*
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// Copyright (c) 2014 Cesanta Software
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// This example demostrates how to send arbitrary files to the client.
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
||||||
|
switch (ev) {
|
||||||
|
case MG_REQUEST:
|
||||||
|
mg_send_file(conn, "send_file.c", NULL); // Also could be a dir, or CGI
|
||||||
|
return MG_MORE; // It is important to return MG_MORE after mg_send_file!
|
||||||
|
case MG_AUTH: return MG_TRUE;
|
||||||
|
default: return MG_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_server *server = mg_create_server(NULL, ev_handler);
|
||||||
|
mg_set_option(server, "listening_port", "8080");
|
||||||
|
|
||||||
|
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
|
||||||
|
for (;;) mg_poll_server(server, 1000);
|
||||||
|
mg_destroy_server(&server);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# Copyright (c) 2014 Cesanta Software
|
||||||
|
# All rights reserved
|
||||||
|
|
||||||
|
PROG = web_server
|
||||||
|
CFLAGS = -W -Wall -I../.. -pthread -g -O0 -DMONGOOSE_ENABLE_THREADS $(CFLAGS_EXTRA)
|
||||||
|
SOURCES = $(PROG).c ../../mongoose.c
|
||||||
|
OPENSSL_FLAGS = -DNS_ENABLE_SSL -lssl
|
||||||
|
|
||||||
|
# PolarSSL paths and flags
|
||||||
|
POLARSSL_PATH = /usr/local
|
||||||
|
POLARSSLCOMPAT_PATH = ./../../../polar
|
||||||
|
SOURCES_POLAR = $(SOURCES) $(POLARSSLCOMPAT_PATH)/polarssl_compat.c
|
||||||
|
INCDIR_POLAR = -I$(POLARSSLCOMPAT_PATH) -I$(POLARSSL_PATH)/include
|
||||||
|
LDFLAGS_POLAR = -L$(POLARSSL_PATH)/lib -lmbedtls
|
||||||
|
CFLAGS_POLAR = $(CFLAGS) $(INCDIR_POLAR) -DNS_ENABLE_SSL
|
||||||
|
#
|
||||||
|
|
||||||
|
$(PROG): $(SOURCES)
|
||||||
|
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
|
||||||
|
|
||||||
|
openssl:
|
||||||
|
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS) $(OPENSSL_FLAGS)
|
||||||
|
|
||||||
|
polarssl:
|
||||||
|
$(CC) -o $(PROG) $(SOURCES_POLAR) $(LDFLAGS_POLAR) $(CFLAGS_POLAR)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC+zCCAeOgAwIBAgIJAPhB8jbL+G82MA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
|
||||||
|
BAMMCTEyNy4wLjAuMTAeFw0xNTAzMDYxMjQzMzNaFw0yNTAzMDMxMjQzMzNaMBQx
|
||||||
|
EjAQBgNVBAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||||
|
ggEBALi3b3daMgzUEROKob1Caf68i+//cTRkPdBJv2cOBak21CdQzY0Nvx73GLzf
|
||||||
|
5TKB347BCHNbYRKGJXDbYdmFp20/WeBHkY7RS3Ad2Q5lzyx66u9PxNx7hJIiqBgF
|
||||||
|
58VU+E3o/I+o8QNIoOT+wtCiq3Nwkp+zGBJmS32rzMEV9bcKxSzMrkfRhF+XAREd
|
||||||
|
DwM9vfPg6WRb/b+vv06uvVwcw390RprLautGfBdaRddVYkIAKJGRRTqZAvTRFW1J
|
||||||
|
FcIVOxlN+iA7qP7xjr3tUP78qMmlu0MXsHrUR2cgfveZK2sdUW5G804yHsU5sC8l
|
||||||
|
FbtLKMEOyLsk2bEIScOXgum7g2sCAwEAAaNQME4wHQYDVR0OBBYEFHtLzUqAsXkH
|
||||||
|
Il8S5sMhJuVhRJLdMB8GA1UdIwQYMBaAFHtLzUqAsXkHIl8S5sMhJuVhRJLdMAwG
|
||||||
|
A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAEzHc0AOr+qs0OFvWMfcSMi7
|
||||||
|
O/aYlLS6f7Sos+lli69+61EcmCTJVarVeAVUsAoqmzBKDbeOpAK1hGX6/GGcXjR2
|
||||||
|
BmuU0hUKyX9l1lwdMKU45BayH/riElwnvAyj2GxKoPpdIjlHns4SAITOCUx9NfpM
|
||||||
|
agd7kjolton0ZQ5DI/2a43PkqHv1lY4Dp60wJlxit9U68bsGOycCJ/BsAyrPROb2
|
||||||
|
D1MkpMBIdfHc8uxRywM3/l9buFX8yrrMUGOYKgfjDwdzbj0iwIixoGpHL7IfeBtu
|
||||||
|
dvGO/g2rEhbtAP+xIgOR3GvzqjZh30er3no7zjDMn65tTME18Aq3tBQY7vPDKms=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC4t293WjIM1BET
|
||||||
|
iqG9Qmn+vIvv/3E0ZD3QSb9nDgWpNtQnUM2NDb8e9xi83+Uygd+OwQhzW2EShiVw
|
||||||
|
22HZhadtP1ngR5GO0UtwHdkOZc8seurvT8Tce4SSIqgYBefFVPhN6PyPqPEDSKDk
|
||||||
|
/sLQoqtzcJKfsxgSZkt9q8zBFfW3CsUszK5H0YRflwERHQ8DPb3z4OlkW/2/r79O
|
||||||
|
rr1cHMN/dEaay2rrRnwXWkXXVWJCACiRkUU6mQL00RVtSRXCFTsZTfogO6j+8Y69
|
||||||
|
7VD+/KjJpbtDF7B61EdnIH73mStrHVFuRvNOMh7FObAvJRW7SyjBDsi7JNmxCEnD
|
||||||
|
l4Lpu4NrAgMBAAECggEAaFuqbAHXOQwuwZ2XFzgIblTTsrncmT7w9VZU/sIbTKif
|
||||||
|
X771AnX7vmDX5w2PjeN2DE7emV3NEAwd5w7qz1wFZWFfQ6jrgYaZWjRixxGZ5IVl
|
||||||
|
aeLlU7OtCGrwEPJ1KTWCO3IgDoHh+Hr1+6o7Imhk+QlmrTcfqHWGvO9s9MGVWt2S
|
||||||
|
RLAnSTFiOe5brdJnmlqq1sKZmnLmpydBaPUOYpZGAgRasrjdMZB+lZOazd1x23/5
|
||||||
|
GAcm0rDREMnO9b2Jt+TNEZHT6d5KpVoExztZEZj8QCLXoic/SpFIqHGtpNlQXa+d
|
||||||
|
BVqgQbIYjO8ldldxZ8YIyJDVF+9e/uBBwu6jBIIsEQKBgQDspEHCyyuh4LG+7BbZ
|
||||||
|
eXlsfCxPTM6K9w31ZwHAwRtAuGqrOrE+pFJG9CEsFZbAI1aOGmZZdjexuSMcOlXl
|
||||||
|
TIVJTQHoFtoGEsanYEXO4O1t02Ab/DCYSpXusXUraRBRPpsTC77Sh5mxLUNd23d9
|
||||||
|
NhnDBuwChAmC+IYexjkXeqPYFwKBgQDH08PEd+2PVo4MD8UVKUlEcgoyCr6ESiyp
|
||||||
|
HfYyhhfd5x3DbZLoKCkunDfBs/hakQk8DA2nn4tl4ZjfmzXmX0EBx+E5YTdYshW7
|
||||||
|
ZcjN5x64B5PEOAR/NZA6agNlp3XGXXXgX+gnN6pgE49eVU22nZ4G+QBKD6NcCviB
|
||||||
|
LBPUxMbvzQKBgHgZYRqonGtaqzsXfP1AjmSFnMNeWtDiU95BOf2Gw/sT3WcrsXr2
|
||||||
|
UJ+cFR3XkxvOk4YpVdp/igKT0ILqBGAMdvTdtWMB/gLpEpMt5B/7veRoS7XIRy1z
|
||||||
|
ZSawP6QZfWOOX4vKAT29/j2SmEcRNFKC245EfBFGy8EBuqfxuFX3MyJfAoGBAJ0y
|
||||||
|
tjsErVmpma1baosvI3g4zlR3p1CimWehLmCopHXorr1iocMIdP0535L+ZU258y3N
|
||||||
|
vaA0HpFTW9PsYgaMwLMJ7uAY3lVkIzx84e849i2HqHMgLkl0dbW+WFXL2xblxylv
|
||||||
|
yU2wuNNED/EB4lTawcpycAvTKYvrBXt4lVE4S9exAoGAGl6vZV3zyw4jpIw4uDfk
|
||||||
|
LTPYUrghFDDGKExyeOnC/W9pqR2veqzfBz02C3jqwhewoqgAcnNc2sg0rJmM+6Oz
|
||||||
|
Z2mmGZTHO9xR++7+W7e8AkQBbS6TB8a+7yNcM4USLP+b9sX5N+8gFhFs9tG7j/no
|
||||||
|
G44qLsJ/yve7/QsOA37uEMs=
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
@@ -1,480 +1,488 @@
|
|||||||
// Copyright (c) 2004-2013 Sergey Lyubka
|
// Copyright (c) 2004-2013 Sergey Lyubka
|
||||||
// Copyright (c) 2013-2014 Cesanta Software Limited
|
// Copyright (c) 2013-2014 Cesanta Software Limited
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
#undef UNICODE // Use ANSI WinAPI functions
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
#undef _UNICODE // Use multibyte encoding on Windows
|
||||||
// in the Software without restriction, including without limitation the rights
|
#define _MBCS // Use multibyte encoding on Windows
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
#define _WIN32_WINNT 0x500 // Enable MIIM_BITMAP
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005
|
||||||
// furnished to do so, subject to the following conditions:
|
#define _XOPEN_SOURCE 600 // For PATH_MAX on linux
|
||||||
//
|
#undef WIN32_LEAN_AND_MEAN // Let windows.h always include winsock2.h
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
#include <sys/stat.h>
|
||||||
//
|
#include <stdio.h>
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
#include <stdlib.h>
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
#include <signal.h>
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
#include <string.h>
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
#include <errno.h>
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
#include <limits.h>
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
#include <stddef.h>
|
||||||
// THE SOFTWARE.
|
#include <stdarg.h>
|
||||||
|
#include <ctype.h>
|
||||||
#undef UNICODE // Use ANSI WinAPI functions
|
#include <time.h>
|
||||||
#undef _UNICODE // Use multibyte encoding on Windows
|
|
||||||
#define _MBCS // Use multibyte encoding on Windows
|
#include "mongoose.h"
|
||||||
#define _WIN32_WINNT 0x500 // Enable MIIM_BITMAP
|
|
||||||
#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005
|
#ifdef _WIN32
|
||||||
#define _XOPEN_SOURCE 600 // For PATH_MAX on linux
|
#include <windows.h>
|
||||||
|
#include <direct.h> // For chdir()
|
||||||
#include <sys/stat.h>
|
#include <winsvc.h>
|
||||||
#include <stdio.h>
|
#include <shlobj.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <signal.h>
|
#ifndef PATH_MAX
|
||||||
#include <string.h>
|
#define PATH_MAX MAX_PATH
|
||||||
#include <errno.h>
|
#endif
|
||||||
#include <limits.h>
|
|
||||||
#include <stddef.h>
|
#ifndef S_ISDIR
|
||||||
#include <stdarg.h>
|
#define S_ISDIR(x) ((x) & _S_IFDIR)
|
||||||
#include <ctype.h>
|
#endif
|
||||||
|
|
||||||
#include "mongoose.h"
|
#define DIRSEP '\\'
|
||||||
|
#define snprintf _snprintf
|
||||||
#ifdef _WIN32
|
#define vsnprintf _vsnprintf
|
||||||
#include <windows.h>
|
#define sleep(x) Sleep((x) * 1000)
|
||||||
#include <direct.h> // For chdir()
|
#define abs_path(rel, abs, abs_size) _fullpath((abs), (rel), (abs_size))
|
||||||
#include <winsvc.h>
|
#define SIGCHLD 0
|
||||||
#include <shlobj.h>
|
typedef struct _stat file_stat_t;
|
||||||
|
#define stat(x, y) _stat((x), (y))
|
||||||
#ifndef PATH_MAX
|
#else
|
||||||
#define PATH_MAX MAX_PATH
|
typedef struct stat file_stat_t;
|
||||||
#endif
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
#ifndef S_ISDIR
|
|
||||||
#define S_ISDIR(x) ((x) & _S_IFDIR)
|
#ifdef IOS
|
||||||
#endif
|
#include <ifaddrs.h>
|
||||||
|
#endif
|
||||||
#define DIRSEP '\\'
|
|
||||||
#define snprintf _snprintf
|
#define DIRSEP '/'
|
||||||
#define vsnprintf _vsnprintf
|
#define __cdecl
|
||||||
#define sleep(x) Sleep((x) * 1000)
|
#define abs_path(rel, abs, abs_size) realpath((rel), (abs))
|
||||||
#define abs_path(rel, abs, abs_size) _fullpath((abs), (rel), (abs_size))
|
#endif // _WIN32
|
||||||
#define SIGCHLD 0
|
|
||||||
typedef struct _stat file_stat_t;
|
#define MAX_OPTIONS 100
|
||||||
#define stat(x, y) _stat((x), (y))
|
#define MAX_CONF_FILE_LINE_SIZE (8 * 1024)
|
||||||
#else
|
|
||||||
typedef struct stat file_stat_t;
|
#ifndef MVER
|
||||||
#include <sys/wait.h>
|
#define MVER MONGOOSE_VERSION
|
||||||
#include <unistd.h>
|
#endif
|
||||||
#define DIRSEP '/'
|
|
||||||
#define __cdecl
|
static int exit_flag;
|
||||||
#define abs_path(rel, abs, abs_size) realpath((rel), (abs))
|
static char server_name[50]; // Set by init_server_name()
|
||||||
#endif // _WIN32
|
static char s_config_file[PATH_MAX]; // Set by process_command_line_arguments
|
||||||
|
static struct mg_server *server; // Set by start_mongoose()
|
||||||
#define MAX_OPTIONS 100
|
static const char *s_default_document_root = ".";
|
||||||
#define MAX_CONF_FILE_LINE_SIZE (8 * 1024)
|
static const char *s_default_listening_port = "8080";
|
||||||
|
static char **s_argv = { NULL };
|
||||||
static int exit_flag;
|
|
||||||
static char server_name[50]; // Set by init_server_name()
|
static void set_options(char *argv[]);
|
||||||
static char config_file[PATH_MAX]; // Set by process_command_line_arguments()
|
|
||||||
static struct mg_server *server; // Set by start_mongoose()
|
#if !defined(CONFIG_FILE)
|
||||||
static const char *s_default_document_root = ".";
|
#define CONFIG_FILE "mongoose.conf"
|
||||||
static const char *s_default_listening_port = "8080";
|
#endif /* !CONFIG_FILE */
|
||||||
|
|
||||||
#if !defined(CONFIG_FILE)
|
static void __cdecl signal_handler(int sig_num) {
|
||||||
#define CONFIG_FILE "mongoose.conf"
|
// Reinstantiate signal handler
|
||||||
#endif /* !CONFIG_FILE */
|
signal(sig_num, signal_handler);
|
||||||
|
|
||||||
static void __cdecl signal_handler(int sig_num) {
|
#ifndef _WIN32
|
||||||
// Reinstantiate signal handler
|
// Do not do the trick with ignoring SIGCHLD, cause not all OSes (e.g. QNX)
|
||||||
signal(sig_num, signal_handler);
|
// reap zombies if SIGCHLD is ignored. On QNX, for example, waitpid()
|
||||||
|
// fails if SIGCHLD is ignored, making system() non-functional.
|
||||||
#ifndef _WIN32
|
if (sig_num == SIGCHLD) {
|
||||||
// Do not do the trick with ignoring SIGCHLD, cause not all OSes (e.g. QNX)
|
do {} while (waitpid(-1, &sig_num, WNOHANG) > 0);
|
||||||
// reap zombies if SIGCHLD is ignored. On QNX, for example, waitpid()
|
} else
|
||||||
// fails if SIGCHLD is ignored, making system() non-functional.
|
#endif
|
||||||
if (sig_num == SIGCHLD) {
|
{ exit_flag = sig_num; }
|
||||||
do {} while (waitpid(-1, &sig_num, WNOHANG) > 0);
|
}
|
||||||
} else
|
|
||||||
#endif
|
static void vnotify(const char *fmt, va_list ap, int must_exit) {
|
||||||
{ exit_flag = sig_num; }
|
vfprintf(stderr, fmt, ap);
|
||||||
}
|
fputc('\n', stderr);
|
||||||
|
if (must_exit) {
|
||||||
static void vnotify(const char *fmt, va_list ap, int must_exit) {
|
exit(EXIT_FAILURE);
|
||||||
char msg[200];
|
}
|
||||||
|
}
|
||||||
vsnprintf(msg, sizeof(msg), fmt, ap);
|
|
||||||
fprintf(stderr, "%s\n", msg);
|
static void notify(const char *fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
if (must_exit) {
|
va_start(ap, fmt);
|
||||||
exit(EXIT_FAILURE);
|
vnotify(fmt, ap, 0);
|
||||||
}
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void notify(const char *fmt, ...) {
|
static void die(const char *fmt, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vnotify(fmt, ap, 0);
|
vnotify(fmt, ap, 1);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void die(const char *fmt, ...) {
|
static void show_usage_and_exit(void) {
|
||||||
va_list ap;
|
const char **names;
|
||||||
va_start(ap, fmt);
|
int i;
|
||||||
vnotify(fmt, ap, 1);
|
|
||||||
va_end(ap);
|
fprintf(stderr, "Mongoose version %s (c) Sergey Lyubka, built on %s\n",
|
||||||
}
|
MVER, __DATE__);
|
||||||
|
fprintf(stderr, "Usage:\n");
|
||||||
static void show_usage_and_exit(void) {
|
#if !defined(MONGOOSE_NO_AUTH) && !defined(MONGOOSE_NO_FILESYSTEM)
|
||||||
const char **names;
|
fprintf(stderr, " mongoose -A <htpasswd_file> <realm> <user> <passwd>\n");
|
||||||
int i;
|
#endif
|
||||||
|
fprintf(stderr, " mongoose [config_file]\n");
|
||||||
fprintf(stderr, "Mongoose version %s (c) Sergey Lyubka, built on %s\n",
|
fprintf(stderr, " mongoose [-option value ...]\n");
|
||||||
MONGOOSE_VERSION, __DATE__);
|
fprintf(stderr, "\nOPTIONS:\n");
|
||||||
fprintf(stderr, "Usage:\n");
|
|
||||||
#ifndef MONGOOSE_NO_AUTH
|
names = mg_get_valid_option_names();
|
||||||
fprintf(stderr, " mongoose -A <htpasswd_file> <realm> <user> <passwd>\n");
|
for (i = 0; names[i] != NULL; i += 2) {
|
||||||
#endif
|
fprintf(stderr, " -%s %s\n",
|
||||||
fprintf(stderr, " mongoose [config_file]\n");
|
names[i], names[i + 1] == NULL ? "<empty>" : names[i + 1]);
|
||||||
fprintf(stderr, " mongoose [-option value ...]\n");
|
}
|
||||||
fprintf(stderr, "\nOPTIONS:\n");
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
names = mg_get_valid_option_names();
|
|
||||||
for (i = 0; names[i] != NULL; i += 2) {
|
#define EV_HANDLER NULL
|
||||||
fprintf(stderr, " -%s %s\n",
|
|
||||||
names[i], names[i + 1] == NULL ? "<empty>" : names[i + 1]);
|
static char *sdup(const char *str) {
|
||||||
}
|
char *p;
|
||||||
exit(EXIT_FAILURE);
|
if ((p = (char *) malloc(strlen(str) + 1)) != NULL) {
|
||||||
}
|
strcpy(p, str);
|
||||||
|
}
|
||||||
static char *sdup(const char *str) {
|
return p;
|
||||||
char *p;
|
}
|
||||||
if ((p = (char *) malloc(strlen(str) + 1)) != NULL) {
|
|
||||||
strcpy(p, str);
|
static void set_option(char **options, const char *name, const char *value) {
|
||||||
}
|
int i;
|
||||||
return p;
|
|
||||||
}
|
for (i = 0; i < MAX_OPTIONS - 3; i++) {
|
||||||
|
if (options[i] == NULL) {
|
||||||
static void set_option(char **options, const char *name, const char *value) {
|
options[i] = sdup(name);
|
||||||
int i;
|
options[i + 1] = sdup(value);
|
||||||
|
options[i + 2] = NULL;
|
||||||
for (i = 0; i < MAX_OPTIONS - 3; i++) {
|
break;
|
||||||
if (options[i] == NULL) {
|
} else if (!strcmp(options[i], name)) {
|
||||||
options[i] = sdup(name);
|
free(options[i + 1]);
|
||||||
options[i + 1] = sdup(value);
|
options[i + 1] = sdup(value);
|
||||||
options[i + 2] = NULL;
|
break;
|
||||||
break;
|
}
|
||||||
} else if (!strcmp(options[i], name)) {
|
}
|
||||||
free(options[i + 1]);
|
|
||||||
options[i + 1] = sdup(value);
|
if (i == MAX_OPTIONS - 3) {
|
||||||
break;
|
die("%s", "Too many options specified");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == MAX_OPTIONS - 3) {
|
static void process_command_line_arguments(char *argv[], char **options) {
|
||||||
die("%s", "Too many options specified");
|
char line[MAX_CONF_FILE_LINE_SIZE], opt[sizeof(line)], val[sizeof(line)],
|
||||||
}
|
*p, cpath[PATH_MAX];
|
||||||
}
|
FILE *fp = NULL;
|
||||||
|
size_t i, cmd_line_opts_start = 1, line_no = 0;
|
||||||
static void process_command_line_arguments(char *argv[], char **options) {
|
|
||||||
char line[MAX_CONF_FILE_LINE_SIZE], opt[sizeof(line)], val[sizeof(line)], *p;
|
// Should we use a config file ?
|
||||||
FILE *fp = NULL;
|
if (argv[1] != NULL && argv[1][0] != '-') {
|
||||||
size_t i, cmd_line_opts_start = 1, line_no = 0;
|
snprintf(cpath, sizeof(cpath), "%s", argv[1]);
|
||||||
|
cmd_line_opts_start = 2;
|
||||||
// Should we use a config file ?
|
} else if ((p = strrchr(argv[0], DIRSEP)) == NULL) {
|
||||||
if (argv[1] != NULL && argv[1][0] != '-') {
|
// No command line flags specified. Look where binary lives
|
||||||
snprintf(config_file, sizeof(config_file), "%s", argv[1]);
|
snprintf(cpath, sizeof(cpath), "%s", CONFIG_FILE);
|
||||||
cmd_line_opts_start = 2;
|
} else {
|
||||||
} else if ((p = strrchr(argv[0], DIRSEP)) == NULL) {
|
snprintf(cpath, sizeof(cpath), "%.*s%c%s",
|
||||||
// No command line flags specified. Look where binary lives
|
(int) (p - argv[0]), argv[0], DIRSEP, CONFIG_FILE);
|
||||||
snprintf(config_file, sizeof(config_file), "%s", CONFIG_FILE);
|
}
|
||||||
} else {
|
abs_path(cpath, s_config_file, sizeof(s_config_file));
|
||||||
snprintf(config_file, sizeof(config_file), "%.*s%c%s",
|
|
||||||
(int) (p - argv[0]), argv[0], DIRSEP, CONFIG_FILE);
|
fp = fopen(s_config_file, "r");
|
||||||
}
|
|
||||||
|
// If config file was set in command line and open failed, die
|
||||||
fp = fopen(config_file, "r");
|
if (cmd_line_opts_start == 2 && fp == NULL) {
|
||||||
|
die("Cannot open config file %s: %s", s_config_file, strerror(errno));
|
||||||
// If config file was set in command line and open failed, die
|
}
|
||||||
if (cmd_line_opts_start == 2 && fp == NULL) {
|
|
||||||
die("Cannot open config file %s: %s", config_file, strerror(errno));
|
// Load config file settings first
|
||||||
}
|
if (fp != NULL) {
|
||||||
|
fprintf(stderr, "Loading config file %s\n", s_config_file);
|
||||||
// Load config file settings first
|
|
||||||
if (fp != NULL) {
|
// Loop over the lines in config file
|
||||||
fprintf(stderr, "Loading config file %s\n", config_file);
|
while (fgets(line, sizeof(line), fp) != NULL) {
|
||||||
|
line_no++;
|
||||||
// Loop over the lines in config file
|
|
||||||
while (fgets(line, sizeof(line), fp) != NULL) {
|
// Ignore empty lines and comments
|
||||||
line_no++;
|
for (i = 0; isspace(* (unsigned char *) &line[i]); ) i++;
|
||||||
|
if (line[i] == '#' || line[i] == '\0') {
|
||||||
// Ignore empty lines and comments
|
continue;
|
||||||
for (i = 0; isspace(* (unsigned char *) &line[i]); ) i++;
|
}
|
||||||
if (line[i] == '#' || line[i] == '\0') {
|
|
||||||
continue;
|
if (sscanf(line, "%s %[^\r\n#]", opt, val) != 2) {
|
||||||
}
|
printf("%s: line %d is invalid, ignoring it:\n %s",
|
||||||
|
s_config_file, (int) line_no, line);
|
||||||
if (sscanf(line, "%s %[^\r\n#]", opt, val) != 2) {
|
} else {
|
||||||
printf("%s: line %d is invalid, ignoring it:\n %s",
|
set_option(options, opt, val);
|
||||||
config_file, (int) line_no, line);
|
}
|
||||||
} else {
|
}
|
||||||
set_option(options, opt, val);
|
|
||||||
}
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
// If we're under MacOS and started by launchd, then the second
|
||||||
}
|
// argument is process serial number, -psn_.....
|
||||||
|
// In this case, don't process arguments at all.
|
||||||
// If we're under MacOS and started by launchd, then the second
|
if (argv[1] == NULL || memcmp(argv[1], "-psn_", 5) != 0) {
|
||||||
// argument is process serial number, -psn_.....
|
// Handle command line flags.
|
||||||
// In this case, don't process arguments at all.
|
// They override config file and default settings.
|
||||||
if (argv[1] == NULL || memcmp(argv[1], "-psn_", 5) != 0) {
|
for (i = cmd_line_opts_start; argv[i] != NULL; i += 2) {
|
||||||
// Handle command line flags.
|
if (argv[i][0] != '-' || argv[i + 1] == NULL) {
|
||||||
// They override config file and default settings.
|
show_usage_and_exit();
|
||||||
for (i = cmd_line_opts_start; argv[i] != NULL; i += 2) {
|
}
|
||||||
if (argv[i][0] != '-' || argv[i + 1] == NULL) {
|
set_option(options, &argv[i][1], argv[i + 1]);
|
||||||
show_usage_and_exit();
|
}
|
||||||
}
|
}
|
||||||
set_option(options, &argv[i][1], argv[i + 1]);
|
}
|
||||||
}
|
|
||||||
}
|
static void init_server_name(void) {
|
||||||
}
|
const char *descr = "";
|
||||||
|
snprintf(server_name, sizeof(server_name), "Mongoose web server v.%s%s",
|
||||||
static void init_server_name(void) {
|
MVER, descr);
|
||||||
const char *descr = "";
|
}
|
||||||
snprintf(server_name, sizeof(server_name), "Mongoose web server v.%s%s",
|
|
||||||
MONGOOSE_VERSION, descr);
|
static int is_path_absolute(const char *path) {
|
||||||
}
|
#ifdef _WIN32
|
||||||
|
return path != NULL &&
|
||||||
static int is_path_absolute(const char *path) {
|
((path[0] == '\\' && path[1] == '\\') || // UNC path, e.g. \\server\dir
|
||||||
#ifdef _WIN32
|
(isalpha(path[0]) && path[1] == ':' && path[2] == '\\')); // E.g. X:\dir
|
||||||
return path != NULL &&
|
#else
|
||||||
((path[0] == '\\' && path[1] == '\\') || // UNC path, e.g. \\server\dir
|
return path != NULL && path[0] == '/';
|
||||||
(isalpha(path[0]) && path[1] == ':' && path[2] == '\\')); // E.g. X:\dir
|
#endif
|
||||||
#else
|
}
|
||||||
return path != NULL && path[0] == '/';
|
|
||||||
#endif
|
static char *get_option(char **options, const char *option_name) {
|
||||||
}
|
int i;
|
||||||
|
|
||||||
static char *get_option(char **options, const char *option_name) {
|
for (i = 0; options[i] != NULL; i++)
|
||||||
int i;
|
if (!strcmp(options[i], option_name))
|
||||||
|
return options[i + 1];
|
||||||
for (i = 0; options[i] != NULL; i++)
|
|
||||||
if (!strcmp(options[i], option_name))
|
return NULL;
|
||||||
return options[i + 1];
|
}
|
||||||
|
|
||||||
return NULL;
|
static void *serving_thread_func(void *param) {
|
||||||
}
|
struct mg_server *srv = (struct mg_server *) param;
|
||||||
|
while (exit_flag == 0) {
|
||||||
static int path_exists(const char *path, int is_dir) {
|
mg_poll_server(srv, 1000);
|
||||||
file_stat_t st;
|
}
|
||||||
return path == NULL || (stat(path, &st) == 0 &&
|
return NULL;
|
||||||
((S_ISDIR(st.st_mode) ? 1 : 0) == is_dir));
|
}
|
||||||
}
|
|
||||||
|
static int path_exists(const char *path, int is_dir) {
|
||||||
static void verify_existence(char **options, const char *name, int is_dir) {
|
file_stat_t st;
|
||||||
const char *path = get_option(options, name);
|
return path == NULL || (stat(path, &st) == 0 &&
|
||||||
if (!path_exists(path, is_dir)) {
|
((S_ISDIR(st.st_mode) ? 1 : 0) == is_dir));
|
||||||
notify("Invalid path for %s: [%s]: (%s). Make sure that path is either "
|
}
|
||||||
"absolute, or it is relative to mongoose executable.",
|
|
||||||
name, path, strerror(errno));
|
static void verify_existence(char **options, const char *name, int is_dir) {
|
||||||
}
|
const char *path = get_option(options, name);
|
||||||
}
|
if (!path_exists(path, is_dir)) {
|
||||||
|
notify("Invalid path for %s: [%s]: (%s). Make sure that path is either "
|
||||||
static void set_absolute_path(char *options[], const char *option_name,
|
"absolute, or it is relative to mongoose executable.",
|
||||||
const char *path_to_mongoose_exe) {
|
name, path, strerror(errno));
|
||||||
char path[PATH_MAX], abs[PATH_MAX], *option_value;
|
}
|
||||||
const char *p;
|
}
|
||||||
|
|
||||||
// Check whether option is already set
|
static void set_absolute_path(char *options[], const char *option_name) {
|
||||||
option_value = get_option(options, option_name);
|
char path[PATH_MAX], abs[PATH_MAX], *option_value;
|
||||||
|
const char *p;
|
||||||
// If option is already set and it is an absolute path,
|
|
||||||
// leave it as it is -- it's already absolute.
|
// Check whether option is already set
|
||||||
if (option_value != NULL && !is_path_absolute(option_value)) {
|
option_value = get_option(options, option_name);
|
||||||
// Not absolute. Use the directory where mongoose executable lives
|
|
||||||
// be the relative directory for everything.
|
// If option is already set and it is an absolute path,
|
||||||
// Extract mongoose executable directory into path.
|
// leave it as it is -- it's already absolute.
|
||||||
if ((p = strrchr(path_to_mongoose_exe, DIRSEP)) == NULL) {
|
if (option_value != NULL && !is_path_absolute(option_value)) {
|
||||||
getcwd(path, sizeof(path));
|
// Not absolute. Use the directory where mongoose executable lives
|
||||||
} else {
|
// be the relative directory for everything.
|
||||||
snprintf(path, sizeof(path), "%.*s", (int) (p - path_to_mongoose_exe),
|
// Extract mongoose executable directory into path.
|
||||||
path_to_mongoose_exe);
|
if ((p = strrchr(s_config_file, DIRSEP)) == NULL) {
|
||||||
}
|
getcwd(path, sizeof(path));
|
||||||
|
} else {
|
||||||
strncat(path, "/", sizeof(path) - 1);
|
snprintf(path, sizeof(path), "%.*s", (int) (p - s_config_file),
|
||||||
strncat(path, option_value, sizeof(path) - 1);
|
s_config_file);
|
||||||
|
}
|
||||||
// Absolutize the path, and set the option
|
|
||||||
abs_path(path, abs, sizeof(abs));
|
strncat(path, "/", sizeof(path) - 1);
|
||||||
set_option(options, option_name, abs);
|
strncat(path, option_value, sizeof(path) - 1);
|
||||||
}
|
|
||||||
}
|
// Absolutize the path, and set the option
|
||||||
|
abs_path(path, abs, sizeof(abs));
|
||||||
#ifndef MONGOOSE_NO_AUTH
|
set_option(options, option_name, abs);
|
||||||
int modify_passwords_file(const char *fname, const char *domain,
|
}
|
||||||
const char *user, const char *pass) {
|
}
|
||||||
int found;
|
|
||||||
char line[512], u[512], d[512], ha1[33], tmp[PATH_MAX];
|
#if !defined(MONGOOSE_NO_AUTH) && !defined(MONGOOSE_NO_FILESYSTEM)
|
||||||
FILE *fp, *fp2;
|
int modify_passwords_file(const char *fname, const char *domain,
|
||||||
|
const char *user, const char *pass) {
|
||||||
found = 0;
|
int found;
|
||||||
fp = fp2 = NULL;
|
char line[512], u[512], d[512], ha1[33], tmp[PATH_MAX];
|
||||||
|
FILE *fp, *fp2;
|
||||||
// Regard empty password as no password - remove user record.
|
|
||||||
if (pass != NULL && pass[0] == '\0') {
|
found = 0;
|
||||||
pass = NULL;
|
fp = fp2 = NULL;
|
||||||
}
|
|
||||||
|
// Regard empty password as no password - remove user record.
|
||||||
(void) snprintf(tmp, sizeof(tmp), "%s.tmp", fname);
|
if (pass != NULL && pass[0] == '\0') {
|
||||||
|
pass = NULL;
|
||||||
// Create the file if does not exist
|
}
|
||||||
if ((fp = fopen(fname, "a+")) != NULL) {
|
|
||||||
fclose(fp);
|
(void) snprintf(tmp, sizeof(tmp), "%s.tmp", fname);
|
||||||
}
|
|
||||||
|
// Create the file if does not exist
|
||||||
// Open the given file and temporary file
|
if ((fp = fopen(fname, "a+")) != NULL) {
|
||||||
if ((fp = fopen(fname, "r")) == NULL) {
|
fclose(fp);
|
||||||
return 0;
|
}
|
||||||
} else if ((fp2 = fopen(tmp, "w+")) == NULL) {
|
|
||||||
fclose(fp);
|
// Open the given file and temporary file
|
||||||
return 0;
|
if ((fp = fopen(fname, "r")) == NULL) {
|
||||||
}
|
return 0;
|
||||||
|
} else if ((fp2 = fopen(tmp, "w+")) == NULL) {
|
||||||
// Copy the stuff to temporary file
|
fclose(fp);
|
||||||
while (fgets(line, sizeof(line), fp) != NULL) {
|
return 0;
|
||||||
if (sscanf(line, "%[^:]:%[^:]:%*s", u, d) != 2) {
|
}
|
||||||
continue;
|
|
||||||
}
|
// Copy the stuff to temporary file
|
||||||
|
while (fgets(line, sizeof(line), fp) != NULL) {
|
||||||
if (!strcmp(u, user) && !strcmp(d, domain)) {
|
if (sscanf(line, "%[^:]:%[^:]:%*s", u, d) != 2) {
|
||||||
found++;
|
continue;
|
||||||
if (pass != NULL) {
|
}
|
||||||
mg_md5(ha1, user, ":", domain, ":", pass, NULL);
|
|
||||||
fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
|
if (!strcmp(u, user) && !strcmp(d, domain)) {
|
||||||
}
|
found++;
|
||||||
} else {
|
if (pass != NULL) {
|
||||||
fprintf(fp2, "%s", line);
|
mg_md5(ha1, user, ":", domain, ":", pass, NULL);
|
||||||
}
|
fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
// If new user, just add it
|
fprintf(fp2, "%s", line);
|
||||||
if (!found && pass != NULL) {
|
}
|
||||||
mg_md5(ha1, user, ":", domain, ":", pass, NULL);
|
}
|
||||||
fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
|
|
||||||
}
|
// If new user, just add it
|
||||||
|
if (!found && pass != NULL) {
|
||||||
// Close files
|
mg_md5(ha1, user, ":", domain, ":", pass, NULL);
|
||||||
fclose(fp);
|
fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
|
||||||
fclose(fp2);
|
}
|
||||||
|
|
||||||
// Put the temp file in place of real file
|
// Close files
|
||||||
remove(fname);
|
fclose(fp);
|
||||||
rename(tmp, fname);
|
fclose(fp2);
|
||||||
|
|
||||||
return 1;
|
// Put the temp file in place of real file
|
||||||
}
|
remove(fname);
|
||||||
#endif
|
rename(tmp, fname);
|
||||||
|
|
||||||
static void start_mongoose(int argc, char *argv[]) {
|
return 1;
|
||||||
char *options[MAX_OPTIONS];
|
}
|
||||||
int i;
|
#endif
|
||||||
|
|
||||||
if ((server = mg_create_server(NULL)) == NULL) {
|
static void start_mongoose(int argc, char *argv[]) {
|
||||||
die("%s", "Failed to start Mongoose.");
|
s_argv = argv;
|
||||||
}
|
if ((server = mg_create_server(NULL, EV_HANDLER)) == NULL) {
|
||||||
|
die("%s", "Failed to start Mongoose.");
|
||||||
#ifndef MONGOOSE_NO_AUTH
|
}
|
||||||
// Edit passwords file if -A option is specified
|
|
||||||
if (argc > 1 && !strcmp(argv[1], "-A")) {
|
#if !defined(MONGOOSE_NO_AUTH) && !defined(MONGOOSE_NO_FILESYSTEM)
|
||||||
if (argc != 6) {
|
// Edit passwords file if -A option is specified
|
||||||
show_usage_and_exit();
|
if (argc > 1 && !strcmp(argv[1], "-A")) {
|
||||||
}
|
if (argc != 6) {
|
||||||
exit(modify_passwords_file(argv[2], argv[3], argv[4], argv[5]) ?
|
show_usage_and_exit();
|
||||||
EXIT_SUCCESS : EXIT_FAILURE);
|
}
|
||||||
}
|
exit(modify_passwords_file(argv[2], argv[3], argv[4], argv[5]) ?
|
||||||
#endif
|
EXIT_SUCCESS : EXIT_FAILURE);
|
||||||
|
}
|
||||||
// Show usage if -h or --help options are specified
|
#endif
|
||||||
if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
|
|
||||||
show_usage_and_exit();
|
// Show usage if -h or --help options are specified
|
||||||
}
|
if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
|
||||||
|
show_usage_and_exit();
|
||||||
options[0] = NULL;
|
}
|
||||||
set_option(options, "document_root", s_default_document_root);
|
set_options(argv);
|
||||||
set_option(options, "listening_port", s_default_listening_port);
|
}
|
||||||
|
|
||||||
// Update config based on command line arguments
|
static void set_options(char *argv[]) {
|
||||||
process_command_line_arguments(argv, options);
|
char *options[MAX_OPTIONS];
|
||||||
|
int i;
|
||||||
// Make sure we have absolute paths for files and directories
|
|
||||||
// https://github.com/valenok/mongoose/issues/181
|
options[0] = NULL;
|
||||||
set_absolute_path(options, "document_root", argv[0]);
|
set_option(options, "document_root", s_default_document_root);
|
||||||
set_absolute_path(options, "dav_auth_file", argv[0]);
|
set_option(options, "listening_port", s_default_listening_port);
|
||||||
set_absolute_path(options, "cgi_interpreter", argv[0]);
|
|
||||||
set_absolute_path(options, "access_log_file", argv[0]);
|
// Update config based on command line arguments
|
||||||
set_absolute_path(options, "global_auth_file", argv[0]);
|
process_command_line_arguments(argv, options);
|
||||||
set_absolute_path(options, "ssl_certificate", argv[0]);
|
|
||||||
|
// Make sure we have absolute paths for files and directories
|
||||||
if (!path_exists(get_option(options, "document_root"), 1)) {
|
// https://github.com/valenok/mongoose/issues/181
|
||||||
set_option(options, "document_root", s_default_document_root);
|
set_absolute_path(options, "document_root");
|
||||||
set_absolute_path(options, "document_root", argv[0]);
|
set_absolute_path(options, "dav_auth_file");
|
||||||
notify("Setting document_root to [%s]",
|
set_absolute_path(options, "cgi_interpreter");
|
||||||
mg_get_option(server, "document_root"));
|
set_absolute_path(options, "access_log_file");
|
||||||
}
|
set_absolute_path(options, "global_auth_file");
|
||||||
|
set_absolute_path(options, "ssl_certificate");
|
||||||
// Make extra verification for certain options
|
|
||||||
verify_existence(options, "document_root", 1);
|
if (!path_exists(get_option(options, "document_root"), 1)) {
|
||||||
verify_existence(options, "cgi_interpreter", 0);
|
set_option(options, "document_root", s_default_document_root);
|
||||||
verify_existence(options, "ssl_certificate", 0);
|
set_absolute_path(options, "document_root");
|
||||||
|
notify("Setting document_root to [%s]",
|
||||||
for (i = 0; options[i] != NULL; i += 2) {
|
mg_get_option(server, "document_root"));
|
||||||
const char *msg = mg_set_option(server, options[i], options[i + 1]);
|
}
|
||||||
if (msg != NULL) {
|
|
||||||
notify("Failed to set option [%s] to [%s]: %s",
|
// Make extra verification for certain options
|
||||||
options[i], options[i + 1], msg);
|
verify_existence(options, "document_root", 1);
|
||||||
if (!strcmp(options[i], "listening_port")) {
|
verify_existence(options, "cgi_interpreter", 0);
|
||||||
mg_set_option(server, "listening_port", s_default_listening_port);
|
verify_existence(options, "ssl_certificate", 0);
|
||||||
notify("Setting %s to [%s]", options[i], s_default_listening_port);
|
|
||||||
}
|
for (i = 0; options[i] != NULL; i += 2) {
|
||||||
}
|
const char *msg = mg_set_option(server, options[i], options[i + 1]);
|
||||||
free(options[i]);
|
if (msg != NULL) {
|
||||||
free(options[i + 1]);
|
notify("Failed to set option [%s] to [%s]: %s",
|
||||||
}
|
options[i], options[i + 1], msg);
|
||||||
|
if (!strcmp(options[i], "listening_port")) {
|
||||||
// Change current working directory to document root. This way,
|
mg_set_option(server, "listening_port", s_default_listening_port);
|
||||||
// scripts can use relative paths.
|
notify("Setting %s to [%s]", options[i], s_default_listening_port);
|
||||||
chdir(mg_get_option(server, "document_root"));
|
}
|
||||||
|
}
|
||||||
// Add an ability to pass listening socket to mongoose
|
free(options[i]);
|
||||||
{
|
free(options[i + 1]);
|
||||||
const char *env = getenv("MONGOOSE_LISTENING_SOCKET");
|
}
|
||||||
if (env != NULL && atoi(env) > 0 ) {
|
|
||||||
mg_set_listening_socket(server, atoi(env));
|
// Change current working directory to document root. This way,
|
||||||
}
|
// scripts can use relative paths.
|
||||||
}
|
chdir(mg_get_option(server, "document_root"));
|
||||||
|
|
||||||
// Setup signal handler: quit on Ctrl-C
|
#if 0
|
||||||
signal(SIGTERM, signal_handler);
|
// Add an ability to pass listening socket to mongoose
|
||||||
signal(SIGINT, signal_handler);
|
{
|
||||||
#ifndef _WIN32
|
const char *env = getenv("MONGOOSE_LISTENING_SOCKET");
|
||||||
signal(SIGCHLD, signal_handler);
|
if (env != NULL && atoi(env) > 0 ) {
|
||||||
#endif
|
mg_set_listening_socket(server, atoi(env));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
int main(int argc, char *argv[]) {
|
#endif
|
||||||
init_server_name();
|
|
||||||
start_mongoose(argc, argv);
|
// Setup signal handler: quit on Ctrl-C
|
||||||
printf("%s serving [%s] on port %s\n",
|
signal(SIGTERM, signal_handler);
|
||||||
server_name, mg_get_option(server, "document_root"),
|
signal(SIGINT, signal_handler);
|
||||||
mg_get_option(server, "listening_port"));
|
#ifndef _WIN32
|
||||||
fflush(stdout); // Needed, Windows terminals might not be line-buffered
|
signal(SIGCHLD, signal_handler);
|
||||||
while (exit_flag == 0) {
|
#endif
|
||||||
mg_poll_server(server, 1000);
|
}
|
||||||
}
|
|
||||||
printf("Exiting on signal %d ...", exit_flag);
|
int main(int argc, char *argv[]) {
|
||||||
fflush(stdout);
|
init_server_name();
|
||||||
mg_destroy_server(&server);
|
start_mongoose(argc, argv);
|
||||||
printf("%s\n", " done.");
|
printf("%s serving [%s] on port %s\n",
|
||||||
|
server_name, mg_get_option(server, "document_root"),
|
||||||
return EXIT_SUCCESS;
|
mg_get_option(server, "listening_port"));
|
||||||
}
|
fflush(stdout); // Needed, Windows terminals might not be line-buffered
|
||||||
|
serving_thread_func(server);
|
||||||
|
printf("Exiting on signal %d ...", exit_flag);
|
||||||
|
fflush(stdout);
|
||||||
|
mg_destroy_server(&server);
|
||||||
|
printf("%s\n", " done.");
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
#include <string.h>
|
|
||||||
#include "mongoose.h"
|
|
||||||
|
|
||||||
extern const char *find_embedded_file(const char *, size_t *);
|
|
||||||
|
|
||||||
static int iterate_callback(struct mg_connection *c) {
|
|
||||||
if (c->is_websocket) {
|
|
||||||
char buf[20];
|
|
||||||
int len = snprintf(buf, sizeof(buf), "%d", * (int *) c->connection_param);
|
|
||||||
mg_websocket_write(c, 1, buf, len);
|
|
||||||
}
|
|
||||||
return MG_REQUEST_PROCESSED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int index_html(struct mg_connection *conn) {
|
|
||||||
size_t index_size;
|
|
||||||
const char *index_html = find_embedded_file("websocket.html", &index_size);
|
|
||||||
|
|
||||||
if (conn->is_websocket) {
|
|
||||||
// This handler is called for each incoming websocket frame, one or more
|
|
||||||
// times for connection lifetime.
|
|
||||||
// Echo websocket data back to the client.
|
|
||||||
mg_websocket_write(conn, 1, conn->content, conn->content_len);
|
|
||||||
return conn->content_len == 4 && !memcmp(conn->content, "exit", 4) ?
|
|
||||||
MG_CLIENT_CLOSE : MG_CLIENT_CONTINUE;
|
|
||||||
} else {
|
|
||||||
mg_send_header(conn, "Content-Type", "text/html");
|
|
||||||
mg_send_data(conn, index_html, index_size);
|
|
||||||
return MG_REQUEST_PROCESSED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
struct mg_server *server = mg_create_server(NULL);
|
|
||||||
unsigned int current_timer = 0, last_timer = 0;
|
|
||||||
|
|
||||||
mg_set_option(server, "listening_port", "8080");
|
|
||||||
mg_set_request_handler(server, index_html);
|
|
||||||
|
|
||||||
printf("Started on port %s\n", mg_get_option(server, "listening_port"));
|
|
||||||
for (;;) {
|
|
||||||
current_timer = mg_poll_server(server, 100);
|
|
||||||
if (current_timer - last_timer > 0) {
|
|
||||||
last_timer = current_timer;
|
|
||||||
mg_iterate_over_connections(server, iterate_callback, ¤t_timer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mg_destroy_server(&server);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Copyright (c) 2014 Cesanta Software
|
||||||
|
# All rights reserved
|
||||||
|
|
||||||
|
PROG = websocket_chat
|
||||||
|
CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
|
||||||
|
SOURCES = $(PROG).c ../../mongoose.c
|
||||||
|
|
||||||
|
$(PROG): $(SOURCES)
|
||||||
|
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>WebSocket Test</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<style type="text/css">
|
||||||
|
body {
|
||||||
|
background-color: #cde; margin: 0;
|
||||||
|
padding: 0; font: 14px Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
div.content {
|
||||||
|
width: 800px; margin: 2em auto; padding: 20px 50px;
|
||||||
|
background-color: #fff; border-radius: 1em;
|
||||||
|
}
|
||||||
|
#messages {
|
||||||
|
border: 2px solid #fec; border-radius: 1em;
|
||||||
|
height: 10em; overflow: scroll; padding: 0.5em 1em;
|
||||||
|
}
|
||||||
|
a:link, a:visited { color: #69c; text-decoration: none; }
|
||||||
|
@media (max-width: 700px) {
|
||||||
|
body { background-color: #fff; }
|
||||||
|
div.content {
|
||||||
|
width: auto; margin: 0 auto; border-radius: 0;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script language="javascript" type="text/javascript">
|
||||||
|
|
||||||
|
var rooms = [];
|
||||||
|
var ws = new WebSocket('ws://' + location.host + '/ws');
|
||||||
|
|
||||||
|
if (!window.console) { window.console = { log: function() {} } };
|
||||||
|
|
||||||
|
ws.onopen = function(ev) { console.log(ev); };
|
||||||
|
ws.onerror = function(ev) { console.log(ev); };
|
||||||
|
ws.onclose = function(ev) { console.log(ev); };
|
||||||
|
ws.onmessage = function(ev) {
|
||||||
|
console.log(ev);
|
||||||
|
var m = (ev.data || '').match(/^(\S+) (.+)/);
|
||||||
|
if (m[1] == 'id') {
|
||||||
|
document.getElementById('my_id').innerText = m[2];
|
||||||
|
} else if (m[1] == 'msg') {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.innerHTML = m[2];
|
||||||
|
document.getElementById('messages').appendChild(div);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onload = function() {
|
||||||
|
document.getElementById('send_button').onclick = function(ev) {
|
||||||
|
var msg = document.getElementById('send_input').value;
|
||||||
|
ws.send('msg ' + msg);
|
||||||
|
};
|
||||||
|
document.getElementById('room_sel').onchange = function(ev) {
|
||||||
|
var roomName = this.value || '?';
|
||||||
|
ws.send('join ' + roomName);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="content">
|
||||||
|
<h1>Websocket PubSub Demonstration</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This page demonstrates how Mongoose web server could be used to implement
|
||||||
|
<a href="http://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern">
|
||||||
|
publish–subscribe pattern</a>. Open this page in several browser
|
||||||
|
windows. Each window initiates persistent
|
||||||
|
<a href="http://en.wikipedia.org/wiki/WebSocket">WebSocket</a>
|
||||||
|
connection with Mongoose, making each browser window a websocket client.
|
||||||
|
Join a room, send messages, and see messages sent by other clients.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
My ID: <b><span id="my_id"></b></span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Join room: <select id="room_sel">
|
||||||
|
<option value="">-- select room -- </option>
|
||||||
|
<option>A</option>
|
||||||
|
<option>B</option>
|
||||||
|
</select>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div id="messages">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<input type="text" id="send_input" />
|
||||||
|
<button id="send_button">Send Message</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
// Copyright (c) 2013-2014 Cesanta Software Limited
|
||||||
|
// $Date: 2014-09-09 17:07:55 UTC $
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static int s_signal_received = 0;
|
||||||
|
static struct mg_server *s_server = NULL;
|
||||||
|
|
||||||
|
// Data associated with each websocket connection
|
||||||
|
struct conn_data {
|
||||||
|
int room;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void signal_handler(int sig_num) {
|
||||||
|
signal(sig_num, signal_handler); // Reinstantiate signal handler
|
||||||
|
s_signal_received = sig_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_websocket_message(struct mg_connection *conn) {
|
||||||
|
struct conn_data *d = (struct conn_data *) conn->connection_param;
|
||||||
|
struct mg_connection *c;
|
||||||
|
|
||||||
|
printf("[%.*s]\n", (int) conn->content_len, conn->content);
|
||||||
|
if (conn->content_len > 5 && !memcmp(conn->content, "join ", 5)) {
|
||||||
|
// Client joined new room
|
||||||
|
d->room = conn->content[5];
|
||||||
|
} else if (conn->content_len > 4 && !memcmp(conn->content, "msg ", 4) &&
|
||||||
|
d->room != 0 && d->room != '?') {
|
||||||
|
// Client has sent a message. Push this message to all clients
|
||||||
|
// that are subscribed to the same room as client
|
||||||
|
for (c = mg_next(s_server, NULL); c != NULL; c = mg_next(s_server, c)) {
|
||||||
|
struct conn_data *d2 = (struct conn_data *) c->connection_param;
|
||||||
|
if (!c->is_websocket || d2->room != d->room) continue;
|
||||||
|
mg_websocket_printf(c, WEBSOCKET_OPCODE_TEXT, "msg %c %p %.*s",
|
||||||
|
(char) d->room, conn,
|
||||||
|
conn->content_len - 4, conn->content + 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
||||||
|
switch (ev) {
|
||||||
|
case MG_REQUEST:
|
||||||
|
if (conn->is_websocket) {
|
||||||
|
handle_websocket_message(conn);
|
||||||
|
return MG_TRUE;
|
||||||
|
} else {
|
||||||
|
mg_send_file(conn, "index.html", NULL); // Return MG_MORE after!
|
||||||
|
return MG_MORE;
|
||||||
|
}
|
||||||
|
case MG_WS_CONNECT:
|
||||||
|
// New websocket connection. Send connection ID back to the client.
|
||||||
|
conn->connection_param = calloc(1, sizeof(struct conn_data));
|
||||||
|
mg_websocket_printf(conn, WEBSOCKET_OPCODE_TEXT, "id %p", conn);
|
||||||
|
return MG_FALSE;
|
||||||
|
case MG_CLOSE:
|
||||||
|
free(conn->connection_param);
|
||||||
|
return MG_TRUE;
|
||||||
|
case MG_AUTH:
|
||||||
|
return MG_TRUE;
|
||||||
|
default:
|
||||||
|
return MG_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
s_server = mg_create_server(NULL, ev_handler);
|
||||||
|
mg_set_option(s_server, "listening_port", "8080");
|
||||||
|
|
||||||
|
signal(SIGTERM, signal_handler);
|
||||||
|
signal(SIGINT, signal_handler);
|
||||||
|
|
||||||
|
printf("Started on port %s\n", mg_get_option(s_server, "listening_port"));
|
||||||
|
while (s_signal_received == 0) {
|
||||||
|
mg_poll_server(s_server, 100);
|
||||||
|
}
|
||||||
|
mg_destroy_server(&s_server);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Copyright (c) 2014 Cesanta Software
|
||||||
|
# All rights reserved
|
||||||
|
|
||||||
|
PROG = websocket_echo_server
|
||||||
|
CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA)
|
||||||
|
SOURCES = $(PROG).c ../../mongoose.c
|
||||||
|
|
||||||
|
$(PROG): $(SOURCES)
|
||||||
|
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
out('<span style="color: blue;">RESPONSE: ' + ev.data + ' </span>');
|
out('<span style="color: blue;">RESPONSE: ' + ev.data + ' </span>');
|
||||||
num_messages++;
|
num_messages++;
|
||||||
}
|
}
|
||||||
if (num_messages > 15) {
|
if (num_messages > 3) {
|
||||||
websocket.send('exit');
|
websocket.send('exit');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
// Copyright (c) 2013-2014 Cesanta Software Limited
|
||||||
|
// $Date: 2014-09-09 17:07:55 UTC $
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static void push_message(struct mg_server *server, time_t current_time) {
|
||||||
|
struct mg_connection *c;
|
||||||
|
char buf[20];
|
||||||
|
int len = sprintf(buf, "%lu", (unsigned long) current_time);
|
||||||
|
|
||||||
|
// Iterate over all connections, and push current time message to websocket ones.
|
||||||
|
for (c = mg_next(server, NULL); c != NULL; c = mg_next(server, c)) {
|
||||||
|
if (c->is_websocket) {
|
||||||
|
mg_websocket_write(c, 1, buf, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int send_reply(struct mg_connection *conn) {
|
||||||
|
if (conn->is_websocket) {
|
||||||
|
// This handler is called for each incoming websocket frame, one or more
|
||||||
|
// times for connection lifetime.
|
||||||
|
// Echo websocket data back to the client.
|
||||||
|
mg_websocket_write(conn, 1, conn->content, conn->content_len);
|
||||||
|
return conn->content_len == 4 && !memcmp(conn->content, "exit", 4) ?
|
||||||
|
MG_FALSE : MG_TRUE;
|
||||||
|
} else {
|
||||||
|
mg_send_file(conn, "index.html", NULL);
|
||||||
|
return MG_MORE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
||||||
|
switch (ev) {
|
||||||
|
case MG_AUTH: return MG_TRUE;
|
||||||
|
case MG_REQUEST: return send_reply(conn);
|
||||||
|
default: return MG_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_server *server = mg_create_server(NULL, ev_handler);
|
||||||
|
time_t current_timer = 0, last_timer = time(NULL);
|
||||||
|
|
||||||
|
mg_set_option(server, "listening_port", "8080");
|
||||||
|
|
||||||
|
printf("Started on port %s\n", mg_get_option(server, "listening_port"));
|
||||||
|
for (;;) {
|
||||||
|
mg_poll_server(server, 100);
|
||||||
|
current_timer = time(NULL);
|
||||||
|
if (current_timer - last_timer > 0) {
|
||||||
|
last_timer = current_timer;
|
||||||
|
push_message(server, current_timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mg_destroy_server(&server);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Copyright (c) 2014 Cesanta Software
|
||||||
|
# All rights reserved
|
||||||
|
|
||||||
|
PROG = ws_ssl
|
||||||
|
CFLAGS = -W -Wall -I../.. -I. -pthread -g -O0 -DMONGOOSE_ENABLE_THREADS -DNS_ENABLE_SSL -DSSL_WRAPPER_USE_AS_LIBRARY $(CFLAGS_EXTRA)
|
||||||
|
LDFLAGS = -lssl
|
||||||
|
SOURCES = ws_ssl.c ../../mongoose.c ssl_wrapper.c
|
||||||
|
|
||||||
|
# PolarSSL paths and flags
|
||||||
|
POLARSSL_PATH = /usr/local
|
||||||
|
POLARSSLCOMPAT_PATH = ./../../../polar
|
||||||
|
SOURCES_POLAR = $(SOURCES) $(POLARSSLCOMPAT_PATH)/polarssl_compat.c
|
||||||
|
INCDIR_POLAR = -I$(POLARSSLCOMPAT_PATH) -I$(POLARSSL_PATH)/include
|
||||||
|
LDFLAGS_POLAR = -L$(POLARSSL_PATH)/lib -lmbedtls
|
||||||
|
CFLAGS_POLAR = $(CFLAGS) $(INCDIR_POLAR)
|
||||||
|
#
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
|
||||||
|
$(PROG): $(SOURCES)
|
||||||
|
$(CC) -o $(PROG) $(SOURCES) $(LDFLAGS) $(CFLAGS)
|
||||||
|
|
||||||
|
polarssl: $(SOURCES_POLAR)
|
||||||
|
$(CC) -o $(PROG) $(SOURCES_POLAR) $(LDFLAGS_POLAR) $(CFLAGS_POLAR)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEowIBAAKCAQEAwizPnrCx+/kPSdEeSJFLDXrBH+cSQsSLrCm99G1hCjzqSlIk
|
||||||
|
1BhkZMEHxBaiVLky4+M/nwhjwwRHI10h6U2Or3tbPLv7z94cPf+uCx1aF7TE3Fm3
|
||||||
|
6YnDk+CjrYVFN5GRPGOPPdFxGoc+vFvQJyAAimvchnS1ZoEQFvermwzOnKspA6gc
|
||||||
|
Px+7wnOeju9TyJuDr5ngtDXFnkcpkBNPxz3En4MJY4xJiaueafh9pIES2vSl7uP0
|
||||||
|
J/qot9v2rdiL7nt1H1vwseeEkZhQ+NLB5e2z4psyktJcwDX7wQ6j7JnKfHeP+ixO
|
||||||
|
TUORgV4foBMVOqo//Guo92Q5HoLNK77V0y4+ZQIDAQABAoIBAGEsx+LlDs3JQQty
|
||||||
|
KjOq8uKWElyC6bKcZkIMydGvg6b6AU6ceW3jnyqFJ/vMUAUSghNmQQq3yiVo2Kks
|
||||||
|
DLKTa9sKYwisE0NeJsgoUtOhJttCTlrwU4f+t/AjtgY68f7zTLnqIV+Ql4ftM0pU
|
||||||
|
sIFEFMExZbWsZrQb1w+Hd0wrRqNEbSOfSjHeigvuw1T3GH2tSBUTGTpcoewCzy7U
|
||||||
|
PKS5pkYyiKySQQNqZTac3NHPjxdK6xxzwURZp1irKdiPdt04KHLVLX8KXelt/J0k
|
||||||
|
AeYkVbpFIeQ9rNBerMEp6uRBt+nE5mvP+xx1XPqKRxuxbMyTnBXeOM2zS/a/dBiz
|
||||||
|
fwokwcECgYEA9RSsv9AQ/AR8tt+aPEQvjhJ5pn/YbCb1DA9IDXpaq3tzacGd8JHj
|
||||||
|
3kUtb79nosu85LvSkAYmtzgfJs6xZyUkscra6q+xlsJ12QRxLzqfxcp9Y0wsdqM4
|
||||||
|
AcOwuiPKrjkWxOQpyWPWRwbmAefLfRMekHt4Y/QY0CwhslpnsOsj3O0CgYEAytOE
|
||||||
|
8I4GBfSQfSjXwfrso++Oi75VSsl5ZeiMGihfEhYFTE8/3rEZf7nf9iFSkN3TT+7f
|
||||||
|
pFqQzddzPBZXlpVM6k1jcEjdpJizbeR8DmICpABFrZvKz1o8pQ2Yw+FYI86ih0x4
|
||||||
|
806snMNgg/RgcVijXKFrC5joJOI+DVgwWoQyMFkCgYBxt4MkiV2oIkjf7ca6GgVa
|
||||||
|
zbXGjOGV5Umkq96J6nDxyplVw/IN8xOhScX4aP6kahaep4vfKguCzjaeIh/stS5e
|
||||||
|
lLqZVKZ5Roe6B7ag7HnAI+GkVm73KWrOXse8xui/iFvJRfkhqgJ9+HR3A9/GjD2N
|
||||||
|
Ws0Uy+lLhn6oLAya6bA9TQKBgAVfZP4aRP6TY+Bs3Io+41XUWqpI+GlqvNR+PHfU
|
||||||
|
6e/ItYs37jEv78T6X3xdlZpQxfAwG6x22a8aLetBjEBo5Aiw1Bl9VKGvidE3ZDHd
|
||||||
|
VsSRXUckAVNMyJ52pb1KktMf/h4nYGzRgLEGW+Ai8QsPlgQ2ImfEPSH8/DfORjmf
|
||||||
|
ltTBAoGBAMxIZ52DrJvuxogSOfA1MoCD6a90trkXCquvi+A/fXojZ8BHmMQshvhK
|
||||||
|
rAO7SDIV1i1Nh3jQ/oFWE8KOprqrOLO6jNTyF65vh+zk7ztGsEME9FkDhHasUiXf
|
||||||
|
t5PE9KeTChHRvIa4FGCl9We9GftE5Ii77LWMOIq22pyxYbvHQFEf
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDlDCCAnygAwIBAgIJAIOoO+AapJ5WMA0GCSqGSIb3DQEBBQUAMDoxDDAKBgNV
|
||||||
|
BAMTA3dzMTEMMAoGA1UEChMDd3MxMQswCQYDVQQGEwJJRTEPMA0GA1UEBxMGRHVi
|
||||||
|
bGluMB4XDTE0MDgwMzA5MTU0NVoXDTI0MDczMTA5MTU0NVowOjEMMAoGA1UEAxMD
|
||||||
|
d3MxMQwwCgYDVQQKEwN3czExCzAJBgNVBAYTAklFMQ8wDQYDVQQHEwZEdWJsaW4w
|
||||||
|
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCLM+esLH7+Q9J0R5IkUsN
|
||||||
|
esEf5xJCxIusKb30bWEKPOpKUiTUGGRkwQfEFqJUuTLj4z+fCGPDBEcjXSHpTY6v
|
||||||
|
e1s8u/vP3hw9/64LHVoXtMTcWbfpicOT4KOthUU3kZE8Y4890XEahz68W9AnIACK
|
||||||
|
a9yGdLVmgRAW96ubDM6cqykDqBw/H7vCc56O71PIm4OvmeC0NcWeRymQE0/HPcSf
|
||||||
|
gwljjEmJq55p+H2kgRLa9KXu4/Qn+qi32/at2Ivue3UfW/Cx54SRmFD40sHl7bPi
|
||||||
|
mzKS0lzANfvBDqPsmcp8d4/6LE5NQ5GBXh+gExU6qj/8a6j3ZDkegs0rvtXTLj5l
|
||||||
|
AgMBAAGjgZwwgZkwHQYDVR0OBBYEFL54xAgtJTW6US4Mbr4QG0yKzvaxMGoGA1Ud
|
||||||
|
IwRjMGGAFL54xAgtJTW6US4Mbr4QG0yKzvaxoT6kPDA6MQwwCgYDVQQDEwN3czEx
|
||||||
|
DDAKBgNVBAoTA3dzMTELMAkGA1UEBhMCSUUxDzANBgNVBAcTBkR1YmxpboIJAIOo
|
||||||
|
O+AapJ5WMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAJz/RzMa9Wa2
|
||||||
|
eEXed7ijH1gcWtgVsVT1xZo0ksFl+QJ5Be1AJpOIe8nKdzYjxPWUkofIoaGHdMLL
|
||||||
|
Uc/udRzsXncup+0mD+Yos6Cqyo9yHq7L1HbXfKYZtBXIjWHdF2+RP8j9tHfITXYI
|
||||||
|
Pb2zsQ+A6PYpp5OLGZTDAnI2qffqsmwXFNhPfFhOANrGlOjsvy1P7JDzvymj/90m
|
||||||
|
NomlO3vjxLHOf6MvedTgCB0dRcAoUWPgbxPWifjBmGBjQjA4ukMQ58wbBQgvIoCW
|
||||||
|
obrXmLCNZIkpWTw4gMRYquY880IYK/OuFNJH/dawxx/WzuVr7IdLmbFY15zf5TUb
|
||||||
|
ZpIpwqRCysg=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpQIBAAKCAQEAwOp1RS9RnE8L5TszDPIOmpf/1pqb+ki99l/sGhqB/KZBKCuq
|
||||||
|
uoCc2VPK3PCByBE15/xJ7t691FnJfForI9DO5p2R0FPD6o357hqRsh0dJNBm0VgG
|
||||||
|
iNtLQ8lyYoE72HJbkgCAUZW4N0OBibOmvp/s3Fmr7rEjW5LmZxOtX+iULKIUZ0w6
|
||||||
|
gJlM8G5QA1SuqndN0PbPx+RZKSXZCoJj+Nboqw03nyJUexzs+lynR9ITMziUaaVM
|
||||||
|
4rzG+P6joQAnUkDNydxo/d4tj4xaioZdKxWLYEbj2BUtOlJJydotWo2wcG85ONrT
|
||||||
|
Gw0ltR1vku1hidMm2QL30uGIL5SeqyE8TqWk4QIDAQABAoIBAQCxHtKauc45MA4g
|
||||||
|
4hCGAzvLTmETnRI2YlEfAoTYlpvf5pkOE8GFyI25r4gjACJ4GO0gWG9dBF7Pt7wZ
|
||||||
|
EwRmttEvxV3aIv5OvRnKNdSs7rQSV9D+xc4CGy1oSG1f6X2TxbMzQoiN32OqQa2O
|
||||||
|
S0Z94IFs8lu8JCDtc9tcqiFVXEmnC3RvJZOShWpsCsbmh5ue1Xed0MQQ47vt7Zt7
|
||||||
|
I0cutvwSFJMsZkZUJp5+KjVNYo9TEJxVD3m2NJNJxBfBoRVHXNii3hUEHcTIdIAz
|
||||||
|
omtRwBU8AKgJirGIRo1h2ZFyubI8ScGOJWIiWMQvQqTHKiOaz3yUar1NSG+kFn0U
|
||||||
|
cj7s3FhdAoGBAOQbx8Jwhtp4iOkP6aW1nVTgiaTj4LMlyJZioFwgPFRIcA3oRHt9
|
||||||
|
5SRetmgFZNvcuNw1udfeaObKmlzxwUruprwOpihgAQWJFTtOjQNrt2gsYuX4l3W6
|
||||||
|
T46dO2W1pV+mW4A5gt0aqhLv7pCS4lpreNAqyHSPqcQWcCeiTzmp/LfDAoGBANiB
|
||||||
|
FQOTyMElR9OzKwmcGfIvnhUfJQwi5qNE3R+xXiP5x36a9HQBey5ri2lnBle0Ksr/
|
||||||
|
G+RKoflmk1eFXVHN0w35yw0dVco//WE4vOknldNEnIT85k02ld8lDTa2Q/EJZtPH
|
||||||
|
un6zeU0Q2/4SZ/GXPssEZPlpPM7WtQzztlH3+sqLAoGBAKnhppvAgi4ippQsLa4j
|
||||||
|
29BiiSAsNiQ1d3XIbfUubL+4UvuIh7gQwp6biu1dVwgHEgWuXYHPOgDn0p51zaao
|
||||||
|
pbRYlJZtKVWeChnpHkv15NnIdL8grGwZHTbxElNlPIxHsM2GB1fzi8YeumUhf0In
|
||||||
|
2AnwUum8NIq8yzo5PxeK6ZNRAoGBAIEA2Q6ankJH/nZsCbbeJq+iI+Wd+ysyGI8s
|
||||||
|
Vz2tJ9Tz3iTYG9SLlWRhfF4/nw3fMqhmPa5Xsg+zSRQbSTGXHKz1LEISOq4aVtX5
|
||||||
|
QscCaUnLVh//uRJE9iRSJX92NyGGYpjKJ5ubQSnkY9EOEpVnc2jwo2HhjPQKBzNC
|
||||||
|
fF53Dh5lAoGALwTN5uxrBZLPu4DtZkOosKkv4l+kzFoOjLJR4vA7ONBx2CSe9G7F
|
||||||
|
tSsH7lZS3b0mxBWjO90WhaSvtMWWrfqq8vrqmoTE795fYxNoLfCLK13W31aTDUsI
|
||||||
|
pQRJIL30MPvASbcFHN2MD2dXz2nQzY8C9lvtvap/krYiDKDU2L7+iP8=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC7DCCAdQCBRQHBXNHMA0GCSqGSIb3DQEBBQUAMDoxDDAKBgNVBAMTA3dzMTEM
|
||||||
|
MAoGA1UEChMDd3MxMQswCQYDVQQGEwJJRTEPMA0GA1UEBxMGRHVibGluMB4XDTE0
|
||||||
|
MDgwMzA5MTU0NVoXDTI0MDczMTA5MTU0NVowOjEMMAoGA1UEAxMDd3MxMQwwCgYD
|
||||||
|
VQQKEwN3czExCzAJBgNVBAYTAklFMQ8wDQYDVQQHEwZHYWx3YXkwggEiMA0GCSqG
|
||||||
|
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA6nVFL1GcTwvlOzMM8g6al//Wmpv6SL32
|
||||||
|
X+waGoH8pkEoK6q6gJzZU8rc8IHIETXn/Enu3r3UWcl8Wisj0M7mnZHQU8Pqjfnu
|
||||||
|
GpGyHR0k0GbRWAaI20tDyXJigTvYcluSAIBRlbg3Q4GJs6a+n+zcWavusSNbkuZn
|
||||||
|
E61f6JQsohRnTDqAmUzwblADVK6qd03Q9s/H5FkpJdkKgmP41uirDTefIlR7HOz6
|
||||||
|
XKdH0hMzOJRppUzivMb4/qOhACdSQM3J3Gj93i2PjFqKhl0rFYtgRuPYFS06UknJ
|
||||||
|
2i1ajbBwbzk42tMbDSW1HW+S7WGJ0ybZAvfS4YgvlJ6rITxOpaThAgMBAAEwDQYJ
|
||||||
|
KoZIhvcNAQEFBQADggEBABPLmq6zKOMY0WRjtBoSymq6f+vXeEwtWCfVejdG6RlG
|
||||||
|
/PTdCKNvp3OL7FDnmQQ+r5rMs4+Os4fX/g315QFKXu01rqxmFb2XVNhhaECdUWtK
|
||||||
|
QP6ZoVZviUiDjhK6a+05aerPCJpkGy/lz0W6gmj4qhuAQbobxb6UbzqTRYY+ZwGk
|
||||||
|
+SI3TAVCdmXFlxN/M9b0DbmkseRG8GGFmyRYyRb84vbV6zemFI++5ROUT9zXT7ey
|
||||||
|
nYfFJvAAk5jJhY5UP2aMlVWYYa4jUZrrPLoiBLUuRrp67EKGebCH9mgCIf8ztNJF
|
||||||
|
fpuvcz++LUeRyTlAGDefe+FyHGIwFzIfZn39D7CaRvM=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpAIBAAKCAQEAyal0BZKRYd+Wpxv4MB8LjjgXv/MxSN5oSAKThlCZ/AWG0FEP
|
||||||
|
d4nrBACT2xUxwo+xbYl3joiwL/eCPAp6QNKRGhvXVOnSIFVSjKZWbdX+toqK9pDS
|
||||||
|
QMDTL4ZJvK6pLZXknyHjEr0PxZh22F7iS1+C8HxBPj0Xgg/u5/+jPhFPPZ1d5elv
|
||||||
|
4cm/z+xy6RjFlA80aIeK7dcWssOsOIPjUNFfmoYgR63ScZIlUZj6j8VX9oX7fJID
|
||||||
|
jumGajDxgD2nBWFbHcGKin6bz/wZ+OIhXOCDdY7oKuMW4JiBwbfBtedkQuQYS11s
|
||||||
|
PRFFYDLoZH59Ivcu0c4F2tomE86qM8THsI910wIDAQABAoIBAG55FAQRfO8/C0rU
|
||||||
|
eavy9eOdOvV+hltC66G3N5X3BcQYSvhHz89OkJ6KqnT0MWRCT5KQIhzFKK++SWwW
|
||||||
|
2U41jCPfaKEtzlzEIQrH/MUC3Byn3OSiBWxPteFtEWv5ytgcKzg52iljxQYcNc7m
|
||||||
|
e9WKpzKS/zLXSM+JZvlVA9p2pRA88kUZ/EE5H+FW3kHj5eGNqX+cxUVpL0VKTiLv
|
||||||
|
aXWjYotpmDJW/Rn9wRQethm6Gdx3bvo+LEVlJRELNq8NM5H/tZIVRzudJOgzsw5v
|
||||||
|
3OQGhfKB6Eg/vqSFoZxX6ApXDxmtaSO83B0kK550bDVv4sBnOExGjKCzybt04tet
|
||||||
|
KtLPPoECgYEA5WUD+mFL99sCX6pzIyUVlxp9eUhVy5nvhoF6u3mvhay2XsZUY0wy
|
||||||
|
+/qVqYSZTvuvJ6JSXc4iVIX8u/gj7914805AwujepIF/8E0AaXLBMndzDE4ze5S5
|
||||||
|
2RHI7Cy4/3AWOcQ9wFFmUdSs7/6oAkcQtvzP40hGg3J2jAEhIdCqmbMCgYEA4Q0G
|
||||||
|
BYP9XeTdh0C+BcP9B5VUEC0jerYS8VqVqriB+9JfT3InI7K08sOG2DiQQBhAHuzL
|
||||||
|
RhCECU2a9j0+u5F5JNeY5m3IhU73Lw+lOlUkMaAO6x7JJEzhXhonE7Kv8fWygr/0
|
||||||
|
OB7yzqz+YsWdQ2VOPZ88ntlAYE65vzcaVswZY2ECgYEAr7Gt2VA6Ei0A5Wq0Yr+d
|
||||||
|
iKz2WzUG2TkelqOG8B4kTDrbNz2qFp+fERV9GWgAz9i+75lIgqZF7vzsdL96LtYv
|
||||||
|
NBLEUURwegjhh5hCb4E/7bpFOLCQh9+CdHpFrHYYfzRHIZlnPmxZ9OTyS6J85bmu
|
||||||
|
WKjLRKXvs++wUkzvJmoesDcCgYEAkTOB6xUZ5/a+J4HSGI43NylVr4owFgBbgHVd
|
||||||
|
k2SwGPXGoM+aCSJINUmKOv9jsrbyyAEntfD5/7aegLlLPGHDs82WzTWP5tLoEOkb
|
||||||
|
ReOhEpOejHy0ckNYNQrSo5bqhkZsAogu3fa52jcrejbeHJnEPWX8CtFJA9pHZeP7
|
||||||
|
jnzo9IECgYBefHg0dymSj2xxN0XmC+S5cvQu2K/NYUpatoWvHnPiQ87wIM0AWz0O
|
||||||
|
D0ghEI+Ze57NbtSrrcTE7hY/LHrAqXGAB9XNIM5g9Pp/lM+XjzKVr1FMf4xpuHf1
|
||||||
|
VJJRHrOU14CvMvKbgbPrL6B0d5yrYmeex7GxNw0ZVvtjCa502Eck+w==
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC7DCCAdQCBRQHBXNGMA0GCSqGSIb3DQEBBQUAMDoxDDAKBgNVBAMTA3dzMTEM
|
||||||
|
MAoGA1UEChMDd3MxMQswCQYDVQQGEwJJRTEPMA0GA1UEBxMGRHVibGluMB4XDTE0
|
||||||
|
MDgwMzA5MTU0NVoXDTI0MDczMTA5MTU0NVowOjEMMAoGA1UEAxMDd3MxMQwwCgYD
|
||||||
|
VQQKEwN3czExCzAJBgNVBAYTAklFMQ8wDQYDVQQHEwZHYWx3YXkwggEiMA0GCSqG
|
||||||
|
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJqXQFkpFh35anG/gwHwuOOBe/8zFI3mhI
|
||||||
|
ApOGUJn8BYbQUQ93iesEAJPbFTHCj7FtiXeOiLAv94I8CnpA0pEaG9dU6dIgVVKM
|
||||||
|
plZt1f62ior2kNJAwNMvhkm8rqktleSfIeMSvQ/FmHbYXuJLX4LwfEE+PReCD+7n
|
||||||
|
/6M+EU89nV3l6W/hyb/P7HLpGMWUDzRoh4rt1xayw6w4g+NQ0V+ahiBHrdJxkiVR
|
||||||
|
mPqPxVf2hft8kgOO6YZqMPGAPacFYVsdwYqKfpvP/Bn44iFc4IN1jugq4xbgmIHB
|
||||||
|
t8G152RC5BhLXWw9EUVgMuhkfn0i9y7RzgXa2iYTzqozxMewj3XTAgMBAAEwDQYJ
|
||||||
|
KoZIhvcNAQEFBQADggEBAE20gAykuuaCoP49GnZ/Z6ZItFry4Fl6iCWBDdEsWI9R
|
||||||
|
wRNYumeaeejdFPXfSJdTT7UlrVK1WWGLQLq+ixHRDX+V9T67ou85F92H/OxbUoPr
|
||||||
|
iz/TZAEBTC1GvTJl49lsfPl1dTWH8T4Ej2hxCUvIJrkCkI2Ov4Wwef6A26USrwBt
|
||||||
|
S/CPInjCe6qkE5E8xfTDl8k5IIgMadTPhi5sbV2piBJoN4floJPqR0hdDKbgUymn
|
||||||
|
5WNSiRkuI6UIDZwQEp+A8TmFBHbSwfTGt2Sz5iI27P8J6pFvR5eRA1k57dRUWNXC
|
||||||
|
WAU1nqteP3QAjj9L3o8IO0T62scaiJX8x01gTmVVe2I=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEowIBAAKCAQEAwXIMpHuTNsro2pxe6y1mu27md2Olhvfx26rO3maO0/stIC2z
|
||||||
|
G/xQatFDLIWzfKFYOT0iSEj252ENFDCw6aDRKpiaUFtXcMAWkNkkKntEyoEgE45k
|
||||||
|
rTrvpay0v0B+ojwjA1Jz/9v35cgvDwTs3vNFno5HhI0m2YF4ocTmeHJ6u0xRL/qy
|
||||||
|
atfKsfuVq5s5CXOYCXp3Ux6kJ1c22J0EdZMvS75SVjAZgRkqQpqt9L3e2ZBCEgUr
|
||||||
|
w0KwlERvpeJF+sJJOshXjfrDzvwL8IpPnGZLJNINFbSJMk5MFGcMyq/28pSZLB9E
|
||||||
|
Dh8vk5D5gUnxM60ONUy2nYPcYr5p1PLDiC8hfQIDAQABAoIBAB0Twpi6xn8W8vdh
|
||||||
|
R9c75NRJsDTD8q6d+GnXe+7sJY3xlG/gzqpnO8NCn0FC+57BNdystsl8xjgzW17s
|
||||||
|
jrsfZDFt7MwlXrhg90NgkFIeY1G5JRQrdDChykHx+t1AmYhTV8P5EdykuNd+RqyQ
|
||||||
|
RfahRJa3tkJTYUKSdoqCaU4zjwU2CSxltuJx24V+WoZE12EwewJ8HPg2XTnbsGE7
|
||||||
|
Fnx5s29O4ItM70CC0536AY/OgfuPix5z573VQiilqqfOQkVkKa1fHd6tGpWU+3kH
|
||||||
|
X9FnhEBf9cN9tVgmaB0sCSVVrfgqSXg1EwKHqe/+FCumuesA68Q35+/K3b+QrNiR
|
||||||
|
ka2yliECgYEA+V/4pbgG/lPYvTwWhKxGXXdJmrSPgZC0mwE+fRuYkeptbIkS0pwt
|
||||||
|
/UDTXk9nttj1f1ZJ3NgQbT/1w8jpXfsCJ8VeGzL9+ADhRKWVFRlu/nyFCMXawLEV
|
||||||
|
rot7SEr8BW/m8moHgY5lYipM3dXJPk0F+KLrN60U/aNmFUtPGW802BkCgYEAxpWy
|
||||||
|
FGL2sEQ0QaRDTcqqF5faVqw+5rVGvN+EX5o26E0QWWnoo3L2c2/5X93iBl+Fqtnm
|
||||||
|
9jSIQUC3rYOawKnZ/HcIE2ergFit/p6JaV9NiLDRtDUmSzlffEGVCj0neYFsnWp5
|
||||||
|
zcmkUyZ6fr19EmKQWfdteNBlXue32TjVlFbfUQUCgYAfMbgi0sBdNBPaqBeRBRPQ
|
||||||
|
QUm9xnRlGrrc4Oz2LWuKZS7G8uad3deK5H8MPxaUMtOS2DJpI8X6RJPzp8A5d1qv
|
||||||
|
quq4sEpAqauEMMpTV1khEGZ70HQqwnwZ12zWgDrCW1siW80QkcVw4CW5YjLITk4+
|
||||||
|
6fJOhqInkDcG1uLQJa8QkQKBgQCfs8l4DbJ4RRGFbLXXvNGXkb68j18yqLxPrq3F
|
||||||
|
OL9JiJhKYBsAP7clVPrG9ykLmQxlP0I35D1jxMkymLD+mlo9Z/itqmTJHggnyZWW
|
||||||
|
kVdIQ3MSKuA2BNjek9tpVY8Gb2hLHFMChVRKrpo6jOclvvB5+bsnOukbLtyyq7tP
|
||||||
|
xaFohQKBgByCmlltjOBWZLFLeA1x8j3inm9zM/FAJuANbHUOZ1RwrRcNFbDv/FXm
|
||||||
|
rLPnPCaH5AwAWhVRJcNHo37Ee0s/xqe+Q4dG4xL943k+6KlopAw1SXhuXF6PnBfF
|
||||||
|
y+ArVlh9d2oWN5cBEzRddnWnKJuMi70kMzYf6dIW9s/dHbq/gFDy
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDlDCCAnygAwIBAgIJAJDtcXU2wiJIMA0GCSqGSIb3DQEBBQUAMDoxDDAKBgNV
|
||||||
|
BAMTA3dzMjEMMAoGA1UEChMDd3MyMQswCQYDVQQGEwJJRTEPMA0GA1UEBxMGRHVi
|
||||||
|
bGluMB4XDTE0MDgwMzA5MTU0OFoXDTI0MDczMTA5MTU0OFowOjEMMAoGA1UEAxMD
|
||||||
|
d3MyMQwwCgYDVQQKEwN3czIxCzAJBgNVBAYTAklFMQ8wDQYDVQQHEwZEdWJsaW4w
|
||||||
|
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBcgyke5M2yujanF7rLWa7
|
||||||
|
buZ3Y6WG9/Hbqs7eZo7T+y0gLbMb/FBq0UMshbN8oVg5PSJISPbnYQ0UMLDpoNEq
|
||||||
|
mJpQW1dwwBaQ2SQqe0TKgSATjmStOu+lrLS/QH6iPCMDUnP/2/flyC8PBOze80We
|
||||||
|
jkeEjSbZgXihxOZ4cnq7TFEv+rJq18qx+5WrmzkJc5gJendTHqQnVzbYnQR1ky9L
|
||||||
|
vlJWMBmBGSpCmq30vd7ZkEISBSvDQrCURG+l4kX6wkk6yFeN+sPO/Avwik+cZksk
|
||||||
|
0g0VtIkyTkwUZwzKr/bylJksH0QOHy+TkPmBSfEzrQ41TLadg9xivmnU8sOILyF9
|
||||||
|
AgMBAAGjgZwwgZkwHQYDVR0OBBYEFLK4flD5QD/mRufsPx63xlEKM8pwMGoGA1Ud
|
||||||
|
IwRjMGGAFLK4flD5QD/mRufsPx63xlEKM8pwoT6kPDA6MQwwCgYDVQQDEwN3czIx
|
||||||
|
DDAKBgNVBAoTA3dzMjELMAkGA1UEBhMCSUUxDzANBgNVBAcTBkR1YmxpboIJAJDt
|
||||||
|
cXU2wiJIMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAEYD+CReikYr
|
||||||
|
Rzvk+/Vdi/7IcaH9CFknIdtineSIw1y98nxnbnNJqxwfNaRblbYvg6OFdUI3POuI
|
||||||
|
+rdYLCFl8z3tWqRHLkGqHSJA9xcng3jLJxz0+ctiVcekJvXaB3O6eSZjhGbmmI/s
|
||||||
|
CQhdy2zpEIVOeUq50DrSJp9CknyGu/IkaGx5GOZtkiHMrpig50CRjX1lS6qrMNYp
|
||||||
|
vB8gfuqpjsL4Ar3vg+lgMSwNWXBNHrIRPHB5VEzBEdmLFZlvueR0ooEMCklpwX/a
|
||||||
|
lFImVc6JcY1pBEkHTiTLGMpGAHG3I1aVUaWb3L+V+2ym/KNRNL5C2+1eiqql5u8m
|
||||||
|
HUaOcNC90ew=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpAIBAAKCAQEA0ucemqFwBFziVOgTgx4mZII4WnGDpA/rWAGHvUZOqy2dQ3Pz
|
||||||
|
woGKxBaVPAl5kxEosROVGa7dTuq5yFZ4XIGvwCKxF30vCmdGCytqq6MMp904jG32
|
||||||
|
KikkmjCApIMGxMO4eoBHZZxiyVvKTbg9M2CRXErwnYWhFH/qGdPnuo0CEaHJA4VK
|
||||||
|
A9incT9dpeEhU30R6ajAe/je9rCj2OMLMFSMfd51L/VYfO60zDwUNY7YVIghQZgJ
|
||||||
|
e44EVGsp1pXaqaD6o3PvGY3ohw2aZjJzlJ7MJHbKV9lft98R3pklbpBzMH849cEy
|
||||||
|
Q/51L/rlfTUgCpTy7wEZpWHQNtHfu/1rhJjpNQIDAQABAoIBAQCUNIHXG/dBuZv7
|
||||||
|
GpMLotZL7w520Co30lAJqhmfMpb5x7YpvoPffXTsUwpQBECAzqAPv7kZMT6nxF8F
|
||||||
|
n245Y5EDrd1QqlGyN9yK4Nm2/39XPygL1wITopHsIIVmFgVdpEQxIZAKoZjx8yT4
|
||||||
|
9K1dO1Eq0CbCKzOE2lbCC51eBNUdWZIMxwC6O/j/KoIkZ/HwlG2hpUuXg8x/XawA
|
||||||
|
ZJDCoTcWHCjYP10FxKVN3vAyWM2IM44o9IbsAGEOswR4gUwRsgq6Ehc1U59XUHi+
|
||||||
|
x30oda55I1/8xD+SfP/zk2dDPHkv/hq5+258GU/THsw2+AAexocvSIS/g9EppTEg
|
||||||
|
biFaDKzJAoGBAPqey10JeyiOlHbBjoSSa7lJYUjocQANFQ4ayOAgfNX72iyabrKF
|
||||||
|
p9sVAeO/nM00+DPrm2wWws03ScsPeh+9BDJMPRBUHfSNp7+F+oyj7PWHBEFHbyO9
|
||||||
|
5HnYZP+1vhdG2dYPIY2gRSFXpiGn3j0M1D0w9c7Ilm8ee3krdR4E/mw3AoGBANdu
|
||||||
|
EfS1dK3+m7sEgc2+3U32z83GpuCHeUIKGPYMLI0fIb1CPpboHU9YjOFJZH9iIIdl
|
||||||
|
00JC963O3+pqLe0XbMOmBVt9QjZfhfB+AY+JHtbPgoQVLtq9X/WvW7h3xn6S971r
|
||||||
|
Crkhqay3Cs4BzsgYDYraQCTw3oq4twR9Nuy4etfzAoGAXOsG5wWe3diO/sCggFJx
|
||||||
|
Eg88vHVBgA1ZoxMXKtGgtw1bRHI1XIblRvqw6qmeDw72fvl5dEe0DbXT7C9ezemc
|
||||||
|
ZrGRaj5lpMfoS7/2trIIJrfaQgGkGRJMZUhvmcbeJW8lUJHnlMS5HLWMaKn+YZAi
|
||||||
|
GFXQrMv9ylD44mHUWD7tvV0CgYBNctPfvvCQsQ05ofgsiKa1Jbs1hmpuJCYy2MB6
|
||||||
|
jIvjvEJ78PnhdNc8tGAJikIoDZYWN0RI+RxkDxCvDLcwGpDOkbwxVQnd1F+pwxM6
|
||||||
|
kBhXL8kDRT5QA28hO4bk/aKN1LZeEcKMJg8C+ddXkozNoOAVgDs5TKMlCh057u41
|
||||||
|
EmmPgwKBgQDOlYi7fPYOCy0yjHMxSrp2SZOS06AMWGbbCoGkjRtvuP+FmKSNB+LZ
|
||||||
|
pOSEPJgzjsRutKjneww4LpV6dViAyTcP5JoeQpokHf7UVo7yq2QH/iwF3zJwsC/S
|
||||||
|
OuVLkqpZzWuye/QCH5NOTfw27ye8jG8VcQW2QPbcbkLXLM7zg2yX7g==
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC7DCCAdQCBRQHBXNJMA0GCSqGSIb3DQEBBQUAMDoxDDAKBgNVBAMTA3dzMjEM
|
||||||
|
MAoGA1UEChMDd3MyMQswCQYDVQQGEwJJRTEPMA0GA1UEBxMGRHVibGluMB4XDTE0
|
||||||
|
MDgwMzA5MTU0OFoXDTI0MDczMTA5MTU0OFowOjEMMAoGA1UEAxMDd3MyMQwwCgYD
|
||||||
|
VQQKEwN3czIxCzAJBgNVBAYTAklFMQ8wDQYDVQQHEwZHYWx3YXkwggEiMA0GCSqG
|
||||||
|
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDS5x6aoXAEXOJU6BODHiZkgjhacYOkD+tY
|
||||||
|
AYe9Rk6rLZ1Dc/PCgYrEFpU8CXmTESixE5UZrt1O6rnIVnhcga/AIrEXfS8KZ0YL
|
||||||
|
K2qrowyn3TiMbfYqKSSaMICkgwbEw7h6gEdlnGLJW8pNuD0zYJFcSvCdhaEUf+oZ
|
||||||
|
0+e6jQIRockDhUoD2KdxP12l4SFTfRHpqMB7+N72sKPY4wswVIx93nUv9Vh87rTM
|
||||||
|
PBQ1jthUiCFBmAl7jgRUaynWldqpoPqjc+8ZjeiHDZpmMnOUnswkdspX2V+33xHe
|
||||||
|
mSVukHMwfzj1wTJD/nUv+uV9NSAKlPLvARmlYdA20d+7/WuEmOk1AgMBAAEwDQYJ
|
||||||
|
KoZIhvcNAQEFBQADggEBACCCAJypO9DFU6GeOH+FwE0JCLTypHoIwERWxNL7xfjg
|
||||||
|
rwVqIxwAEo+fJjL+QY7JbAb/eqKaXIBYkAF2lFc4iEmecXX/A3Aqw95AYi78o7HD
|
||||||
|
MwRPqJha9mxLcCWwjX8XK8pT152BvYFPNhi+6jd++rDRxKDfmNvgdUQ2/YW6a5Wv
|
||||||
|
zEmLDPUWRIuMQIEmOa2/JhlllDviMExTw51nbqYgCghycRvDACyQAuu8re7P6gcg
|
||||||
|
bXObNlfxcU/8Ph6MFI+2S9ODtQ4BHyuKd4kRNsYn8vV42a0h3bCYSGPk3kSIgxd7
|
||||||
|
XijwHT/o8E9ddH2BvDv+6Nhno9C6/MbezEOIs4nlhRk=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpQIBAAKCAQEA29iFnMf4pjty6knOt4wT0joPUlU2dGCFWxQ5Eg77Yx3Lou2a
|
||||||
|
FOzNGp7zLYH8gauOK+mgY+B9cBv8PvVtUQQKB0SKTTV8ZNKVyP3O5F2gRSJ+tHtT
|
||||||
|
FqaPfG0WPOn/f02YbOpAe6Rk+NnlJoeuBxG4uapUSq7r0mTGJQe+52y1LcMs23ID
|
||||||
|
ENBfDoUMVt5vCnF+cYK5ndeFVLyPO3JjohDH1zv3a9ECG28rtjKHLpNYFDsPJaD7
|
||||||
|
UPuyyk3hIvfPCZoJOUlEVfpLT/lM+9oCPnq9PwIp5NqYofkuc3eKooCo7N4r4IlP
|
||||||
|
Ajktaao6b0ScNwNQB3leOIdEUFSIYy8N1JszVwIDAQABAoIBAFlIvjrGG/2m9yyf
|
||||||
|
fQyeHw6p9b8CTHNHH+G1fNgQrZe7ahBpXsJQyZueIjTBLcOb4MmEwFbPvSHiu7b2
|
||||||
|
Bcd5VHlPJLvmlPZ9b8eJDJVCUOzC7aJu03fHfU6THwzuG42f/d9942JTiY5nL+FO
|
||||||
|
CSdl0xfUTRdnou53buFrG+TxCUPj13HP1HY6DAVzEIq1H4TZwIZo7KRRTIYpTB3P
|
||||||
|
6yvr9xsISLlnmfQ4tp2pApl5o+bHJEhr1VO6SAT/pSyShi79KmMMqYtyTmOMz7w6
|
||||||
|
VJkre5ybnXBDN6tfMHWqdobJ4gRWK9rqf+LIZig5XQnyzkue8k+I7aPgO4xNFh56
|
||||||
|
dkejQcECgYEA9MDCWViqpfvof+epiKzccqnIRnz1EfHdRQjiKsKGRe39+K+pyaqJ
|
||||||
|
FOOPFy3aOw6M4cFWwcdMYzKTItvzyLVhDqMzT5eup/NVqo5tPoy93XPf2qRYiTl4
|
||||||
|
2j5wvm0RVkYEONd3pk2lbfbUmn7XQXj0+AG60SvsqErF/UhIBGec/xsCgYEA5fLC
|
||||||
|
EdiiC98kr4sVaE8G854WI+aAkStqO5YXyrnsMzRsqk8KVVYE1yCC9rYyymDBYmlx
|
||||||
|
uEW+vbWqLc8PO3v4ty3o5ff303lPMWIrvKiUldjqMjS6ncWxsQjU0bygGVgOgHO7
|
||||||
|
c8rjiDH5M0JgWSREYUVFT5mW/5+Y1LVT8mYNlHUCgYEAhMSX6N23XGkFW3Twu2qB
|
||||||
|
/1Vohgw86OoaDNvfzDBPpFmQ3rlz0ijHSeSTd5BxBH5FICXACUgygNErjcphOSxj
|
||||||
|
JQyUxgVTQlo2y1mNm1O/nwS/lxx1xqK9ky4x/Kqvr+w1WBxSFI2kQr2V4OUTobma
|
||||||
|
sXpGvDcmnrhJJLd0EaefO6cCgYEA3Xw/S9tC8nZjqqYn34nHI16Q6tF54tpTf8Np
|
||||||
|
dT4x8Xw8cqqhRGMPVHsfSi1irKYXfwgbnienuqlBmtAHVv9pKF+TJfb7gXkmO2XY
|
||||||
|
xOYIAHGn2uYJHjCun9vmyYKLHv4/MaDH3Jd/I88mviXgEdyp9Js5UJua4utB1Rg3
|
||||||
|
HJMJ34UCgYEAr0PpHEBMbZXZBybNU96+jRTgkrNeJpzlnMy7et2IsRAtLjZ0mpbn
|
||||||
|
NaX8i8eO+ubweqFdhOvbh7Hd0zr7BzrYcUG1e3njhtxJE1MgWL5plnLVUbIyDAm3
|
||||||
|
iBpIHIBASNCN3sqeq+VqXvavRmeZh5O0vyLP46/kxZx0rzR/NCi9xxU=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC7DCCAdQCBRQHBXNIMA0GCSqGSIb3DQEBBQUAMDoxDDAKBgNVBAMTA3dzMjEM
|
||||||
|
MAoGA1UEChMDd3MyMQswCQYDVQQGEwJJRTEPMA0GA1UEBxMGRHVibGluMB4XDTE0
|
||||||
|
MDgwMzA5MTU0OFoXDTI0MDczMTA5MTU0OFowOjEMMAoGA1UEAxMDd3MyMQwwCgYD
|
||||||
|
VQQKEwN3czIxCzAJBgNVBAYTAklFMQ8wDQYDVQQHEwZHYWx3YXkwggEiMA0GCSqG
|
||||||
|
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDb2IWcx/imO3LqSc63jBPSOg9SVTZ0YIVb
|
||||||
|
FDkSDvtjHcui7ZoU7M0anvMtgfyBq44r6aBj4H1wG/w+9W1RBAoHRIpNNXxk0pXI
|
||||||
|
/c7kXaBFIn60e1MWpo98bRY86f9/TZhs6kB7pGT42eUmh64HEbi5qlRKruvSZMYl
|
||||||
|
B77nbLUtwyzbcgMQ0F8OhQxW3m8KcX5xgrmd14VUvI87cmOiEMfXO/dr0QIbbyu2
|
||||||
|
Mocuk1gUOw8loPtQ+7LKTeEi988Jmgk5SURV+ktP+Uz72gI+er0/Aink2pih+S5z
|
||||||
|
d4qigKjs3ivgiU8COS1pqjpvRJw3A1AHeV44h0RQVIhjLw3UmzNXAgMBAAEwDQYJ
|
||||||
|
KoZIhvcNAQEFBQADggEBALi/RmqeXGazT/WRj9+ZqdcnbcHwK5wwr2/YkpFPJ0Hf
|
||||||
|
ZDm+2vgjDdTT6cJS6fau0M5nliYdz89aQQo1j9RSRZnzlc/2YCFXyRLCOJYaINbj
|
||||||
|
1MEUAvNDGL7xTpepK9hVkXASRkbyNXERXRKFI1N+vpKu6UorT6/osEV/qM+MFJ3s
|
||||||
|
24xE8/J3J4MirVQVt6eY6Jb+tkliOPMIugr6YQlLsqJygEWATP8Qsr81XSfcZhVq
|
||||||
|
rXzVt7QV8dO0nStMjKK5omrtEAhVnASk7w1tFHkpBF1rqXGoo9ML40RnFZ+E5zqi
|
||||||
|
iZtzp+NzzLnEnWMNs+fJpPJ96P0kbq2bQzuSBcUynq0=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,253 @@
|
|||||||
|
// Copyright (c) 2014 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 <http://cesanta.com/>.
|
||||||
|
//
|
||||||
|
// $Date: 2014-09-28 05:04:41 UTC $
|
||||||
|
|
||||||
|
#ifndef NS_SKELETON_HEADER_INCLUDED
|
||||||
|
#define NS_SKELETON_HEADER_INCLUDED
|
||||||
|
|
||||||
|
#define NS_SKELETON_VERSION "2.1.0"
|
||||||
|
|
||||||
|
#undef UNICODE // Use ANSI WinAPI functions
|
||||||
|
#undef _UNICODE // Use multibyte encoding on Windows
|
||||||
|
#define _MBCS // Use multibyte encoding on Windows
|
||||||
|
#define _INTEGRAL_MAX_BITS 64 // Enable _stati64() on Windows
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005+
|
||||||
|
#undef WIN32_LEAN_AND_MEAN // Let windows.h always include winsock2.h
|
||||||
|
#define _XOPEN_SOURCE 600 // For flockfile() on Linux
|
||||||
|
#define __STDC_FORMAT_MACROS // <inttypes.h> wants this for C++
|
||||||
|
#define __STDC_LIMIT_MACROS // C++ wants that for INT64_MAX
|
||||||
|
#ifndef _LARGEFILE_SOURCE
|
||||||
|
#define _LARGEFILE_SOURCE // Enable fseeko() and ftello() functions
|
||||||
|
#endif
|
||||||
|
#define _FILE_OFFSET_BITS 64 // Enable 64-bit file offsets
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning (disable : 4127) // FD_SET() emits warning, disable it
|
||||||
|
#pragma warning (disable : 4204) // missing c99 support
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma comment(lib, "ws2_32.lib") // Linking with winsock library
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
#include <process.h>
|
||||||
|
#ifndef EINPROGRESS
|
||||||
|
#define EINPROGRESS WSAEINPROGRESS
|
||||||
|
#endif
|
||||||
|
#ifndef EWOULDBLOCK
|
||||||
|
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||||
|
#endif
|
||||||
|
#ifndef __func__
|
||||||
|
#define STRX(x) #x
|
||||||
|
#define STR(x) STRX(x)
|
||||||
|
#define __func__ __FILE__ ":" STR(__LINE__)
|
||||||
|
#endif
|
||||||
|
#ifndef va_copy
|
||||||
|
#define va_copy(x,y) x = y
|
||||||
|
#endif // MINGW #defines va_copy
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#define vsnprintf _vsnprintf
|
||||||
|
#define sleep(x) Sleep((x) * 1000)
|
||||||
|
#define to64(x) _atoi64(x)
|
||||||
|
typedef int socklen_t;
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
typedef unsigned short uint16_t;
|
||||||
|
typedef unsigned __int64 uint64_t;
|
||||||
|
typedef __int64 int64_t;
|
||||||
|
typedef SOCKET sock_t;
|
||||||
|
typedef struct _stati64 ns_stat_t;
|
||||||
|
#ifndef S_ISDIR
|
||||||
|
#define S_ISDIR(x) ((x) & _S_IFDIR)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <arpa/inet.h> // For inet_pton() when NS_ENABLE_IPV6 is defined
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#define closesocket(x) close(x)
|
||||||
|
#define __cdecl
|
||||||
|
#define INVALID_SOCKET (-1)
|
||||||
|
#define to64(x) strtoll(x, NULL, 10)
|
||||||
|
typedef int sock_t;
|
||||||
|
typedef struct stat ns_stat_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NS_ENABLE_DEBUG
|
||||||
|
#define DBG(x) do { printf("%-20s ", __func__); printf x; putchar('\n'); \
|
||||||
|
fflush(stdout); } while(0)
|
||||||
|
#else
|
||||||
|
#define DBG(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ARRAY_SIZE
|
||||||
|
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NS_ENABLE_SSL
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
#endif
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#else
|
||||||
|
typedef void *SSL;
|
||||||
|
typedef void *SSL_CTX;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
union socket_address {
|
||||||
|
struct sockaddr sa;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
#ifdef NS_ENABLE_IPV6
|
||||||
|
struct sockaddr_in6 sin6;
|
||||||
|
#else
|
||||||
|
struct sockaddr sin6;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// Describes chunk of memory
|
||||||
|
struct ns_str {
|
||||||
|
const char *p;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
// IO buffers interface
|
||||||
|
struct iobuf {
|
||||||
|
char *buf;
|
||||||
|
size_t len;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
void iobuf_init(struct iobuf *, size_t initial_size);
|
||||||
|
void iobuf_free(struct iobuf *);
|
||||||
|
size_t iobuf_append(struct iobuf *, const void *data, size_t data_size);
|
||||||
|
void iobuf_remove(struct iobuf *, size_t data_size);
|
||||||
|
void iobuf_resize(struct iobuf *, size_t new_size);
|
||||||
|
|
||||||
|
// Callback function (event handler) prototype, must be defined by user.
|
||||||
|
// Net skeleton will call event handler, passing events defined above.
|
||||||
|
struct ns_connection;
|
||||||
|
typedef void (*ns_callback_t)(struct ns_connection *, int event_num, void *evp);
|
||||||
|
|
||||||
|
// Events. Meaning of event parameter (evp) is given in the comment.
|
||||||
|
#define NS_POLL 0 // Sent to each connection on each call to ns_mgr_poll()
|
||||||
|
#define NS_ACCEPT 1 // New connection accept()-ed. union socket_address *addr
|
||||||
|
#define NS_CONNECT 2 // connect() succeeded or failed. int *success_status
|
||||||
|
#define NS_RECV 3 // Data has benn received. int *num_bytes
|
||||||
|
#define NS_SEND 4 // Data has been written to a socket. int *num_bytes
|
||||||
|
#define NS_CLOSE 5 // Connection is closed. NULL
|
||||||
|
|
||||||
|
|
||||||
|
struct ns_mgr {
|
||||||
|
struct ns_connection *active_connections;
|
||||||
|
const char *hexdump_file; // Debug hexdump file path
|
||||||
|
sock_t ctl[2]; // Socketpair for mg_wakeup()
|
||||||
|
void *user_data; // User data
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ns_connection {
|
||||||
|
struct ns_connection *next, *prev; // ns_mgr::active_connections linkage
|
||||||
|
struct ns_connection *listener; // Set only for accept()-ed connections
|
||||||
|
struct ns_mgr *mgr;
|
||||||
|
|
||||||
|
sock_t sock; // Socket
|
||||||
|
union socket_address sa; // Peer address
|
||||||
|
struct iobuf recv_iobuf; // Received data
|
||||||
|
struct iobuf send_iobuf; // Data scheduled for sending
|
||||||
|
SSL *ssl;
|
||||||
|
SSL_CTX *ssl_ctx;
|
||||||
|
void *user_data; // User-specific data
|
||||||
|
void *proto_data; // Application protocol-specific data
|
||||||
|
time_t last_io_time; // Timestamp of the last socket IO
|
||||||
|
ns_callback_t callback; // Event handler function
|
||||||
|
|
||||||
|
unsigned int flags;
|
||||||
|
#define NSF_FINISHED_SENDING_DATA (1 << 0)
|
||||||
|
#define NSF_BUFFER_BUT_DONT_SEND (1 << 1)
|
||||||
|
#define NSF_SSL_HANDSHAKE_DONE (1 << 2)
|
||||||
|
#define NSF_CONNECTING (1 << 3)
|
||||||
|
#define NSF_CLOSE_IMMEDIATELY (1 << 4)
|
||||||
|
#define NSF_WANT_READ (1 << 5)
|
||||||
|
#define NSF_WANT_WRITE (1 << 6)
|
||||||
|
#define NSF_LISTENING (1 << 7)
|
||||||
|
#define NSF_UDP (1 << 8)
|
||||||
|
|
||||||
|
#define NSF_USER_1 (1 << 20)
|
||||||
|
#define NSF_USER_2 (1 << 21)
|
||||||
|
#define NSF_USER_3 (1 << 22)
|
||||||
|
#define NSF_USER_4 (1 << 23)
|
||||||
|
#define NSF_USER_5 (1 << 24)
|
||||||
|
#define NSF_USER_6 (1 << 25)
|
||||||
|
};
|
||||||
|
|
||||||
|
void ns_mgr_init(struct ns_mgr *, void *user_data);
|
||||||
|
void ns_mgr_free(struct ns_mgr *);
|
||||||
|
time_t ns_mgr_poll(struct ns_mgr *, int milli);
|
||||||
|
void ns_broadcast(struct ns_mgr *, ns_callback_t, void *, size_t);
|
||||||
|
|
||||||
|
struct ns_connection *ns_next(struct ns_mgr *, struct ns_connection *);
|
||||||
|
struct ns_connection *ns_add_sock(struct ns_mgr *, sock_t,
|
||||||
|
ns_callback_t, void *);
|
||||||
|
struct ns_connection *ns_bind(struct ns_mgr *, const char *,
|
||||||
|
ns_callback_t, void *);
|
||||||
|
struct ns_connection *ns_connect(struct ns_mgr *, const char *,
|
||||||
|
ns_callback_t, void *);
|
||||||
|
|
||||||
|
int ns_send(struct ns_connection *, const void *buf, int len);
|
||||||
|
int ns_printf(struct ns_connection *, const char *fmt, ...);
|
||||||
|
int ns_vprintf(struct ns_connection *, const char *fmt, va_list ap);
|
||||||
|
|
||||||
|
// Utility functions
|
||||||
|
void *ns_start_thread(void *(*f)(void *), void *p);
|
||||||
|
int ns_socketpair(sock_t [2]);
|
||||||
|
int ns_socketpair2(sock_t [2], int sock_type); // SOCK_STREAM or SOCK_DGRAM
|
||||||
|
void ns_set_close_on_exec(sock_t);
|
||||||
|
void ns_sock_to_str(sock_t sock, char *buf, size_t len, int flags);
|
||||||
|
int ns_hexdump(const void *buf, int len, char *dst, int dst_len);
|
||||||
|
int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap);
|
||||||
|
int ns_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // NS_SKELETON_HEADER_INCLUDED
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
// Copyright (c) 2014 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 <http://cesanta.com/products.html>.
|
||||||
|
//
|
||||||
|
// $Date$
|
||||||
|
|
||||||
|
#include "net_skeleton.h"
|
||||||
|
#include "ssl_wrapper.h"
|
||||||
|
|
||||||
|
static void ev_handler(struct ns_connection *nc, int ev, void *p) {
|
||||||
|
const char *target_addr = (const char *) nc->mgr->user_data;
|
||||||
|
struct ns_connection *pc = (struct ns_connection *) nc->user_data;
|
||||||
|
struct iobuf *io = &nc->recv_iobuf;
|
||||||
|
|
||||||
|
(void) p;
|
||||||
|
switch (ev) {
|
||||||
|
case NS_ACCEPT:
|
||||||
|
// Create a connection to the target, and interlink both connections
|
||||||
|
nc->user_data = ns_connect(nc->mgr, target_addr, ev_handler, nc);
|
||||||
|
if (nc->user_data == NULL) {
|
||||||
|
nc->flags |= NSF_CLOSE_IMMEDIATELY;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NS_CLOSE:
|
||||||
|
// If either connection closes, unlink them and shedule closing
|
||||||
|
if (pc != NULL) {
|
||||||
|
pc->flags |= NSF_FINISHED_SENDING_DATA;
|
||||||
|
pc->user_data = NULL;
|
||||||
|
}
|
||||||
|
nc->user_data = NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NS_RECV:
|
||||||
|
// Forward arrived data to the other connection, and discard from buffer
|
||||||
|
if (pc != NULL) {
|
||||||
|
ns_send(pc, io->buf, io->len);
|
||||||
|
iobuf_remove(io, io->len);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ssl_wrapper_init(const char *local_addr, const char *target_addr,
|
||||||
|
const char **err_msg) {
|
||||||
|
struct ns_mgr *mgr = (struct ns_mgr *) calloc(1, sizeof(mgr[0]));
|
||||||
|
*err_msg = NULL;
|
||||||
|
|
||||||
|
if (mgr == NULL) {
|
||||||
|
*err_msg = "malloc failed";
|
||||||
|
} else {
|
||||||
|
ns_mgr_init(mgr, (void *) target_addr);
|
||||||
|
if (ns_bind(mgr, local_addr, ev_handler, NULL) == NULL) {
|
||||||
|
*err_msg = "ns_bind() failed: bad listening_port";
|
||||||
|
ns_mgr_free(mgr);
|
||||||
|
free(mgr);
|
||||||
|
mgr = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssl_wrapper_serve(void *param, volatile int *quit) {
|
||||||
|
struct ns_mgr *mgr = (struct ns_mgr *) param;
|
||||||
|
|
||||||
|
while (*quit == 0) {
|
||||||
|
ns_mgr_poll(mgr, 1000);
|
||||||
|
}
|
||||||
|
ns_mgr_free(mgr);
|
||||||
|
free(mgr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef SSL_WRAPPER_USE_AS_LIBRARY
|
||||||
|
static int s_received_signal = 0;
|
||||||
|
|
||||||
|
static void signal_handler(int sig_num) {
|
||||||
|
signal(sig_num, signal_handler);
|
||||||
|
s_received_signal = sig_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_usage_and_exit(const char *prog) {
|
||||||
|
fprintf(stderr, "Usage: %s <listening_address> <target_address>\n", prog);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
void *wrapper;
|
||||||
|
const char *err_msg;
|
||||||
|
|
||||||
|
if (argc != 3) {
|
||||||
|
show_usage_and_exit(argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup signal handlers
|
||||||
|
signal(SIGTERM, signal_handler);
|
||||||
|
signal(SIGINT, signal_handler);
|
||||||
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
|
if ((wrapper = ssl_wrapper_init(argv[1], argv[2], &err_msg)) == NULL) {
|
||||||
|
fprintf(stderr, "Error: %s\n", err_msg);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
ssl_wrapper_serve(wrapper, &s_received_signal);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
#endif // SSL_WRAPPER_USE_AS_LIBRARY
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (c) 2014 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 <http://cesanta.com/products.html>.
|
||||||
|
//
|
||||||
|
// $Date$
|
||||||
|
|
||||||
|
#ifndef SSL_WRAPPER_HEADER_INCLUDED
|
||||||
|
#define SSL_WRAPPER_HEADER_INCLUDED
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
void *ssl_wrapper_init(const char *listen_addr, const char *target_addr,
|
||||||
|
const char **err_msg);
|
||||||
|
void ssl_wrapper_serve(void *, volatile int *stop_marker);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // SSL_WRAPPER_HEADER_INCLUDED
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
// Copyright (c) 2014 Cesanta Software
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// This example demostrates proxying of WebSocket traffic, regardless of the
|
||||||
|
// protocol (ws:// or wss://).
|
||||||
|
// To use this example:
|
||||||
|
// 1. configure your browser to use a proxy on port 2014
|
||||||
|
// 2. import certs/ws1_ca.pem and certs/ws2_ca.pem into the trusted
|
||||||
|
// certificates list on your browser
|
||||||
|
// 3. make && ./ws_ssl
|
||||||
|
// 4. Point your browser to http://ws_ssl.com
|
||||||
|
// A page with 4 sections should appear, showing websocket echoes
|
||||||
|
|
||||||
|
#include "net_skeleton.h"
|
||||||
|
#include "mongoose.h"
|
||||||
|
#include "ssl_wrapper.h"
|
||||||
|
|
||||||
|
#define S1_PEM "certs/ws1_server.pem"
|
||||||
|
#define C1_PEM "certs/ws1_client.pem"
|
||||||
|
#define CA1_PEM "certs/ws1_ca.pem"
|
||||||
|
#define S2_PEM "certs/ws2_server.pem"
|
||||||
|
#define C2_PEM "certs/ws2_client.pem"
|
||||||
|
#define CA2_PEM "certs/ws2_ca.pem"
|
||||||
|
|
||||||
|
struct config {
|
||||||
|
const char *uri;
|
||||||
|
const char *wrapper_server_addr;
|
||||||
|
const char *wrapper_client_addr;
|
||||||
|
const char *target_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct config s_wrappers[] = {
|
||||||
|
{
|
||||||
|
"ws1:80",
|
||||||
|
"tcp://127.0.0.1:7001",
|
||||||
|
"tcp://127.0.0.1:7001",
|
||||||
|
"tcp://127.0.0.1:9001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ws1:443",
|
||||||
|
"ssl://127.0.0.1:7002:" S1_PEM,
|
||||||
|
"tcp://127.0.0.1:7002",
|
||||||
|
"tcp://127.0.0.1:9001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ws2:80",
|
||||||
|
"tcp://127.0.0.1:7003",
|
||||||
|
"tcp://127.0.0.1:7003",
|
||||||
|
"ssl://127.0.0.1:9002:" C2_PEM ":" CA2_PEM
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ws2:443",
|
||||||
|
"ssl://127.0.0.1:7004:" S2_PEM,
|
||||||
|
"tcp://127.0.0.1:7004",
|
||||||
|
"ssl://127.0.0.1:9002:" C2_PEM ":" CA2_PEM
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int s_received_signal = 0;
|
||||||
|
|
||||||
|
static void signal_handler(int sig_num) {
|
||||||
|
signal(sig_num, signal_handler);
|
||||||
|
s_received_signal = sig_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
switch (ev) {
|
||||||
|
case MG_AUTH:
|
||||||
|
return MG_TRUE;
|
||||||
|
|
||||||
|
case MG_REQUEST:
|
||||||
|
printf("==> [%s] [%s]\n", conn->request_method, conn->uri);
|
||||||
|
|
||||||
|
if (strcmp(conn->request_method, "CONNECT") == 0) {
|
||||||
|
// Iterate over configured wrappers, see if we can use one of them
|
||||||
|
for (i = 0; i < (int) ARRAY_SIZE(s_wrappers); i++) {
|
||||||
|
if (strcmp(conn->uri, s_wrappers[i].uri) == 0) {
|
||||||
|
mg_forward(conn, s_wrappers[i].wrapper_client_addr);
|
||||||
|
return MG_MORE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No suitable wrappers found. Disallow that CONNECT request.
|
||||||
|
mg_send_status(conn, 405);
|
||||||
|
return MG_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not a CONNECT request, serve HTML file.
|
||||||
|
mg_send_file(conn, "ws_ssl.html", NULL);
|
||||||
|
return MG_MORE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return MG_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ws_handler(struct mg_connection *conn, enum mg_event ev) {
|
||||||
|
switch (ev) {
|
||||||
|
case MG_AUTH:
|
||||||
|
return MG_TRUE;
|
||||||
|
case MG_REQUEST:
|
||||||
|
if (conn->is_websocket) {
|
||||||
|
// Simple websocket echo server
|
||||||
|
mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT,
|
||||||
|
conn->content, conn->content_len);
|
||||||
|
} else {
|
||||||
|
mg_printf_data(conn, "%s", "websocket connection expected");
|
||||||
|
}
|
||||||
|
return MG_TRUE;
|
||||||
|
default:
|
||||||
|
return MG_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *serve_thread_func(void *param) {
|
||||||
|
struct mg_server *server = (struct mg_server *) param;
|
||||||
|
printf("Listening on port %s\n", mg_get_option(server, "listening_port"));
|
||||||
|
while (s_received_signal == 0) {
|
||||||
|
mg_poll_server(server, 1000);
|
||||||
|
}
|
||||||
|
mg_destroy_server(&server);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *wrapper_thread_func(void *param) {
|
||||||
|
struct config *c = (struct config *) param;
|
||||||
|
const char *err_msg;
|
||||||
|
void *wrapper;
|
||||||
|
|
||||||
|
wrapper = ssl_wrapper_init(c->wrapper_server_addr, c->target_addr, &err_msg);
|
||||||
|
if (wrapper == NULL) {
|
||||||
|
fprintf(stderr, "Error: %s\n", err_msg);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
//((struct ns_mgr *) wrapper)->hexdump_file = "/dev/stderr";
|
||||||
|
ssl_wrapper_serve(wrapper, &s_received_signal);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_server *proxy_server = mg_create_server(NULL, ev_handler);
|
||||||
|
struct mg_server *ws1_server = mg_create_server(NULL, ws_handler);
|
||||||
|
struct mg_server *ws2_server = mg_create_server(NULL, ws_handler);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
((struct ns_mgr *) proxy_server)->hexdump_file = "/dev/stderr";
|
||||||
|
|
||||||
|
// Configure proxy server to listen on port 2014
|
||||||
|
mg_set_option(proxy_server, "listening_port", "2014");
|
||||||
|
//mg_set_option(proxy_server, "enable_proxy", "yes");
|
||||||
|
|
||||||
|
// Configure two websocket echo servers:
|
||||||
|
// ws1 is WS, listening on 9001
|
||||||
|
// ws2 is WSS, listening on 9002
|
||||||
|
// Note that HTML page thinks that ws1 is WSS, and ws2 is WS,
|
||||||
|
// where in reality it is vice versa and proxy server makes the decision.
|
||||||
|
mg_set_option(ws1_server, "listening_port", "tcp://127.0.0.1:9001");
|
||||||
|
mg_set_option(ws2_server, "listening_port",
|
||||||
|
"ssl://127.0.0.1:9002:" S2_PEM ":" CA2_PEM);
|
||||||
|
|
||||||
|
// Setup signal handlers
|
||||||
|
signal(SIGTERM, signal_handler);
|
||||||
|
signal(SIGINT, signal_handler);
|
||||||
|
|
||||||
|
// Start SSL wrappers, each in it's own thread
|
||||||
|
for (i = 0; i < ARRAY_SIZE(s_wrappers); i++) {
|
||||||
|
ns_start_thread(wrapper_thread_func, &s_wrappers[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start websocket servers in separate threads
|
||||||
|
mg_start_thread(serve_thread_func, ws1_server);
|
||||||
|
mg_start_thread(serve_thread_func, ws2_server);
|
||||||
|
|
||||||
|
// Finally, start proxy server in this thread: this call blocks
|
||||||
|
serve_thread_func(proxy_server);
|
||||||
|
|
||||||
|
printf("Existing on signal %d\n", s_received_signal);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Websocket Proxy SSL Test</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
var protocols = ['ws://', 'wss://'];
|
||||||
|
var websocketServers = ['ws1', 'ws2'];
|
||||||
|
//protocols = ['wss://'];
|
||||||
|
//websocketServers = ['ws1']
|
||||||
|
|
||||||
|
var createWebsocketConnection = function(proto, server) {
|
||||||
|
var conn = new WebSocket(proto + server);
|
||||||
|
|
||||||
|
var div = document.createElement('div');
|
||||||
|
var h2 = document.createElement('h2');
|
||||||
|
h2.innerHTML = 'Connection to ' + proto + server;
|
||||||
|
document.body.appendChild(h2);
|
||||||
|
document.body.appendChild(div);
|
||||||
|
|
||||||
|
conn.onmessage = function(ev) {
|
||||||
|
var el = document.createElement('div');
|
||||||
|
el.innerHTML = 'websocket message: ' + ev.data;
|
||||||
|
div.appendChild(el);
|
||||||
|
// Keep only last 5 messages in the list
|
||||||
|
while (div.childNodes.length > 5) div.removeChild(div.firstChild);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send some string to the websocket connection periodically.
|
||||||
|
// websocket server much echo it back.
|
||||||
|
window.setInterval(function() { conn.send(Math.random()); }, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var i = 0; i < protocols.length; i++) {
|
||||||
|
for (var j = 0; j < websocketServers.length; j++) {
|
||||||
|
createWebsocketConnection(protocols[i], websocketServers[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
body > div {
|
||||||
|
border: 1px solid #ccc; background: #f0f0f0; padding: 0 1em;
|
||||||
|
margin: 0 2em; min-height: 4em; max-width: 40em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
LOCAL_PATH := $(call my-dir)/..
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_CFLAGS := -std=c99 -O2 -W -Wall -pthread -pipe $(COPT)
|
||||||
|
LOCAL_MODULE := mongoose
|
||||||
|
LOCAL_SRC_FILES := examples/web_server/web_server.c mongoose.c
|
||||||
|
|
||||||
|
include $(BUILD_EXECUTABLE)
|
||||||
+2655
-1462
File diff suppressed because it is too large.
Load diff
+152
-123
@@ -1,123 +1,152 @@
|
|||||||
// Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
|
// Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
|
||||||
// Copyright (c) 2013-2014 Cesanta Software Limited
|
// Copyright (c) 2013-2014 Cesanta Software Limited
|
||||||
// All rights reserved
|
// All rights reserved
|
||||||
//
|
//
|
||||||
// This library is dual-licensed: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License version 2 as
|
||||||
// published by the Free Software Foundation. For the terms of this
|
// published by the Free Software Foundation. For the terms of this
|
||||||
// license, see <http://www.gnu.org/licenses/>.
|
// license, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
// You are free to use this library under the terms of the GNU General
|
// You are free to use this software under the terms of the GNU General
|
||||||
// Public License, but WITHOUT ANY WARRANTY; without even the implied
|
// Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||||
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
// See the GNU General Public License for more details.
|
// See the GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// Alternatively, you can license this library under a commercial
|
// Alternatively, you can license this software under a commercial
|
||||||
// license, as set out in <http://cesanta.com/>.
|
// license, as set out in <http://cesanta.com/>.
|
||||||
//
|
|
||||||
// NOTE: Detailed API documentation is at http://cesanta.com/#docs
|
#ifndef MONGOOSE_HEADER_INCLUDED
|
||||||
|
#define MONGOOSE_HEADER_INCLUDED
|
||||||
#ifndef MONGOOSE_HEADER_INCLUDED
|
|
||||||
#define MONGOOSE_HEADER_INCLUDED
|
#define MONGOOSE_VERSION "5.6"
|
||||||
|
|
||||||
#define MONGOOSE_VERSION "5.2"
|
#include <stdio.h> // required for FILE
|
||||||
|
#include <stddef.h> // required for size_t
|
||||||
#include <stdio.h> // required for FILE
|
#include <sys/types.h> // required for time_t
|
||||||
#include <stddef.h> // required for size_t
|
|
||||||
|
#ifdef __cplusplus
|
||||||
#ifdef __cplusplus
|
extern "C" {
|
||||||
extern "C" {
|
#endif // __cplusplus
|
||||||
#endif // __cplusplus
|
|
||||||
|
// This structure contains information about HTTP request.
|
||||||
// This structure contains information about HTTP request.
|
struct mg_connection {
|
||||||
struct mg_connection {
|
const char *request_method; // "GET", "POST", etc
|
||||||
const char *request_method; // "GET", "POST", etc
|
const char *uri; // URL-decoded URI
|
||||||
const char *uri; // URL-decoded URI
|
const char *http_version; // E.g. "1.0", "1.1"
|
||||||
const char *http_version; // E.g. "1.0", "1.1"
|
const char *query_string; // URL part after '?', not including '?', or NULL
|
||||||
const char *query_string; // URL part after '?', not including '?', or NULL
|
|
||||||
|
char remote_ip[48]; // Max IPv6 string length is 45 characters
|
||||||
char remote_ip[48]; // Max IPv6 string length is 45 characters
|
char local_ip[48]; // Local IP address
|
||||||
const char *local_ip; // Local IP address
|
unsigned short remote_port; // Client's port
|
||||||
unsigned short remote_port; // Client's port
|
unsigned short local_port; // Local port number
|
||||||
unsigned short local_port; // Local port number
|
|
||||||
|
int num_headers; // Number of HTTP headers
|
||||||
int num_headers; // Number of HTTP headers
|
struct mg_header {
|
||||||
struct mg_header {
|
const char *name; // HTTP header name
|
||||||
const char *name; // HTTP header name
|
const char *value; // HTTP header value
|
||||||
const char *value; // HTTP header value
|
} http_headers[30];
|
||||||
} http_headers[30];
|
|
||||||
|
char *content; // POST (or websocket message) data, or NULL
|
||||||
char *content; // POST (or websocket message) data, or NULL
|
size_t content_len; // Data length
|
||||||
size_t content_len; // content length
|
|
||||||
|
int is_websocket; // Connection is a websocket connection
|
||||||
int is_websocket; // Connection is a websocket connection
|
int status_code; // HTTP status code for HTTP error handler
|
||||||
int status_code; // HTTP status code for HTTP error handler
|
int wsbits; // First byte of the websocket frame
|
||||||
int wsbits; // First byte of the websocket frame
|
void *server_param; // Parameter passed to mg_create_server()
|
||||||
void *server_param; // Parameter passed to mg_add_uri_handler()
|
void *connection_param; // Placeholder for connection-specific data
|
||||||
void *connection_param; // Placeholder for connection-specific data
|
void *callback_param;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mg_server; // Opaque structure describing server instance
|
struct mg_server; // Opaque structure describing server instance
|
||||||
typedef int (*mg_handler_t)(struct mg_connection *);
|
enum mg_result { MG_FALSE, MG_TRUE, MG_MORE };
|
||||||
|
enum mg_event {
|
||||||
// Server management functions
|
MG_POLL = 100, // Callback return value is ignored
|
||||||
struct mg_server *mg_create_server(void *server_param);
|
MG_CONNECT, // If callback returns MG_FALSE, connect fails
|
||||||
void mg_destroy_server(struct mg_server **);
|
MG_AUTH, // If callback returns MG_FALSE, authentication fails
|
||||||
const char *mg_set_option(struct mg_server *, const char *opt, const char *val);
|
MG_REQUEST, // If callback returns MG_FALSE, Mongoose continues with req
|
||||||
unsigned int mg_poll_server(struct mg_server *, int milliseconds);
|
MG_REPLY, // If callback returns MG_FALSE, Mongoose closes connection
|
||||||
void mg_set_request_handler(struct mg_server *, mg_handler_t);
|
MG_RECV, // Mongoose has received POST data chunk.
|
||||||
void mg_set_http_error_handler(struct mg_server *, mg_handler_t);
|
// Callback should return a number of bytes to discard from
|
||||||
void mg_set_auth_handler(struct mg_server *, mg_handler_t);
|
// the receive buffer, or -1 to close the connection.
|
||||||
const char **mg_get_valid_option_names(void);
|
MG_CLOSE, // Connection is closed, callback return value is ignored
|
||||||
const char *mg_get_option(const struct mg_server *server, const char *name);
|
MG_WS_HANDSHAKE, // New websocket connection, handshake request
|
||||||
void mg_set_listening_socket(struct mg_server *, int sock);
|
MG_WS_CONNECT, // New websocket connection established
|
||||||
int mg_get_listening_socket(struct mg_server *);
|
MG_HTTP_ERROR // If callback returns MG_FALSE, Mongoose continues with err
|
||||||
void mg_iterate_over_connections(struct mg_server *, mg_handler_t, void *);
|
};
|
||||||
|
typedef int (*mg_handler_t)(struct mg_connection *, enum mg_event);
|
||||||
// Connection management functions
|
|
||||||
void mg_send_status(struct mg_connection *, int status_code);
|
// Websocket opcodes, from http://tools.ietf.org/html/rfc6455
|
||||||
void mg_send_header(struct mg_connection *, const char *name, const char *val);
|
enum {
|
||||||
void mg_send_data(struct mg_connection *, const void *data, int data_len);
|
WEBSOCKET_OPCODE_CONTINUATION = 0x0,
|
||||||
void mg_printf_data(struct mg_connection *, const char *format, ...);
|
WEBSOCKET_OPCODE_TEXT = 0x1,
|
||||||
|
WEBSOCKET_OPCODE_BINARY = 0x2,
|
||||||
int mg_websocket_write(struct mg_connection *, int opcode,
|
WEBSOCKET_OPCODE_CONNECTION_CLOSE = 0x8,
|
||||||
const char *data, size_t data_len);
|
WEBSOCKET_OPCODE_PING = 0x9,
|
||||||
|
WEBSOCKET_OPCODE_PONG = 0xa
|
||||||
// Deprecated in favor of mg_send_* interface
|
};
|
||||||
int mg_write(struct mg_connection *, const void *buf, int len);
|
|
||||||
int mg_printf(struct mg_connection *conn, const char *fmt, ...);
|
// Server management functions
|
||||||
|
struct mg_server *mg_create_server(void *server_param, mg_handler_t handler);
|
||||||
const char *mg_get_header(const struct mg_connection *, const char *name);
|
void mg_destroy_server(struct mg_server **);
|
||||||
const char *mg_get_mime_type(const char *name, const char *default_mime_type);
|
const char *mg_set_option(struct mg_server *, const char *opt, const char *val);
|
||||||
int mg_get_var(const struct mg_connection *conn, const char *var_name,
|
time_t mg_poll_server(struct mg_server *, int milliseconds);
|
||||||
char *buf, size_t buf_len);
|
const char **mg_get_valid_option_names(void);
|
||||||
int mg_parse_header(const char *hdr, const char *var_name, char *buf, size_t);
|
const char *mg_get_option(const struct mg_server *server, const char *name);
|
||||||
int mg_parse_multipart(const char *buf, int buf_len,
|
void mg_copy_listeners(struct mg_server *from, struct mg_server *to);
|
||||||
char *var_name, int var_name_len,
|
struct mg_connection *mg_next(struct mg_server *, struct mg_connection *);
|
||||||
char *file_name, int file_name_len,
|
void mg_wakeup_server(struct mg_server *);
|
||||||
const char **data, int *data_len);
|
void mg_wakeup_server_ex(struct mg_server *, mg_handler_t, const char *, ...);
|
||||||
|
struct mg_connection *mg_connect(struct mg_server *, const char *);
|
||||||
// Utility functions
|
|
||||||
void *mg_start_thread(void *(*func)(void *), void *param);
|
// Connection management functions
|
||||||
char *mg_md5(char buf[33], ...);
|
void mg_send_status(struct mg_connection *, int status_code);
|
||||||
int mg_authorize_digest(struct mg_connection *c, FILE *fp);
|
void mg_send_header(struct mg_connection *, const char *name, const char *val);
|
||||||
|
size_t mg_send_data(struct mg_connection *, const void *data, int data_len);
|
||||||
// Callback function return codes
|
size_t mg_printf_data(struct mg_connection *, const char *format, ...);
|
||||||
enum { MG_REQUEST_NOT_PROCESSED, MG_REQUEST_PROCESSED, MG_REQUEST_CALL_AGAIN };
|
size_t mg_write(struct mg_connection *, const void *buf, size_t len);
|
||||||
enum { MG_AUTH_FAIL, MG_AUTH_OK };
|
size_t mg_printf(struct mg_connection *conn, const char *fmt, ...);
|
||||||
enum { MG_ERROR_NOT_PROCESSED, MG_ERROR_PROCESSED };
|
|
||||||
enum { MG_CLIENT_CONTINUE, MG_CLIENT_CLOSE };
|
size_t mg_websocket_write(struct mg_connection *, int opcode,
|
||||||
|
const char *data, size_t data_len);
|
||||||
// HTTP client events
|
size_t mg_websocket_printf(struct mg_connection* conn, int opcode,
|
||||||
enum {
|
const char *fmt, ...);
|
||||||
MG_CONNECT_SUCCESS, MG_CONNECT_FAILURE,
|
|
||||||
MG_DOWNLOAD_SUCCESS, MG_DOWNLOAD_FAILURE
|
void mg_send_file(struct mg_connection *, const char *path, const char *);
|
||||||
};
|
void mg_send_file_data(struct mg_connection *, int fd);
|
||||||
int mg_connect(struct mg_server *, const char *host, int port, int use_ssl,
|
|
||||||
mg_handler_t handler, void *param);
|
const char *mg_get_header(const struct mg_connection *, const char *name);
|
||||||
|
const char *mg_get_mime_type(const char *name, const char *default_mime_type);
|
||||||
#ifdef __cplusplus
|
int mg_get_var(const struct mg_connection *conn, const char *var_name,
|
||||||
}
|
char *buf, size_t buf_len);
|
||||||
#endif // __cplusplus
|
int mg_parse_header(const char *hdr, const char *var_name, char *buf, size_t);
|
||||||
|
int mg_parse_multipart(const char *buf, int buf_len,
|
||||||
#endif // MONGOOSE_HEADER_INCLUDED
|
char *var_name, int var_name_len,
|
||||||
|
char *file_name, int file_name_len,
|
||||||
|
const char **data, int *data_len);
|
||||||
|
|
||||||
|
|
||||||
|
// Utility functions
|
||||||
|
void *mg_start_thread(void *(*func)(void *), void *param);
|
||||||
|
char *mg_md5(char buf[33], ...);
|
||||||
|
int mg_authorize_digest(struct mg_connection *c, FILE *fp);
|
||||||
|
size_t mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len);
|
||||||
|
int mg_url_decode(const char *src, size_t src_len, char *dst, size_t dst_len, int);
|
||||||
|
int mg_terminate_ssl(struct mg_connection *c, const char *cert);
|
||||||
|
int mg_forward(struct mg_connection *c, const char *addr);
|
||||||
|
void *mg_mmap(FILE *fp, size_t size);
|
||||||
|
void mg_munmap(void *p, size_t size);
|
||||||
|
|
||||||
|
|
||||||
|
// Templates support
|
||||||
|
struct mg_expansion {
|
||||||
|
const char *keyword;
|
||||||
|
void (*handler)(struct mg_connection *);
|
||||||
|
};
|
||||||
|
void mg_template(struct mg_connection *, const char *text,
|
||||||
|
struct mg_expansion *expansions);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // MONGOOSE_HEADER_INCLUDED
|
||||||
File renamed without changes.
@@ -0,0 +1,21 @@
|
|||||||
|
# Copyright (c) 2014 Cesanta Software
|
||||||
|
# All rights reserved
|
||||||
|
|
||||||
|
PROG = unit_test
|
||||||
|
PROF_FLAGS = -fprofile-arcs -ftest-coverage -g -O0 -DGUI
|
||||||
|
CFLAGS = -W -Wall -pthread -I.. $(PROF_FLAGS) $(CFLAGS_EXTRA)
|
||||||
|
SOURCES = $(PROG).c
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
./$(PROG)
|
||||||
|
gcov -b $(PROG).c | egrep '^(File|Lines)'
|
||||||
|
|
||||||
|
$(PROG): $(SOURCES) Makefile ../mongoose.c clean
|
||||||
|
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS) -ldl -lssl
|
||||||
|
|
||||||
|
win:
|
||||||
|
wine cl $(SOURCES) /MD /nologo /DNDEBUG /O1 /Fe$(PROG).exe
|
||||||
|
wine $(PROG).exe
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib *.gc*
|
||||||
+135
-245
@@ -3,13 +3,13 @@
|
|||||||
// cl unit_test.c /MD
|
// cl unit_test.c /MD
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#define MONGOOSE_USE_IPV6
|
#define NS_ENABLE_IPV6
|
||||||
#define MONGOOSE_USE_SSL
|
#define NS_ENABLE_SSL
|
||||||
#endif
|
#endif
|
||||||
#define MONGOOSE_USE_POST_SIZE_LIMIT 999
|
#define MONGOOSE_POST_SIZE_LIMIT 999
|
||||||
|
|
||||||
// USE_* definitions must be made before #include "mongoose.c" !
|
// USE_* definitions must be made before #include "mongoose.c" !
|
||||||
#include "mongoose.c"
|
#include "../mongoose.c"
|
||||||
|
|
||||||
#define FAIL(str, line) do { \
|
#define FAIL(str, line) do { \
|
||||||
printf("Fail on line %d: [%s]\n", line, str); \
|
printf("Fail on line %d: [%s]\n", line, str); \
|
||||||
@@ -120,8 +120,8 @@ static const char *test_parse_http_message() {
|
|||||||
ASSERT(strcmp(ri.http_version, "1.1") == 0);
|
ASSERT(strcmp(ri.http_version, "1.1") == 0);
|
||||||
ASSERT(ri.num_headers == 0);
|
ASSERT(ri.num_headers == 0);
|
||||||
|
|
||||||
ASSERT(parse_http_message(req2, sizeof(req2) - 1, &ri) == -1);
|
ASSERT(parse_http_message(req2, sizeof(req2) - 1, &ri) == (size_t) ~0);
|
||||||
ASSERT(parse_http_message(req6, 0, &ri) == -1);
|
ASSERT(parse_http_message(req6, 0, &ri) == (size_t) ~0);
|
||||||
ASSERT(parse_http_message(req8, sizeof(req8) - 1, &ri) == sizeof(req8) - 1);
|
ASSERT(parse_http_message(req8, sizeof(req8) - 1, &ri) == sizeof(req8) - 1);
|
||||||
|
|
||||||
// TODO(lsm): Fix this. Header value may span multiple lines.
|
// TODO(lsm): Fix this. Header value may span multiple lines.
|
||||||
@@ -166,49 +166,51 @@ static const char *test_should_keep_alive(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char *test_match_prefix(void) {
|
static const char *test_match_prefix(void) {
|
||||||
ASSERT(match_prefix("/api", 4, "/api") == 4);
|
ASSERT(mg_match_prefix("/api", 4, "/api") == 4);
|
||||||
ASSERT(match_prefix("/a/", 3, "/a/b/c") == 3);
|
ASSERT(mg_match_prefix("/a/", 3, "/a/b/c") == 3);
|
||||||
ASSERT(match_prefix("/a/", 3, "/ab/c") == -1);
|
ASSERT(mg_match_prefix("/a/", 3, "/ab/c") == -1);
|
||||||
ASSERT(match_prefix("/*/", 3, "/ab/c") == 4);
|
ASSERT(mg_match_prefix("/*/", 3, "/ab/c") == 4);
|
||||||
ASSERT(match_prefix("**", 2, "/a/b/c") == 6);
|
ASSERT(mg_match_prefix("**", 2, "/a/b/c") == 6);
|
||||||
ASSERT(match_prefix("/*", 2, "/a/b/c") == 2);
|
ASSERT(mg_match_prefix("/*", 2, "/a/b/c") == 2);
|
||||||
ASSERT(match_prefix("*/*", 3, "/a/b/c") == 2);
|
ASSERT(mg_match_prefix("*/*", 3, "/a/b/c") == 2);
|
||||||
ASSERT(match_prefix("**/", 3, "/a/b/c") == 5);
|
ASSERT(mg_match_prefix("**/", 3, "/a/b/c") == 5);
|
||||||
ASSERT(match_prefix("**.foo|**.bar", 13, "a.bar") == 5);
|
ASSERT(mg_match_prefix("**.foo|**.bar", 13, "a.bar") == 5);
|
||||||
ASSERT(match_prefix("a|b|cd", 6, "cdef") == 2);
|
ASSERT(mg_match_prefix("a|b|cd", 6, "cdef") == 2);
|
||||||
ASSERT(match_prefix("a|b|c?", 6, "cdef") == 2);
|
ASSERT(mg_match_prefix("a|b|c?", 6, "cdef") == 2);
|
||||||
ASSERT(match_prefix("a|?|cd", 6, "cdef") == 1);
|
ASSERT(mg_match_prefix("a|?|cd", 6, "cdef") == 1);
|
||||||
ASSERT(match_prefix("/a/**.cgi", 9, "/foo/bar/x.cgi") == -1);
|
ASSERT(mg_match_prefix("/a/**.cgi", 9, "/foo/bar/x.cgi") == -1);
|
||||||
ASSERT(match_prefix("/a/**.cgi", 9, "/a/bar/x.cgi") == 12);
|
ASSERT(mg_match_prefix("/a/**.cgi", 9, "/a/bar/x.cgi") == 12);
|
||||||
ASSERT(match_prefix("**/", 3, "/a/b/c") == 5);
|
ASSERT(mg_match_prefix("**/", 3, "/a/b/c") == 5);
|
||||||
ASSERT(match_prefix("**/$", 4, "/a/b/c") == -1);
|
ASSERT(mg_match_prefix("**/$", 4, "/a/b/c") == -1);
|
||||||
ASSERT(match_prefix("**/$", 4, "/a/b/") == 5);
|
ASSERT(mg_match_prefix("**/$", 4, "/a/b/") == 5);
|
||||||
ASSERT(match_prefix("$", 1, "") == 0);
|
ASSERT(mg_match_prefix("$", 1, "") == 0);
|
||||||
ASSERT(match_prefix("$", 1, "x") == -1);
|
ASSERT(mg_match_prefix("$", 1, "x") == -1);
|
||||||
ASSERT(match_prefix("*$", 2, "x") == 1);
|
ASSERT(mg_match_prefix("*$", 2, "x") == 1);
|
||||||
ASSERT(match_prefix("/$", 2, "/") == 1);
|
ASSERT(mg_match_prefix("/$", 2, "/") == 1);
|
||||||
ASSERT(match_prefix("**/$", 4, "/a/b/c") == -1);
|
ASSERT(mg_match_prefix("**/$", 4, "/a/b/c") == -1);
|
||||||
ASSERT(match_prefix("**/$", 4, "/a/b/") == 5);
|
ASSERT(mg_match_prefix("**/$", 4, "/a/b/") == 5);
|
||||||
ASSERT(match_prefix("*", 1, "/hello/") == 0);
|
ASSERT(mg_match_prefix("*", 1, "/hello/") == 0);
|
||||||
ASSERT(match_prefix("**.a$|**.b$", 11, "/a/b.b/") == -1);
|
ASSERT(mg_match_prefix("**.a$|**.b$", 11, "/a/b.b/") == -1);
|
||||||
ASSERT(match_prefix("**.a$|**.b$", 11, "/a/b.b") == 6);
|
ASSERT(mg_match_prefix("**.a$|**.b$", 11, "/a/b.b") == 6);
|
||||||
ASSERT(match_prefix("**.a$|**.b$", 11, "/a/B.A") == 6);
|
ASSERT(mg_match_prefix("**.a$|**.b$", 11, "/a/B.A") == 6);
|
||||||
ASSERT(match_prefix("**o$", 4, "HELLO") == 5);
|
ASSERT(mg_match_prefix("**o$", 4, "HELLO") == 5);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *test_remove_double_dots() {
|
static const char *test_remove_double_dots() {
|
||||||
struct { char before[20], after[20]; } data[] = {
|
struct { char before[30], after[30]; } data[] = {
|
||||||
{"////a", "/a"},
|
{"////a", "/a"},
|
||||||
{"/.....", "/."},
|
{"/.....", "/....."},
|
||||||
{"/......", "/"},
|
{"/......", "/......"},
|
||||||
{"...", "..."},
|
{"...", "..."},
|
||||||
{"/...///", "/./"},
|
{"/...///", "/.../"},
|
||||||
{"/a...///", "/a.../"},
|
{"/a...///", "/a.../"},
|
||||||
{"/.x", "/.x"},
|
{"/.x", "/.x"},
|
||||||
{"/\\", "/"},
|
{"/\\", "/"},
|
||||||
{"/a\\", "/a\\"},
|
{"/a\\", "/a\\"},
|
||||||
{"/a\\\\...", "/a\\."},
|
{"/a\\\\...", "/a\\..."},
|
||||||
|
{"foo/x..y/././y/../../..", "foo/x..y/y/"},
|
||||||
|
{"foo/..x", "foo/..x"},
|
||||||
};
|
};
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
@@ -261,6 +263,7 @@ static const char *test_url_decode(void) {
|
|||||||
ASSERT(strcmp(buf, "a ") == 0);
|
ASSERT(strcmp(buf, "a ") == 0);
|
||||||
|
|
||||||
ASSERT(mg_url_decode("%61", 1, buf, sizeof(buf), 1) == 1);
|
ASSERT(mg_url_decode("%61", 1, buf, sizeof(buf), 1) == 1);
|
||||||
|
printf("[%s]\n", buf);
|
||||||
ASSERT(strcmp(buf, "%") == 0);
|
ASSERT(strcmp(buf, "%") == 0);
|
||||||
|
|
||||||
ASSERT(mg_url_decode("%61", 2, buf, sizeof(buf), 1) == 2);
|
ASSERT(mg_url_decode("%61", 2, buf, sizeof(buf), 1) == 2);
|
||||||
@@ -271,6 +274,17 @@ static const char *test_url_decode(void) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *test_url_encode(void) {
|
||||||
|
char buf[100];
|
||||||
|
ASSERT(mg_url_encode("", 0, buf, sizeof(buf)) == 0);
|
||||||
|
ASSERT(buf[0] == '\0');
|
||||||
|
ASSERT(mg_url_encode("foo", 3, buf, sizeof(buf)) == 3);
|
||||||
|
ASSERT(strcmp(buf, "foo") == 0);
|
||||||
|
ASSERT(mg_url_encode("f o", 3, buf, sizeof(buf)) == 5);
|
||||||
|
ASSERT(strcmp(buf, "f%20o") == 0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static const char *test_to64(void) {
|
static const char *test_to64(void) {
|
||||||
ASSERT(to64("0") == 0);
|
ASSERT(to64("0") == 0);
|
||||||
ASSERT(to64("") == 0);
|
ASSERT(to64("") == 0);
|
||||||
@@ -280,32 +294,6 @@ static const char *test_to64(void) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *test_parse_port_string(void) {
|
|
||||||
static const char *valid[] = {
|
|
||||||
"1", "1.2.3.4:1",
|
|
||||||
#if defined(USE_IPV6)
|
|
||||||
"[::1]:123", "[3ffe:2a00:100:7031::1]:900",
|
|
||||||
#endif
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
static const char *invalid[] = {
|
|
||||||
"99999", "1k", "1.2.3", "1.2.3.4:", "1.2.3.4:2p", NULL
|
|
||||||
};
|
|
||||||
union socket_address sa;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; valid[i] != NULL; i++) {
|
|
||||||
ASSERT(parse_port_string(valid[i], &sa) != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; invalid[i] != NULL; i++) {
|
|
||||||
ASSERT(parse_port_string(invalid[i], &sa) == 0);
|
|
||||||
}
|
|
||||||
ASSERT(parse_port_string("0", &sa) != 0);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *test_base64_encode(void) {
|
static const char *test_base64_encode(void) {
|
||||||
const char *in[] = {"a", "ab", "abc", "abcd", NULL};
|
const char *in[] = {"a", "ab", "abc", "abcd", NULL};
|
||||||
const char *out[] = {"YQ==", "YWI=", "YWJj", "YWJjZA=="};
|
const char *out[] = {"YQ==", "YWI=", "YWJj", "YWJjZA=="};
|
||||||
@@ -321,9 +309,9 @@ static const char *test_base64_encode(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char *test_mg_parse_header(void) {
|
static const char *test_mg_parse_header(void) {
|
||||||
const char *str = "xx=1 kl yy, ert=234 kl=123, "
|
const char *str = "xx=1 kl yy, ert=234 kl=123, uri=\"/?name=x,y\", "
|
||||||
"ii=\"12\\\"34\" zz='aa bb',tt=2,gf=\"xx d=1234";
|
"ii=\"12\\\"34\" zz='aa bb',tt=2,gf=\"xx d=1234";
|
||||||
char buf[10];
|
char buf[20];
|
||||||
ASSERT(mg_parse_header(str, "yy", buf, sizeof(buf)) == 0);
|
ASSERT(mg_parse_header(str, "yy", buf, sizeof(buf)) == 0);
|
||||||
ASSERT(mg_parse_header(str, "ert", buf, sizeof(buf)) == 3);
|
ASSERT(mg_parse_header(str, "ert", buf, sizeof(buf)) == 3);
|
||||||
ASSERT(strcmp(buf, "234") == 0);
|
ASSERT(strcmp(buf, "234") == 0);
|
||||||
@@ -346,6 +334,7 @@ static const char *test_mg_parse_header(void) {
|
|||||||
ASSERT(strcmp(buf, "12\"34") == 0);
|
ASSERT(strcmp(buf, "12\"34") == 0);
|
||||||
ASSERT(mg_parse_header(str, "tt", buf, sizeof(buf)) == 1);
|
ASSERT(mg_parse_header(str, "tt", buf, sizeof(buf)) == 1);
|
||||||
ASSERT(strcmp(buf, "2") == 0);
|
ASSERT(strcmp(buf, "2") == 0);
|
||||||
|
ASSERT(mg_parse_header(str, "uri", buf, sizeof(buf)) == 10);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,60 +354,60 @@ static const char *test_next_option(void) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cb1(struct mg_connection *conn) {
|
static int evh1(struct mg_connection *conn, enum mg_event ev) {
|
||||||
int result = MG_REQUEST_NOT_PROCESSED;
|
char *buf = (char *) conn->connection_param;
|
||||||
if (!strcmp(conn->uri, "/cb1")) {
|
int result = MG_FALSE;
|
||||||
mg_printf(conn, "%s %s %s",
|
|
||||||
conn->server_param == NULL ? "?" : (char *) conn->server_param,
|
switch (ev) {
|
||||||
conn->connection_param == NULL ? "?" : "!", conn->remote_ip);
|
case MG_CONNECT:
|
||||||
result = MG_REQUEST_PROCESSED;
|
mg_printf(conn, "GET %s HTTP/1.0\r\n\r\n",
|
||||||
|
buf[0] == '1' ? "/cb1" : "/non_exist");
|
||||||
|
result = MG_TRUE;
|
||||||
|
break;
|
||||||
|
case MG_HTTP_ERROR:
|
||||||
|
mg_printf(conn, "HTTP/1.0 404 NF\r\n\r\nERR: %d", conn->status_code);
|
||||||
|
result = MG_TRUE;
|
||||||
|
break;
|
||||||
|
case MG_REQUEST:
|
||||||
|
if (!strcmp(conn->uri, "/cb1")) {
|
||||||
|
mg_printf(conn, "HTTP/1.0 200 OK\r\n\r\n%s %s %s",
|
||||||
|
(char *) conn->server_param,
|
||||||
|
buf == NULL ? "?" : "!", conn->remote_ip);
|
||||||
|
result = MG_TRUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MG_REPLY:
|
||||||
|
if (buf != NULL) {
|
||||||
|
sprintf(buf + 1, "%.*s", (int) conn->content_len, conn->content);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MG_AUTH:
|
||||||
|
result = MG_TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int error_handler(struct mg_connection *conn) {
|
|
||||||
mg_printf(conn, "HTTP/1.0 404 NF\r\n\r\nERR: %d", conn->status_code);
|
|
||||||
return MG_ERROR_PROCESSED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ts1(struct mg_connection *conn) {
|
|
||||||
if (conn->status_code == MG_CONNECT_SUCCESS) {
|
|
||||||
mg_printf(conn, "%s", "GET /cb1 HTTP/1.0\r\n\r\n");
|
|
||||||
return MG_CLIENT_CONTINUE;
|
|
||||||
} else if (conn->status_code == MG_DOWNLOAD_SUCCESS) {
|
|
||||||
sprintf((char *) conn->connection_param, "%.*s",
|
|
||||||
(int) conn->content_len, conn->content);
|
|
||||||
}
|
|
||||||
return MG_CLIENT_CLOSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ts2(struct mg_connection *conn) {
|
|
||||||
if (conn->status_code == MG_CONNECT_SUCCESS) {
|
|
||||||
mg_printf(conn, "%s", "GET /non_exist HTTP/1.0\r\n\r\n");
|
|
||||||
return MG_CLIENT_CONTINUE;
|
|
||||||
} else if (conn->status_code == MG_DOWNLOAD_SUCCESS) {
|
|
||||||
sprintf((char *) conn->connection_param, "%s %.*s",
|
|
||||||
conn->uri, (int) conn->content_len, conn->content);
|
|
||||||
}
|
|
||||||
return MG_CLIENT_CLOSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *test_server(void) {
|
static const char *test_server(void) {
|
||||||
char buf1[100] = "", buf2[100] = "";
|
char buf1[100] = "1", buf2[100] = "2";
|
||||||
struct mg_server *server = mg_create_server((void *) "foo");
|
struct mg_server *server = mg_create_server((void *) "foo", evh1);
|
||||||
|
struct mg_connection *conn;
|
||||||
|
|
||||||
ASSERT(server != NULL);
|
ASSERT(server != NULL);
|
||||||
ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == NULL);
|
ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == NULL);
|
||||||
ASSERT(mg_set_option(server, "document_root", ".") == NULL);
|
ASSERT(mg_set_option(server, "document_root", ".") == NULL);
|
||||||
mg_set_request_handler(server, cb1);
|
|
||||||
mg_set_http_error_handler(server, error_handler);
|
|
||||||
|
|
||||||
ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, ts1, buf1) == 1);
|
ASSERT((conn = mg_connect(server, "127.0.0.1:" HTTP_PORT)) != NULL);
|
||||||
ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, ts2, buf2) == 1);
|
conn->connection_param = buf1;
|
||||||
|
ASSERT((conn = mg_connect(server, "127.0.0.1:" HTTP_PORT)) != NULL);
|
||||||
|
conn->connection_param = buf2;
|
||||||
|
|
||||||
{ int i; for (i = 0; i < 50; i++) mg_poll_server(server, 1); }
|
{ int i; for (i = 0; i < 50; i++) mg_poll_server(server, 1); }
|
||||||
ASSERT(strcmp(buf1, "foo ? 127.0.0.1") == 0);
|
ASSERT(strcmp(buf1, "1foo ? 127.0.0.1") == 0);
|
||||||
ASSERT(strcmp(buf2, "404 ERR: 404") == 0);
|
ASSERT(strcmp(buf2, "2ERR: 404") == 0);
|
||||||
|
|
||||||
ASSERT(strcmp(static_config_options[URL_REWRITES * 2], "url_rewrites") == 0);
|
ASSERT(strcmp(static_config_options[URL_REWRITES * 2], "url_rewrites") == 0);
|
||||||
mg_destroy_server(&server);
|
mg_destroy_server(&server);
|
||||||
@@ -426,90 +415,6 @@ static const char *test_server(void) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This http client sends two requests using one connection
|
|
||||||
static int cb2(struct mg_connection *conn) {
|
|
||||||
const char *file1 = "mongoose.h", *file2 = "mongoose.c", *file_name = file2;
|
|
||||||
char *buf = (char *) conn->connection_param, *file_data;
|
|
||||||
int file_len, ret_val = 1;
|
|
||||||
|
|
||||||
switch (conn->status_code) {
|
|
||||||
case MG_CONNECT_SUCCESS:
|
|
||||||
mg_printf(conn, "GET /%s HTTP/1.1\r\n\r\n", file1);
|
|
||||||
strcat(buf, "a");
|
|
||||||
ret_val = 0;
|
|
||||||
break;
|
|
||||||
case MG_CONNECT_FAILURE: strcat(buf, "b"); break;
|
|
||||||
case MG_DOWNLOAD_FAILURE: strcat(buf, "c"); break;
|
|
||||||
case MG_DOWNLOAD_SUCCESS:
|
|
||||||
if (!strcmp(buf, "a")) {
|
|
||||||
// Send second request
|
|
||||||
mg_printf(conn, "GET /%s HTTP/1.1\r\n\r\n", file2);
|
|
||||||
file_name = file1;
|
|
||||||
}
|
|
||||||
if ((file_data = read_file(file_name, &file_len)) != NULL) {
|
|
||||||
if ((size_t) file_len == conn->content_len &&
|
|
||||||
memcmp(file_data, conn->content, file_len) == 0) {
|
|
||||||
strcat(buf, "d");
|
|
||||||
} else {
|
|
||||||
strcat(buf, "f");
|
|
||||||
}
|
|
||||||
free(file_data);
|
|
||||||
}
|
|
||||||
ret_val = !strcmp(buf, "ad") ? 0 : 1;
|
|
||||||
break;
|
|
||||||
default: strcat(buf, "e"); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret_val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cb4h(struct mg_connection *conn) {
|
|
||||||
int result = MG_REQUEST_NOT_PROCESSED;
|
|
||||||
if (!strcmp(conn->uri, "/x")) {
|
|
||||||
mg_send_data(conn, ":-)", 3);
|
|
||||||
result = MG_REQUEST_PROCESSED;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cb4(struct mg_connection *conn) {
|
|
||||||
if (conn->status_code == MG_CONNECT_SUCCESS) {
|
|
||||||
mg_printf(conn, "%s", "POST /x HTTP/1.0\r\nContent-Length: 999999\r\n\r\n");
|
|
||||||
return MG_CLIENT_CONTINUE;
|
|
||||||
} else {
|
|
||||||
sprintf((char *) conn->connection_param, "%.*s",
|
|
||||||
(int) conn->content_len, conn->content);
|
|
||||||
}
|
|
||||||
return MG_CLIENT_CLOSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cb3(struct mg_connection *conn) {
|
|
||||||
sprintf((char *) conn->connection_param, "%d", conn->status_code);
|
|
||||||
return MG_CLIENT_CLOSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *test_mg_connect(void) {
|
|
||||||
char buf2[40] = "", buf3[40] = "", buf4[40] = "";
|
|
||||||
struct mg_server *server = mg_create_server(NULL);
|
|
||||||
|
|
||||||
ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == NULL);
|
|
||||||
ASSERT(mg_set_option(server, "document_root", ".") == NULL);
|
|
||||||
mg_set_request_handler(server, cb4h);
|
|
||||||
ASSERT(mg_connect(server, "", 0, 0, NULL, NULL) == 0);
|
|
||||||
ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, cb2, buf2) == 1);
|
|
||||||
ASSERT(mg_connect(server, "127.0.0.1", 29, 0, cb3, buf3) == 1);
|
|
||||||
ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, cb4, buf4) == 1);
|
|
||||||
|
|
||||||
{ int i; for (i = 0; i < 50; i++) mg_poll_server(server, 1); }
|
|
||||||
|
|
||||||
ASSERT(strcmp(buf2, "add") == 0);
|
|
||||||
ASSERT(strcmp(buf3, "1") == 0);
|
|
||||||
ASSERT(strcmp(buf4, "500 Server Error\nPOST size > 999") == 0);
|
|
||||||
mg_destroy_server(&server);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DISP "Content-Disposition: form/data; "
|
#define DISP "Content-Disposition: form/data; "
|
||||||
#define CRLF "\r\n"
|
#define CRLF "\r\n"
|
||||||
#define BOUNDARY "--xyz"
|
#define BOUNDARY "--xyz"
|
||||||
@@ -545,49 +450,36 @@ static const char *test_parse_multipart(void) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int us1(struct mg_connection *conn) {
|
static int evh2(struct mg_connection *conn, enum mg_event ev) {
|
||||||
static const char *file_name = "mongoose.h";
|
char *file_data, *cp = (char *) conn->connection_param;
|
||||||
char *cp = (char *) conn->connection_param;
|
int file_size, result = MG_FALSE;
|
||||||
int file_size;
|
|
||||||
|
|
||||||
if (conn->status_code == MG_CONNECT_SUCCESS) {
|
switch (ev) {
|
||||||
mg_printf(conn, "GET /%s HTTP/1.0\r\n\r\n", cp);
|
case MG_AUTH:
|
||||||
return 0;
|
result = MG_TRUE;
|
||||||
} else if (conn->status_code == MG_DOWNLOAD_SUCCESS) {
|
break;
|
||||||
char *file_data = read_file(file_name, &file_size);
|
case MG_CONNECT:
|
||||||
sprintf(cp, "%d %s", (size_t) file_size == conn->content_len &&
|
mg_printf(conn, "GET /%s HTTP/1.0\r\n\r\n", cp);
|
||||||
memcmp(file_data, conn->content, file_size) == 0 ? 1 : 0,
|
result = MG_TRUE;
|
||||||
conn->query_string == NULL ? "?" : conn->query_string);
|
break;
|
||||||
free(file_data);
|
case MG_REQUEST:
|
||||||
} else if (conn->status_code == MG_CONNECT_FAILURE) {
|
break;
|
||||||
sprintf(cp, "%s", "cf");
|
case MG_REPLY:
|
||||||
} else {
|
file_data = read_file("unit_test.c", &file_size);
|
||||||
sprintf(cp, "%s", "df");
|
sprintf(cp, "%d %s", (size_t) file_size == conn->content_len &&
|
||||||
|
memcmp(file_data, conn->content, file_size) == 0 ? 1 : 0,
|
||||||
|
conn->query_string == NULL ? "?" : conn->query_string);
|
||||||
|
free(file_data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MONGOOSE_USE_SSL
|
|
||||||
static const char *test_ssl(void) {
|
|
||||||
static const char *ssl_cert = "examples/ssl_cert.pem";
|
|
||||||
char buf1[100] = "mongoose.h";
|
|
||||||
struct mg_server *server = mg_create_server(NULL);
|
|
||||||
|
|
||||||
ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == NULL);
|
|
||||||
ASSERT(mg_set_option(server, "document_root", ".") == NULL);
|
|
||||||
ASSERT(mg_set_option(server, "ssl_certificate", ssl_cert) == NULL);
|
|
||||||
|
|
||||||
ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 1, us1, buf1) == 1);
|
|
||||||
|
|
||||||
{ int i; for (i = 0; i < 50; i++) mg_poll_server(server, 1); }
|
|
||||||
ASSERT(strcmp(buf1, "1 ?") == 0);
|
|
||||||
mg_destroy_server(&server);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const char *test_mg_set_option(void) {
|
static const char *test_mg_set_option(void) {
|
||||||
struct mg_server *server = mg_create_server(NULL);
|
struct mg_server *server = mg_create_server(NULL, NULL);
|
||||||
ASSERT(mg_set_option(server, "listening_port", "0") == NULL);
|
ASSERT(mg_set_option(server, "listening_port", "0") == NULL);
|
||||||
ASSERT(mg_get_option(server, "listening_port")[0] != '\0');
|
ASSERT(mg_get_option(server, "listening_port")[0] != '\0');
|
||||||
mg_destroy_server(&server);
|
mg_destroy_server(&server);
|
||||||
@@ -595,19 +487,21 @@ static const char *test_mg_set_option(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char *test_rewrites(void) {
|
static const char *test_rewrites(void) {
|
||||||
char buf1[100] = "xx";
|
char buf1[100] = "xx", addr[50];
|
||||||
struct mg_server *server = mg_create_server(NULL);
|
struct mg_server *server = mg_create_server(NULL, evh2);
|
||||||
|
struct mg_connection *conn;
|
||||||
|
const char *port;
|
||||||
|
|
||||||
ASSERT(mg_set_option(server, "listening_port", "0") == NULL);
|
ASSERT(mg_set_option(server, "listening_port", "0") == NULL);
|
||||||
ASSERT(mg_set_option(server, "document_root", ".") == NULL);
|
ASSERT(mg_set_option(server, "document_root", ".") == NULL);
|
||||||
ASSERT(mg_set_option(server, "url_rewrites", "/xx=./mongoose.h") == NULL);
|
ASSERT(mg_set_option(server, "url_rewrites", "/xx=unit_test.c") == NULL);
|
||||||
|
ASSERT((port = mg_get_option(server, "listening_port")) != NULL);
|
||||||
ASSERT(mg_connect(server, "127.0.0.1",
|
snprintf(addr, sizeof(addr), "127.0.0.1:%s", port);
|
||||||
atoi(mg_get_option(server, "listening_port")),
|
ASSERT((conn = mg_connect(server, addr)) != NULL);
|
||||||
0, us1, buf1) == 1);
|
conn->connection_param = buf1;
|
||||||
|
|
||||||
{ int i; for (i = 0; i < 50; i++) mg_poll_server(server, 1); }
|
{ int i; for (i = 0; i < 50; i++) mg_poll_server(server, 1); }
|
||||||
//printf("[%s]\n", buf1);
|
|
||||||
ASSERT(strcmp(buf1, "1 ?") == 0);
|
ASSERT(strcmp(buf1, "1 ?") == 0);
|
||||||
mg_destroy_server(&server);
|
mg_destroy_server(&server);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -618,21 +512,17 @@ static const char *run_all_tests(void) {
|
|||||||
RUN_TEST(test_match_prefix);
|
RUN_TEST(test_match_prefix);
|
||||||
RUN_TEST(test_remove_double_dots);
|
RUN_TEST(test_remove_double_dots);
|
||||||
RUN_TEST(test_parse_http_message);
|
RUN_TEST(test_parse_http_message);
|
||||||
RUN_TEST(test_parse_port_string);
|
|
||||||
RUN_TEST(test_to64);
|
RUN_TEST(test_to64);
|
||||||
RUN_TEST(test_url_decode);
|
RUN_TEST(test_url_decode);
|
||||||
|
RUN_TEST(test_url_encode);
|
||||||
RUN_TEST(test_base64_encode);
|
RUN_TEST(test_base64_encode);
|
||||||
RUN_TEST(test_mg_parse_header);
|
RUN_TEST(test_mg_parse_header);
|
||||||
RUN_TEST(test_get_var);
|
RUN_TEST(test_get_var);
|
||||||
RUN_TEST(test_next_option);
|
RUN_TEST(test_next_option);
|
||||||
RUN_TEST(test_parse_multipart);
|
RUN_TEST(test_parse_multipart);
|
||||||
RUN_TEST(test_server);
|
|
||||||
RUN_TEST(test_mg_connect);
|
|
||||||
RUN_TEST(test_mg_set_option);
|
RUN_TEST(test_mg_set_option);
|
||||||
|
RUN_TEST(test_server);
|
||||||
RUN_TEST(test_rewrites);
|
RUN_TEST(test_rewrites);
|
||||||
#ifdef MONGOOSE_USE_SSL
|
|
||||||
RUN_TEST(test_ssl);
|
|
||||||
#endif
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user