Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54250f5fbf | ||
|
|
f3f397f31e | ||
|
|
d806ed5d5f | ||
|
|
37e9a2ee95 | ||
|
|
7ad6a08002 | ||
|
|
90686ee5c9 | ||
|
|
85c5577955 | ||
|
|
30d4a1ad0f | ||
|
|
1b551741b8 | ||
|
|
369f44adfa | ||
|
|
763f4551d5 | ||
|
|
42d7865e14 | ||
|
|
cf62702f08 | ||
|
|
14ccd78782 | ||
|
|
6c4b5efd98 | ||
|
|
05a43c563c | ||
|
|
94d2e86b60 | ||
|
|
d1b8f9e01f | ||
|
|
228acefa36 | ||
|
|
d1d8a77bf6 | ||
|
|
7ea3293aba | ||
|
|
082a498afd | ||
|
|
866c987409 | ||
|
|
1d0e65d17a | ||
|
|
136a37ef73 | ||
|
|
0ce49b5c71 | ||
|
|
490ad3834b | ||
|
|
bcc62c96c8 | ||
|
|
15d6cb3065 | ||
|
|
a490660b38 | ||
|
|
72019b7427 | ||
|
|
21c0024a2f | ||
|
|
d7a02d13e4 | ||
|
|
cb220837b9 | ||
|
|
ddaae51d42 | ||
|
|
629e55f97d | ||
|
|
909ebad276 | ||
|
|
cb7743fa39 | ||
|
|
6197842bca | ||
|
|
77d461dcbf | ||
|
|
47b6060910 | ||
|
|
47d3fe5af6 | ||
|
|
6691a2fdad | ||
|
|
746f56f42a | ||
|
|
87de05881c | ||
|
|
f2fba1d200 | ||
|
|
34d4fb8cf0 | ||
|
|
be64f81eee | ||
|
|
9fe1c93c9b | ||
|
|
a4b6d58b24 | ||
|
|
86f391c701 | ||
|
|
36de38bd11 | ||
|
|
a308872c88 | ||
|
|
a369160296 | ||
|
|
0a09b46c94 | ||
|
|
b0a1cd7b0d | ||
|
|
73a2b92278 | ||
|
|
c3bb5bd89e | ||
|
|
d22ff2fce7 | ||
|
|
fee2980d95 | ||
|
|
d6693ed360 | ||
|
|
4880069775 | ||
|
|
5d217a1262 | ||
|
|
f778d22eac | ||
|
|
3aa76dcaec | ||
|
|
4680573a6b | ||
|
|
95fcb261eb | ||
|
|
5867c67da2 | ||
|
|
80d74e9e34 | ||
|
|
43a0b500f5 | ||
|
|
3d53ed17fb | ||
|
|
4ea452307e | ||
|
|
e61f20f1ed | ||
|
|
ca11f5ab49 | ||
|
|
000d24d31a | ||
|
|
ef92f2e9c5 | ||
|
|
4e89eac8dd | ||
|
|
b015e33ea5 | ||
|
|
96e762d4a1 | ||
|
|
359060a151 | ||
|
|
af1aff7fbb | ||
|
|
517ef216c1 | ||
|
|
734c13cdf5 | ||
|
|
1bf3ad2426 | ||
|
|
884b9a4813 | ||
|
|
7153690016 | ||
|
|
f00b3a2b3a | ||
|
|
c2b5e4f3b8 | ||
|
|
bc15e9ce9a | ||
|
|
70dc6d8dc9 | ||
|
|
10b11b03a8 | ||
|
|
cb602f178c | ||
|
|
464113c5ae | ||
|
|
c34f6c54e7 | ||
|
|
8fb58ebbca | ||
|
|
dce60c6dbb | ||
|
|
f668d08804 | ||
|
|
c41a22195c | ||
|
|
900c05213b | ||
|
|
c5850e4b05 | ||
|
|
ff4649fe42 | ||
|
|
1a38e91042 | ||
|
|
b6196371bb | ||
|
|
d5beb7ba3f | ||
|
|
19acf23c49 | ||
|
|
5cd3291fec | ||
|
|
b3e0f780c3 | ||
|
|
2bdbfc27f6 | ||
|
|
3fc61a3edc | ||
|
|
12339bbf4c | ||
|
|
1fb9f922b0 | ||
|
|
b93bc02ab0 | ||
|
|
747e393a54 | ||
|
|
4e8660a21f | ||
|
|
3fe77fa9a6 | ||
|
|
b4fbaf7c13 | ||
|
|
9884241df8 | ||
|
|
63d7a4fa45 | ||
|
|
8f4b6c41a2 | ||
|
|
4493d65ec9 | ||
|
|
e5910da300 | ||
|
|
c277a1d878 | ||
|
|
7820ad3a59 | ||
|
|
23533b83a4 | ||
|
|
ab650ec5c9 | ||
|
|
8f36597048 | ||
|
|
d0213ee90a | ||
|
|
1e9fabe1ca | ||
|
|
148d3f0562 | ||
|
|
c3057df3f5 | ||
|
|
0b2e474d52 | ||
|
|
95a36b1759 | ||
|
|
86ffa3a3ea | ||
|
|
69e2b2985d | ||
|
|
c431904b56 | ||
|
|
c2a10601b9 | ||
|
|
e9a8e5468d | ||
|
|
22e602debb | ||
|
|
455cec67a5 | ||
|
|
e2dfac946d | ||
|
|
c198d2e5f1 | ||
|
|
9a70abef24 | ||
|
|
53e1c469a2 | ||
|
|
139c2061a8 | ||
|
|
15b361fbac | ||
|
|
3130e59244 | ||
|
|
93286836f9 | ||
|
|
91b57aa9a8 | ||
|
|
220231e647 | ||
|
|
c438bb0bc5 | ||
|
|
95afa323c0 | ||
|
|
bc56353a79 | ||
|
|
1ffccdb7b2 | ||
|
|
e79fe4b8f0 | ||
|
|
aaf1fc3a4a | ||
|
|
8b42353039 | ||
|
|
05c687e251 | ||
|
|
492b8f6950 | ||
|
|
8ccee82059 | ||
|
|
b99a94a652 | ||
|
|
41e5d7e471 | ||
|
|
1adea37c45 | ||
|
|
98f6c8aa4f | ||
|
|
341ae53e85 | ||
|
|
291fc024cd | ||
|
|
f63d833a33 | ||
|
|
ab035901f8 | ||
|
|
20f54059ad | ||
|
|
563c31303e | ||
|
|
421e099f2b | ||
|
|
955d4a3129 | ||
|
|
b84981ad03 | ||
|
|
777b8e94e2 | ||
|
|
6df642623a | ||
|
|
0a3e186f11 | ||
|
|
c2d83a9db0 | ||
|
|
f33d3a4e02 | ||
|
|
86b8a56b05 | ||
|
|
ac6ec15aed | ||
|
|
31632c6361 | ||
|
|
98c99279c3 | ||
|
|
cdb8d7b692 | ||
|
|
93ac3e19f0 | ||
|
|
6a51af9efe | ||
|
|
9d73b3470b | ||
|
|
1c8449cea6 | ||
|
|
3bbbd41196 | ||
|
|
339bbee0df | ||
|
|
9ba6eb716d | ||
|
|
d949c19c7e | ||
|
|
1299d6118f | ||
|
|
244ff92e78 | ||
|
|
53f34dea04 | ||
|
|
1f5c3fac31 | ||
|
|
7014258c8d | ||
|
|
1614e7ba8d | ||
|
|
43b5a4e735 | ||
|
|
43191db63e | ||
|
|
e89be2e944 | ||
|
|
c2fbff6d0e | ||
|
|
b8eca17c55 | ||
|
|
4650e491df | ||
|
|
3e33e57707 | ||
|
|
c80f4c5313 | ||
|
|
132ecbec2f | ||
|
|
0a90cab44a | ||
|
|
d16dbc197f | ||
|
|
127f27e375 | ||
|
|
6523cc4da0 | ||
|
|
2516da1c89 | ||
|
|
0ae2b82b60 | ||
|
|
dab526936f | ||
|
|
780077d118 | ||
|
|
ad8f1d88d4 | ||
|
|
a3c4a48ef7 | ||
|
|
84a11fe3b1 | ||
|
|
2a3cfc9858 | ||
|
|
b9b20c6494 | ||
|
|
a8a7d2cf7e | ||
|
|
50ecc30b4d | ||
|
|
cd89db5c2f | ||
|
|
1ed99999bd | ||
|
|
4afebdcb2b | ||
|
|
c3d9d17e34 | ||
|
|
7bf5144e62 | ||
|
|
3eb4eb8074 | ||
|
|
ab000c684a | ||
|
|
aba60dadec | ||
|
|
f29457e967 | ||
|
|
8742fac5d8 | ||
|
|
0ab1c7ef76 | ||
|
|
47abc641f1 | ||
|
|
7519b2ef3a | ||
|
|
ce8657f12f | ||
|
|
8e366916d5 | ||
|
|
33f53ab000 | ||
|
|
bd15ad4301 | ||
|
|
e5b3b8ad32 | ||
|
|
e116c48bef | ||
|
|
7d7bb3b388 | ||
|
|
0b4bf13335 | ||
|
|
228984a3fc | ||
|
|
f084ad8008 | ||
|
|
255da78bed | ||
|
|
5d5badfcee | ||
|
|
4cf9f99ae9 | ||
|
|
673f25f75a | ||
|
|
961fb96bb7 | ||
|
|
d6475fcd19 | ||
|
|
ac538f755f | ||
|
|
5b2eb4f0e1 | ||
|
|
10c274c774 | ||
|
|
eb3b81297d | ||
|
|
80f4133bbf | ||
|
|
d10fb9451c | ||
|
|
88ae2ecadb | ||
|
|
85d19dad47 | ||
|
|
c5cc414181 | ||
|
|
17703fe3e8 | ||
|
|
04aeeba2fa | ||
|
|
4e11d5cdbf | ||
|
|
be63c0dc89 | ||
|
|
987bc1d580 | ||
|
|
ddd35c0cba | ||
|
|
c97b615785 | ||
|
|
9ab6d084df | ||
|
|
cf8d0a25aa | ||
|
|
0a0852b576 | ||
|
|
90716417c9 | ||
|
|
101afbc9b8 | ||
|
|
a197646867 | ||
|
|
00d1d2c0e7 | ||
|
|
6e50fe4475 | ||
|
|
7942803a75 | ||
|
|
a8b74a9021 | ||
|
|
27a9a62843 | ||
|
|
9b268b6c77 | ||
|
|
3b3ac48edd | ||
|
|
598e96a0cc | ||
|
|
b5dd0e8093 | ||
|
|
9b24fdfd1d | ||
|
|
8313896a85 | ||
|
|
8193302162 | ||
|
|
6e3e5560d0 | ||
|
|
f0c6630a16 | ||
|
|
1db747da29 | ||
|
|
8065439f96 | ||
|
|
62c896a872 | ||
|
|
2db07dfc3b | ||
|
|
34eb3f1e66 | ||
|
|
9d30e892e9 | ||
|
|
0aaba7a461 | ||
|
|
3d6b568c6e | ||
|
|
2b2816cfe4 | ||
|
|
2fa18b47db | ||
|
|
c8af7cdd27 | ||
|
|
f857f6394f | ||
|
|
97d733e129 | ||
|
|
77e44c7c0e | ||
|
|
abf89d32d9 | ||
|
|
177e05deb2 | ||
|
|
eb5645241c | ||
|
|
202300952c | ||
|
|
c7bea65ae7 | ||
|
|
d5a9000d46 | ||
|
|
f62018451f | ||
|
|
0a93e301c9 | ||
|
|
6fe9cae62a | ||
|
|
38e984a008 | ||
|
|
09e4254718 | ||
|
|
d4b55c4ceb | ||
|
|
7d5479985d | ||
|
|
6517af3dea | ||
|
|
7632a5e4af | ||
|
|
7f20c41dd5 | ||
|
|
66b23b11b0 | ||
|
|
448b44094a | ||
|
|
8bbb44f90c | ||
|
|
0fba87c755 | ||
|
|
fea648496c | ||
|
|
944a6b761c | ||
|
|
f1ae183752 | ||
|
|
a0ece4e969 | ||
|
|
0bb14abbdd | ||
|
|
4c37e49274 | ||
|
|
2a2bc33a89 | ||
|
|
41558bbf64 | ||
|
|
4d0cc95ff4 | ||
|
|
cfd28a4f7a | ||
|
|
5a0b6fc35a | ||
|
|
3e59e1c465 | ||
|
|
ae611a6e55 | ||
|
|
a7a2e3deb1 | ||
|
|
cae0a1cbc0 | ||
|
|
244e5f67d3 | ||
|
|
ff078882d5 | ||
|
|
8d76733fad | ||
|
|
fb3a5a7d90 | ||
|
|
f374ac5f9a | ||
|
|
02707364f0 | ||
|
|
104106b9cf | ||
|
|
474e065a30 | ||
|
|
27094896b1 | ||
|
|
cd48bcfd7d | ||
|
|
5baeba53d7 | ||
|
|
3a3b433849 | ||
|
|
a2192ae483 | ||
|
|
023b55f2e5 | ||
|
|
e4309d472b | ||
|
|
c5452fc2ec | ||
|
|
f78ee9d42e | ||
|
|
c8416cc17d | ||
|
|
cf0a969a65 | ||
|
|
06670d3401 | ||
|
|
acfc66cd60 | ||
|
|
6f140202ad | ||
|
|
cfe77a3d58 | ||
|
|
a0527a7f0e | ||
|
|
c90cffa688 | ||
|
|
d7a633bfa3 | ||
|
|
0ea3cdd228 | ||
|
|
ddef065493 | ||
|
|
ac857d18db | ||
|
|
663e928d65 | ||
|
|
189cd8c5f6 | ||
|
|
692f436b3d | ||
|
|
2e65ce8272 | ||
|
|
a35e5bd966 | ||
|
|
83fe5a17f3 | ||
|
|
49bbfaf130 | ||
|
|
cd9c7dcbec | ||
|
|
f868fc861b | ||
|
|
84907d5bc4 | ||
|
|
1cee8a16b9 | ||
|
|
57e32b87c7 | ||
|
|
6926655513 | ||
|
|
8354319e72 | ||
|
|
f9596cc1db | ||
|
|
b2e2ad9a45 | ||
|
|
a07fb2be51 | ||
|
|
7f259f2a79 | ||
|
|
7c0493071f | ||
|
|
c60fe0c6f6 | ||
|
|
8ce34af9f3 | ||
|
|
82761bb875 | ||
|
|
08a10a8af5 | ||
|
|
bd130136bc | ||
|
|
fb04203b72 | ||
|
|
4172c190e5 | ||
|
|
920abd627b | ||
|
|
02b7399f9a | ||
|
|
b8402ed073 | ||
|
|
06c5c4d2a4 | ||
|
|
57a4ec31d1 | ||
|
|
511c9a6d4a | ||
|
|
8ec47111d5 | ||
|
|
8b67274cc0 | ||
|
|
af22fb7a06 | ||
|
|
df5fff5e72 | ||
|
|
d9243d1c0b | ||
|
|
2fb145d39d | ||
|
|
14094aaef7 | ||
|
|
ec752645ee | ||
|
|
ceb2f1da41 | ||
|
|
aab857a66e | ||
|
|
066be0fe30 | ||
|
|
380e87ddfa | ||
|
|
e9a7a2af18 | ||
|
|
a83e7d8c42 | ||
|
|
bf7dd7ac63 | ||
|
|
0fc3370859 | ||
|
|
c416012f97 | ||
|
|
d3a8862bd8 | ||
|
|
08353731ef | ||
|
|
16700244b0 | ||
|
|
49ca223e9c | ||
|
|
38efe632ae | ||
|
|
39a3bb7e44 | ||
|
|
920e8d9145 | ||
|
|
aed6d05d8c | ||
|
|
d85d95a40b | ||
|
|
b5dd54a404 | ||
|
|
f7c0a2ee15 | ||
|
|
874b5bfdbf | ||
|
|
71d09722be | ||
|
|
349d25dccf | ||
|
|
3942914945 | ||
|
|
60c16bbb5d | ||
|
|
70b5f4130e | ||
|
|
17cfecc5c3 | ||
|
|
ebdd18769b | ||
|
|
f974fddd2a | ||
|
|
b1a46da309 | ||
|
|
81879be4be | ||
|
|
0a094d4c1f | ||
|
|
66a96410d4 | ||
|
|
d4b23f08b6 | ||
|
|
d6d956b9d8 | ||
|
|
383b2a48c5 | ||
|
|
ab1c464950 | ||
|
|
f20b5191f2 | ||
|
|
fc113d64f5 | ||
|
|
6f6b12bee7 | ||
|
|
4e6c2867da | ||
|
|
54989e819a | ||
|
|
bf505bb68d | ||
|
|
4072062b72 | ||
|
|
d6ba37dc3c | ||
|
|
a58d21aa28 | ||
|
|
6e8d4129b2 | ||
|
|
2485a8f8d9 | ||
|
|
1ae908f6d5 | ||
|
|
6b923bdff1 | ||
|
|
d39969d1e6 | ||
|
|
eaef5bd133 | ||
|
|
7cc7df8c0e | ||
|
|
551f393da7 | ||
|
|
e81f8373a2 | ||
|
|
dfa83f2c85 | ||
|
|
91bdbc5193 | ||
|
|
707b9ed2d6 | ||
|
|
cd6b846e22 | ||
|
|
807e4ea6ec | ||
|
|
507e8bfac9 | ||
|
|
2ea63a0ea6 | ||
|
|
7988acbff4 | ||
|
|
b8c3740446 | ||
|
|
7bdbd80552 | ||
|
|
577ad2599c | ||
|
|
4d9f8168b8 | ||
|
|
f1d0b451b1 | ||
|
|
ac921d4657 | ||
|
|
f046434f3b | ||
|
|
58b9ee41fa | ||
|
|
d28d7a67f2 | ||
|
|
20370e65d6 | ||
|
|
67626d49c9 | ||
|
|
cd9e179fcb | ||
|
|
0ba28e6153 | ||
|
|
de791765b2 | ||
|
|
e79121acb7 | ||
|
|
4bdec5c1c1 | ||
|
|
fa39d2f2fa | ||
|
|
c55d06ed57 | ||
|
|
3829873552 | ||
|
|
54ebcc5bd8 | ||
|
|
7782500dbb | ||
|
|
86ec6bb2f8 | ||
|
|
02499d672b | ||
|
|
8c2e641ed7 | ||
|
|
29c53082eb | ||
|
|
2fa988fc7b | ||
|
|
72f1d444d3 | ||
|
|
7dcc94202d | ||
|
|
a447ae5eab | ||
|
|
54ad1e4e47 | ||
|
|
39ea91cfc2 | ||
|
|
5ebff5d15e | ||
|
|
731512a947 | ||
|
|
304dbca63d | ||
|
|
18ff0fafe0 | ||
|
|
25de791424 | ||
|
|
6e88c9cfd1 | ||
|
|
9937e88985 | ||
|
|
57f964a139 | ||
|
|
cbd5835112 | ||
|
|
fba32acb73 | ||
|
|
2fdb1f78a2 | ||
|
|
ea2069df51 | ||
|
|
7267fc757d | ||
|
|
ea7d69060d | ||
|
|
6e5e2eb694 | ||
|
|
51466df7b9 | ||
|
|
d6259332d4 | ||
|
|
260229a4d1 | ||
|
|
7776df241c | ||
|
|
e17fdcb077 | ||
|
|
d96629cdf4 | ||
|
|
0c79fcfbd0 | ||
|
|
9125830de6 | ||
|
|
55963d0c9a | ||
|
|
44f7b91826 | ||
|
|
731ea5d50d | ||
|
|
9e517fde00 | ||
|
|
1ff61837ac | ||
|
|
3a8464e4b8 | ||
|
|
39b0b8e2fd | ||
|
|
3a61186491 | ||
|
|
2180e1786c | ||
|
|
8fb5e8ef19 | ||
|
|
a8f54d1851 | ||
|
|
c9721d4d7f | ||
|
|
c848372bbe | ||
|
|
a23daa1547 | ||
|
|
9dba6c806b | ||
|
|
fc635a9340 | ||
|
|
81f738af3f | ||
|
|
f6165d23e4 | ||
|
|
e4a4b6f260 | ||
|
|
0ceee1dc05 | ||
|
|
8a6cf95fad | ||
|
|
37a7031f4e | ||
|
|
8874f3de9d | ||
|
|
3c5d48ea13 | ||
|
|
a0d98b7a39 | ||
|
|
74b75899d3 | ||
|
|
240eca0b68 | ||
|
|
cd54b18de3 | ||
|
|
65e01dbabc | ||
|
|
62276ce63e | ||
|
|
f67fe352cf | ||
|
|
4805797752 | ||
|
|
4c038508f2 | ||
|
|
15db11c0e6 | ||
|
|
97fe505bb4 | ||
|
|
fd45a6d31b | ||
|
|
e1a9ad7f82 | ||
|
|
296affc6e4 | ||
|
|
1889e12b54 | ||
|
|
5e91d919e0 | ||
|
|
5934846852 | ||
|
|
5045dfab74 | ||
|
|
499a7d6a37 | ||
|
|
f72c3fa9a7 | ||
|
|
d0c50632cd | ||
|
|
fffb54e2c6 | ||
|
|
8bf3bd48a6 | ||
|
|
dbe976ad3e | ||
|
|
9a8a6b53ae | ||
|
|
84132b7b2a | ||
|
|
e69a7a1b25 | ||
|
|
7f2bdc217a | ||
|
|
76bb35d5db | ||
|
|
0187f297d1 | ||
|
|
6ff49dc196 | ||
|
|
cd778396ff | ||
|
|
0dcb50d39c | ||
|
|
fd763846e5 | ||
|
|
f4f310cf51 | ||
|
|
0798b72470 | ||
|
|
39a17f8a72 | ||
|
|
78454da3b3 | ||
|
|
e62dc8f3b2 | ||
|
|
e99088348d | ||
|
|
6a12bd7abc | ||
|
|
b39e30fb0c | ||
|
|
92b15395a4 | ||
|
|
7411ff1fca | ||
|
|
f2e7facbc3 | ||
|
|
f1b4f0c463 | ||
|
|
c04e3f80b9 | ||
|
|
717e872fdd | ||
|
|
dbff932d8b | ||
|
|
5c9f463cab | ||
|
|
3a8f47befd | ||
|
|
a3e2a41834 | ||
|
|
b667bd709d | ||
|
|
a4c668e37a | ||
|
|
900bbe724a | ||
|
|
f5a2857620 | ||
|
|
2ef6f7248d | ||
|
|
06b430e57f | ||
|
|
f061dcf8b6 | ||
|
|
99377bdd30 | ||
|
|
c6b5343c9b | ||
|
|
7f4e2a93d0 | ||
|
|
c151f9bc59 | ||
|
|
204bf9acec | ||
|
|
e3bac87016 | ||
|
|
1f09505248 | ||
|
|
7f99013179 | ||
|
|
8d72c2a7b2 | ||
|
|
c722cfec18 | ||
|
|
835af2cae1 | ||
|
|
bd2a4097b2 | ||
|
|
fcc75c6a3f | ||
|
|
e08b234326 | ||
|
|
5bd3df7a0f | ||
|
|
5bbf24bf41 | ||
|
|
ace1dc53b2 | ||
|
|
100480a1d5 | ||
|
|
a89a2df603 | ||
|
|
988ad66a12 | ||
|
|
85d6292b8f | ||
|
|
98ab0950c9 | ||
|
|
a7f9043072 | ||
|
|
6d8b747ff2 | ||
|
|
a17eae4142 | ||
|
|
7b05d70042 | ||
|
|
f328907da4 | ||
|
|
1cea7ba487 | ||
|
|
6848452149 | ||
|
|
f9a1d47f13 | ||
|
|
492dcdca8d | ||
|
|
4ef3a778c1 | ||
|
|
31c5ef1bc3 | ||
|
|
4656e7b0dd | ||
|
|
4216cf2ac1 | ||
|
|
37e4f51668 | ||
|
|
1dae0373c8 | ||
|
|
e928f36456 | ||
|
|
fcb94a1742 | ||
|
|
8ff010ca0f | ||
|
|
241090a82b | ||
|
|
618bef0eb2 | ||
|
|
3b69f5d500 | ||
|
|
b298d46a40 | ||
|
|
75059d1bdc | ||
|
|
15e9a92798 | ||
|
|
bafc30bec6 | ||
|
|
0a8f839281 | ||
|
|
ab48174bac | ||
|
|
4439251f17 | ||
|
|
f9a6403b11 | ||
|
|
786f46c655 | ||
|
|
5ebd9fe7a5 | ||
|
|
2302ae5e88 | ||
|
|
8b12263dbc | ||
|
|
376d2666a5 | ||
|
|
d90622630f | ||
|
|
da447b1067 | ||
|
|
460d95afc5 | ||
|
|
8f522048d8 | ||
|
|
147c095105 | ||
|
|
fecb11f2fa | ||
|
|
56e50c2dbe | ||
|
|
c1b5e9b260 | ||
|
|
286fa90ee9 | ||
|
|
d63fb70c69 | ||
|
|
4d76a3be4c | ||
|
|
d9c612ef2b | ||
|
|
3b3ca1c1b3 | ||
|
|
2e748fdbf1 | ||
|
|
6c99691d1c | ||
|
|
fd067c8077 | ||
|
|
04012760d1 | ||
|
|
0ec1a141f1 | ||
|
|
7414a4fb06 | ||
|
|
abbd44e276 | ||
|
|
13e80e6bd5 | ||
|
|
ffa981d172 | ||
|
|
806f07db67 | ||
|
|
6746933a3d | ||
|
|
8cb2833fa7 | ||
|
|
1730f3c0c9 | ||
|
|
d6dda04f4f | ||
|
|
1b0825ef4b | ||
|
|
7249b2bd5f | ||
|
|
238bf1a29e | ||
|
|
4cbf81da59 | ||
|
|
d9b7ec18e7 | ||
|
|
ffed9c4d8c | ||
|
|
0dc0c5a0e0 | ||
|
|
57f826ece1 | ||
|
|
729bdebc50 | ||
|
|
2a541175b5 | ||
|
|
5f93f7162f | ||
|
|
3640554503 | ||
|
|
12437fd7fe | ||
|
|
4120f953c7 | ||
|
|
844c7787f9 | ||
|
|
0fe9ec1499 | ||
|
|
b3fb21dacc | ||
|
|
2deaf084e4 | ||
|
|
1b324510cc | ||
|
|
fd839f1827 | ||
|
|
f149f4aab1 | ||
|
|
af6fc64ab9 | ||
|
|
ff159bf30a | ||
|
|
8cdd19bcae | ||
|
|
2efc859829 | ||
|
|
d4a8351464 | ||
|
|
5fa544fc78 | ||
|
|
1070dd2d87 | ||
|
|
af98854ce4 | ||
|
|
7cace648c0 | ||
|
|
447bf4adb0 | ||
|
|
6572c1c692 | ||
|
|
7b48859f8d | ||
|
|
a6230bafe7 | ||
|
|
cc8f1466c7 | ||
|
|
69f810febc | ||
|
|
e5da7440d7 | ||
|
|
849ec1684a | ||
|
|
4f210cd8eb | ||
|
|
285f75764c | ||
|
|
3586203753 | ||
|
|
e406de7e00 | ||
|
|
53ed8502c9 | ||
|
|
ac8c756879 | ||
|
|
07faacdaf9 | ||
|
|
8464844518 | ||
|
|
fe2d1ff027 | ||
|
|
8d129e359e | ||
|
|
39aa56457b | ||
|
|
8491d5da8b | ||
|
|
681196e2c8 | ||
|
|
836ad5ebab | ||
|
|
a3ea1eddfb | ||
|
|
a2c06ac6ba | ||
|
|
a5c697fa2d | ||
|
|
be199b4fe9 | ||
|
|
cc15320cfe | ||
|
|
70bae59ec6 | ||
|
|
d4f3361805 | ||
|
|
332c855d40 | ||
|
|
01e3fa4d13 | ||
|
|
15a0f7a00a | ||
|
|
a751adba2a | ||
|
|
10eed010df | ||
|
|
033ca26216 | ||
|
|
40793cbdce | ||
|
|
48a1b2ec75 | ||
|
|
1a55556c66 | ||
|
|
3edd3ccbe6 | ||
|
|
194933e037 | ||
|
|
38deaedaef | ||
|
|
fc3dd5900c | ||
|
|
b1213425d0 | ||
|
|
40f0b450a8 | ||
|
|
0bab3977a8 | ||
|
|
2c46760b77 | ||
|
|
878c9ae5ae | ||
|
|
c8553de09e | ||
|
|
6738858e11 | ||
|
|
61cd6ab86e | ||
|
|
77704b669a | ||
|
|
770be613d7 | ||
|
|
9790366449 | ||
|
|
89f0a8c530 | ||
|
|
f72a06e25a | ||
|
|
8b975533e5 | ||
|
|
b32f7a9b57 | ||
|
|
e1e0083897 | ||
|
|
ca08ac0e3c | ||
|
|
a5b85b4462 | ||
|
|
3feab3a16d | ||
|
|
5d76e57b81 | ||
|
|
9101cd0339 | ||
|
|
4b2d3f5f5b | ||
|
|
482a471abb | ||
|
|
4d90bb0d02 | ||
|
|
202dfc18be | ||
|
|
13f4742699 | ||
|
|
33e769bd75 | ||
|
|
992f3000ef | ||
|
|
7ea4adae5e | ||
|
|
5ed9991135 | ||
|
|
dc2527c11f | ||
|
|
bee95654f3 | ||
|
|
48296bb1cf | ||
|
|
1ee9735354 | ||
|
|
f8da303ca1 | ||
|
|
6ae6ee9fd2 | ||
|
|
a11eafc5b3 | ||
|
|
efe53b57e4 | ||
|
|
e2330944d4 | ||
|
|
1c18906db7 | ||
|
|
873ceb48bd | ||
|
|
a48b955d89 | ||
|
|
b92fae2bfb | ||
|
|
156be17191 | ||
|
|
92290cfe81 | ||
|
|
29725c97f1 | ||
|
|
56b9cd14cb | ||
|
|
3550cc8f48 | ||
|
|
6a3d01ee6b | ||
|
|
27986213aa | ||
|
|
a2d07ef983 | ||
|
|
3cf4e32d9f | ||
|
|
a54584b716 | ||
|
|
51907e2642 | ||
|
|
5dd9d37ef2 | ||
|
|
f900854e0d | ||
|
|
d20e94f763 | ||
|
|
58de2ad2d7 | ||
|
|
f30c7b75d0 | ||
|
|
c5b8e55e12 | ||
|
|
559874fce7 | ||
|
|
1875653b34 | ||
|
|
6df770e72d | ||
|
|
51d415c8dd | ||
|
|
63bf428c34 | ||
|
|
a5d2772082 | ||
|
|
43c317ef4c | ||
|
|
01ffdb69d0 | ||
|
|
a78f346ac6 | ||
|
|
4ae88c859e | ||
|
|
e8a97f12d7 | ||
|
|
06aabdefbe | ||
|
|
15643f8e67 | ||
|
|
b987df1974 | ||
|
|
cbe63d43df | ||
|
|
e91a7c9599 | ||
|
|
3054952a5e | ||
|
|
3244df9cd1 | ||
|
|
1f75081f6e | ||
|
|
2c83a50a8a | ||
|
|
1c80fc28ee | ||
|
|
810eab9a58 | ||
|
|
256aa0296d | ||
|
|
2eb506c5e0 | ||
|
|
9f78a2902b | ||
|
|
613ae4ee34 | ||
|
|
ab208b71c4 | ||
|
|
68dd8d277d | ||
|
|
36a1927915 | ||
|
|
68437de416 | ||
|
|
459cd1b095 | ||
|
|
6f7f774080 | ||
|
|
fc0bf1953a | ||
|
|
c907e6c5fb | ||
|
|
29b3950ee7 | ||
|
|
0e0c6b8357 | ||
|
|
6f17f3e2c2 | ||
|
|
df107a272e | ||
|
|
b7a0748312 | ||
|
|
421b420a0c | ||
|
|
a478dc5935 | ||
|
|
4d65cb1c0f | ||
|
|
ced823cd95 | ||
|
|
79325bd219 | ||
|
|
5a19135c35 | ||
|
|
290e5f83d4 | ||
|
|
b535cb319a | ||
|
|
e3a9c6afb4 | ||
|
|
3f1a33e4b4 | ||
|
|
441eaa7f6c | ||
|
|
632153a1b4 | ||
|
|
f9d0ad9dc3 | ||
|
|
a67323fc12 | ||
|
|
1daa5e69b1 | ||
|
|
1718490982 | ||
|
|
1d4f97bb4c | ||
|
|
183fc7ced9 | ||
|
|
dcf1cedec9 | ||
|
|
845e608280 | ||
|
|
d6ecfe7f24 | ||
|
|
06b6bf6185 | ||
|
|
04a38b446f | ||
|
|
dfde5785a6 | ||
|
|
1a61455eef | ||
|
|
9f2ecb0144 | ||
|
|
3265060dc8 | ||
|
|
58b8acd68a | ||
|
|
3ec09ceedf | ||
|
|
1ce4aa81ee | ||
|
|
177e829f4b | ||
|
|
b5b672ec89 | ||
|
|
d41419c8d3 | ||
|
|
5e4d9dc17a | ||
|
|
4ac688e560 | ||
|
|
5d0a5cfe72 | ||
|
|
d4b81bb911 | ||
|
|
23122b327c | ||
|
|
f443c64341 | ||
|
|
c84af7d1e2 | ||
|
|
19a28b3c81 | ||
|
|
69944c1d3a | ||
|
|
81bf4921d4 | ||
|
|
91f6eedb24 | ||
|
|
dae150a3a5 | ||
|
|
8a81dce0c1 | ||
|
|
203d4a79e2 | ||
|
|
b04d47c3a9 | ||
|
|
8fcd1906a2 | ||
|
|
9939212379 | ||
|
|
38752f1327 | ||
|
|
6b51ec3371 | ||
|
|
5714056f9f | ||
|
|
21665e367c | ||
|
|
dff844b40a | ||
|
|
54403dfcbc | ||
|
|
61672c7805 | ||
|
|
69bb96113b | ||
|
|
51328efb22 | ||
|
|
f159666ae3 | ||
|
|
7fdb50807c | ||
|
|
890c7b42dc | ||
|
|
55398684cc | ||
|
|
c85edc38aa | ||
|
|
fa368b56ba | ||
|
|
41d7520585 | ||
|
|
0f23618324 | ||
|
|
bf9a2b45ef | ||
|
|
063c017bb7 | ||
|
|
7519a3765b | ||
|
|
56c687b39b | ||
|
|
083d398631 | ||
|
|
466183113f | ||
|
|
923c432977 | ||
|
|
e433ba8d7b | ||
|
|
848c884fff | ||
|
|
0769bbb7ff | ||
|
|
7054b09584 | ||
|
|
2633628ad1 | ||
|
|
e5ae1c2ea3 | ||
|
|
d2844580a1 | ||
|
|
42f5a3e2f7 | ||
|
|
8a62005a2d | ||
|
|
616f54c4a2 | ||
|
|
2140e5992a | ||
|
|
cd38c62430 | ||
|
|
67ac6ae191 | ||
|
|
7addae0fdd | ||
|
|
a3e8ba5506 | ||
|
|
6a302c38ab | ||
|
|
129bb6b1c3 | ||
|
|
c8b09c2238 | ||
|
|
76364af243 | ||
|
|
0efa8f9d3f | ||
|
|
f36b452f00 | ||
|
|
0be132f3b5 | ||
|
|
d31d8a764b | ||
|
|
68b29b683d | ||
|
|
eee293518c | ||
|
|
c4adc86f5e | ||
|
|
3ebda76def | ||
|
|
7564623d46 | ||
|
|
dc6b44571f | ||
|
|
ccd0167e40 | ||
|
|
7dd1004b93 | ||
|
|
19dd02acfd | ||
|
|
5e31914dc1 | ||
|
|
8296e0f485 | ||
|
|
afa5e3f469 | ||
|
|
f57fcbcb50 | ||
|
|
ce53e9dd2b | ||
|
|
55c2634416 | ||
|
|
fe0d340c03 | ||
|
|
5a02c9dbed | ||
|
|
2c4ffcf70d | ||
|
|
53c3e1338f | ||
|
|
79454a9072 | ||
|
|
21c2c5650b | ||
|
|
81ee559905 | ||
|
|
4a637a6e9a | ||
|
|
aaf4802d80 | ||
|
|
96310d761b | ||
|
|
96150bf568 | ||
|
|
f49df51544 | ||
|
|
673796fb3a | ||
|
|
482ab33c03 | ||
|
|
fb53cd37e7 | ||
|
|
c9fc7a1320 | ||
|
|
5f59b7e747 | ||
|
|
024b24932c | ||
|
|
604c0b189f | ||
|
|
356f1f5119 | ||
|
|
06659844b6 | ||
|
|
57cf363be9 | ||
|
|
2fc1ff68cf | ||
|
|
6c4fecc4f7 | ||
|
|
0991ad7cc8 | ||
|
|
d03b96b699 | ||
|
|
a690c1442f | ||
|
|
d742b67878 | ||
|
|
41971a95b2 | ||
|
|
b6d700077a | ||
|
|
c091e6910b | ||
|
|
35f633b533 | ||
|
|
85e4ed7c25 | ||
|
|
3b345a81c4 | ||
|
|
a55c48a4ce | ||
|
|
6f4c21c218 | ||
|
|
5060640408 | ||
|
|
f1cc8379e7 | ||
|
|
4f9627c612 | ||
|
|
012f241005 | ||
|
|
ccf67dbf05 | ||
|
|
a43709b4a8 | ||
|
|
e95c074965 | ||
|
|
4ca73566b6 | ||
|
|
d0b347517c | ||
|
|
7bed7ff482 | ||
|
|
d38b0dbf5b | ||
|
|
29d6c4ac04 | ||
|
|
8148b6d037 | ||
|
|
3327e0e871 | ||
|
|
0456f0f59b | ||
|
|
72cf78de2c | ||
|
|
1d0a89879c | ||
|
|
d1cc952859 | ||
|
|
f56c5b201d | ||
|
|
077b9eb7a4 | ||
|
|
15c333feb0 | ||
|
|
31c20ab32c | ||
|
|
69215cf9eb | ||
|
|
f89b51eace | ||
|
|
c581b5e532 | ||
|
|
df311203dc | ||
|
|
4927195ee4 | ||
|
|
63be1ebd38 | ||
|
|
796dc18cfb | ||
|
|
14e116553f | ||
|
|
c82ccd6cf7 | ||
|
|
0adb080319 | ||
|
|
dbb38fffae | ||
|
|
672a68219a | ||
|
|
22cb0efd00 | ||
|
|
a68d3d63b2 | ||
|
|
cf48c7280a | ||
|
|
1295973028 | ||
|
|
d5b9eda0f2 | ||
|
|
41c078d25c | ||
|
|
5614224e7d | ||
|
|
9ba44cb0d5 | ||
|
|
c18828af7b | ||
|
|
8a5f8439b4 | ||
|
|
8f0374569e | ||
|
|
09dde636d2 | ||
|
|
d347247bf3 | ||
|
|
a6c66fb669 | ||
|
|
b4dbc825b1 | ||
|
|
4a0cc8223e | ||
|
|
7db10857b3 | ||
|
|
7e927b43ad | ||
|
|
9eea072f2a | ||
|
|
aa2ff674db | ||
|
|
de24bfdf2f | ||
|
|
2a084c3d98 | ||
|
|
db8df41396 | ||
|
|
bda05d9372 | ||
|
|
59bc2af4d6 | ||
|
|
00a23ee330 | ||
|
|
51ad50a641 | ||
|
|
148e1926e8 | ||
|
|
96c023df41 | ||
|
|
44f37f49a1 | ||
|
|
a8a30f6d3f | ||
|
|
ba80b1cd55 | ||
|
|
b56e985ccc | ||
|
|
67521fd9f6 | ||
|
|
8c394f44b8 | ||
|
|
77b4fff268 | ||
|
|
f56a0c6075 | ||
|
|
9ce8486059 | ||
|
|
04a321150a | ||
|
|
d333c3c09e | ||
|
|
81d977c720 | ||
|
|
f477898c7c | ||
|
|
566193a1eb | ||
|
|
5d6eeb5d1d | ||
|
|
d9b9d71b2d | ||
|
|
643ee1df14 | ||
|
|
6c4d37ee68 | ||
|
|
97b79cd04a | ||
|
|
56c6229dd6 | ||
|
|
0fe2dd9b48 | ||
|
|
910aee7f7b | ||
|
|
97063937ff | ||
|
|
7e68b097d1 | ||
|
|
4d41dff4fd | ||
|
|
05082cec88 | ||
|
|
f05733da69 | ||
|
|
3c53909e82 | ||
|
|
1e53ec47a9 | ||
|
|
17802735d7 | ||
|
|
d2eb67a1ae | ||
|
|
3f254dd3fc | ||
|
|
e139bde6ae | ||
|
|
5f62951143 | ||
|
|
2207e87c8f | ||
|
|
5bd59c7b70 | ||
|
|
02f6867a2f | ||
|
|
b93fa3144a | ||
|
|
a68e0d9a3f | ||
|
|
cfe80ba9b7 | ||
|
|
35abfd44dd | ||
|
|
e98b5a691e | ||
|
|
ed24afd172 | ||
|
|
714556de65 | ||
|
|
547ec85b58 | ||
|
|
845d751e87 | ||
|
|
518a7f8a71 | ||
|
|
31323b01bc | ||
|
|
3a138ecc83 | ||
|
|
7294674a8b | ||
|
|
423b978395 | ||
|
|
ecf20ec7b8 | ||
|
|
c948a509fb | ||
|
|
f5ad19d76b | ||
|
|
d665d9e90e | ||
|
|
a5e10450dd | ||
|
|
e9d79b130d | ||
|
|
7951dac9d5 | ||
|
|
6c77351c58 | ||
|
|
7c4cda622f | ||
|
|
d8f8c1cb99 | ||
|
|
d2b9ad570f | ||
|
|
5b36f32996 | ||
|
|
3298030b8e | ||
|
|
6cfc696439 | ||
|
|
a93b3a06dd | ||
|
|
79e8d77ea0 | ||
|
|
d68fab9ee5 | ||
|
|
bda470245e | ||
|
|
0c95290f93 | ||
|
|
8989739d32 | ||
|
|
1112981e6e | ||
|
|
0cf82744ce | ||
|
|
5cdf838325 | ||
|
|
6418cad39f | ||
|
|
46529fd51e | ||
|
|
c09ba40a48 | ||
|
|
47d52896a1 | ||
|
|
d60c99b01c | ||
|
|
b8aeba06a2 | ||
|
|
8a0bc2d614 | ||
|
|
e34747d1ad | ||
|
|
1a6bc7c514 | ||
|
|
ffa0ddfdbf | ||
|
|
ca55bff1cf | ||
|
|
cfee5c4fdb | ||
|
|
e46185068b | ||
|
|
6ef2fea45e | ||
|
|
e244dd84a9 | ||
|
|
5034937a15 | ||
|
|
060045be65 | ||
|
|
9adfe8d484 | ||
|
|
799cc369e0 | ||
|
|
b97d3fea4b | ||
|
|
2a4ca9d5c3 | ||
|
|
747e40e74e | ||
|
|
cf279e7885 | ||
|
|
cbf968735a | ||
|
|
57b35e6007 | ||
|
|
1eaabdd8e5 | ||
|
|
dcd4e660a3 | ||
|
|
96409e74e5 | ||
|
|
e28ee097a1 | ||
|
|
2b4e544867 | ||
|
|
ee042a3481 | ||
|
|
63075f6846 | ||
|
|
7f2e42a06d | ||
|
|
3fbfa33b9a | ||
|
|
179aa75047 | ||
|
|
4658194d08 | ||
|
|
b35657814c | ||
|
|
a2322c77c6 | ||
|
|
b50c183c19 | ||
|
|
a941687db0 | ||
|
|
c2eef52b65 | ||
|
|
3e6cbbde04 | ||
|
|
6400536282 | ||
|
|
776103068f | ||
|
|
93beff3b65 | ||
|
|
22f8d86b05 | ||
|
|
3a9a9c7ad0 | ||
|
|
13238b1ad2 | ||
|
|
56f661e9c6 | ||
|
|
5351f46efb | ||
|
|
0cd3335b78 | ||
|
|
0611627448 | ||
|
|
f014918435 | ||
|
|
51e016089e | ||
|
|
8a66ff5278 | ||
|
|
e1dd3f06fe | ||
|
|
32ab35f61f | ||
|
|
8ab96ec74b | ||
|
|
0730590e35 | ||
|
|
f7e0b1331c | ||
|
|
17aa2a7092 | ||
|
|
7d38d05ca7 | ||
|
|
33bad047f0 | ||
|
|
5234b73c29 | ||
|
|
c566e2eba5 | ||
|
|
e565977481 | ||
|
|
8927c9d22b | ||
|
|
28eb251ccd | ||
|
|
b99dc95b1d | ||
|
|
75aadb3e79 | ||
|
|
b6ecd5fb4c | ||
|
|
1e7f55ed84 | ||
|
|
eeadc5ecff | ||
|
|
568ca42988 | ||
|
|
7b758bfc9d | ||
|
|
8ef454b75f | ||
|
|
0a2f2fda5c | ||
|
|
6b440918ec | ||
|
|
a73fce945c | ||
|
|
d349bb3cc7 | ||
|
|
7c4119a287 | ||
|
|
8a71ad99e6 | ||
|
|
41b405d7bf | ||
|
|
30b80dc5ee | ||
|
|
524aa2e586 | ||
|
|
990a1b9ae0 | ||
|
|
4cb0c6864e | ||
|
|
5183693951 | ||
|
|
e47506f957 | ||
|
|
824e4dc0e4 | ||
|
|
d033497714 | ||
|
|
d8028df29d | ||
|
|
564683d25a | ||
|
|
30c0a3f201 | ||
|
|
08fe9ac518 | ||
|
|
14d6f71f82 | ||
|
|
29454e2296 | ||
|
|
d6cbf9f77d | ||
|
|
b9fead4d6e | ||
|
|
c6a04e1719 | ||
|
|
c839a61fea | ||
|
|
c06abbc5f7 | ||
|
|
c8e88e1710 | ||
|
|
bf7a115bf2 | ||
|
|
b8dfb69cf5 | ||
|
|
1cd9715095 | ||
|
|
5c7aeac148 | ||
|
|
09a80628e6 | ||
|
|
2ff2c369f7 | ||
|
|
eef70aaf74 | ||
|
|
89ac97caba | ||
|
|
c00b236c8d | ||
|
|
eacd3f35e0 | ||
|
|
8a2aa72571 | ||
|
|
7da8f273d2 | ||
|
|
a90a5a2b6a | ||
|
|
b5b819b4a3 | ||
|
|
821e2b3a75 | ||
|
|
773efb0745 | ||
|
|
ed1904a75d | ||
|
|
a66663f0f6 | ||
|
|
1104688b02 | ||
|
|
36d95e230e | ||
|
|
8a27a95a2a | ||
|
|
2e63b5a5e5 | ||
|
|
4cbd113d01 | ||
|
|
ba5ae74144 | ||
|
|
f2b40e5fae | ||
|
|
8ed682930b | ||
|
|
86ad7922b0 | ||
|
|
f7476f53c7 | ||
|
|
5d6f7ac8ef | ||
|
|
f16fa5ed55 | ||
|
|
c0ba32f7a6 | ||
|
|
409c12a851 | ||
|
|
bcdcbf20ee | ||
|
|
8fc5b5a55f | ||
|
|
7cf28a5623 | ||
|
|
6668c456ac | ||
|
|
98f2476751 | ||
|
|
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 |
No files matched your search
@@ -0,0 +1,6 @@
|
|||||||
|
BasedOnStyle: Google
|
||||||
|
AllowShortFunctionsOnASingleLine: false
|
||||||
|
SpaceAfterCStyleCast: true
|
||||||
|
PointerBindsToType: false
|
||||||
|
DerivePointerBinding: false
|
||||||
|
IncludeBlocks: Preserve
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
language: c
|
||||||
|
sudo: false
|
||||||
|
after_success: bash <(curl -s https://codecov.io/bash)
|
||||||
|
install:
|
||||||
|
- if test "$TRAVIS_OS_NAME" = linux; then sudo apt-get install libmbedtls-dev; else brew install jq mbedtls; fi
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
|
- osx
|
||||||
|
compiler:
|
||||||
|
- clang
|
||||||
|
- gcc
|
||||||
|
script: make test test++ ex
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: osx
|
||||||
|
compiler: clang
|
||||||
|
script: make mg_prefix
|
||||||
|
- os: linux
|
||||||
|
compiler: msvc98
|
||||||
|
script: make vc98 vc2017
|
||||||
|
sudo: required
|
||||||
|
services:
|
||||||
|
- docker
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
|
Copyright (c) 2004-2013 Sergey Lyubka
|
||||||
Copyright (c) 2013 Cesanta Software Limited
|
Copyright (c) 2013-2020 Cesanta Software Limited
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
This code 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 code 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 code 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 <https://www.cesanta.com/license>.
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
SRCS = $(wildcard src/*.c)
|
||||||
|
HDRS = $(wildcard src/*.h)
|
||||||
|
DEFS ?= -DMG_MAX_HTTP_HEADERS=5 -DMG_ENABLE_LINES -DMG_ENABLE_HTTP_DEBUG_ENDPOINT=1 -DMG_ENABLE_DIRECTORY_LISTING=1
|
||||||
|
CFLAGS ?= -W -Wall -Werror -Isrc -I. -O0 -g $(DEFS) $(TFLAGS) $(EXTRA)
|
||||||
|
SSL ?= MBEDTLS
|
||||||
|
CDIR ?= $(realpath $(CURDIR))
|
||||||
|
VC98 = docker run --rm -e WINEDEBUG=-all -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/vc98
|
||||||
|
VC2017 = docker run --rm -e WINEDEBUG=-all -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/vc2017
|
||||||
|
GCC = docker run --rm -v $(CDIR):$(CDIR) -w $(CDIR) mdashnet/cc2
|
||||||
|
VCFLAGS = /nologo /W3 /O2 /I. $(DEFS) $(TFLAGS)
|
||||||
|
CLANG ?= clang # /usr/local/opt/llvm\@9/bin/clang
|
||||||
|
ASAN_OPTIONS ?=
|
||||||
|
EXAMPLES := $(wildcard examples/*)
|
||||||
|
EXAMPLE_TARGET ?= example
|
||||||
|
.PHONY: ex test
|
||||||
|
|
||||||
|
ifeq "$(SSL)" "MBEDTLS"
|
||||||
|
MBEDTLS_DIR ?= $(shell brew --cellar mbedtls)
|
||||||
|
MBEDTLS_VER ?= $(shell brew info mbedtls --json | jq -j .[0].installed[0].version)
|
||||||
|
MBEDTLS ?= $(MBEDTLS_DIR)/$(MBEDTLS_VER)
|
||||||
|
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS)/include -I/usr/include
|
||||||
|
LDFLAGS ?= -L$(MBEDTLS)/lib -lmbedtls -lmbedcrypto -lmbedx509
|
||||||
|
endif
|
||||||
|
ifeq "$(SSL)" "OPENSSL"
|
||||||
|
OPENSSLDIR ?= $(shell "$(brew --cellar openssl)/$(brew info openssl --json | jq -j .[0].installed[0].version)")
|
||||||
|
CFLAGS += -DMG_ENABLE_OPENSSL=1 -I$(OPENSSLDIR)/include
|
||||||
|
LDFLAGS ?= -L$(OPENSSLDIR)/lib -lssl -lcrypto
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: mg_prefix test test++ ex vc98 vc2017 linux linux++ infer fuzz
|
||||||
|
|
||||||
|
ex:
|
||||||
|
@for X in $(EXAMPLES); do $(MAKE) -C $$X $(EXAMPLE_TARGET); done
|
||||||
|
|
||||||
|
# Check that all external (exported) symbols have "mg_" prefix
|
||||||
|
mg_prefix: mongoose.c mongoose.h
|
||||||
|
$(CLANG) mongoose.c $(CFLAGS) -c -o /tmp/x.o && nm /tmp/x.o | grep ' T' | grep -v 'mg_' ; test $$? = 1
|
||||||
|
|
||||||
|
# C++ build
|
||||||
|
test++: CLANG = g++ -Wno-deprecated -Wno-missing-field-initializers
|
||||||
|
test++: unamalgamated
|
||||||
|
|
||||||
|
# Make sure we can build from an unamalgamated sources
|
||||||
|
unamalgamated: $(SRCS) $(HDRS) Makefile
|
||||||
|
$(CLANG) src/*.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -g -o unit_test
|
||||||
|
|
||||||
|
fuzz: mongoose.c mongoose.h Makefile test/fuzz.c
|
||||||
|
$(CLANG) mongoose.c test/fuzz.c $(CFLAGS) -DMG_ENABLE_LOG=0 -fsanitize=fuzzer,signed-integer-overflow,address $(LDFLAGS) -g -o fuzzer
|
||||||
|
$(DEBUGGER) ./fuzzer
|
||||||
|
|
||||||
|
# make CLANG=/usr/local/opt/llvm\@8/bin/clang ASAN_OPTIONS=detect_leaks=1
|
||||||
|
test: CFLAGS += -DMG_ENABLE_IPV6=1 -fsanitize=address#,undefined
|
||||||
|
test: mongoose.c mongoose.h Makefile test/unit_test.c
|
||||||
|
$(CLANG) mongoose.c test/unit_test.c $(CFLAGS) -coverage $(LDFLAGS) -g -o unit_test
|
||||||
|
ASAN_OPTIONS=$(ASAN_OPTIONS) $(DEBUGGER) ./unit_test
|
||||||
|
|
||||||
|
coverage: test
|
||||||
|
gcov -l -n *.gcno | sed '/^$$/d' | sed 'N;s/\n/ /'
|
||||||
|
gcov mongoose.gcno >/dev/null
|
||||||
|
|
||||||
|
infer:
|
||||||
|
infer run -- cc test/unit_test.c -c -W -Wall -Werror -Isrc -I. -O2 -DMG_ENABLE_MBEDTLS=1 -DMG_ENABLE_LINES -I/usr/local/Cellar/mbedtls/2.23.0/include -DMG_ENABLE_IPV6=1 -g -o /dev/null
|
||||||
|
|
||||||
|
#vc98: VCFLAGS += -DMG_ENABLE_IPV6=1
|
||||||
|
vc98: Makefile mongoose.c mongoose.h test/unit_test.c
|
||||||
|
$(VC98) wine cl mongoose.c test/unit_test.c $(VCFLAGS) ws2_32.lib /Fe$@.exe
|
||||||
|
$(VC98) wine $@.exe
|
||||||
|
|
||||||
|
vc2017: CFLAGS += -DMG_ENABLE_IPV6=1
|
||||||
|
vc2017: Makefile mongoose.c mongoose.h test/unit_test.c
|
||||||
|
$(VC2017) wine64 cl mongoose.c test/unit_test.c $(VCFLAGS) ws2_32.lib /Fe$@.exe
|
||||||
|
$(VC2017) wine64 $@.exe
|
||||||
|
|
||||||
|
linux: CFLAGS += -DMG_ENABLE_IPV6=1 -fsanitize=address,undefined
|
||||||
|
linux: Makefile mongoose.c mongoose.h test/unit_test.c
|
||||||
|
$(GCC) $(CC) mongoose.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -o unit_test_gcc
|
||||||
|
$(GCC) ./unit_test_gcc
|
||||||
|
|
||||||
|
linux++: CC = g++ -Wno-missing-field-initializers
|
||||||
|
linux++: linux
|
||||||
|
|
||||||
|
mongoose.c: $(SRCS) Makefile
|
||||||
|
(cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/private.h src/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@
|
||||||
|
|
||||||
|
mongoose.h: $(HDRS) Makefile
|
||||||
|
(cat src/license.h src/version.h ; cat src/arch.h src/arch_*.h src/config.h src/str.h src/log.h src/timer.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/event.h src/net.h src/http.h src/tls.h src/ws.h src/sntp.h src/mqtt.h src/dns.h | sed -e 's,#include ".*,,' -e 's,^#pragma once,,')> $@
|
||||||
|
|
||||||
|
clean: EXAMPLE_TARGET = clean
|
||||||
|
clean: ex
|
||||||
|
rm -rf $(PROG) *.o *.dSYM unit_test* ut fuzzer *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb slow-unit* _CL_* infer-out data.txt crash-*
|
||||||
@@ -1,86 +1,78 @@
|
|||||||
# <img src="http://cesanta.com/images/mongoose_logo.png" width="64" height="64"> Mongoose Web Server
|
# Mongoose - Embedded Web Server / Embedded Networking Library
|
||||||
|
|
||||||
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.
|

|
||||||
|
[](https://travis-ci.org/cesanta/mongoose)
|
||||||
|
[](https://codecov.io/gh/cesanta/mongoose)
|
||||||
|
|
||||||
Mongoose is built on top of Libmongoose embedded library, which can turn
|
Mongoose is a networking library for C/C++. It implements event-driven
|
||||||
anything into a web server in 5 minutes worth of effort and few lines of code.
|
non-blocking APIs for TCP, UDP, HTTP, WebSocket, MQTT. It has been designed
|
||||||
Libmongoose is used to serve Web GUI on embedded devices, implement RESTful
|
for connecting devices and bringing them online. On the market since 2004, used
|
||||||
services, RPC frameworks (e.g. JSON-RPC), handle telemetry data exchange, and
|
by vast number of open source and commercial products - it even runs on the
|
||||||
perform many other tasks in various different industries including aerospace,
|
International Space Station! Mongoose makes embedded network programming fast,
|
||||||
manufacturing, finance, research, automotive, gaming, IT.
|
robust, and easy.
|
||||||
|
|
||||||
|
- [Download Mongoose Source Code here](https://www.cesanta.com/download.html)
|
||||||
|
- [Read Mongoose documentation](https://cesanta.com/docs/)
|
||||||
|
|
||||||
* [Mailing list](http://groups.google.com/group/mongoose-users)
|
Connectivity is vital for software and embedded devices, but there are many
|
||||||
* [Downloads](http://cesanta.com/mongoose.shtml)
|
pitfalls to consider when embedding a web server. This white paper breaks down
|
||||||
* [Documentation](http://cesanta.com/docs.shtml)
|
on the top 9 things to avoid when embedding a web server.
|
||||||
|
|
||||||
|
- [Download “9 Things NOT to do when embedding a web server” white paper here](https://www.cesanta.com/whitepaper.html)
|
||||||
|
|
||||||
|
Looking for a complete IoT solution? Check out
|
||||||
|
- [VCON](https://vcon.io) - Arduino compatible MCU modules with built-in firmware OTA updates
|
||||||
|
- [Mongoose OS](https://mongoose-os.com) - open source embedded operating system for low-power connected microcontrollers. Secure, designed for commercial Internet of Things products
|
||||||
|
|
||||||
|
# Support
|
||||||
|
- [Study Mongoose examples](https://github.com/cesanta/mongoose/tree/master/examples)
|
||||||
|
- [Support Forum - ask your technical questions here](https://forum.cesanta.com/c/mongoose-library/6)
|
||||||
|
- [Commercial licensing and support available](https://www.cesanta.com/licensing.html)
|
||||||
|
- [Check out latest releases](https://github.com/cesanta/mongoose/releases)
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
|
|
||||||
- Works on Windows, Mac, UNIX/Linux, iPhone, Android eCos, QNX
|
* Cross-platform: works on Linux/UNIX, MacOS, QNX, eCos, Windows, Android,
|
||||||
and many other platforms
|
iPhone, FreeRTOS, etc
|
||||||
- CGI, SSI, SSL, Digest auth, Websocket, WEbDAV, Resumed download,
|
* Supported hardware platforms: TI CC3200, TI MSP432, NRF52, STM32, PIC32, ESP8266, ESP32 and more
|
||||||
URL rewrite, file blacklist
|
* Builtin protocols:
|
||||||
- Custom error pages, Virtual hosts, IP-based ACL, Windows service,
|
- plain TCP, plain UDP, SSL/TLS (over TCP, one-way or two-way)
|
||||||
HTTP/HTTPS client
|
- HTTP client, HTTP server
|
||||||
- Simple and clean
|
- WebSocket client, WebSocket server
|
||||||
[embedding API](https://github.com/cesanta/mongoose/blob/master/mongoose.h).
|
- MQTT client
|
||||||
The source is in single
|
- DNS client, async DNS resolver
|
||||||
[mongoose.c](https://github.com/cesanta/mongoose/blob/master/mongoose.c) file
|
* Single-threaded, asynchronous, non-blocking core with simple event-based API
|
||||||
to make embedding easy
|
* Native support for [LWIP embedded TCP/IP stack](https://en.wikipedia.org/wiki/LwIP)
|
||||||
- Extremely lightweight, has a core of under 40kB and tiny runtime footprint
|
* Tiny static and run-time footprint
|
||||||
- Asynchronous, non-blocking core supporting single- or multi-threaded usage
|
* Source code is both ISO C and ISO C++ compliant
|
||||||
- On the market since 2004 with over 1 million cumulative downloads
|
* Very easy to integrate: just copy
|
||||||
- Stable, mature and tested, has several man-years invested
|
[mongoose.c](https://raw.githubusercontent.com/cesanta/mongoose/master/mongoose.c) and
|
||||||
in continuous improvement and refinement
|
[mongoose.h](https://raw.githubusercontent.com/cesanta/mongoose/master/mongoose.h)
|
||||||
|
files to your build tree
|
||||||
# Screenshots
|
|
||||||
|
|
||||||
Download, double-click to start, run browser -- that's all!
|
|
||||||
|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
# Acknowledgements
|
|
||||||
|
|
||||||
Mongoose made better thanks to the contribution of following people:
|
|
||||||
|
|
||||||
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,
|
|
||||||
W.Mar, J.Wilander, Santa from Memphis, S.Davies, C.Beck,
|
|
||||||
O.M.Vilhunen, C.Radik, G.Woodcock, M.Szczepkowski,
|
|
||||||
Eternal Lands Dev Team, T.Tollet, C.Tangerino, G.Karsai, A.Bourgett,
|
|
||||||
C.Blakemore, D.Fonaryov, T.Andrle, O.IJsselmuiden, R.Womack, M.Tomlinson,
|
|
||||||
A.Slåttå, L.Farrell, J.D.P.Ballestero, V.Albaev, B.Harker, T.Scheffel, H.Klein,
|
|
||||||
R.Merit, T.Bennett, H.Solis, A.Zincenko, M.S., S.Krul, K.Cooke, S.McCallum,
|
|
||||||
F.Morenius, and 10 others.
|
|
||||||
|
|
||||||
# Licensing
|
# Licensing
|
||||||
|
|
||||||
Mongoose is released under commercial and
|
Mongoose is released under Commercial and [GNU GPL v.2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) open source licenses.
|
||||||
[GNU GPL v.2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) open
|
|
||||||
source licenses. The GPLv2 open source License does not generally permit
|
|
||||||
incorporating this software into non-open source programs.
|
|
||||||
For those customers who do not wish to comply with the GPLv2 open
|
|
||||||
source license requirements,
|
|
||||||
[Cesanta Software](http://cesanta.com) offers a full,
|
|
||||||
royalty-free commercial license and professional support
|
|
||||||
without any of the GPL restrictions.
|
|
||||||
|
|
||||||
# Other products by Cesanta Software: simple and effective
|
Commercial Projects: [Contact us for commercial license.](https://www.cesanta.com/contact.html)
|
||||||
|
|
||||||
- [SSL Wrapper](https://github.com/cesanta/ssl_wrapper) - application to
|
# Dashboard Example
|
||||||
secure network communications
|
|
||||||
- [Frozen](https://github.com/cesanta/frozen) - JSON parser and generator
|
Mongoose is often used to implement device dashboards and real-time
|
||||||
- [SLRE](https://github.com/cesanta/slre) - Super Light Regular Expression
|
data exchange over Websocket. Here is a dashboard example that illustrates
|
||||||
library
|
the functionality:
|
||||||
- [Net Skeleton](https://github.com/cesanta/net_skeleton) - framework for
|
|
||||||
building network applications
|

|
||||||
- [SLDR](https://github.com/cesanta/sldr) - Super Light DNS Resolver
|
|
||||||
|
[Developing a new product? Contact us today to discuss how Mongoose can help.](https://www.cesanta.com/contact.html)
|
||||||
|
|
||||||
|
# Contributions
|
||||||
|
|
||||||
|
Contributions are welcome! Please follow the guidelines below:
|
||||||
|
|
||||||
|
- Sign [Cesanta CLA](https://cesanta.com/cla.html) and send GitHub pull request
|
||||||
|
- When making pull requests, please make sure that it has only one commit,
|
||||||
|
and imlements/fixes only one piece of functionality
|
||||||
|
|
||||||
|
# Looking for a pre-compiled Mongoose web server Windows or Mac binary?
|
||||||
|
- [Download pre-compiled Mongoose web server binary.](https://www.cesanta.com/binary.html)
|
||||||
@@ -1,245 +0,0 @@
|
|||||||
# Mongoose API Reference
|
|
||||||
|
|
||||||
struct mg_server *mg_create_server(void *server_param);
|
|
||||||
|
|
||||||
Creates web server instance. Returns opaque instance pointer, or NULL if
|
|
||||||
there is not enough memory. `server_param`: Could be any pointer, or NULL.
|
|
||||||
This pointer will be passed
|
|
||||||
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
|
|
||||||
as `user_param`, to let the callback get the pointer to the C++ object.
|
|
||||||
|
|
||||||
Note that this function doesn't make the
|
|
||||||
server instance to serve. Serving is done by `mg_poll_server()` function.
|
|
||||||
Mongoose has single-threaded, event-driven, asynchronous, non-blocking core.
|
|
||||||
When server instance is created, it contains an information about
|
|
||||||
the configuration and the state of each connection.
|
|
||||||
Server instance is capable on listening on only one port. After creation,
|
|
||||||
`struct mg_server` has a list
|
|
||||||
of active connections and configuration parameters.
|
|
||||||
|
|
||||||
Side-effect: on UNIX, `mg_create_server()` ignores SIGPIPE signals. If custom
|
|
||||||
processing is required SIGPIPE, signal handler must be set up after
|
|
||||||
calling `mg_create_server()`.
|
|
||||||
|
|
||||||
Important: Mongoose does not install `SIGCHLD` handler. If CGI is used,
|
|
||||||
`SIGCHLD` handler must be set up to reap CGI zombie processes.
|
|
||||||
|
|
||||||
|
|
||||||
void mg_destroy_server(struct mg_server **server);
|
|
||||||
|
|
||||||
Deallocates web server instance, closes all pending connections, and makes
|
|
||||||
server pointer a NULL pointer.
|
|
||||||
|
|
||||||
const char mg_set_option(struct mg_server *server, const char *name,
|
|
||||||
const char *value);
|
|
||||||
|
|
||||||
Sets a particular server option. Note that at least one option,
|
|
||||||
`listening_port`, must be specified. To serve static files, `document_root`
|
|
||||||
must be specified too. If `document_root` option is left unset, Mongoose
|
|
||||||
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
|
|
||||||
allowed to call `mg_set_option()` by the same thread that does
|
|
||||||
`mg_poll_server()` (Mongoose thread) and change server configuration while it
|
|
||||||
is serving, in between `mg_poll_server()` calls.
|
|
||||||
|
|
||||||
void mg_poll_server(struct mg_server *server, int milliseconds);
|
|
||||||
|
|
||||||
Performs one iteration of IO loop by iterating over all
|
|
||||||
active connections, performing `select()` syscall on all sockets with a timeout
|
|
||||||
of `milliseconds`. When `select()` returns, Mongoose
|
|
||||||
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
|
|
||||||
one thread calling `mg_poll_server()`, `mg_set_option()` or any other function
|
|
||||||
that take `struct mg_server *` parameter. Mongoose does not
|
|
||||||
mutex-protect `struct mg_server *`, therefore only single thread
|
|
||||||
(Mongoose thread) should make Mongoose calls.
|
|
||||||
|
|
||||||
`mg_poll_server()` calls user-specified event handler when certain events
|
|
||||||
occur. Sequence of events for the accepted 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. Event handler return value is ignored.
|
|
||||||
|
|
||||||
Sequence of events for the client connection is this:
|
|
||||||
|
|
||||||
* `MG_CONNECT` sent when Mongoose has connected to the remote host.
|
|
||||||
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.
|
|
||||||
POST data is available to the callback as `struct mg_connection::content`,
|
|
||||||
and POST data length is in `struct mg_connection::content_len`.
|
|
||||||
|
|
||||||
Note that websocket connections are treated the same way. Mongoose buffers
|
|
||||||
websocket frame in memory, and calls event handler when frame is fully
|
|
||||||
buffered. Frame data is available `struct mg_connection::content`, and
|
|
||||||
data length is in `struct mg_connection::content_len`, i.e. very similar to
|
|
||||||
the POST request. `struct mg_connection::is_websocket` flag indicates
|
|
||||||
whether the request is websocket or not. Also, for websocket requests,
|
|
||||||
there is `struct mg_connection::wsbits` field which contains first byte
|
|
||||||
of the websocket frame which URI handler can examine. Note that to
|
|
||||||
reply to the websocket client, `mg_websocket_write()` should be used.
|
|
||||||
To reply to the plain HTTP client, `mg_write_data()` should be used.
|
|
||||||
|
|
||||||
|
|
||||||
const char **mg_get_valid_option_names(void);
|
|
||||||
|
|
||||||
Returns a NULL-terminated array of option names and their default values.
|
|
||||||
There are two entries per option in an array: an option name followed by a
|
|
||||||
default value. A default value could be NULL. A NULL name indicates an end
|
|
||||||
of the array.
|
|
||||||
|
|
||||||
const char *mg_get_option(const struct mg_server *server, const char *name);
|
|
||||||
|
|
||||||
Returns the value of particular configuration parameter. If
|
|
||||||
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
|
|
||||||
is returned.
|
|
||||||
|
|
||||||
void mg_wakeup_server_ex(struct mg_server *, mg_handler_t func,
|
|
||||||
const char *fmt, ...);
|
|
||||||
|
|
||||||
Sends string message to a server. Function `func` is called for every active
|
|
||||||
connection. String message is passed in `struct mg_connection::callback_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
|
|
||||||
the message, currently at 8 kilobytes.
|
|
||||||
|
|
||||||
void mg_send_status(struct mg_connection *, int status_code);
|
|
||||||
void mg_send_header(struct mg_connection *, const char *name,
|
|
||||||
const char *value);
|
|
||||||
void mg_send_data(struct mg_connection *, const void *data, int data_len);
|
|
||||||
void mg_printf_data(struct mg_connection *, const char *format, ...);
|
|
||||||
|
|
||||||
These functions are used to construct a response to the client. HTTP response
|
|
||||||
consists of three parts: a status line, zero or more HTTP headers,
|
|
||||||
a response body. Mongoose provides functions for all three parts:
|
|
||||||
* `mg_send_status()` is used to create status line. This function can be
|
|
||||||
called zero or once. If `mg_send_status()` is not called, then Mongoose
|
|
||||||
will send status 200 (success) implicitly.
|
|
||||||
* `mg_send_header()` adds HTTP header to the response. This function could
|
|
||||||
be called zero or more times.
|
|
||||||
* `mg_send_data()` and `mg_printf_data()` are used to send data to the
|
|
||||||
client. Note that Mongoose adds `Transfer-Encoding: chunked` header
|
|
||||||
implicitly, and sends data in chunks. Therefore, it is not necessary to
|
|
||||||
set `Content-Length` header. Note that `mg_send_data()` and
|
|
||||||
`mg_printf_data()` do not send data immediately. Instead, they spool
|
|
||||||
data in memory, and Mongoose sends that data later after URI handler
|
|
||||||
returns. If data to be sent is huge, an URI handler might
|
|
||||||
send data in pieces by saving state in
|
|
||||||
`struct mg_connection::connection_param` variable and returning `0`. Then
|
|
||||||
Mongoose will call a handler repeatedly after each socket write.
|
|
||||||
|
|
||||||
<!-- -->
|
|
||||||
|
|
||||||
void mg_send_file(struct mg_connection *, const char *path);
|
|
||||||
|
|
||||||
Tells Mongoose to serve given file. Mongoose handles file according to
|
|
||||||
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`.
|
|
||||||
|
|
||||||
int mg_websocket_write(struct mg_connection* conn, int opcode,
|
|
||||||
const char *data, size_t data_len);
|
|
||||||
|
|
||||||
Similar to `mg_write()`, 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);
|
|
||||||
|
|
||||||
Get the value of particular HTTP header. This is a helper function.
|
|
||||||
It traverses http_headers array, and if the header is present in the array,
|
|
||||||
returns its value. If it is not present, NULL is returned.
|
|
||||||
|
|
||||||
|
|
||||||
int mg_get_var(const struct mg_connection *conn, const char *var_name,
|
|
||||||
char *buf, size_t buf_len);
|
|
||||||
|
|
||||||
Gets HTTP form variable. Both POST buffer and query string are inspected.
|
|
||||||
Form variable is url-decoded and written to the buffer. On success, this
|
|
||||||
function returns the length of decoded variable. On error, -1 is returned if
|
|
||||||
variable not found, and -2 is returned if destination buffer is too small
|
|
||||||
to hold the variable. Destination buffer is guaranteed to be
|
|
||||||
'\0' - terminated if it is not NULL or zero length.
|
|
||||||
|
|
||||||
int mg_parse_header(const char *hdr, const char *var_name, char *buf,
|
|
||||||
size_t buf_size);
|
|
||||||
|
|
||||||
This function parses HTTP header and fetches given variable's value in a buffer.
|
|
||||||
A header should be like `x=123, y=345, z="other value"`. This function is
|
|
||||||
designed to parse Cookie headers, Authorization headers, and similar. Returns
|
|
||||||
the length of the fetched value, or 0 if variable not found.
|
|
||||||
|
|
||||||
int mg_modify_passwords_file(const char *passwords_file_name,
|
|
||||||
const char *domain,
|
|
||||||
const char *user,
|
|
||||||
const char *password);
|
|
||||||
|
|
||||||
Add, edit or delete the entry in the passwords file.
|
|
||||||
This function allows an application to manipulate .htpasswd files on 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,
|
|
||||||
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 NULL, entry is deleted.
|
|
||||||
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.
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# Mongoose Build on Android
|
|
||||||
|
|
||||||
This is a small guide to help you run mongoose on Android. Currently it is
|
|
||||||
tested on the HTC Wildfire. If you have managed to run it on other devices
|
|
||||||
as well, please comment or drop an email in the mailing list.
|
|
||||||
Note : You dont need root access to run mongoose on Android.
|
|
||||||
|
|
||||||
- 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)
|
|
||||||
- Run `/path-to-ndk/ndk-build -C /path-to-mongoose/examples`
|
|
||||||
That should generate mongoose/lib/armeabi/mongoose
|
|
||||||
- Using the adb tool (you need to have Android SDK installed for that),
|
|
||||||
push the generated mongoose binary to `/data/local` folder on device.
|
|
||||||
- From adb shell, navigate to `/data/local` and execute `./mongoose`.
|
|
||||||
- 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.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
|
|
||||||
- `jni` stands for Java Native Interface. Read up on Android NDK if you want
|
|
||||||
to know how to interact with the native C functions of mongoose in Android
|
|
||||||
Java applications.
|
|
||||||
- TODO: A Java application that interacts with the native binary or a
|
|
||||||
shared library.
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
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.
|
|
||||||
|
|
||||||

|
|
||||||
@@ -1,179 +0,0 @@
|
|||||||
# Mongoose Embedding Guide
|
|
||||||
|
|
||||||
Embedding Mongoose is done in two steps:
|
|
||||||
|
|
||||||
1. Copy
|
|
||||||
[mongoose.c](https://raw.github.com/cesanta/mongoose/master/mongoose.c) and
|
|
||||||
[mongoose.h](https://raw.github.com/cesanta/mongoose/master/mongoose.h)
|
|
||||||
to your application's source tree and include them in the build.
|
|
||||||
2. Somewhere in the application code, call `mg_create_server()` to create
|
|
||||||
a server, configure it with `mg_set_option()` and loop with
|
|
||||||
`mg_poll_server()` until done. Call `mg_destroy_server()` to cleanup.
|
|
||||||
|
|
||||||
Here's a minimal application `app.c` that embeds mongoose:
|
|
||||||
|
|
||||||
#include "mongoose.h"
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
struct mg_server *server = mg_create_server(NULL, NULL);
|
|
||||||
mg_set_option(server, "document_root", "."); // Serve current directory
|
|
||||||
mg_set_option(server, "listening_port", "8080"); // Open port 8080
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
mg_poll_server(server, 1000); // Infinite loop, Ctrl-C to stop
|
|
||||||
}
|
|
||||||
mg_destroy_server(&server);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
and run the following command:
|
|
||||||
|
|
||||||
cc app.c mongoose.c -pthread -o app # on Unix
|
|
||||||
cl.exe app.c mongoose.c /TC /MD # on Windows
|
|
||||||
|
|
||||||
When run, this simple application opens port 8080 and serves static files,
|
|
||||||
CGI files and lists directory content in the current working directory.
|
|
||||||
|
|
||||||
It is possible to generate HTML page content. Mongoose can call user-defined
|
|
||||||
function when certain events occur.
|
|
||||||
That function is called _an event handler_, and it is the second parameter
|
|
||||||
to `mg_create_server()` function. Here is the example event handler function:
|
|
||||||
|
|
||||||
int event_handler(struct mg_connection *conn, enum mg_event ev) {
|
|
||||||
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
|
|
||||||
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
|
|
||||||
create an URI that will be served by user's C code. The app will handle
|
|
||||||
`/hello` URI by showing a hello message. So, when app is run,
|
|
||||||
http://127.0.0.1:8080/hello will say hello, and here's the code:
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include "mongoose.h"
|
|
||||||
|
|
||||||
static int event_handler(struct mg_connection *conn, enum mg_event ev) {
|
|
||||||
if (ev == MG_AUTH) {
|
|
||||||
return MG_TRUE; // Authorize all requests
|
|
||||||
} 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) {
|
|
||||||
struct mg_server *server = mg_create_server(NULL, event_handler);
|
|
||||||
mg_set_option(server, "document_root", ".");
|
|
||||||
mg_set_option(server, "listening_port", "8080");
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
mg_poll_server(server, 1000); // Infinite loop, Ctrl-C to stop
|
|
||||||
}
|
|
||||||
mg_destroy_server(&server);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
## Example code
|
|
||||||
|
|
||||||
Mongoose source code contains a well-commented example code, listed below:
|
|
||||||
|
|
||||||
* [hello.c](https://github.com/cesanta/mongoose/blob/master/examples/hello.c)
|
|
||||||
a minimalistic hello world example
|
|
||||||
* [post.c](https://github.com/cesanta/mongoose/blob/master/examples/post.c)
|
|
||||||
shows how to handle form input
|
|
||||||
* [upload.c](https://github.com/cesanta/mongoose/blob/master/examples/post.c)
|
|
||||||
shows how to upload files
|
|
||||||
* [websocket.c](https://github.com/cesanta/mongoose/blob/master/examples/websocket.c) demonstrates websocket usage
|
|
||||||
* [auth.c](https://github.com/cesanta/mongoose/blob/master/examples/auth.c) demonstrates API-controlled Digest authorization
|
|
||||||
* [mjpg.c](https://github.com/cesanta/mongoose/blob/master/examples/mjpg.c) demonstrates MJPEG streaming implementation
|
|
||||||
|
|
||||||
## Compilation flags
|
|
||||||
|
|
||||||
Below is the list of compilation flags that enable or disable certain
|
|
||||||
features. By default, some features are enabled, and could be disabled
|
|
||||||
by setting appropriate `NO_*` flag. Features that are disabled by default
|
|
||||||
could be enabled by setting appropriate `USE_*` flag. Bare bones Mongoose
|
|
||||||
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.
|
|
||||||
|
|
||||||
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_CGI Disable CGI support
|
|
||||||
-DMONGOOSE_NO_DAV Disable WebDAV support
|
|
||||||
(PUT, DELETE, MKCOL, PROPFIND methods)
|
|
||||||
-DMONGOOSE_NO_DIRECTORY_LISTING Disable directory listing
|
|
||||||
-DMONGOOSE_NO_FILESYSTEM Disables all file IO, serving from memory only
|
|
||||||
-DMONGOOSE_NO_LOGGING Disable access/error logging
|
|
||||||
-DMONGOOSE_NO_THREADS
|
|
||||||
-DMONGOOSE_NO_WEBSOCKET Disable WebSocket support
|
|
||||||
|
|
||||||
-DMONGOOSE_USE_IDLE_TIMEOUT_SECONDS=X Idle connection timeout, default is 30
|
|
||||||
-DMONGOOSE_USE_LUA Enable Lua scripting
|
|
||||||
-DMONGOOSE_USE_LUA_SQLITE3 Enable sqlite3 binding for Lua
|
|
||||||
-DMONGOOSE_USE_POST_SIZE_LIMIT=X POST requests larger than X will be
|
|
||||||
rejected, not set by default
|
|
||||||
-DMONGOOSE_USE_EXTRA_HTTP_HEADERS=X Append X to the HTTP headers
|
|
||||||
for static files, empty by default
|
|
||||||
|
|
||||||
-DNS_ENABLE_DEBUG Enables debug messages on stdout, very noisy
|
|
||||||
-DNS_ENABLE_SSL Enable SSL
|
|
||||||
-DNS_ENABLE_IPV6 Enable IPv6 support
|
|
||||||
-DNS_ENABLE_HEXDUMP Enables hexdump of sent and received traffic
|
|
||||||
-DNS_STACK_SIZE=X Sets stack size to X for ns_start_thread()
|
|
||||||
-DNS_DISABLE_THREADS Disable threads support
|
|
||||||
-DNS_DISABLE_SOCKETPAIR For systems without loopback interface
|
|
||||||
-DMONGOOSE_SEND_NS_EVENTS Send Net Skeleton events to the event handler
|
|
||||||
in addition to the Mongoose events
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
# Mongoose FAQ
|
|
||||||
|
|
||||||
## 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,
|
|
||||||
correct interpreter is `php-cgi.exe` (`php-cgi` on UNIX). Solution: specify
|
|
||||||
full path to the PHP interpreter, e.g.:
|
|
||||||
|
|
||||||
mongoose -cgi_interpreter /full/path/to/php-cgi
|
|
||||||
|
|
||||||
## Mongoose fails to start
|
|
||||||
|
|
||||||
If Mongoose exits immediately when run, this
|
|
||||||
usually indicates a syntax error in the configuration file
|
|
||||||
(named `mongoose.conf` by default) or the command-line arguments.
|
|
||||||
Syntax checking is omitted from Mongoose to keep its size low. However,
|
|
||||||
the Manual should be of help. Note: the syntax changes from time to time,
|
|
||||||
so updating the config file might be necessary after executable update.
|
|
||||||
|
|
||||||
### Embedding with OpenSSL on Windows might fail because of calling convention
|
|
||||||
|
|
||||||
To force Mongoose to use `__stdcall` convention, add `/Gz` compilation
|
|
||||||
flag to the Visual Studio project settings.
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
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,44 +0,0 @@
|
|||||||
# Mongoose Internals
|
|
||||||
|
|
||||||
Mongoose has single-threaded, event-driven, asynchronous, non-blocking core.
|
|
||||||
`mg_create_server()` creates a web server instance. An instance is a container
|
|
||||||
for the config options and list of active connections. To do the actual
|
|
||||||
serving, user must call `mg_poll_server()`, which iterates over all
|
|
||||||
active connections, performing `select()` syscall on all sockets with a
|
|
||||||
timeout of specified number of milliseconds. When `select()` returns, Mongoose
|
|
||||||
does an IO for each socket that has data to be sent or received. Application
|
|
||||||
code must call `mg_poll_server()` in a loop.
|
|
||||||
|
|
||||||
Mongoose server instance is designed to be used by a single thread.
|
|
||||||
It is an error to have more then
|
|
||||||
one thread calling `mg_poll_server()`, `mg_set_option()` or any other function
|
|
||||||
that take `struct mg_server *` parameter. Mongoose does not
|
|
||||||
mutex-protect `struct mg_server *`, therefore the best practice is
|
|
||||||
to call server management functions from the same thread (an IO thread).
|
|
||||||
On a multi-core systems, many server instances can be created, sharing the
|
|
||||||
same listening socket and managed by separate threads (see [multi_threaded.c](https://github.com/cesanta/mongoose/blob/master/examples/multi_threaded.c))
|
|
||||||
example.
|
|
||||||
|
|
||||||
It is an error to pass and store `struct mg_connection *` pointers for
|
|
||||||
later use to send data. The reason is that they can be invalidated by the
|
|
||||||
next `mg_poll_server()` call. For such a task,
|
|
||||||
there is `mg_iterate_over_connections()` API
|
|
||||||
exists, which sends a callback function to the IO thread, then IO thread
|
|
||||||
calls specified function for all active connection.
|
|
||||||
|
|
||||||
When mongoose buffers in HTTP request and successfully parses it, it calls
|
|
||||||
appropriate URI handler immediately for GET requests. For POST requests,
|
|
||||||
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`,
|
|
||||||
and POST data length is in `struct mg_connection::content_len`.
|
|
||||||
|
|
||||||
Note that websocket connections are treated the same way. Mongoose buffers
|
|
||||||
websocket frame in memory, and calls URI handler when frame is fully
|
|
||||||
buffered. Frame data is available `struct mg_connection::content`, and
|
|
||||||
data length is in `struct mg_connection::content_len`, i.e. very similar to
|
|
||||||
the POST request. `struct mg_connection::is_websocket` flag indicates
|
|
||||||
whether the request is websocket or not. Also, for websocket requests,
|
|
||||||
there is `struct mg_connection::wsbits` field which contains first byte
|
|
||||||
of the websocket frame which URI handler can examine. Note that to
|
|
||||||
reply to the websocket client, `mg_websocket_write()` should be used.
|
|
||||||
To reply to the plain HTTP client, `mg_write()` should be used.
|
|
||||||
@@ -1,51 +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.3, 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 `ANY_NAME.lp`. For example,
|
|
||||||
`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 via the `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 via the `mg.request_info` object.
|
|
||||||
Check out [prime_numbers.lp](https://github.com/cesanta/mongoose/blob/master/examples/lua/prime_numbers.lp) for some example.
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
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 all following blocks.
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
# Mongoose Configuration Options
|
|
||||||
|
|
||||||
### access\_control\_list
|
|
||||||
An Access Control List (ACL) allows restrictions to be put on the list of IP
|
|
||||||
addresses which have access to the web server. In the case of the Mongoose
|
|
||||||
web server, the ACL is a comma separated list of IP subnets, where each
|
|
||||||
subnet is prepended by either a `-` or a `+` sign. A plus sign means allow,
|
|
||||||
where a minus sign means deny. If a subnet mask is omitted, such as `-1.2.3.4`,
|
|
||||||
this means to deny only that single IP address.
|
|
||||||
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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)
|
|
||||||
|
|
||||||
Default: not set, all accesses are allowed.
|
|
||||||
|
|
||||||
### access\_log\_file
|
|
||||||
Path to a file for access logs. Either full path, or relative to the
|
|
||||||
mongoose executable. Default: not set, no query logging is done.
|
|
||||||
|
|
||||||
### auth_domain
|
|
||||||
Authorization realm used in `.htpasswd` authorization. Default: `mydomain.com`
|
|
||||||
|
|
||||||
### cgi_interpreter
|
|
||||||
Path to an executable to be used use as an interpreter for __all__ CGI scripts
|
|
||||||
regardless script extension. Default: not set, Mongoose looks at
|
|
||||||
[shebang line](http://en.wikipedia.org/wiki/Shebang_(Unix\).
|
|
||||||
|
|
||||||
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
|
|
||||||
respective CGI scripts. Note that paths should be either full file paths,
|
|
||||||
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
|
|
||||||
`cgi_interpreter` option can be set to the path to `php-cgi.exe` executable and
|
|
||||||
shebang line in the CGI scripts can be omitted.
|
|
||||||
**Note**: PHP scripts must use `php-cgi.exe`, not `php.exe`.
|
|
||||||
|
|
||||||
### cgi_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,
|
|
||||||
use `/path/to/cgi-bin/**.cgi` as a pattern. Note that **full file path** is
|
|
||||||
matched against the pattern, not the URI.
|
|
||||||
|
|
||||||
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$`
|
|
||||||
|
|
||||||
### dav\_auth\_file
|
|
||||||
Authentication file for WebDAV mutation requests: `PUT`, `DELETE`, `MKCOL`.
|
|
||||||
The format of that file is the same as for the `.htpasswd` file
|
|
||||||
used for digest authentication. It can be created and managed by
|
|
||||||
`mongoose -A` command. Default: not set, WebDAV mutations are disallowed.
|
|
||||||
|
|
||||||
### document_root
|
|
||||||
A directory to serve. Default: current working directory.
|
|
||||||
|
|
||||||
### enable\_directory\_listing
|
|
||||||
Enable directory listing, either `yes` or `no`. Default: `yes`.
|
|
||||||
|
|
||||||
### extra\_mime\_types
|
|
||||||
Extra mime types to recognize, in form `extension1=type1,extension2=type2,...`.
|
|
||||||
Extension must include dot. Example:
|
|
||||||
`mongoose -extra_mime_types .cpp=plain/text,.java=plain/text`. Default: not set.
|
|
||||||
|
|
||||||
|
|
||||||
### global\_auth\_file
|
|
||||||
Path to a global passwords file, either full path or relative to the mongoose
|
|
||||||
executable. If set, per-directory `.htpasswd` files are ignored,
|
|
||||||
and all requests are authorised against that file. Use `mongoose -A` to
|
|
||||||
manage passwords, or third party utilities like
|
|
||||||
[htpasswd-generator](http://www.askapache.com/online-tools/htpasswd-generator).
|
|
||||||
Default: not set, per-directory `.htpasswd` files are respected.
|
|
||||||
|
|
||||||
### hide\_files\_patterns
|
|
||||||
A pattern for the files to hide. Files that match the pattern will not
|
|
||||||
show up in directory listing and return `404 Not Found` if requested. Pattern
|
|
||||||
must be for a file name only, not including directory name, e.g.
|
|
||||||
`mongoose -hide_files_patterns secret.txt|even_more_secret.txt`. Default:
|
|
||||||
not set.
|
|
||||||
|
|
||||||
### index_files
|
|
||||||
Comma-separated list of files to be treated as directory index
|
|
||||||
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
|
|
||||||
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
|
|
||||||
will bind to all addresses. Default: 8080.
|
|
||||||
|
|
||||||
### run\_as\_user
|
|
||||||
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.
|
|
||||||
|
|
||||||
$ sudo mongoose -listening_port 80 -run_as_user nobody
|
|
||||||
|
|
||||||
Default: not set.
|
|
||||||
|
|
||||||
### url\_rewrites
|
|
||||||
Comma-separated list of URL rewrites in the form of
|
|
||||||
`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.
|
|
||||||
However, if the rewrite option is used and `uri_pattern` matches the
|
|
||||||
requested URI, then `document_root` is ignored. Instead,
|
|
||||||
`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
|
|
||||||
`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`
|
|
||||||
should be an URI to redirect to. Mongoose will issue `302` temporary redirect
|
|
||||||
to the specified URI with following parameters:
|
|
||||||
`?code=HTTP_ERROR_CODE&orig_uri=ORIGINAL_URI&query_string=QUERY_STRING`.
|
|
||||||
|
|
||||||
If `uri_pattern` starts with `@` symbol, then Mongoose compares
|
|
||||||
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
|
|
||||||
mongoose -url_rewrites **.doc$=/path/to/cgi-bin/handle_doc.cgi
|
|
||||||
|
|
||||||
# Implement user home directories support
|
|
||||||
mongoose -url_rewrites /~joe/=/home/joe/,/~bill=/home/bill/
|
|
||||||
|
|
||||||
# Redirect 404 errors to a specific error page
|
|
||||||
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.
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
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`.
|
|
||||||
|
|
||||||

|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
# Mongoose Release Notes
|
|
||||||
|
|
||||||
## 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 buy 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)
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
# Mongoose SSL guide
|
|
||||||
|
|
||||||
SSL is a protocol that makes web communication secure. To enable SSL
|
|
||||||
in mongoose, 3 steps are required:
|
|
||||||
|
|
||||||
1. Valid certificate file must be created
|
|
||||||
2. `ssl_certificate` options must be set to contain path to the
|
|
||||||
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:
|
|
||||||
|
|
||||||
document_root www_root # Serve files in www_root directory
|
|
||||||
listening_ports 80r,443s # Redirect all HTTP requests to HTTPS
|
|
||||||
ssl_certificate ssl_cert.pem # Location of certificate file
|
|
||||||
|
|
||||||
## How to create SSL certificate file
|
|
||||||
|
|
||||||
SSL certificate file is a text file that must contain at least two
|
|
||||||
sections:
|
|
||||||
|
|
||||||
1. A private key
|
|
||||||
2. A certificate
|
|
||||||
|
|
||||||
Both sections should be chunks of text in PEM format. When PEM file is
|
|
||||||
opened in a text editor, it looks like this:
|
|
||||||
|
|
||||||
-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIIEogIBAAKCAQEAwONaLOP7EdegqjRuQKSDXzvHmFMZfBufjhELhNjo5KsL4ieH
|
|
||||||
hYN0Zii2yTb63jGxKY6gH1R/r9dL8kXaJmcZrfSa3AgywnteJWg=
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDBjCCAe4CCQCX05m0b053QzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJB
|
|
||||||
SEGI4JSxV56lYg==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
|
|
||||||
Two aforementioned sections are clearly seen. Typically, those section
|
|
||||||
are bigger then in the example shown. The text between the `BEGIN` and
|
|
||||||
`END` is the text representation of binary data, a private key and a
|
|
||||||
certificate. Therefore, in order to create a certificate file,
|
|
||||||
|
|
||||||
* private key must be converted to PEM format
|
|
||||||
* certificate must be converted to PEM format
|
|
||||||
* those two should be concatenated into a single file
|
|
||||||
|
|
||||||
If the certificate chain in used, a chain file also needs to be
|
|
||||||
converted into PEM format and appended to the certificate file.
|
|
||||||
|
|
||||||
## How SSL works
|
|
||||||
|
|
||||||
SSL is a protocol that can encrypt communication between two parties. If third
|
|
||||||
party observes all messages passed by, it would be very
|
|
||||||
hard for the third party (though not impossible) to decrypt the communication.
|
|
||||||
|
|
||||||
The idea is based on so-called public key encryption. Communicating parties
|
|
||||||
have two keys: a public key and a private key. A public key is advertised
|
|
||||||
to everybody, and it is contained in a certificate. A private key is kept
|
|
||||||
secret. Security algorithm works in a way that anybody can encrypt
|
|
||||||
a message using public key, and only private key can decrypt it.
|
|
||||||
|
|
||||||
This is why web server needs both private key and certificate: private key
|
|
||||||
is used to decrypt incoming messages, and certificate is used to tell the
|
|
||||||
public key to the other party. When communication starts, parties exchange
|
|
||||||
their public keys, and keep private keys to themselves. Man-in-the-middle
|
|
||||||
who observes the communication is unable to decrypt the messages cause
|
|
||||||
private keys are required for decryption.
|
|
||||||
|
|
||||||
Encryption algorithms are built on top of hard mathematical problem, which
|
|
||||||
makes it very expensive for man-in-the-middle to compute private keys.
|
|
||||||
For example, RSA algorithm is based on a mathematical problem of factorization.
|
|
||||||
It is easy to generate two very large prime numbers `P` and `Q` and make
|
|
||||||
a product `P * Q`. But given a product, it is very hard to recover these
|
|
||||||
two prime numbers - this is called factorization.
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
# Mongoose User Guide
|
|
||||||
|
|
||||||
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,
|
|
||||||
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
|
|
||||||
[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.
|
|
||||||
|
|
||||||
On Windows and Mac, Mongoose iconifies itself to the system tray when started.
|
|
||||||
Right-click on the icon to pop up a menu, where it is possible to stop
|
|
||||||
mongoose, or configure it.
|
|
||||||
|
|
||||||
On UNIX, `mongoose` is a command line utility. Running `mongoose` in
|
|
||||||
terminal, optionally followed by configuration parameters
|
|
||||||
(`mongoose [OPTIONS]`) or configuration file name
|
|
||||||
(`mongoose [config_file_name]`) starts the
|
|
||||||
web server:
|
|
||||||
|
|
||||||
$ mongoose -document_root /var/www # Running mongoose with cmdline options
|
|
||||||
$ mongoose /etc/my_config.txt # Running mongoose with config file
|
|
||||||
$ mongoose # Running with no parameters. This will
|
|
||||||
# serve current directory on port 8080
|
|
||||||
|
|
||||||
Mongoose does not detach from terminal. Pressing `Ctrl-C` keys
|
|
||||||
stops the server.
|
|
||||||
|
|
||||||
When started, mongoose first searches for the configuration file.
|
|
||||||
If configuration file is specified explicitly in the command line, then
|
|
||||||
specified configuration file is used.
|
|
||||||
Otherwise, mongoose would search for file `mongoose.conf` in the same directory
|
|
||||||
where binary is located, and use it. Configuration file can be absent.
|
|
||||||
|
|
||||||
Configuration file is a sequence of lines, each line containing
|
|
||||||
command line argument name and it's value. Empty lines and lines beginning
|
|
||||||
with `#` are ignored. Here is the example of `mongoose.conf` file:
|
|
||||||
|
|
||||||
# This is a comment
|
|
||||||
document_root C:\www
|
|
||||||
listening_port 80
|
|
||||||
ssl_certificate C:\mongoose\ssl_cert.pem
|
|
||||||
|
|
||||||
Command line arguments are highest priority and can override
|
|
||||||
configuration file settings. For example, if `mongoose.conf` has line
|
|
||||||
`document_root /var/www`, and mongoose has been started as
|
|
||||||
`mongoose -document_root /etc`, then `/etc` directory will be used as
|
|
||||||
document root.
|
|
||||||
|
|
||||||
Note that configuration options on the command line must start with `-`,
|
|
||||||
and their names are the same as in the config file. Exampli gratia,
|
|
||||||
the following two setups are equivalent:
|
|
||||||
|
|
||||||
$ mongoose -listening_port 1234 -document_root /var/www
|
|
||||||
|
|
||||||
$ cat > mongoose.conf
|
|
||||||
listening_ports 1234
|
|
||||||
document_root /var/www
|
|
||||||
^D
|
|
||||||
$ mongoose
|
|
||||||
|
|
||||||
Mongoose can also be used to modify `.htpasswd` passwords file:
|
|
||||||
|
|
||||||
$ mongoose -A .htpasswd mydomain.com user_name user_password
|
|
||||||
|
|
||||||
Unlike other web servers, mongoose does not require CGI scripts be located in
|
|
||||||
a special directory. CGI scripts can be anywhere. CGI (and SSI) files are
|
|
||||||
recognized by the file name pattern. Mongoose uses shell-like glob
|
|
||||||
patterns. Pattern match starts at the beginning of the string, so essentially
|
|
||||||
patterns are prefix patterns. Syntax is as follows:
|
|
||||||
|
|
||||||
** Matches everything
|
|
||||||
* Matches everything but slash character, '/'
|
|
||||||
? Matches any character
|
|
||||||
$ Matches the end of the string
|
|
||||||
| Matches if pattern on the left side or the right side matches.
|
|
||||||
|
|
||||||
All other characters in the pattern match themselves. Examples:
|
|
||||||
|
|
||||||
# Pattern Meaning
|
|
||||||
**.cgi$ Any string that ends with .cgi
|
|
||||||
/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:
|
|
||||||
|
|
||||||
$ mongoose -cgi_pattern /cgi-bin/*.cgi # Emulate /cgi-bin/ restriction
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
CFLAGS = -W -Wall -I.. -pthread -g -pipe $(CFLAGS_EXTRA)
|
|
||||||
RM = rm -rf
|
|
||||||
OUT = -o $@
|
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT)
|
|
||||||
MSVC = ../../vc6
|
|
||||||
RM = del /q /f
|
|
||||||
OUT =
|
|
||||||
CC = $(MSVC)/bin/cl
|
|
||||||
CFLAGS = /MD /TC /nologo /W3 /I$(MSVC)/include /I..
|
|
||||||
CFLAGS += /link /incremental:no /libpath:$(MSVC)/lib /machine:IX86
|
|
||||||
CFLAGS += $(CFLAGS_EXTRA)
|
|
||||||
else
|
|
||||||
UNAME_S := $(shell uname -s)
|
|
||||||
CC = g++
|
|
||||||
CFLAGS += -lssl -g -O0
|
|
||||||
|
|
||||||
ifeq ($(UNAME_S),Linux)
|
|
||||||
CFLAGS += -ldl
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(UNAME_S),Darwin)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
all: hello websocket server post multi_threaded upload auth
|
|
||||||
|
|
||||||
# To enable Lua in a server, uncomment following lines
|
|
||||||
LUA = ../lua-5.2.3/src
|
|
||||||
#CFLAGS += -I$(LUA) -L$(LUA) -llua -DMONGOOSE_USE_LUA
|
|
||||||
|
|
||||||
server: server.c ../mongoose.c
|
|
||||||
$(CC) server.c ../mongoose.c $(OUT) $(CFLAGS)
|
|
||||||
|
|
||||||
hello: hello.c ../mongoose.c
|
|
||||||
$(CC) hello.c ../mongoose.c $(OUT) $(CFLAGS)
|
|
||||||
|
|
||||||
websocket: websocket_html.c websocket.c ../mongoose.c
|
|
||||||
$(CC) websocket.c websocket_html.c ../mongoose.c $(OUT) $(CFLAGS)
|
|
||||||
|
|
||||||
post: post.c ../mongoose.c
|
|
||||||
$(CC) post.c ../mongoose.c $(OUT) $(CFLAGS)
|
|
||||||
|
|
||||||
multi_threaded: multi_threaded.c ../mongoose.c
|
|
||||||
$(CC) multi_threaded.c ../mongoose.c $(OUT) $(CFLAGS)
|
|
||||||
|
|
||||||
upload: upload.c ../mongoose.c
|
|
||||||
$(CC) upload.c ../mongoose.c $(OUT) $(CFLAGS)
|
|
||||||
|
|
||||||
auth: auth.c ../mongoose.c
|
|
||||||
$(CC) auth.c ../mongoose.c $(OUT) $(CFLAGS)
|
|
||||||
|
|
||||||
file: file.c ../mongoose.c
|
|
||||||
$(CC) file.c ../mongoose.c $(OUT) $(CFLAGS)
|
|
||||||
|
|
||||||
form: form.c ../mongoose.c
|
|
||||||
$(CC) form.c ../mongoose.c $(OUT) $(CFLAGS)
|
|
||||||
|
|
||||||
mjpg: mjpg.c ../mongoose.c
|
|
||||||
$(CC) mjpg.c ../mongoose.c $(OUT) $(CFLAGS)
|
|
||||||
|
|
||||||
pubsub: websocket2.c ../mongoose.c
|
|
||||||
$(CC) websocket2.c ../mongoose.c $(OUT) $(CFLAGS)
|
|
||||||
|
|
||||||
|
|
||||||
proxy: proxy.c ../mongoose.c
|
|
||||||
$(CC) proxy.c ../mongoose.c $(OUT) \
|
|
||||||
-I../../net_skeleton -DNS_ENABLE_SSL -lssl $(CFLAGS)
|
|
||||||
|
|
||||||
websocket_html.c: websocket.html
|
|
||||||
perl mkdata.pl $< > $@
|
|
||||||
|
|
||||||
u:
|
|
||||||
$(CC) unit_test.c $(OUT) $(CFLAGS)
|
|
||||||
./$@
|
|
||||||
|
|
||||||
clean:
|
|
||||||
-@$(RM) hello mjpg upload post websocket auth file server multi_threaded proxy websocket_html.c *.exe *.dSYM *.obj .*o u a.out
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
#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,88 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "mongoose.h"
|
|
||||||
|
|
||||||
struct file_data {
|
|
||||||
FILE *fp;
|
|
||||||
const char *data;
|
|
||||||
int data_len;
|
|
||||||
int written;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int handle_request(struct mg_connection *conn) {
|
|
||||||
const char *data;
|
|
||||||
int data_len;
|
|
||||||
char var_name[100], file_name[100], path[100];
|
|
||||||
|
|
||||||
if (strcmp(conn->uri, "/upload") == 0) {
|
|
||||||
if (mg_parse_multipart(conn->content, conn->content_len,
|
|
||||||
var_name, sizeof(var_name),
|
|
||||||
file_name, sizeof(file_name),
|
|
||||||
&data, &data_len) > 0) {
|
|
||||||
struct file_data *p = (struct file_data *) malloc(sizeof(*p));
|
|
||||||
snprintf(path, sizeof(path), "UPLOAD_%s", file_name);
|
|
||||||
p->fp = fopen(path, "wb");
|
|
||||||
p->data = data;
|
|
||||||
p->data_len = data_len;
|
|
||||||
p->written = 0;
|
|
||||||
conn->connection_param = p;
|
|
||||||
mg_send_header(conn, "Content-Type", "text/html");
|
|
||||||
}
|
|
||||||
return MG_MORE; // Tell mongoose to keep this connection open
|
|
||||||
} 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int handle_poll(struct mg_connection *conn) {
|
|
||||||
struct file_data *p = (struct file_data *) conn->connection_param;
|
|
||||||
if (p != NULL) {
|
|
||||||
// Write no more then 100 bytes in one go
|
|
||||||
int len = p->data_len - p->written;
|
|
||||||
int n = fwrite(p->data + p->written, 1, len > 100 ? 100 : len, p->fp);
|
|
||||||
if (n > 0) {
|
|
||||||
p->written += n;
|
|
||||||
mg_send_data(conn, " ", 1); // Send something back to wake up select()
|
|
||||||
}
|
|
||||||
|
|
||||||
// If everything is written, close the connection
|
|
||||||
if (p->written >= p->data_len) {
|
|
||||||
mg_printf_data(conn, "Written %d bytes.", p->written);
|
|
||||||
fclose(p->fp);
|
|
||||||
free(p);
|
|
||||||
conn->connection_param = NULL;
|
|
||||||
return MG_TRUE; // Tell mongoose to close this connection
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return MG_FALSE; // Tell mongoose to keep this connection open
|
|
||||||
}
|
|
||||||
|
|
||||||
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_POLL: return handle_poll(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,43 +0,0 @@
|
|||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,68 +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_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()
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIIEpAIBAAKCAQEA8FV466yTGIUkJqjBv2CTU/HeYKXYd7D6m8fY9daRLm9cKPhB
|
|
||||||
kPvLyhdenOH88uAAYqmKf2dZvP5SxFnBKT52Hr0XpUfC8Y3iVjHxwMgNRaiSkfDP
|
|
||||||
mIEb2qcpJoMrdos/ff46itqwr9wW3+7kjRlxM1Mu5pq4EibSHeVyaPWVCgENcA1m
|
|
||||||
4beQujI1SSBkLOfmgpw/SsyzyTgXm+kOdj7vKy3EbXseGPtHJ04oZ7qwol1NFrrq
|
|
||||||
HwO87HWHxyQr7uJ4TBH37gL7QCdjHsOdN94alxEUWTRfmzZFXVlsTnq5DBnnGhtq
|
|
||||||
ibpUC8WeI3QiFNtTBKkHviAm+6iWW6gG2TO4twIDAQABAoIBAHxLWBxaxkB6KzYr
|
|
||||||
NPirE8boYiAN5aQRTarfcp/B9pfTVBCERDSdZMoByBbO8akSnGBqWoyFgO2zgk62
|
|
||||||
NKYF/cTr+pyqPnH69UGq1uLjE6ohApyjtFmk/CjbJvcaA5JtdcrNfq1taM+qvdHW
|
|
||||||
lTE8JUVsEeeFwQjyNtzrW35Y9FmVLSmMNsESChLnrsa7IxwnfRpHc+hmj+7lxZO6
|
|
||||||
ZzAaCCo9qHR1Ddi5f+0DJoXGBBGOk6C4BWLaV+fHPcsYHESrepitGfS96AQ0Wspn
|
|
||||||
qqtAp6jv+iIfgpohYylIjOPcHf3dXpINTxwz/r3XicqBaSAx2lXb+vnxERmagGKC
|
|
||||||
RUpELVECgYEA/EHUDwJRBUMvGXjRQO9R0JLp59U2UZOvAjmIAHkLM/48k8//kpgJ
|
|
||||||
CDUVvuyQUfwCphmaiAm5BZfDbmhBEirjCai8fYkrGugQl9H1YrVsi+UhQudnSRM0
|
|
||||||
7plKIb9nz9by31J1iu5YHTpovO5MQjH5UP1boqAioBNoBuzFI0QK1uMCgYEA8+Za
|
|
||||||
0NDocnE+V2NpRag+oMbM/LBgSWyk49NXYUOhuv4CZ8f20nFYx6p9RLD0ICUOxC3B
|
|
||||||
TkHybnGhRjuR+LkbuynW2wM2+jwcLe+ZPnXZsNKJwST9fzus06BWHyBTJHfhUDO3
|
|
||||||
cq6PUDJua6NQa++rj+ur1LSFPuwnC+X2FxMd6x0CgYEAweyhZ4ByZMdHWB+nTnIs
|
|
||||||
xVmL9CvW/FO6gM1Vnndvg2L5kvCeG0ZB+0tEEmiucjh4mNSqFdbTpFcNaL1A+QR7
|
|
||||||
UZukfCWNO7wXtX81U9MBRXK6ZUKcBnN7h8nUUalh10f5onEz58BfgOi8SDIx8dmV
|
|
||||||
Pwvm/Fh7BfClUl2HGBtg8d0CgYBEDWwdg4y4EdzhKT3AT9dZqN6dSuEy23uOjfN9
|
|
||||||
kg9YS3OEXYkC4tlwrKNTPUSAi5Z5KoMbQM9R/aaQICL0kUGpkVz/sv/uBkOelZHe
|
|
||||||
madp7PS+zYFltNLeIYimGrDYJhLZ+/QdrZMTP18L7X+M/kySVaGWMeBT1DR432sw
|
|
||||||
uQbKCQKBgQC9D9fxDXCFxJmJc2Cp8ZYQha4Oc10JsanM1DM1YWIaOILfoExz46vZ
|
|
||||||
UJzRfe2LkkhhRN9YG4ZW6zJ1E/HZSjKC2iwHog/4bDjykVPrFIfPdWS2C1CQF/Jq
|
|
||||||
tYnHTpuxE3JFXZrLXbDobFKbxHOZRdlSUu8NK/V507Y34NaMPHnffw==
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIID4DCCAsigAwIBAgIJAM1yCH8CR4Z+MA0GCSqGSIb3DQEBBQUAMFMxFDASBgNV
|
|
||||||
BAMTC2Nlc2FudGEuY29tMR0wGwYDVQQKExRDZXNhbnRhIFNvZnR3YXJlIEx0ZDEL
|
|
||||||
MAkGA1UEBhMCSUUxDzANBgNVBAcTBkR1YmxpbjAeFw0xNDA2MjcxMDUwNTBaFw0y
|
|
||||||
NDA2MjQxMDUwNTBaMFMxFDASBgNVBAMTC2Nlc2FudGEuY29tMR0wGwYDVQQKExRD
|
|
||||||
ZXNhbnRhIFNvZnR3YXJlIEx0ZDELMAkGA1UEBhMCSUUxDzANBgNVBAcTBkR1Ymxp
|
|
||||||
bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPBVeOuskxiFJCaowb9g
|
|
||||||
k1Px3mCl2Hew+pvH2PXWkS5vXCj4QZD7y8oXXpzh/PLgAGKpin9nWbz+UsRZwSk+
|
|
||||||
dh69F6VHwvGN4lYx8cDIDUWokpHwz5iBG9qnKSaDK3aLP33+OorasK/cFt/u5I0Z
|
|
||||||
cTNTLuaauBIm0h3lcmj1lQoBDXANZuG3kLoyNUkgZCzn5oKcP0rMs8k4F5vpDnY+
|
|
||||||
7ystxG17Hhj7RydOKGe6sKJdTRa66h8DvOx1h8ckK+7ieEwR9+4C+0AnYx7DnTfe
|
|
||||||
GpcRFFk0X5s2RV1ZbE56uQwZ5xobaom6VAvFniN0IhTbUwSpB74gJvuolluoBtkz
|
|
||||||
uLcCAwEAAaOBtjCBszAdBgNVHQ4EFgQUwvetHY2/J2F788UvFPADTlaUS10wgYMG
|
|
||||||
A1UdIwR8MHqAFML3rR2Nvydhe/PFLxTwA05WlEtdoVekVTBTMRQwEgYDVQQDEwtj
|
|
||||||
ZXNhbnRhLmNvbTEdMBsGA1UEChMUQ2VzYW50YSBTb2Z0d2FyZSBMdGQxCzAJBgNV
|
|
||||||
BAYTAklFMQ8wDQYDVQQHEwZEdWJsaW6CCQDNcgh/AkeGfjAMBgNVHRMEBTADAQH/
|
|
||||||
MA0GCSqGSIb3DQEBBQUAA4IBAQDA3QTlZ2aUe4IIDU+yZmu3XRxJ4FGpOlC0nD1j
|
|
||||||
uwHWDaHfr0WMDjwSoEHbhsc0tapXOpG+hFImHemDS82SuC2c8lNKEJeXgdF3Rqeo
|
|
||||||
aIB8sklgHsJG1DoCwC5TIMaccmbALWctouELGFb8aDF+dczKaaDTW+/dgR47GvD5
|
|
||||||
NBTka2A56U3emmXRpOOtzOz/68lxgACXc+M3yrxbYt9a95rl6wwzNlLHDwPzqhzd
|
|
||||||
ayQ9Q8wmZpWZK1oc8oKKuEXA3zG6jJkrmC8VD5j0WRLgC7SV/zlaAUR/zEisstrh
|
|
||||||
ZVMiJ0NoZmAPVRm0MyBHtBHJFcn/z/FlhqCBLsmDxJ/aOEMT
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#include "mongoose.h"
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
struct mg_server *server = mg_create_server(NULL);
|
|
||||||
mg_set_option(server, "listening_port", "8080");
|
|
||||||
mg_set_option(server, "document_root", "chat_html_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;
|
|
||||||
}
|
|
||||||
|
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>
|
|
||||||
@@ -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>
|
|
||||||
|
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: 'api.lp',
|
|
||||||
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({
|
|
||||||
data: {last_id: chat.lastMessageId, cmd: 'get_messages'},
|
|
||||||
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({
|
|
||||||
data: { text: input.value, cmd: 'send_message' },
|
|
||||||
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() {
|
|
||||||
$.ajaxSetup({
|
|
||||||
dataType: 'json',
|
|
||||||
url: chat.backendUrl
|
|
||||||
});
|
|
||||||
$('.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;
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIIEowIBAAKCAQEA4+LVrSV4kvgr2AM5NSIewSfGwK5fXUOoYQ4vpjq2+H2hhOPP
|
|
||||||
0WVyHkLWZXYek8ZmCqPFBvavzO9bveBprQIDTHexj83paaoV8IMugzymeWVONEwU
|
|
||||||
8E9S6sGihCF01yOO5g4X7lmX7mypUDNJHZd/0SuSGezwSd+c41pY/CWmCW+61hls
|
|
||||||
HjKdBp3Nked/u2aJ619D8NYPeu03V89P5x5hWrOWLSfmpd8pQ5tceVO56XjgmZLr
|
|
||||||
FwUTK5Dq/3hUv1lyxHoSWGp5sQirZ5artLgkqCI+K+dwc2YZeeJBACllSqVuzJYh
|
|
||||||
HSpnmKUwMXykJfKtTckfLoJX2VGgbqJWSZFkowIDAQABAoIBAHAKDR30p0QyyXOJ
|
|
||||||
mi26Wb6DbN88m9xBsF4PWHP0uBKRycCJNJpxstqX58q4eS4URAUFIZBb5nDuWX+P
|
|
||||||
/sS1kaOd0WmvRgvSOLkn9c1GG17h5MInib/gcBbFHr6xqD1B2TbYRQHFgMITIGcy
|
|
||||||
38axvoC7WDhw2m6nhv3sZIWLiQdnvsUWF+mXQoRwyK9Me/3/N9atRELPd9rvbwkz
|
|
||||||
ITyZQPE7IScSwVClspSBQMdJj4Bak8sQ8uKpxmIqpRGe9bqz2IO2hxkW9RiAT2CE
|
|
||||||
4KZ1eqSM8q+VUlFfEo7IJ1lh8Anuo/h/qVnN2JTyCWoAW/YLIWUreLAOVCm3feV/
|
|
||||||
fFO5sQkCgYEA8yzhvPegx1cPgtvEaAVJKbI9WBVCT7qAroDrfxBS3m37jHip8SDr
|
|
||||||
4qfh+5OWG6J0hXEKCf1FbhDCDQOf6sQCMlBgR5BU/ALqiFWfEp+ysC10VtdCpEhA
|
|
||||||
PgldtzLhXyApw536y05Ak3Yucii70m80bsXZR2alGWTfJ64e511hSM0CgYEA7+eI
|
|
||||||
QXh9kuKwM143Bk7HWvLNJ71TAb+mp0OkOjmzMe2duoGi0DzTBlSh6AYdSYkMYSbc
|
|
||||||
PW8bF88bTiq4rak9PuJGiFr7Iq5SMccpaZ+JIPnF2S8gdNB1hgfRsUDNHhb691/u
|
|
||||||
3Q/7gOUpiWGrP5uP55/yuFyKkrp+gPGKLhrFIy8CgYA096q34WxI30LGqx3t1nDo
|
|
||||||
PyWzgPXvrd0HpZcmFyUlw+kN4N6LYjNfLFhB1xTUMh+VTVj1chBkeAv8j7SOi2E7
|
|
||||||
GlzOWbbZKb1yMswyX0ypqUz0+XBPnlk36gxash96++N883VEQWg5dn2Jaiv3Gzfd
|
|
||||||
hQTd05LUpC8jUn7ywFlHZQKBgE3agWldxMKqNiw1Yv31CtUE/nbrBckHfPnDBcSv
|
|
||||||
fOuzBQDFmSSi2IixZml5sn9urknI5qg5Kj2rxFy1mIEi7vE9VU5i2CUFFT96NoJE
|
|
||||||
d6fv5rj4hjvieoEogHBZazdclc05oLa0vRWzSKuAuqZFwYmVaptRzNaZFvyZZhJY
|
|
||||||
NamZAoGBANL8Jqht1s1qcLuBis1jZdjzUuF3xNMuxwqszD0zFZFAIUN097460zw+
|
|
||||||
8LIeZgVMJOCmbVHja/RII9PI4vQ7h5rhTmeFWS80QMe22C1yukqEqljYO0POhxsu
|
|
||||||
sm3plGS3rfGkMp1URDgnJL6m/y8gC4+/O6NIEoVaHpraW8//qCD6
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDEjCCAfoCBRQDhmJSMA0GCSqGSIb3DQEBBQUAMFMxFDASBgNVBAMTC2Nlc2Fu
|
|
||||||
dGEuY29tMR0wGwYDVQQKExRDZXNhbnRhIFNvZnR3YXJlIEx0ZDELMAkGA1UEBhMC
|
|
||||||
SUUxDzANBgNVBAcTBkR1YmxpbjAeFw0xNDA2MjcxMDUwNTFaFw0yNDA2MjQxMDUw
|
|
||||||
NTFaMEcxFTATBgNVBAMTDDE5Mi4xNjguMS4yODEQMA4GA1UEChMHRm9vK0x0ZDEL
|
|
||||||
MAkGA1UEBhMCSUUxDzANBgNVBAcTBkdhbHdheTCCASIwDQYJKoZIhvcNAQEBBQAD
|
|
||||||
ggEPADCCAQoCggEBAOPi1a0leJL4K9gDOTUiHsEnxsCuX11DqGEOL6Y6tvh9oYTj
|
|
||||||
z9Flch5C1mV2HpPGZgqjxQb2r8zvW73gaa0CA0x3sY/N6WmqFfCDLoM8pnllTjRM
|
|
||||||
FPBPUurBooQhdNcjjuYOF+5Zl+5sqVAzSR2Xf9Erkhns8EnfnONaWPwlpglvutYZ
|
|
||||||
bB4ynQadzZHnf7tmietfQ/DWD3rtN1fPT+ceYVqzli0n5qXfKUObXHlTuel44JmS
|
|
||||||
6xcFEyuQ6v94VL9ZcsR6ElhqebEIq2eWq7S4JKgiPivncHNmGXniQQApZUqlbsyW
|
|
||||||
IR0qZ5ilMDF8pCXyrU3JHy6CV9lRoG6iVkmRZKMCAwEAATANBgkqhkiG9w0BAQUF
|
|
||||||
AAOCAQEAAxJSilcxos3v5aKllKTsx04Q/P39wQ07ywS1Yf9NsA7MlPU++qs3BqJJ
|
|
||||||
kAaCPpfeAl8GjQLh75XV7rLvycvrluthpHzMRZhnbd+DLCt+FrS5zWWhm6M7535V
|
|
||||||
FHGjuW59sAurARgcB530+bh6a0YNhKJbp3Si5ONhQfEuKPf+R6bPA1Slr2k/ts+K
|
|
||||||
GIzwJbNTVRSor/wlb4F0seHFEv2rdtHt1g+VYlFVwBFawIOx3dU7hHxgzeoRYnik
|
|
||||||
RGrPvhqK3u1wQ+2s/m2HPWj8CFjZ8V7f4sYRjLhpsbeJCy4A28nWvl+cCjAhCQKq
|
|
||||||
Rawa0TcZiQtsj0jaTe71jhAMSMC6qw==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
PROG ?= example
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(DEBUGGER) ./$(PROG)
|
||||||
|
|
||||||
|
$(PROG):
|
||||||
|
$(CC) ../../mongoose.c -I../.. $(CFLAGS) $(EXTRA) -o $(PROG) main.c mjson.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb log.txt
|
||||||
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 10 KiB |
@@ -0,0 +1,203 @@
|
|||||||
|
// Copyright (c) 2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
|
||||||
|
#include "mjson.h"
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
// Authenticated user.
|
||||||
|
// A user can be authenticated by:
|
||||||
|
// - a name:pass pair
|
||||||
|
// - a token
|
||||||
|
// When a user is shown a login screen, she enters a user:pass. If successful,
|
||||||
|
// a server returns user info which includes token. From that point on,
|
||||||
|
// client can use token for authentication. Tokens could be refreshed/changed
|
||||||
|
// on a server side, forcing clients to re-login.
|
||||||
|
struct user {
|
||||||
|
const char *name, *pass, *token;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is a configuration structure we're going to show on a dashboard
|
||||||
|
static struct config {
|
||||||
|
int value1;
|
||||||
|
char *value2;
|
||||||
|
} s_config = {123, NULL};
|
||||||
|
|
||||||
|
// Stringifies the config. A caller must free() it.
|
||||||
|
static char *stringify_config(struct config *cfg) {
|
||||||
|
char *s = NULL;
|
||||||
|
mjson_printf(mjson_print_dynamic_buf, &s, "{%Q:%d,%Q:%Q}", "value1",
|
||||||
|
cfg->value1, "value2", cfg->value2);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update config structure. Return true if changed, false otherwise
|
||||||
|
static bool update_config(struct mg_http_message *hm, struct config *cfg) {
|
||||||
|
bool changed = false;
|
||||||
|
char buf[256];
|
||||||
|
double dv;
|
||||||
|
if (mjson_get_number(hm->body.ptr, hm->body.len, "$.value1", &dv)) {
|
||||||
|
s_config.value1 = dv;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (mjson_get_string(hm->body.ptr, hm->body.len, "$.value2", buf,
|
||||||
|
sizeof(buf)) > 0) {
|
||||||
|
free(s_config.value2);
|
||||||
|
s_config.value2 = strdup(buf);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse HTTP requests, return authenticated user or NULL
|
||||||
|
static struct user *getuser(struct mg_http_message *hm) {
|
||||||
|
// In production, make passwords strong and tokens randomly generated
|
||||||
|
// In this example, user list is kept in RAM. In production, it can
|
||||||
|
// be backed by file, database, or some other method.
|
||||||
|
static struct user users[] = {
|
||||||
|
{"admin", "admin", "admin_token"},
|
||||||
|
{"user1", "pass1", "user1_token"},
|
||||||
|
{"user2", "pass2", "user2_token"},
|
||||||
|
{NULL, NULL, NULL},
|
||||||
|
};
|
||||||
|
char user[256], pass[256];
|
||||||
|
struct user *u;
|
||||||
|
mg_http_creds(hm, user, sizeof(user), pass, sizeof(pass));
|
||||||
|
if (user[0] != '\0' && pass[0] != '\0') {
|
||||||
|
// Both user and password is set, search by user/password
|
||||||
|
for (u = users; u->name != NULL; u++)
|
||||||
|
if (strcmp(user, u->name) == 0 && strcmp(pass, u->pass) == 0) return u;
|
||||||
|
} else if (user[0] == '\0') {
|
||||||
|
// Only password is set, search by token
|
||||||
|
for (u = users; u->name != NULL; u++)
|
||||||
|
if (strcmp(pass, u->token) == 0) return u;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify all config watchers about the config change
|
||||||
|
static void notify_config_change(struct mg_mgr *mgr) {
|
||||||
|
struct mg_connection *c;
|
||||||
|
char *s = stringify_config(&s_config);
|
||||||
|
for (c = mgr->conns; c != NULL; c = c->next) {
|
||||||
|
if (c->label[0] == 'W') mg_http_printf_chunk(c, "%s\n", s);
|
||||||
|
}
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTP request handler function
|
||||||
|
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
struct user *u = getuser(hm);
|
||||||
|
// LOG(LL_INFO, ("%p [%.*s] auth %s", c->fd, (int) hm->uri.len, hm->uri.ptr,
|
||||||
|
// u ? u->name : "NULL"));
|
||||||
|
if (u == NULL && mg_http_match_uri(hm, "/api/#")) {
|
||||||
|
// All URIs starting with /api/ must be authenticated
|
||||||
|
mg_printf(c, "%s", "HTTP/1.1 403 Denied\r\nContent-Length: 0\r\n\r\n");
|
||||||
|
} else if (mg_http_match_uri(hm, "/api/config/get")) {
|
||||||
|
char *s = stringify_config(&s_config);
|
||||||
|
mg_printf(c, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s\n",
|
||||||
|
(int) strlen(s) + 1, s);
|
||||||
|
free(s);
|
||||||
|
} else if (mg_http_match_uri(hm, "/api/config/set")) {
|
||||||
|
// Admins only
|
||||||
|
if (strcmp(u->name, "admin") == 0) {
|
||||||
|
if (update_config(hm, &s_config)) notify_config_change(fn_data);
|
||||||
|
mg_printf(c, "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
|
||||||
|
} else {
|
||||||
|
mg_printf(c, "%s", "HTTP/1.1 403 Denied\r\nContent-Length: 0\r\n\r\n");
|
||||||
|
}
|
||||||
|
} else if (mg_http_match_uri(hm, "/api/config/watch")) {
|
||||||
|
c->label[0] = 'W'; // Mark ourselves as a config watcher
|
||||||
|
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||||
|
} else if (mg_http_match_uri(hm, "/api/video1")) {
|
||||||
|
c->label[0] = 'S'; // Mark that connection as live streamer
|
||||||
|
mg_printf(
|
||||||
|
c, "%s",
|
||||||
|
"HTTP/1.0 200 OK\r\n"
|
||||||
|
"Cache-Control: no-cache\r\n"
|
||||||
|
"Pragma: no-cache\r\nExpires: Thu, 01 Dec 1994 16:00:00 GMT\r\n"
|
||||||
|
"Content-Type: multipart/x-mixed-replace; boundary=--foo\r\n\r\n");
|
||||||
|
} else if (mg_http_match_uri(hm, "/api/log/static")) {
|
||||||
|
mg_http_serve_file(c, hm, "log.txt", "text/plain");
|
||||||
|
} else if (mg_http_match_uri(hm, "/api/log/live")) {
|
||||||
|
c->label[0] = 'L'; // Mark that connection as live log listener
|
||||||
|
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||||
|
} else if (mg_http_match_uri(hm, "/api/login")) {
|
||||||
|
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||||
|
mg_http_printf_chunk(c, "{\"user\":\"%s\",\"token\":\"%s\"}\n", u->name,
|
||||||
|
u->token);
|
||||||
|
mg_http_printf_chunk(c, "");
|
||||||
|
} else {
|
||||||
|
mg_http_serve_dir(c, ev_data, "web_root");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The image stream is simulated by sending MJPEG frames specified by the
|
||||||
|
// "files" array of file names.
|
||||||
|
static void broadcast_mjpeg_frame(struct mg_mgr *mgr) {
|
||||||
|
const char *files[] = {"images/1.jpg", "images/2.jpg", "images/3.jpg",
|
||||||
|
"images/4.jpg", "images/5.jpg", "images/6.jpg"};
|
||||||
|
size_t nfiles = sizeof(files) / sizeof(files[0]);
|
||||||
|
static size_t i;
|
||||||
|
const char *path = files[i++ % nfiles];
|
||||||
|
size_t size = mg_file_size(path);
|
||||||
|
char *data = mg_file_read(path); // Read next file
|
||||||
|
struct mg_connection *c;
|
||||||
|
for (c = mgr->conns; c != NULL; c = c->next) {
|
||||||
|
if (c->label[0] != 'S') continue; // Skip non-stream connections
|
||||||
|
if (data == NULL || size == 0) continue; // Skip on file read error
|
||||||
|
mg_printf(c,
|
||||||
|
"--foo\r\nContent-Type: image/jpeg\r\n"
|
||||||
|
"Content-Length: %lu\r\n\r\n",
|
||||||
|
(unsigned long) size);
|
||||||
|
mg_send(c, data, size);
|
||||||
|
mg_send(c, "\r\n", 2);
|
||||||
|
}
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mjpeg_cb(void *arg) {
|
||||||
|
broadcast_mjpeg_frame(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void log_message(const char *filename, const char *message) {
|
||||||
|
FILE *fp = fopen(filename, "a");
|
||||||
|
if (fp != NULL) {
|
||||||
|
fprintf(fp, "%s", message);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void broadcast_message(struct mg_mgr *mgr, const char *message) {
|
||||||
|
struct mg_connection *c;
|
||||||
|
for (c = mgr->conns; c != NULL; c = c->next) {
|
||||||
|
if (c->label[0] == 'L') mg_http_printf_chunk(c, "%s", message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timer function - called periodically.
|
||||||
|
// Prepare log message. Save it to a file, and broadcast.
|
||||||
|
static void log_cb(void *arg) {
|
||||||
|
char buf[64];
|
||||||
|
snprintf(buf, sizeof(buf), "Time is: %lu\n", (unsigned long) time(NULL));
|
||||||
|
log_message("log.txt", buf);
|
||||||
|
broadcast_message(arg, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_mgr mgr;
|
||||||
|
struct mg_timer t1, t2;
|
||||||
|
|
||||||
|
mg_mgr_init(&mgr);
|
||||||
|
mg_http_listen(&mgr, "http://localhost:8000", cb, &mgr);
|
||||||
|
mg_timer_init(&t1, 500, MG_TIMER_REPEAT, mjpeg_cb, &mgr);
|
||||||
|
mg_timer_init(&t2, 1000, MG_TIMER_REPEAT, log_cb, &mgr);
|
||||||
|
for (;;) mg_mgr_poll(&mgr, 50);
|
||||||
|
mg_timer_free(&t1);
|
||||||
|
mg_timer_free(&t2);
|
||||||
|
mg_mgr_free(&mgr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,981 @@
|
|||||||
|
// Copyright (c) 2018-2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
#include "mjson.h"
|
||||||
|
|
||||||
|
#if !defined(_MSC_VER) || _MSC_VER >= 1700
|
||||||
|
#else
|
||||||
|
#define va_copy(x, y) (x) = (y)
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#define alloca _alloca
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int mjson_esc(int c, int esc) {
|
||||||
|
const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\"";
|
||||||
|
for (p = esc ? esc1 : esc2; *p != '\0'; p++) {
|
||||||
|
if (*p == c) return esc ? esc2[p - esc1] : esc1[p - esc2];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mjson_pass_string(const char *s, int len) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (s[i] == '\\' && i + 1 < len && mjson_esc(s[i + 1], 1)) {
|
||||||
|
i++;
|
||||||
|
} else if (s[i] == '\0') {
|
||||||
|
return MJSON_ERROR_INVALID_INPUT;
|
||||||
|
} else if (s[i] == '"') {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MJSON_ERROR_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson(const char *s, int len, mjson_cb_t cb, void *ud) {
|
||||||
|
enum { S_VALUE, S_KEY, S_COLON, S_COMMA_OR_EOO } expecting = S_VALUE;
|
||||||
|
unsigned char nesting[MJSON_MAX_DEPTH];
|
||||||
|
int i, depth = 0;
|
||||||
|
#define MJSONCALL(ev) \
|
||||||
|
if (cb != NULL && cb(ev, s, start, i - start + 1, ud)) return i + 1;
|
||||||
|
|
||||||
|
// In the ascii table, the distance between `[` and `]` is 2.
|
||||||
|
// Ditto for `{` and `}`. Hence +2 in the code below.
|
||||||
|
#define MJSONEOO() \
|
||||||
|
do { \
|
||||||
|
if (c != nesting[depth - 1] + 2) return MJSON_ERROR_INVALID_INPUT; \
|
||||||
|
depth--; \
|
||||||
|
if (depth == 0) { \
|
||||||
|
MJSONCALL(tok); \
|
||||||
|
return i + 1; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
int start = i;
|
||||||
|
unsigned char c = ((unsigned char *) s)[i];
|
||||||
|
int tok = c;
|
||||||
|
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue;
|
||||||
|
// printf("- %c [%.*s] %d %d\n", c, i, s, depth, expecting);
|
||||||
|
switch (expecting) {
|
||||||
|
case S_VALUE:
|
||||||
|
if (c == '{') {
|
||||||
|
if (depth >= (int) sizeof(nesting)) return MJSON_ERROR_TOO_DEEP;
|
||||||
|
nesting[depth++] = c;
|
||||||
|
expecting = S_KEY;
|
||||||
|
break;
|
||||||
|
} else if (c == '[') {
|
||||||
|
if (depth >= (int) sizeof(nesting)) return MJSON_ERROR_TOO_DEEP;
|
||||||
|
nesting[depth++] = c;
|
||||||
|
break;
|
||||||
|
} else if (c == ']' && depth > 0) { // Empty array
|
||||||
|
MJSONEOO();
|
||||||
|
} else if (c == 't' && i + 3 < len && memcmp(&s[i], "true", 4) == 0) {
|
||||||
|
i += 3;
|
||||||
|
tok = MJSON_TOK_TRUE;
|
||||||
|
} else if (c == 'n' && i + 3 < len && memcmp(&s[i], "null", 4) == 0) {
|
||||||
|
i += 3;
|
||||||
|
tok = MJSON_TOK_NULL;
|
||||||
|
} else if (c == 'f' && i + 4 < len && memcmp(&s[i], "false", 5) == 0) {
|
||||||
|
i += 4;
|
||||||
|
tok = MJSON_TOK_FALSE;
|
||||||
|
} else if (c == '-' || ((c >= '0' && c <= '9'))) {
|
||||||
|
char *end = NULL;
|
||||||
|
strtod(&s[i], &end);
|
||||||
|
if (end != NULL) i += end - &s[i] - 1;
|
||||||
|
tok = MJSON_TOK_NUMBER;
|
||||||
|
} else if (c == '"') {
|
||||||
|
int n = mjson_pass_string(&s[i + 1], len - i - 1);
|
||||||
|
if (n < 0) return n;
|
||||||
|
i += n + 1;
|
||||||
|
tok = MJSON_TOK_STRING;
|
||||||
|
} else {
|
||||||
|
return MJSON_ERROR_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
if (depth == 0) {
|
||||||
|
MJSONCALL(tok);
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
expecting = S_COMMA_OR_EOO;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_KEY:
|
||||||
|
if (c == '"') {
|
||||||
|
int n = mjson_pass_string(&s[i + 1], len - i - 1);
|
||||||
|
if (n < 0) return n;
|
||||||
|
i += n + 1;
|
||||||
|
tok = MJSON_TOK_KEY;
|
||||||
|
expecting = S_COLON;
|
||||||
|
} else if (c == '}') { // Empty object
|
||||||
|
MJSONEOO();
|
||||||
|
expecting = S_COMMA_OR_EOO;
|
||||||
|
} else {
|
||||||
|
return MJSON_ERROR_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_COLON:
|
||||||
|
if (c == ':') {
|
||||||
|
expecting = S_VALUE;
|
||||||
|
} else {
|
||||||
|
return MJSON_ERROR_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_COMMA_OR_EOO:
|
||||||
|
if (depth <= 0) return MJSON_ERROR_INVALID_INPUT;
|
||||||
|
if (c == ',') {
|
||||||
|
expecting = (nesting[depth - 1] == '{') ? S_KEY : S_VALUE;
|
||||||
|
} else if (c == ']' || c == '}') {
|
||||||
|
MJSONEOO();
|
||||||
|
} else {
|
||||||
|
return MJSON_ERROR_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
MJSONCALL(tok);
|
||||||
|
}
|
||||||
|
return MJSON_ERROR_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct msjon_get_data {
|
||||||
|
const char *path; // Lookup json path
|
||||||
|
int pos; // Current path index
|
||||||
|
int d1; // Current depth of traversal
|
||||||
|
int d2; // Expected depth of traversal
|
||||||
|
int i1; // Index in an array
|
||||||
|
int i2; // Expected index in an array
|
||||||
|
int obj; // If the value is array/object, offset where it starts
|
||||||
|
const char **tokptr; // Destination
|
||||||
|
int *toklen; // Destination length
|
||||||
|
int tok; // Returned token
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mjson_plen(const char *s) {
|
||||||
|
int i = 0;
|
||||||
|
while (s[i] != '\0' && s[i] != '.' && s[i] != '[') i++;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mjson_get_cb(int tok, const char *s, int off, int len, void *ud) {
|
||||||
|
struct msjon_get_data *data = (struct msjon_get_data *) ud;
|
||||||
|
// printf("--> %2x %2d %2d %2d %2d\t'%s'\t'%.*s'\t\t'%.*s'\n", tok, data->d1,
|
||||||
|
// data->d2, data->i1, data->i2, data->path + data->pos, off, s, len,
|
||||||
|
// s + off);
|
||||||
|
if (data->tok != MJSON_TOK_INVALID) return 1; // Found
|
||||||
|
|
||||||
|
if (tok == '{') {
|
||||||
|
if (!data->path[data->pos] && data->d1 == data->d2) data->obj = off;
|
||||||
|
data->d1++;
|
||||||
|
} else if (tok == '[') {
|
||||||
|
if (data->d1 == data->d2 && data->path[data->pos] == '[') {
|
||||||
|
data->i1 = 0;
|
||||||
|
data->i2 = (int) strtod(&data->path[data->pos + 1], NULL);
|
||||||
|
if (data->i1 == data->i2) {
|
||||||
|
data->d2++;
|
||||||
|
data->pos += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!data->path[data->pos] && data->d1 == data->d2) data->obj = off;
|
||||||
|
data->d1++;
|
||||||
|
} else if (tok == ',') {
|
||||||
|
if (data->d1 == data->d2 + 1) {
|
||||||
|
data->i1++;
|
||||||
|
if (data->i1 == data->i2) {
|
||||||
|
while (data->path[data->pos] != ']') data->pos++;
|
||||||
|
data->pos++;
|
||||||
|
data->d2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (tok == MJSON_TOK_KEY && data->d1 == data->d2 + 1 &&
|
||||||
|
data->path[data->pos] == '.' && s[off] == '"' &&
|
||||||
|
s[off + len - 1] == '"' &&
|
||||||
|
mjson_plen(&data->path[data->pos + 1]) == len - 2 &&
|
||||||
|
!memcmp(s + off + 1, &data->path[data->pos + 1], len - 2)) {
|
||||||
|
data->d2++;
|
||||||
|
data->pos += len - 1;
|
||||||
|
} else if (tok == MJSON_TOK_KEY && data->d1 == data->d2) {
|
||||||
|
return 1; // Exhausted path, not found
|
||||||
|
} else if (tok == '}' || tok == ']') {
|
||||||
|
data->d1--;
|
||||||
|
// data->d2--;
|
||||||
|
if (!data->path[data->pos] && data->d1 == data->d2 && data->obj != -1) {
|
||||||
|
data->tok = tok - 2;
|
||||||
|
if (data->tokptr) *data->tokptr = s + data->obj;
|
||||||
|
if (data->toklen) *data->toklen = off - data->obj + 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if (MJSON_TOK_IS_VALUE(tok)) {
|
||||||
|
// printf("TOK --> %d\n", tok);
|
||||||
|
if (data->d1 == data->d2 && !data->path[data->pos]) {
|
||||||
|
data->tok = tok;
|
||||||
|
if (data->tokptr) *data->tokptr = s + off;
|
||||||
|
if (data->toklen) *data->toklen = len;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum mjson_tok mjson_find(const char *s, int len, const char *jp,
|
||||||
|
const char **tokptr, int *toklen) {
|
||||||
|
struct msjon_get_data data = {jp, 1, 0, 0, 0,
|
||||||
|
0, -1, tokptr, toklen, MJSON_TOK_INVALID};
|
||||||
|
if (jp[0] != '$') return MJSON_TOK_INVALID;
|
||||||
|
if (mjson(s, len, mjson_get_cb, &data) < 0) return MJSON_TOK_INVALID;
|
||||||
|
return (enum mjson_tok) data.tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_get_number(const char *s, int len, const char *path, double *v) {
|
||||||
|
const char *p;
|
||||||
|
int tok, n;
|
||||||
|
if ((tok = mjson_find(s, len, path, &p, &n)) == MJSON_TOK_NUMBER) {
|
||||||
|
if (v != NULL) *v = strtod(p, NULL);
|
||||||
|
}
|
||||||
|
return tok == MJSON_TOK_NUMBER ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_get_bool(const char *s, int len, const char *path, int *v) {
|
||||||
|
int tok = mjson_find(s, len, path, NULL, NULL);
|
||||||
|
if (tok == MJSON_TOK_TRUE && v != NULL) *v = 1;
|
||||||
|
if (tok == MJSON_TOK_FALSE && v != NULL) *v = 0;
|
||||||
|
return tok == MJSON_TOK_TRUE || tok == MJSON_TOK_FALSE ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mjson_unescape(const char *s, int len, char *to, int n) {
|
||||||
|
int i, j;
|
||||||
|
for (i = 0, j = 0; i < len && j < n; i++, j++) {
|
||||||
|
if (s[i] == '\\' && i + 1 < len) {
|
||||||
|
int c = mjson_esc(s[i + 1], 0);
|
||||||
|
if (c == 0) return -1;
|
||||||
|
to[j] = c;
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
to[j] = s[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j >= n) return -1;
|
||||||
|
if (n > 0) to[j] = '\0';
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_get_string(const char *s, int len, const char *path, char *to,
|
||||||
|
int n) {
|
||||||
|
const char *p;
|
||||||
|
int sz;
|
||||||
|
if (mjson_find(s, len, path, &p, &sz) != MJSON_TOK_STRING) return -1;
|
||||||
|
return mjson_unescape(p + 1, sz - 2, to, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_get_hex(const char *s, int len, const char *x, char *to, int n) {
|
||||||
|
const char *p;
|
||||||
|
int i, j, sz;
|
||||||
|
if (mjson_find(s, len, x, &p, &sz) != MJSON_TOK_STRING) return -1;
|
||||||
|
for (i = j = 0; i < sz - 3 && j < n; i += 2, j++) {
|
||||||
|
#define HEXTOI(x) (x >= '0' && x <= '9' ? x - '0' : x - 'W')
|
||||||
|
unsigned char a = *(const unsigned char *) (p + i + 1);
|
||||||
|
unsigned char b = *(const unsigned char *) (p + i + 2);
|
||||||
|
((unsigned char *) to)[j] = (HEXTOI(a) << 4) | HEXTOI(b);
|
||||||
|
}
|
||||||
|
if (j < n) to[j] = '\0';
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_BASE64
|
||||||
|
static int mjson_base64rev(int c) {
|
||||||
|
if (c >= 'A' && c <= 'Z') {
|
||||||
|
return c - 'A';
|
||||||
|
} else if (c >= 'a' && c <= 'z') {
|
||||||
|
return c + 26 - 'a';
|
||||||
|
} else if (c >= '0' && c <= '9') {
|
||||||
|
return c + 52 - '0';
|
||||||
|
} else if (c == '+') {
|
||||||
|
return 62;
|
||||||
|
} else if (c == '/') {
|
||||||
|
return 63;
|
||||||
|
} else {
|
||||||
|
return 64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_base64_dec(const char *src, int n, char *dst, int dlen) {
|
||||||
|
const char *end = src + n;
|
||||||
|
int len = 0;
|
||||||
|
while (src + 3 < end && len < dlen) {
|
||||||
|
int a = mjson_base64rev(src[0]), b = mjson_base64rev(src[1]),
|
||||||
|
c = mjson_base64rev(src[2]), d = mjson_base64rev(src[3]);
|
||||||
|
dst[len++] = (a << 2) | (b >> 4);
|
||||||
|
if (src[2] != '=' && len < dlen) {
|
||||||
|
dst[len++] = (b << 4) | (c >> 2);
|
||||||
|
if (src[3] != '=' && len < dlen) {
|
||||||
|
dst[len++] = (c << 6) | d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
src += 4;
|
||||||
|
}
|
||||||
|
if (len < dlen) dst[len] = '\0';
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_get_base64(const char *s, int len, const char *path, char *to,
|
||||||
|
int n) {
|
||||||
|
const char *p;
|
||||||
|
int sz;
|
||||||
|
if (mjson_find(s, len, path, &p, &sz) != MJSON_TOK_STRING) return 0;
|
||||||
|
return mjson_base64_dec(p + 1, sz - 2, to, n);
|
||||||
|
}
|
||||||
|
#endif // MJSON_ENABLE_BASE64
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_NEXT
|
||||||
|
struct nextdata {
|
||||||
|
int off, len, depth, t, vo, arrayindex;
|
||||||
|
int *koff, *klen, *voff, *vlen, *vtype;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int next_cb(int tok, const char *s, int off, int len, void *ud) {
|
||||||
|
struct nextdata *d = (struct nextdata *) ud;
|
||||||
|
// int i;
|
||||||
|
switch (tok) {
|
||||||
|
case '{':
|
||||||
|
case '[':
|
||||||
|
if (d->depth == 0 && tok == '[') d->arrayindex = 0;
|
||||||
|
if (d->depth == 1 && off > d->off) {
|
||||||
|
d->vo = off;
|
||||||
|
d->t = tok == '{' ? MJSON_TOK_OBJECT : MJSON_TOK_ARRAY;
|
||||||
|
if (d->voff) *d->voff = off;
|
||||||
|
if (d->vtype) *d->vtype = d->t;
|
||||||
|
}
|
||||||
|
d->depth++;
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
case ']':
|
||||||
|
d->depth--;
|
||||||
|
if (d->depth == 1 && d->vo) {
|
||||||
|
d->len = off + len;
|
||||||
|
if (d->vlen) *d->vlen = d->len - d->vo;
|
||||||
|
if (d->arrayindex >= 0) {
|
||||||
|
if (d->koff) *d->koff = d->arrayindex; // koff holds array index
|
||||||
|
if (d->klen) *d->klen = 0; // klen holds 0
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (d->depth == 1 && d->arrayindex >= 0) d->arrayindex++;
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
case ':':
|
||||||
|
break;
|
||||||
|
case MJSON_TOK_KEY:
|
||||||
|
if (d->depth == 1 && d->off < off) {
|
||||||
|
if (d->koff) *d->koff = off; // And report back to the user
|
||||||
|
if (d->klen) *d->klen = len; // If we have to
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (d->depth != 1) break;
|
||||||
|
// If we're iterating over the array
|
||||||
|
if (off > d->off) {
|
||||||
|
d->len = off + len;
|
||||||
|
if (d->vlen) *d->vlen = len; // value length
|
||||||
|
if (d->voff) *d->voff = off; // value offset
|
||||||
|
if (d->vtype) *d->vtype = tok; // value type
|
||||||
|
if (d->arrayindex >= 0) {
|
||||||
|
if (d->koff) *d->koff = d->arrayindex; // koff holds array index
|
||||||
|
if (d->klen) *d->klen = 0; // klen holds 0
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (d->arrayindex >= 0) d->arrayindex++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
(void) s;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_next(const char *s, int n, int off, int *koff, int *klen, int *voff,
|
||||||
|
int *vlen, int *vtype) {
|
||||||
|
struct nextdata d = {off, 0, 0, 0, 0, -1, koff, klen, voff, vlen, vtype};
|
||||||
|
mjson(s, n, next_cb, &d);
|
||||||
|
return d.len;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_PRINT
|
||||||
|
int mjson_print_fixed_buf(const char *ptr, int len, void *fndata) {
|
||||||
|
struct mjson_fixedbuf *fb = (struct mjson_fixedbuf *) fndata;
|
||||||
|
int i, left = fb->size - 1 - fb->len;
|
||||||
|
if (left < len) len = left;
|
||||||
|
for (i = 0; i < len; i++) fb->ptr[fb->len + i] = ptr[i];
|
||||||
|
fb->len += len;
|
||||||
|
fb->ptr[fb->len] = '\0';
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_print_dynamic_buf(const char *ptr, int len, void *fndata) {
|
||||||
|
char *s, *buf = *(char **) fndata;
|
||||||
|
int curlen = buf == NULL ? 0 : strlen(buf);
|
||||||
|
if ((s = (char *) realloc(buf, curlen + len + 1)) == NULL) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
memcpy(s + curlen, ptr, len);
|
||||||
|
s[curlen + len] = '\0';
|
||||||
|
*(char **) fndata = s;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_print_null(const char *ptr, int len, void *userdata) {
|
||||||
|
(void) ptr;
|
||||||
|
(void) userdata;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_print_file(const char *ptr, int len, void *userdata) {
|
||||||
|
return fwrite(ptr, 1, len, (FILE *) userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_print_buf(mjson_print_fn_t fn, void *fndata, const char *buf,
|
||||||
|
int len) {
|
||||||
|
return fn(buf, len, fndata);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_print_int(mjson_print_fn_t fn, void *fndata, int value,
|
||||||
|
int is_signed) {
|
||||||
|
char buf[20];
|
||||||
|
int len = snprintf(buf, sizeof(buf), is_signed ? "%d" : "%u", value);
|
||||||
|
return fn(buf, len, fndata);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_print_long(mjson_print_fn_t fn, void *fndata, long value,
|
||||||
|
int is_signed) {
|
||||||
|
char buf[20];
|
||||||
|
const char *fmt = (is_signed ? "%ld" : "%lu");
|
||||||
|
int len = snprintf(buf, sizeof(buf), fmt, value);
|
||||||
|
return fn(buf, len, fndata);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_print_dbl(mjson_print_fn_t fn, void *fndata, double d,
|
||||||
|
const char *fmt) {
|
||||||
|
char buf[40];
|
||||||
|
int n = snprintf(buf, sizeof(buf), fmt, d);
|
||||||
|
return fn(buf, n, fndata);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_print_str(mjson_print_fn_t fn, void *fndata, const char *s, int len) {
|
||||||
|
int i, n = fn("\"", 1, fndata);
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
char c = mjson_esc(s[i], 1);
|
||||||
|
if (c) {
|
||||||
|
n += fn("\\", 1, fndata);
|
||||||
|
n += fn(&c, 1, fndata);
|
||||||
|
} else {
|
||||||
|
n += fn(&s[i], 1, fndata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n + fn("\"", 1, fndata);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_BASE64
|
||||||
|
int mjson_print_b64(mjson_print_fn_t fn, void *fndata, const unsigned char *s,
|
||||||
|
int n) {
|
||||||
|
const char *t =
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
int i, len = fn("\"", 1, fndata);
|
||||||
|
for (i = 0; i < n; i += 3) {
|
||||||
|
int a = s[i], b = i + 1 < n ? s[i + 1] : 0, c = i + 2 < n ? s[i + 2] : 0;
|
||||||
|
char buf[4] = {t[a >> 2], t[(a & 3) << 4 | (b >> 4)], '=', '='};
|
||||||
|
if (i + 1 < n) buf[2] = t[(b & 15) << 2 | (c >> 6)];
|
||||||
|
if (i + 2 < n) buf[3] = t[c & 63];
|
||||||
|
len += fn(buf, sizeof(buf), fndata);
|
||||||
|
}
|
||||||
|
return len + fn("\"", 1, fndata);
|
||||||
|
}
|
||||||
|
#endif /* MJSON_ENABLE_BASE64 */
|
||||||
|
|
||||||
|
int mjson_vprintf(mjson_print_fn_t fn, void *fndata, const char *fmt,
|
||||||
|
va_list xap) {
|
||||||
|
int i = 0, n = 0;
|
||||||
|
va_list ap;
|
||||||
|
va_copy(ap, xap);
|
||||||
|
while (fmt[i] != '\0') {
|
||||||
|
if (fmt[i] == '%') {
|
||||||
|
char fc = fmt[++i];
|
||||||
|
int is_long = 0;
|
||||||
|
if (fc == 'l') {
|
||||||
|
is_long = 1;
|
||||||
|
fc = fmt[i + 1];
|
||||||
|
}
|
||||||
|
if (fc == 'Q') {
|
||||||
|
char *buf = va_arg(ap, char *);
|
||||||
|
n += mjson_print_str(fn, fndata, buf ? buf : "", buf ? strlen(buf) : 0);
|
||||||
|
} else if (strncmp(&fmt[i], ".*Q", 3) == 0) {
|
||||||
|
int len = va_arg(ap, int);
|
||||||
|
char *buf = va_arg(ap, char *);
|
||||||
|
n += mjson_print_str(fn, fndata, buf, len);
|
||||||
|
i += 2;
|
||||||
|
} else if (fc == 'd' || fc == 'u') {
|
||||||
|
int is_signed = (fc == 'd');
|
||||||
|
if (is_long) {
|
||||||
|
long val = va_arg(ap, long);
|
||||||
|
n += mjson_print_long(fn, fndata, val, is_signed);
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
int val = va_arg(ap, int);
|
||||||
|
n += mjson_print_int(fn, fndata, val, is_signed);
|
||||||
|
}
|
||||||
|
} else if (fc == 'B') {
|
||||||
|
const char *s = va_arg(ap, int) ? "true" : "false";
|
||||||
|
n += mjson_print_buf(fn, fndata, s, strlen(s));
|
||||||
|
} else if (fc == 's') {
|
||||||
|
char *buf = va_arg(ap, char *);
|
||||||
|
n += mjson_print_buf(fn, fndata, buf, strlen(buf));
|
||||||
|
} else if (strncmp(&fmt[i], ".*s", 3) == 0) {
|
||||||
|
int len = va_arg(ap, int);
|
||||||
|
char *buf = va_arg(ap, char *);
|
||||||
|
n += mjson_print_buf(fn, fndata, buf, len);
|
||||||
|
i += 2;
|
||||||
|
} else if (fc == 'g') {
|
||||||
|
n += mjson_print_dbl(fn, fndata, va_arg(ap, double), "%g");
|
||||||
|
} else if (fc == 'f') {
|
||||||
|
n += mjson_print_dbl(fn, fndata, va_arg(ap, double), "%f");
|
||||||
|
#if MJSON_ENABLE_BASE64
|
||||||
|
} else if (fc == 'V') {
|
||||||
|
int len = va_arg(ap, int);
|
||||||
|
const char *buf = va_arg(ap, const char *);
|
||||||
|
n += mjson_print_b64(fn, fndata, (unsigned char *) buf, len);
|
||||||
|
#endif
|
||||||
|
} else if (fc == 'H') {
|
||||||
|
const char *hex = "0123456789abcdef";
|
||||||
|
int i, len = va_arg(ap, int);
|
||||||
|
const unsigned char *p = va_arg(ap, const unsigned char *);
|
||||||
|
n += fn("\"", 1, fndata);
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
n += fn(&hex[(p[i] >> 4) & 15], 1, fndata);
|
||||||
|
n += fn(&hex[p[i] & 15], 1, fndata);
|
||||||
|
}
|
||||||
|
n += fn("\"", 1, fndata);
|
||||||
|
} else if (fc == 'M') {
|
||||||
|
mjson_vprint_fn_t vfn = va_arg(ap, mjson_vprint_fn_t);
|
||||||
|
n += vfn(fn, fndata, &ap);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
n += mjson_print_buf(fn, fndata, &fmt[i++], 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
va_end(xap);
|
||||||
|
va_end(ap);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_printf(mjson_print_fn_t fn, void *fndata, const char *fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
int len;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
len = mjson_vprintf(fn, fndata, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
#endif /* MJSON_ENABLE_PRINT */
|
||||||
|
|
||||||
|
#if MJSON_IMPLEMENT_STRTOD
|
||||||
|
static inline int is_digit(int c) {
|
||||||
|
return c >= '0' && c <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTE: strtod() implementation by Yasuhiro Matsumoto. */
|
||||||
|
double strtod(const char *str, char **end) {
|
||||||
|
double d = 0.0;
|
||||||
|
int sign = 1, n = 0;
|
||||||
|
const char *p = str, *a = str;
|
||||||
|
|
||||||
|
/* decimal part */
|
||||||
|
if (*p == '-') {
|
||||||
|
sign = -1;
|
||||||
|
++p;
|
||||||
|
} else if (*p == '+')
|
||||||
|
++p;
|
||||||
|
if (is_digit(*p)) {
|
||||||
|
d = (double) (*p++ - '0');
|
||||||
|
while (*p && is_digit(*p)) {
|
||||||
|
d = d * 10.0 + (double) (*p - '0');
|
||||||
|
++p;
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
a = p;
|
||||||
|
} else if (*p != '.')
|
||||||
|
goto done;
|
||||||
|
d *= sign;
|
||||||
|
|
||||||
|
/* fraction part */
|
||||||
|
if (*p == '.') {
|
||||||
|
double f = 0.0;
|
||||||
|
double base = 0.1;
|
||||||
|
++p;
|
||||||
|
|
||||||
|
if (is_digit(*p)) {
|
||||||
|
while (*p && is_digit(*p)) {
|
||||||
|
f += base * (*p - '0');
|
||||||
|
base /= 10.0;
|
||||||
|
++p;
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d += f * sign;
|
||||||
|
a = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* exponential part */
|
||||||
|
if ((*p == 'E') || (*p == 'e')) {
|
||||||
|
int e = 0;
|
||||||
|
++p;
|
||||||
|
|
||||||
|
sign = 1;
|
||||||
|
if (*p == '-') {
|
||||||
|
sign = -1;
|
||||||
|
++p;
|
||||||
|
} else if (*p == '+')
|
||||||
|
++p;
|
||||||
|
|
||||||
|
if (is_digit(*p)) {
|
||||||
|
while (*p == '0') ++p;
|
||||||
|
e = (int) (*p++ - '0');
|
||||||
|
while (*p && is_digit(*p)) {
|
||||||
|
e = e * 10 + (int) (*p - '0');
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
e *= sign;
|
||||||
|
} else if (!is_digit(*(a - 1))) {
|
||||||
|
a = str;
|
||||||
|
goto done;
|
||||||
|
} else if (*p == 0)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (d == 2.2250738585072011 && e == -308) {
|
||||||
|
d = 0.0;
|
||||||
|
a = p;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (d == 2.2250738585072012 && e <= -308) {
|
||||||
|
d *= 1.0e-308;
|
||||||
|
a = p;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 10; i++) d *= 10;
|
||||||
|
}
|
||||||
|
a = p;
|
||||||
|
} else if (p > str && !is_digit(*(p - 1))) {
|
||||||
|
a = str;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (end) *end = (char *) a;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_MERGE
|
||||||
|
int mjson_merge(const char *s, int n, const char *s2, int n2,
|
||||||
|
mjson_print_fn_t fn, void *userdata) {
|
||||||
|
int koff, klen, voff, vlen, t, t2, k, off = 0, len = 0, comma = 0;
|
||||||
|
if (n < 2) return len;
|
||||||
|
len += fn("{", 1, userdata);
|
||||||
|
while ((off = mjson_next(s, n, off, &koff, &klen, &voff, &vlen, &t)) != 0) {
|
||||||
|
#if !defined(_MSC_VER) || _MSC_VER >= 1700
|
||||||
|
char path[klen + 1];
|
||||||
|
#else
|
||||||
|
char *path = (char *) alloca(klen + 1);
|
||||||
|
#endif
|
||||||
|
const char *val;
|
||||||
|
memcpy(path, "$.", 2);
|
||||||
|
memcpy(path + 2, s + koff + 1, klen - 2);
|
||||||
|
path[klen] = '\0';
|
||||||
|
if ((t2 = mjson_find(s2, n2, path, &val, &k)) != MJSON_TOK_INVALID) {
|
||||||
|
if (t2 == MJSON_TOK_NULL) continue; // null deletes the key
|
||||||
|
} else {
|
||||||
|
val = s + voff; // Key is not found in the update. Copy the old value.
|
||||||
|
}
|
||||||
|
if (comma) len += fn(",", 1, userdata);
|
||||||
|
len += fn(s + koff, klen, userdata);
|
||||||
|
len += fn(":", 1, userdata);
|
||||||
|
if (t == MJSON_TOK_OBJECT && t2 == MJSON_TOK_OBJECT) {
|
||||||
|
len += mjson_merge(s + voff, vlen, val, k, fn, userdata);
|
||||||
|
} else {
|
||||||
|
if (t2 != MJSON_TOK_INVALID) vlen = k;
|
||||||
|
len += fn(val, vlen, userdata);
|
||||||
|
}
|
||||||
|
comma = 1;
|
||||||
|
}
|
||||||
|
// Add missing keys
|
||||||
|
off = 0;
|
||||||
|
while ((off = mjson_next(s2, n2, off, &koff, &klen, &voff, &vlen, &t)) != 0) {
|
||||||
|
#if !defined(_MSC_VER) || _MSC_VER >= 1700
|
||||||
|
char path[klen + 1];
|
||||||
|
#else
|
||||||
|
char *path = (char *) alloca(klen + 1);
|
||||||
|
#endif
|
||||||
|
const char *val;
|
||||||
|
if (t == MJSON_TOK_NULL) continue;
|
||||||
|
memcpy(path, "$.", 2);
|
||||||
|
memcpy(path + 2, s2 + koff + 1, klen - 2);
|
||||||
|
path[klen] = '\0';
|
||||||
|
if (mjson_find(s, n, path, &val, &vlen) != MJSON_TOK_INVALID) continue;
|
||||||
|
if (comma) len += fn(",", 1, userdata);
|
||||||
|
len += fn(s2 + koff, klen, userdata);
|
||||||
|
len += fn(":", 1, userdata);
|
||||||
|
len += fn(s2 + voff, vlen, userdata);
|
||||||
|
comma = 1;
|
||||||
|
}
|
||||||
|
len += fn("}", 1, userdata);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
#endif // MJSON_ENABLE_MERGE
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_PRETTY
|
||||||
|
struct prettydata {
|
||||||
|
int level;
|
||||||
|
int len;
|
||||||
|
int prev;
|
||||||
|
const char *pad;
|
||||||
|
int padlen;
|
||||||
|
mjson_print_fn_t fn;
|
||||||
|
void *userdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pretty_cb(int ev, const char *s, int off, int len, void *ud) {
|
||||||
|
struct prettydata *d = (struct prettydata *) ud;
|
||||||
|
int i;
|
||||||
|
switch (ev) {
|
||||||
|
case '{':
|
||||||
|
case '[':
|
||||||
|
d->level++;
|
||||||
|
d->len += d->fn(s + off, len, d->userdata);
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
case ']':
|
||||||
|
d->level--;
|
||||||
|
if (d->prev != '[' && d->prev != '{' && d->padlen > 0) {
|
||||||
|
d->len += d->fn("\n", 1, d->userdata);
|
||||||
|
for (i = 0; i < d->level; i++)
|
||||||
|
d->len += d->fn(d->pad, d->padlen, d->userdata);
|
||||||
|
}
|
||||||
|
d->len += d->fn(s + off, len, d->userdata);
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
d->len += d->fn(s + off, len, d->userdata);
|
||||||
|
if (d->padlen > 0) {
|
||||||
|
d->len += d->fn("\n", 1, d->userdata);
|
||||||
|
for (i = 0; i < d->level; i++)
|
||||||
|
d->len += d->fn(d->pad, d->padlen, d->userdata);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ':':
|
||||||
|
d->len += d->fn(s + off, len, d->userdata);
|
||||||
|
if (d->padlen > 0) d->len += d->fn(" ", 1, d->userdata);
|
||||||
|
break;
|
||||||
|
case MJSON_TOK_KEY:
|
||||||
|
if (d->prev == '{' && d->padlen > 0) {
|
||||||
|
d->len += d->fn("\n", 1, d->userdata);
|
||||||
|
for (i = 0; i < d->level; i++)
|
||||||
|
d->len += d->fn(d->pad, d->padlen, d->userdata);
|
||||||
|
}
|
||||||
|
d->len += d->fn(s + off, len, d->userdata);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (d->prev == '[' && d->padlen > 0) {
|
||||||
|
d->len += d->fn("\n", 1, d->userdata);
|
||||||
|
for (i = 0; i < d->level; i++)
|
||||||
|
d->len += d->fn(d->pad, d->padlen, d->userdata);
|
||||||
|
}
|
||||||
|
d->len += d->fn(s + off, len, d->userdata);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
d->prev = ev;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_pretty(const char *s, int n, const char *pad, mjson_print_fn_t fn,
|
||||||
|
void *userdata) {
|
||||||
|
struct prettydata d = {0, 0, 0, pad, strlen(pad), fn, userdata};
|
||||||
|
if (mjson(s, n, pretty_cb, &d) < 0) return -1;
|
||||||
|
return d.len;
|
||||||
|
}
|
||||||
|
#endif // MJSON_ENABLE_PRETTY
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_RPC
|
||||||
|
struct jsonrpc_ctx jsonrpc_default_context;
|
||||||
|
struct jsonrpc_userdata {
|
||||||
|
mjson_print_fn_t fn;
|
||||||
|
void *fndata;
|
||||||
|
};
|
||||||
|
|
||||||
|
int mjson_globmatch(const char *s1, int n1, const char *s2, int n2) {
|
||||||
|
int i = 0, j = 0, ni = 0, nj = 0;
|
||||||
|
while (i < n1 || j < n2) {
|
||||||
|
if (i < n1 && j < n2 && (s1[i] == '?' || s2[j] == s1[i])) {
|
||||||
|
i++, j++;
|
||||||
|
} else if (i < n1 && (s1[i] == '*' || s1[i] == '#')) {
|
||||||
|
ni = i, nj = j + 1, i++;
|
||||||
|
} else if (nj > 0 && nj <= n2 && (s1[i - 1] == '#' || s2[j] != '/')) {
|
||||||
|
i = ni, j = nj;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jsonrpc_printer(const char *buf, int len, void *userdata) {
|
||||||
|
struct jsonrpc_userdata *u = (struct jsonrpc_userdata *) userdata;
|
||||||
|
return u->fn(buf, len, u->fndata);
|
||||||
|
}
|
||||||
|
|
||||||
|
void jsonrpc_return_errorv(struct jsonrpc_request *r, int code,
|
||||||
|
const char *message, const char *data_fmt,
|
||||||
|
va_list ap) {
|
||||||
|
if (r->id_len == 0) return;
|
||||||
|
mjson_printf(r->fn, r->fndata,
|
||||||
|
"{\"id\":%.*s,\"error\":{\"code\":%d,\"message\":%Q", r->id_len,
|
||||||
|
r->id, code, message == NULL ? "" : message);
|
||||||
|
if (data_fmt != NULL) {
|
||||||
|
mjson_printf(r->fn, r->fndata, ",\"data\":");
|
||||||
|
mjson_vprintf(r->fn, r->fndata, data_fmt, ap);
|
||||||
|
}
|
||||||
|
mjson_printf(r->fn, r->fndata, "}}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void jsonrpc_return_error(struct jsonrpc_request *r, int code,
|
||||||
|
const char *message, const char *data_fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, data_fmt);
|
||||||
|
jsonrpc_return_errorv(r, code, message, data_fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void jsonrpc_return_successv(struct jsonrpc_request *r, const char *result_fmt,
|
||||||
|
va_list ap) {
|
||||||
|
if (r->id_len == 0) return;
|
||||||
|
mjson_printf(r->fn, r->fndata, "{\"id\":%.*s,\"result\":", r->id_len, r->id);
|
||||||
|
if (result_fmt != NULL) {
|
||||||
|
mjson_vprintf(r->fn, r->fndata, result_fmt, ap);
|
||||||
|
} else {
|
||||||
|
mjson_printf(r->fn, r->fndata, "%s", "null");
|
||||||
|
}
|
||||||
|
mjson_printf(r->fn, r->fndata, "}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void jsonrpc_return_success(struct jsonrpc_request *r, const char *result_fmt,
|
||||||
|
...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, result_fmt);
|
||||||
|
jsonrpc_return_successv(r, result_fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void jsonrpc_ctx_process(struct jsonrpc_ctx *ctx, const char *req, int req_sz,
|
||||||
|
mjson_print_fn_t fn, void *fndata) {
|
||||||
|
const char *result = NULL, *error = NULL;
|
||||||
|
int result_sz = 0, error_sz = 0;
|
||||||
|
struct jsonrpc_method *m = NULL;
|
||||||
|
struct jsonrpc_userdata d;
|
||||||
|
struct jsonrpc_request r = {req, req_sz, 0, 0, 0, 0, 0,
|
||||||
|
0, &jsonrpc_printer, NULL, NULL};
|
||||||
|
|
||||||
|
d.fn = fn;
|
||||||
|
d.fndata = fndata;
|
||||||
|
r.fndata = &d;
|
||||||
|
|
||||||
|
// Is is a response frame?
|
||||||
|
mjson_find(req, req_sz, "$.result", &result, &result_sz);
|
||||||
|
if (result == NULL) mjson_find(req, req_sz, "$.error", &error, &error_sz);
|
||||||
|
if (result_sz > 0 || error_sz > 0) {
|
||||||
|
if (ctx->response_cb != NULL) ctx->response_cb(req, req_sz, ctx->userdata);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method must exist and must be a string
|
||||||
|
if (mjson_find(req, req_sz, "$.method", &r.method, &r.method_len) !=
|
||||||
|
MJSON_TOK_STRING) {
|
||||||
|
mjson_printf(fn, fndata, "{\"error\":{\"code\":-32700,\"message\":%.*Q}}\n",
|
||||||
|
req_sz, req);
|
||||||
|
ctx->in_len = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// id and params are optional
|
||||||
|
mjson_find(req, req_sz, "$.id", &r.id, &r.id_len);
|
||||||
|
mjson_find(req, req_sz, "$.params", &r.params, &r.params_len);
|
||||||
|
|
||||||
|
for (m = ctx->methods; m != NULL; m = m->next) {
|
||||||
|
if (mjson_globmatch(m->method, m->method_sz, r.method + 1,
|
||||||
|
r.method_len - 2) > 0) {
|
||||||
|
if (r.params == NULL) r.params = "";
|
||||||
|
r.userdata = m->cbdata;
|
||||||
|
m->cb(&r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m == NULL) {
|
||||||
|
jsonrpc_return_error(&r, JSONRPC_ERROR_NOT_FOUND, "method not found", NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jsonrpc_print_methods(mjson_print_fn_t fn, void *fndata,
|
||||||
|
va_list *ap) {
|
||||||
|
struct jsonrpc_ctx *ctx = va_arg(*ap, struct jsonrpc_ctx *);
|
||||||
|
struct jsonrpc_method *m;
|
||||||
|
int len = 0;
|
||||||
|
for (m = ctx->methods; m != NULL; m = m->next) {
|
||||||
|
if (m != ctx->methods) len += mjson_print_buf(fn, fndata, ",", 1);
|
||||||
|
len += mjson_print_str(fn, fndata, m->method, strlen(m->method));
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rpclist(struct jsonrpc_request *r) {
|
||||||
|
jsonrpc_return_success(r, "[%M]", jsonrpc_print_methods, r->userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
void jsonrpc_ctx_init(struct jsonrpc_ctx *ctx, mjson_print_fn_t response_cb,
|
||||||
|
void *userdata) {
|
||||||
|
ctx->response_cb = response_cb;
|
||||||
|
ctx->userdata = userdata;
|
||||||
|
jsonrpc_ctx_export(ctx, MJSON_RPC_LIST_NAME, rpclist, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void jsonrpc_ctx_process_byte(struct jsonrpc_ctx *ctx, unsigned char ch,
|
||||||
|
mjson_print_fn_t fn, void *p) {
|
||||||
|
if (ctx->in_len >= (int) sizeof(ctx->in)) ctx->in_len = 0; // Overflow
|
||||||
|
if (ch == '\n') { // If new line, parse frame
|
||||||
|
if (ctx->in_len > 1) jsonrpc_ctx_process(ctx, ctx->in, ctx->in_len, fn, p);
|
||||||
|
ctx->in_len = 0;
|
||||||
|
} else {
|
||||||
|
ctx->in[ctx->in_len] = ch; // Append to the buffer
|
||||||
|
ctx->in_len++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void jsonrpc_init(mjson_print_fn_t response_cb, void *userdata) {
|
||||||
|
jsonrpc_ctx_init(&jsonrpc_default_context, response_cb, userdata);
|
||||||
|
}
|
||||||
|
#endif // MJSON_ENABLE_RPC
|
||||||
@@ -0,0 +1,220 @@
|
|||||||
|
// Copyright (c) 2018-2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef MJSON_H
|
||||||
|
#define MJSON_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifndef MJSON_ENABLE_PRINT
|
||||||
|
#define MJSON_ENABLE_PRINT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MJSON_ENABLE_RPC
|
||||||
|
#define MJSON_ENABLE_RPC 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MJSON_ENABLE_BASE64
|
||||||
|
#define MJSON_ENABLE_BASE64 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MJSON_ENABLE_MERGE
|
||||||
|
#define MJSON_ENABLE_MERGE 0
|
||||||
|
#elif MJSON_ENABLE_MERGE
|
||||||
|
#define MJSON_ENABLE_NEXT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MJSON_ENABLE_PRETTY
|
||||||
|
#define MJSON_ENABLE_PRETTY 0
|
||||||
|
#elif MJSON_ENABLE_PRETTY
|
||||||
|
#define MJSON_ENABLE_NEXT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MJSON_ENABLE_NEXT
|
||||||
|
#define MJSON_ENABLE_NEXT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef MJSON_RPC_IN_BUF_SIZE
|
||||||
|
#define MJSON_RPC_IN_BUF_SIZE 256
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MJSON_RPC_LIST_NAME
|
||||||
|
#define MJSON_RPC_LIST_NAME "rpc.list"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MJSON_ERROR_INVALID_INPUT = -1,
|
||||||
|
MJSON_ERROR_TOO_DEEP = -2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum mjson_tok {
|
||||||
|
MJSON_TOK_INVALID = 0,
|
||||||
|
MJSON_TOK_KEY = 1,
|
||||||
|
MJSON_TOK_STRING = 11,
|
||||||
|
MJSON_TOK_NUMBER = 12,
|
||||||
|
MJSON_TOK_TRUE = 13,
|
||||||
|
MJSON_TOK_FALSE = 14,
|
||||||
|
MJSON_TOK_NULL = 15,
|
||||||
|
MJSON_TOK_ARRAY = 91,
|
||||||
|
MJSON_TOK_OBJECT = 123,
|
||||||
|
};
|
||||||
|
#define MJSON_TOK_IS_VALUE(t) ((t) > 10 && (t) < 20)
|
||||||
|
|
||||||
|
typedef int (*mjson_cb_t)(int ev, const char *s, int off, int len, void *ud);
|
||||||
|
|
||||||
|
#ifndef MJSON_MAX_DEPTH
|
||||||
|
#define MJSON_MAX_DEPTH 20
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int mjson(const char *s, int len, mjson_cb_t cb, void *ud);
|
||||||
|
enum mjson_tok mjson_find(const char *s, int len, const char *jp,
|
||||||
|
const char **tokptr, int *toklen);
|
||||||
|
int mjson_get_number(const char *s, int len, const char *path, double *v);
|
||||||
|
int mjson_get_bool(const char *s, int len, const char *path, int *v);
|
||||||
|
int mjson_get_string(const char *s, int len, const char *path, char *to, int n);
|
||||||
|
int mjson_get_hex(const char *s, int len, const char *path, char *to, int n);
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_NEXT
|
||||||
|
int mjson_next(const char *s, int n, int off, int *koff, int *klen, int *voff,
|
||||||
|
int *vlen, int *vtype);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_BASE64
|
||||||
|
int mjson_get_base64(const char *s, int len, const char *path, char *to, int n);
|
||||||
|
int mjson_base64_dec(const char *src, int n, char *dst, int dlen);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_PRINT
|
||||||
|
typedef int (*mjson_print_fn_t)(const char *buf, int len, void *userdata);
|
||||||
|
typedef int (*mjson_vprint_fn_t)(mjson_print_fn_t, void *, va_list *);
|
||||||
|
|
||||||
|
struct mjson_fixedbuf {
|
||||||
|
char *ptr;
|
||||||
|
int size, len;
|
||||||
|
};
|
||||||
|
|
||||||
|
int mjson_printf(mjson_print_fn_t, void *, const char *fmt, ...);
|
||||||
|
int mjson_vprintf(mjson_print_fn_t, void *, const char *fmt, va_list ap);
|
||||||
|
int mjson_print_str(mjson_print_fn_t, void *, const char *s, int len);
|
||||||
|
int mjson_print_int(mjson_print_fn_t, void *, int value, int is_signed);
|
||||||
|
int mjson_print_long(mjson_print_fn_t, void *, long value, int is_signed);
|
||||||
|
int mjson_print_buf(mjson_print_fn_t fn, void *, const char *buf, int len);
|
||||||
|
|
||||||
|
int mjson_print_null(const char *ptr, int len, void *userdata);
|
||||||
|
int mjson_print_file(const char *ptr, int len, void *userdata);
|
||||||
|
int mjson_print_fixed_buf(const char *ptr, int len, void *userdata);
|
||||||
|
int mjson_print_dynamic_buf(const char *ptr, int len, void *userdata);
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_PRETTY
|
||||||
|
int mjson_pretty(const char *, int, const char *, mjson_print_fn_t, void *);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_MERGE
|
||||||
|
int mjson_merge(const char *, int, const char *, int, mjson_print_fn_t, void *);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // MJSON_ENABLE_PRINT
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_RPC
|
||||||
|
|
||||||
|
void jsonrpc_init(mjson_print_fn_t, void *userdata);
|
||||||
|
int mjson_globmatch(const char *s1, int n1, const char *s2, int n2);
|
||||||
|
|
||||||
|
struct jsonrpc_request {
|
||||||
|
const char *frame; // Points to the whole frame
|
||||||
|
int frame_len; // Frame length
|
||||||
|
const char *params; // Points to the "params" in the request frame
|
||||||
|
int params_len; // Length of the "params"
|
||||||
|
const char *id; // Points to the "id" in the request frame
|
||||||
|
int id_len; // Length of the "id"
|
||||||
|
const char *method; // Points to the "method" in the request frame
|
||||||
|
int method_len; // Length of the "method"
|
||||||
|
mjson_print_fn_t fn; // Printer function
|
||||||
|
void *fndata; // Printer function data
|
||||||
|
void *userdata; // Callback's user data as specified at export time
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jsonrpc_method {
|
||||||
|
const char *method;
|
||||||
|
int method_sz;
|
||||||
|
void (*cb)(struct jsonrpc_request *);
|
||||||
|
void *cbdata;
|
||||||
|
struct jsonrpc_method *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Main RPC context, stores current request information and a list of
|
||||||
|
// exported RPC methods.
|
||||||
|
struct jsonrpc_ctx {
|
||||||
|
struct jsonrpc_method *methods;
|
||||||
|
void *userdata;
|
||||||
|
mjson_print_fn_t response_cb;
|
||||||
|
int in_len;
|
||||||
|
char in[MJSON_RPC_IN_BUF_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Registers function fn under the given name within the given RPC context
|
||||||
|
#define jsonrpc_ctx_export(ctx, name, fn, ud) \
|
||||||
|
do { \
|
||||||
|
static struct jsonrpc_method m = {(name), sizeof(name) - 1, (fn), 0, 0}; \
|
||||||
|
m.cbdata = (ud); \
|
||||||
|
m.next = (ctx)->methods; \
|
||||||
|
(ctx)->methods = &m; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
void jsonrpc_ctx_init(struct jsonrpc_ctx *ctx, mjson_print_fn_t, void *);
|
||||||
|
void jsonrpc_return_error(struct jsonrpc_request *r, int code,
|
||||||
|
const char *message, const char *data_fmt, ...);
|
||||||
|
void jsonrpc_return_success(struct jsonrpc_request *r, const char *result_fmt,
|
||||||
|
...);
|
||||||
|
void jsonrpc_ctx_process(struct jsonrpc_ctx *ctx, const char *req, int req_sz,
|
||||||
|
mjson_print_fn_t fn, void *fndata);
|
||||||
|
void jsonrpc_ctx_process_byte(struct jsonrpc_ctx *ctx, unsigned char ch,
|
||||||
|
mjson_print_fn_t fn, void *fndata);
|
||||||
|
|
||||||
|
extern struct jsonrpc_ctx jsonrpc_default_context;
|
||||||
|
|
||||||
|
#define jsonrpc_export(name, fn, ud) \
|
||||||
|
jsonrpc_ctx_export(&jsonrpc_default_context, (name), (fn), (ud))
|
||||||
|
|
||||||
|
#define jsonrpc_process(buf, len, fn, data) \
|
||||||
|
jsonrpc_ctx_process(&jsonrpc_default_context, (buf), (len), (fn), (data))
|
||||||
|
|
||||||
|
#define jsonrpc_process_byte(x, fn, data) \
|
||||||
|
jsonrpc_ctx_process_byte(&jsonrpc_default_context, (x), (fn), (data))
|
||||||
|
|
||||||
|
#define JSONRPC_ERROR_INVALID -32700 /* Invalid JSON was received */
|
||||||
|
#define JSONRPC_ERROR_NOT_FOUND -32601 /* The method does not exist */
|
||||||
|
#define JSONRPC_ERROR_BAD_PARAMS -32602 /* Invalid params passed */
|
||||||
|
#define JSONRPC_ERROR_INTERNAL -32603 /* Internal JSON-RPC error */
|
||||||
|
|
||||||
|
#endif // MJSON_ENABLE_RPC
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif // MJSON_H
|
||||||
@@ -0,0 +1,312 @@
|
|||||||
|
const {h, render, Component} = preact;
|
||||||
|
const html = htm.bind(h);
|
||||||
|
|
||||||
|
class Login extends Component {
|
||||||
|
state = {user: '', pass: ''};
|
||||||
|
onclick = (app) => {
|
||||||
|
const authhdr = 'Basic ' + btoa(this.state.user + ':' + this.state.pass);
|
||||||
|
const headers = {Authorization: authhdr};
|
||||||
|
return axios.get('/api/login', {headers})
|
||||||
|
.then(res => app.setUser(res.data.token))
|
||||||
|
.catch(err => alert('Login failed'));
|
||||||
|
};
|
||||||
|
onpassinput = (ev) => this.setState({pass: ev.target.value});
|
||||||
|
onuserinput = (ev) => this.setState({user: ev.target.value});
|
||||||
|
render({app}, {user, pass, signup}) {
|
||||||
|
return html`
|
||||||
|
<div class='mx-auto bg-light rounded border my-5' style='max-width: 480px;'>
|
||||||
|
<div class='form p-5 rounded form-sm'>
|
||||||
|
<h4 class="text-muted mb-4">Login </h4>
|
||||||
|
<input type='email' placeholder='Email' class='my-2 form-control'
|
||||||
|
oninput=${this.onuserinput} value=${user} />
|
||||||
|
<input type="password" placeholder="Password" class="my-2 form-control"
|
||||||
|
oninput=${this.onpassinput} value=${pass}
|
||||||
|
onchange=${ev => this.onclick(app)} />
|
||||||
|
<div class="mb-4">
|
||||||
|
<button class="btn btn-info btn-block"
|
||||||
|
disabled=${!user || !pass} onclick="${ev => this.onclick(app)}"
|
||||||
|
> Login </button>
|
||||||
|
</div>
|
||||||
|
<div class="text-muted small">
|
||||||
|
Valid logins: admin:admin, user1:pass1, user2:pass2
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Dropdown extends Component {
|
||||||
|
state = {show: false};
|
||||||
|
render(props, state) {
|
||||||
|
const onclick = x => this.setState({show: x});
|
||||||
|
const show = state.show ? 'show' : '';
|
||||||
|
return html`
|
||||||
|
<div class="dropdown autoexpand ${props.cls}">
|
||||||
|
<div type="buttonx" onclick=${() => onclick(!state.show)}
|
||||||
|
class="dropdown-toggle my-0 ${props.bcls}"
|
||||||
|
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
${props.title}
|
||||||
|
</div>
|
||||||
|
<div onclick=${() => onclick(false)} style=${props.dstyle}
|
||||||
|
class="dropdown-menu ${props.dcls} ${show}">
|
||||||
|
${props.children}
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const NavLink = ({href, title, url}) => html`<a class="nav-item nav-link
|
||||||
|
${url == href ? 'active' : ''}"
|
||||||
|
target=${href.match(/^http/) ? '_blank' : ''}
|
||||||
|
href="${href.match(/^http/) ? '' : '#'}${href}">${title}</a>`;
|
||||||
|
|
||||||
|
class Header extends Component {
|
||||||
|
state = {expanded: false};
|
||||||
|
ontoggle = () => this.setState({expanded: !this.state.expanded});
|
||||||
|
render(props, state) {
|
||||||
|
const u = props.app.state.user || {};
|
||||||
|
return html`
|
||||||
|
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
|
||||||
|
<a class="navbar-brand" href="#">
|
||||||
|
<img src="images/logo.png" width="26" height="26" alt="" class="mr-2" />
|
||||||
|
MyProduct
|
||||||
|
</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"
|
||||||
|
onclick=${() => this.ontoggle()} >
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="navbar-collapse ${state.expanded ? '' : 'collapse'}"
|
||||||
|
id="navbarNav">
|
||||||
|
<div class="nav navbar-nav mr-auto">
|
||||||
|
<${NavLink} href="/" title="Dashboard" url=${props.url} />
|
||||||
|
<${NavLink} href="/logs" title="Logs" url=${props.url} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form class="form-inline">
|
||||||
|
<${Dropdown} title="${u.user}" cls="mr-2"
|
||||||
|
bcls="btn btn-sm btn-outline-light pointer" dcls="m-0 dropdown-menu-right">
|
||||||
|
<div onclick=${() => props.app.setUser('')}
|
||||||
|
class="dropdown-item small pointer text-center">logout</div>
|
||||||
|
</${Dropdown}>
|
||||||
|
<img src="images/user.png" class="rounded-circle nav-item mr-2" width="30" />
|
||||||
|
</form>
|
||||||
|
</nav>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Info = () => html`<div class="alert alert-secondary my-3">
|
||||||
|
This dashboard shows values kept in server memory. Many clients
|
||||||
|
can open this page. As soon as any client changes any value,
|
||||||
|
all clients update automatically.
|
||||||
|
The JS code that watches state changes, reconnects on network failures.
|
||||||
|
That means if server restarts, dashboard on all connected clients
|
||||||
|
refresh automatically.
|
||||||
|
You can use <code>curl</code> command-line utility:
|
||||||
|
<br/><code>curl localhost:8000/api/config/get</code>
|
||||||
|
<br/><code>curl localhost:8000/api/config/watch</code>
|
||||||
|
<br/><code>curl localhost:8000/api/config/set -d '{"a":123}'</code>
|
||||||
|
<br/><span class="badge badge-danger">NOTE:</span> administrators
|
||||||
|
can change settings values, whilst users cannot.
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
class DashVideo extends Component {
|
||||||
|
render(props, state) {
|
||||||
|
const onclick = ev => axios.post(
|
||||||
|
'/api/config/set', {value1: +state.value1, value2: state.value2});
|
||||||
|
// alert(JSON.stringify(state));
|
||||||
|
return html`<div id="form">
|
||||||
|
<div><b>Change values</b></div>
|
||||||
|
<table>
|
||||||
|
<tr><td>Value 1 (number):</td><td><input value=${state.value1}
|
||||||
|
onInput=${linkState(this, 'value1')} /></td></tr>
|
||||||
|
<tr><td>Value 2 (string):</td><td><input value=${state.value2}
|
||||||
|
onInput=${linkState(this, 'value2')}/></td></tr>
|
||||||
|
<tr><td></td>
|
||||||
|
<td><button onClick=${onclick}>Save values</button></td></tr>
|
||||||
|
</table>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class DashForm extends Component {
|
||||||
|
render(props, state) {
|
||||||
|
const onclick = ev => axios.post(
|
||||||
|
'/api/config/set', {value1: +state.value1, value2: state.value2});
|
||||||
|
// alert(JSON.stringify(state));
|
||||||
|
return html`<div id="form">
|
||||||
|
<div><b>Change values</b></div>
|
||||||
|
<table>
|
||||||
|
<tr><td>Value 1 (number):</td><td><input class="form-control form-control-sm"
|
||||||
|
value=${state.value1}
|
||||||
|
onInput=${linkState(this, 'value1')} /></td></tr>
|
||||||
|
<tr><td>Value 2 (string):</td><td><input class="form-control form-control-sm"
|
||||||
|
value=${state.value2}
|
||||||
|
onInput=${linkState(this, 'value2')}/></td></tr>
|
||||||
|
<tr><td></td>
|
||||||
|
<td><button class="btn btn-primary btn-block"
|
||||||
|
onClick=${onclick}>Save values</button></td></tr>
|
||||||
|
</table>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class DashSettings extends Component {
|
||||||
|
state = {value1: null, value2: null};
|
||||||
|
componentDidMount() {
|
||||||
|
axios.get('/api/config/get')
|
||||||
|
.then(r => this.setState(r.data))
|
||||||
|
.catch(e => console.log(e));
|
||||||
|
var self = this;
|
||||||
|
var f = function(reader) {
|
||||||
|
return reader.read().then(function(result) {
|
||||||
|
var data = String.fromCharCode.apply(null, result.value);
|
||||||
|
self.setState(JSON.parse(data));
|
||||||
|
// console.log(JSON.parse(data));
|
||||||
|
if (!result.done) return f(reader);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
fetch('/api/config/watch')
|
||||||
|
.then(r => r.body.getReader())
|
||||||
|
.then(f)
|
||||||
|
.catch(e => setTimeout(x => self.componentDidMount(), 1000));
|
||||||
|
}
|
||||||
|
render(props, state) {
|
||||||
|
return html
|
||||||
|
`<div id="dashboard" style="display: flex; justify-content: flex-evenly;">
|
||||||
|
<div style="width:50%;text-align:center;">Value 1 (number):
|
||||||
|
<div style="font-size:140%;"><b>${state.value1}</b></div></div>
|
||||||
|
<div style="width:50%;text-align:center;">Value 2 (string):
|
||||||
|
<div style="font-size:140%;"><b>${state.value2}</b></div></div>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AdminDashboard extends Component {
|
||||||
|
render(props, state) {
|
||||||
|
return html`<div class="container-fluid">
|
||||||
|
<${Info} />
|
||||||
|
<div class="card-deck">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">Settings</div>
|
||||||
|
<div class="card-body"><${DashSettings} /></div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">Video stream</div>
|
||||||
|
<div class="card-body"><img src="/api/video1" class="mw-100" /></div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">Change settings</div>
|
||||||
|
<div class="card-body"><${DashForm} /></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UserDashboard extends Component {
|
||||||
|
render(props, state) {
|
||||||
|
return html`<div class="container-fluid">
|
||||||
|
<${Info} />
|
||||||
|
<div class="card-deck">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">Settings</div>
|
||||||
|
<div class="card-body"><${DashSettings} /></div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">Video stream</div>
|
||||||
|
<div class="card-body"><img src="/api/video1" class="mw-100" /></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Logs extends Component {
|
||||||
|
state = {live: '', static: ''};
|
||||||
|
componentDidMount() {
|
||||||
|
var self = this;
|
||||||
|
var f = function(r) {
|
||||||
|
return r.read().then(function(result) {
|
||||||
|
var data = String.fromCharCode.apply(null, result.value);
|
||||||
|
var live = self.state.live + data;
|
||||||
|
self.setState({live}); // Append live log
|
||||||
|
if (!result.done) f(r); // Read next chunk
|
||||||
|
});
|
||||||
|
};
|
||||||
|
fetch('/api/log/static')
|
||||||
|
.then(r => r.text())
|
||||||
|
.then(r => {
|
||||||
|
self.setState({static: r});
|
||||||
|
})
|
||||||
|
.then(r => fetch('/api/log/live'))
|
||||||
|
.then(r => r.body.getReader())
|
||||||
|
.then(f);
|
||||||
|
}
|
||||||
|
render(props, state) {
|
||||||
|
return html`<div class="container-fluid">
|
||||||
|
<div class="alert alert-secondary my-3">
|
||||||
|
A div below shows file log.txt, which is produced by the server.
|
||||||
|
The server appends a new log message to that file every second,
|
||||||
|
and a div below also shows that, implementing a "live log" feature.
|
||||||
|
JS code on this page first fetches /api/log/static that returns
|
||||||
|
log.txt contents, then fetches /api/log/live that does not return,
|
||||||
|
but feeds chunks of data as they arrive (live log).
|
||||||
|
<br/><br/>
|
||||||
|
You can also use <code>curl</code> command-line utility to see
|
||||||
|
live logs:
|
||||||
|
<br/><code>curl localhost:8000/api/log/live</code>
|
||||||
|
</div>
|
||||||
|
<div class="card-deck">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">Static</div>
|
||||||
|
<div class="card-body"><pre class="log">${state.static}</pre></div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">Live</div>
|
||||||
|
<div class="card-body"><pre class="log">${state.live}</pre></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class App extends Component {
|
||||||
|
state = {user: null, url: '/'};
|
||||||
|
setUser(token) {
|
||||||
|
const maxAge = token ? 86400 : 0;
|
||||||
|
document.cookie = `access_token=${token};path=/;max-age=${maxAge}`;
|
||||||
|
// this.setState({token});
|
||||||
|
return axios.get('/api/login')
|
||||||
|
.then(res => this.setState({user: res.data}))
|
||||||
|
.catch(err => this.setState({user: {}}));
|
||||||
|
}
|
||||||
|
componentDidMount() {
|
||||||
|
const getCookie = name => {
|
||||||
|
var v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');
|
||||||
|
return v ? v[2] : '';
|
||||||
|
};
|
||||||
|
this.setUser(getCookie('access_token')); // Move from state1 to 2 or 3
|
||||||
|
}
|
||||||
|
render(props, state) {
|
||||||
|
// We have three states:
|
||||||
|
// 1. Beginning. We don't know if we have a valid auth token or not
|
||||||
|
// 2. We sent an /api/login request, and failed to login
|
||||||
|
// 3. We sent an /api/login request, and succeeded to login
|
||||||
|
|
||||||
|
if (!state.user) return ''; // State 1
|
||||||
|
if (!state.user.user) return h(Login, {app: this}); // State 2
|
||||||
|
return h( // State 3
|
||||||
|
'div', {}, h(Header, {url: state.url, app: this}),
|
||||||
|
h(preactRouter.Router, {
|
||||||
|
history: History.createHashHistory(),
|
||||||
|
onChange: ev => this.setState({url: ev.url}),
|
||||||
|
},
|
||||||
|
h(state.user.user == 'admin' ? AdminDashboard : UserDashboard,
|
||||||
|
{default: true, app: this}),
|
||||||
|
h(Logs, {path: 'logs', app: this})));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onload = () => render(h(App), document.body);
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
/* axios v0.19.0-beta.1 | (c) 2018 by Matt Zabriskie */
|
||||||
|
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function r(e){var t=new i(e),n=s(i.prototype.request,t);return o.extend(n,i.prototype,t),o.extend(n,t),n}var o=n(2),s=n(3),i=n(5),a=n(22),u=n(11),c=r(u);c.Axios=i,c.create=function(e){return r(a(c.defaults,e))},c.Cancel=n(23),c.CancelToken=n(24),c.isCancel=n(10),c.all=function(e){return Promise.all(e)},c.spread=n(25),e.exports=c,e.exports.default=c},function(e,t,n){"use strict";function r(e){return"[object Array]"===j.call(e)}function o(e){return"[object ArrayBuffer]"===j.call(e)}function s(e){return"undefined"!=typeof FormData&&e instanceof FormData}function i(e){var t;return t="undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function a(e){return"string"==typeof e}function u(e){return"number"==typeof e}function c(e){return"undefined"==typeof e}function f(e){return null!==e&&"object"==typeof e}function p(e){return"[object Date]"===j.call(e)}function d(e){return"[object File]"===j.call(e)}function l(e){return"[object Blob]"===j.call(e)}function h(e){return"[object Function]"===j.call(e)}function m(e){return f(e)&&h(e.pipe)}function y(e){return"undefined"!=typeof URLSearchParams&&e instanceof URLSearchParams}function g(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function x(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product&&"NativeScript"!==navigator.product&&"NS"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)}function v(e,t){if(null!==e&&"undefined"!=typeof e)if("object"!=typeof e&&(e=[e]),r(e))for(var n=0,o=e.length;n<o;n++)t.call(null,e[n],n,e);else for(var s in e)Object.prototype.hasOwnProperty.call(e,s)&&t.call(null,e[s],s,e)}function w(){function e(e,n){"object"==typeof t[n]&&"object"==typeof e?t[n]=w(t[n],e):t[n]=e}for(var t={},n=0,r=arguments.length;n<r;n++)v(arguments[n],e);return t}function b(){function e(e,n){"object"==typeof t[n]&&"object"==typeof e?t[n]=b(t[n],e):"object"==typeof e?t[n]=b({},e):t[n]=e}for(var t={},n=0,r=arguments.length;n<r;n++)v(arguments[n],e);return t}function E(e,t,n){return v(t,function(t,r){n&&"function"==typeof t?e[r]=S(t,n):e[r]=t}),e}var S=n(3),R=n(4),j=Object.prototype.toString;e.exports={isArray:r,isArrayBuffer:o,isBuffer:R,isFormData:s,isArrayBufferView:i,isString:a,isNumber:u,isObject:f,isUndefined:c,isDate:p,isFile:d,isBlob:l,isFunction:h,isStream:m,isURLSearchParams:y,isStandardBrowserEnv:x,forEach:v,merge:w,deepMerge:b,extend:E,trim:g}},function(e,t){"use strict";e.exports=function(e,t){return function(){for(var n=new Array(arguments.length),r=0;r<n.length;r++)n[r]=arguments[r];return e.apply(t,n)}}},function(e,t){/*!
|
||||||
|
* Determine if an object is a Buffer
|
||||||
|
*
|
||||||
|
* @author Feross Aboukhadijeh <https://feross.org>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
e.exports=function(e){return null!=e&&null!=e.constructor&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}},function(e,t,n){"use strict";function r(e){this.defaults=e,this.interceptors={request:new i,response:new i}}var o=n(2),s=n(6),i=n(7),a=n(8),u=n(22);r.prototype.request=function(e){"string"==typeof e?(e=arguments[1]||{},e.url=arguments[0]):e=e||{},e=u(this.defaults,e),e.method=e.method?e.method.toLowerCase():"get";var t=[a,void 0],n=Promise.resolve(e);for(this.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),this.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)n=n.then(t.shift(),t.shift());return n},r.prototype.getUri=function(e){return e=u(this.defaults,e),s(e.url,e.params,e.paramsSerializer).replace(/^\?/,"")},o.forEach(["delete","get","head","options"],function(e){r.prototype[e]=function(t,n){return this.request(o.merge(n||{},{method:e,url:t}))}}),o.forEach(["post","put","patch"],function(e){r.prototype[e]=function(t,n,r){return this.request(o.merge(r||{},{method:e,url:t,data:n}))}}),e.exports=r},function(e,t,n){"use strict";function r(e){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var o=n(2);e.exports=function(e,t,n){if(!t)return e;var s;if(n)s=n(t);else if(o.isURLSearchParams(t))s=t.toString();else{var i=[];o.forEach(t,function(e,t){null!==e&&"undefined"!=typeof e&&(o.isArray(e)?t+="[]":e=[e],o.forEach(e,function(e){o.isDate(e)?e=e.toISOString():o.isObject(e)&&(e=JSON.stringify(e)),i.push(r(t)+"="+r(e))}))}),s=i.join("&")}return s&&(e+=(e.indexOf("?")===-1?"?":"&")+s),e}},function(e,t,n){"use strict";function r(){this.handlers=[]}var o=n(2);r.prototype.use=function(e,t){return this.handlers.push({fulfilled:e,rejected:t}),this.handlers.length-1},r.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)},r.prototype.forEach=function(e){o.forEach(this.handlers,function(t){null!==t&&e(t)})},e.exports=r},function(e,t,n){"use strict";function r(e){e.cancelToken&&e.cancelToken.throwIfRequested()}var o=n(2),s=n(9),i=n(10),a=n(11),u=n(20),c=n(21);e.exports=function(e){r(e),e.baseURL&&!u(e.url)&&(e.url=c(e.baseURL,e.url)),e.headers=e.headers||{},e.data=s(e.data,e.headers,e.transformRequest),e.headers=o.merge(e.headers.common||{},e.headers[e.method]||{},e.headers||{}),o.forEach(["delete","get","head","post","put","patch","common"],function(t){delete e.headers[t]});var t=e.adapter||a.adapter;return t(e).then(function(t){return r(e),t.data=s(t.data,t.headers,e.transformResponse),t},function(t){return i(t)||(r(e),t&&t.response&&(t.response.data=s(t.response.data,t.response.headers,e.transformResponse))),Promise.reject(t)})}},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t,n){return r.forEach(n,function(n){e=n(e,t)}),e}},function(e,t){"use strict";e.exports=function(e){return!(!e||!e.__CANCEL__)}},function(e,t,n){"use strict";function r(e,t){!s.isUndefined(e)&&s.isUndefined(e["Content-Type"])&&(e["Content-Type"]=t)}function o(){var e;return"undefined"!=typeof process&&"[object process]"===Object.prototype.toString.call(process)?e=n(13):"undefined"!=typeof XMLHttpRequest&&(e=n(13)),e}var s=n(2),i=n(12),a={"Content-Type":"application/x-www-form-urlencoded"},u={adapter:o(),transformRequest:[function(e,t){return i(t,"Accept"),i(t,"Content-Type"),s.isFormData(e)||s.isArrayBuffer(e)||s.isBuffer(e)||s.isStream(e)||s.isFile(e)||s.isBlob(e)?e:s.isArrayBufferView(e)?e.buffer:s.isURLSearchParams(e)?(r(t,"application/x-www-form-urlencoded;charset=utf-8"),e.toString()):s.isObject(e)?(r(t,"application/json;charset=utf-8"),JSON.stringify(e)):e}],transformResponse:[function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(e){}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,validateStatus:function(e){return e>=200&&e<300}};u.headers={common:{Accept:"application/json, text/plain, */*"}},s.forEach(["delete","get","head"],function(e){u.headers[e]={}}),s.forEach(["post","put","patch"],function(e){u.headers[e]=s.merge(a)}),e.exports=u},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t){r.forEach(e,function(n,r){r!==t&&r.toUpperCase()===t.toUpperCase()&&(e[t]=n,delete e[r])})}},function(e,t,n){"use strict";var r=n(2),o=n(14),s=n(6),i=n(17),a=n(18),u=n(15);e.exports=function(e){return new Promise(function(t,c){var f=e.data,p=e.headers;r.isFormData(f)&&delete p["Content-Type"];var d=new XMLHttpRequest;if(e.auth){var l=e.auth.username||"",h=e.auth.password||"";p.Authorization="Basic "+btoa(l+":"+h)}if(d.open(e.method.toUpperCase(),s(e.url,e.params,e.paramsSerializer),!0),d.timeout=e.timeout,d.onreadystatechange=function(){if(d&&4===d.readyState&&(0!==d.status||d.responseURL&&0===d.responseURL.indexOf("file:"))){var n="getAllResponseHeaders"in d?i(d.getAllResponseHeaders()):null,r=e.responseType&&"text"!==e.responseType?d.response:Line truncated
|
||||||
|
//# sourceMappingURL=axios.min.map
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
/*!
|
||||||
|
* Bootstrap v4.3.1 (https://getbootstrap.com/)
|
||||||
|
* Copyright 2011-2019 The Bootstrap Authors
|
||||||
|
* Copyright 2011-2019 Twitter, Inc.
|
||||||
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
|
*/:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,Line truncated
|
||||||
|
/*# sourceMappingURL=bootstrap.min.css.map */
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.History=n():t.History=n()}(this,function(){return function(t){function n(o){if(e[o])return e[o].exports;var r=e[o]={exports:{},id:o,loaded:!1};return t[o].call(r.exports,r,r.exports,n),r.loaded=!0,r.exports}var e={};return n.m=t,n.c=e,n.p="",n(0)}([function(t,n,e){"use strict";function o(t){return t&&t.__esModule?t:{default:t}}n.__esModule=!0,n.createPath=n.parsePath=n.locationsAreEqual=n.createLocation=n.createMemoryHistory=n.createHashHistory=n.createBrowserHistory=void 0;var r=e(2);Object.defineProperty(n,"createLocation",{enumerable:!0,get:function(){return r.createLocation}}),Object.defineProperty(n,"locationsAreEqual",{enumerable:!0,get:function(){return r.locationsAreEqual}});var i=e(1);Object.defineProperty(n,"parsePath",{enumerable:!0,get:function(){return i.parsePath}}),Object.defineProperty(n,"createPath",{enumerable:!0,get:function(){return i.createPath}});var a=e(7),c=o(a),u=e(8),s=o(u),f=e(9),l=o(f);n.createBrowserHistory=c.default,n.createHashHistory=s.default,n.createMemoryHistory=l.default},function(t,n){"use strict";n.__esModule=!0;n.addLeadingSlash=function(t){return"/"===t.charAt(0)?t:"/"+t},n.stripLeadingSlash=function(t){return"/"===t.charAt(0)?t.substr(1):t},n.stripPrefix=function(t,n){return 0===t.indexOf(n)?t.substr(n.length):t},n.stripTrailingSlash=function(t){return"/"===t.charAt(t.length-1)?t.slice(0,-1):t},n.parsePath=function(t){var n=t||"/",e="",o="",r=n.indexOf("#");r!==-1&&(o=n.substr(r),n=n.substr(0,r));var i=n.indexOf("?");return i!==-1&&(e=n.substr(i),n=n.substr(0,i)),n=decodeURI(n),{pathname:n,search:"?"===e?"":e,hash:"#"===o?"":o}},n.createPath=function(t){var n=t.pathname,e=t.search,o=t.hash,r=encodeURI(n||"/");return e&&"?"!==e&&(r+="?"===e.charAt(0)?e:"?"+e),o&&"#"!==o&&(r+="#"===o.charAt(0)?o:"#"+o),r}},function(t,n,e){"use strict";function o(t){return t&&t.__esModule?t:{default:t}}n.__esModule=!0,n.locationsAreEqual=n.createLocation=void 0;var r=Object.assign||function(t){for(var n=1;n<arguments.length;n++){var e=arguments[n];for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=e[o])}return t},i=e(10),a=o(i),c=e(11),u=o(c),s=e(1);n.createLocation=function(t,n,e,o){var i=void 0;return"string"==typeof t?(i=(0,s.parsePath)(t),i.state=n):(i=r({},t),void 0===i.pathname&&(i.pathname=""),i.search?"?"!==i.search.charAt(0)&&(i.search="?"+i.search):i.search="",i.hash?"#"!==i.hash.charAt(0)&&(i.hash="#"+i.hash):i.hash="",void 0!==n&&void 0===i.state&&(i.state=n)),i.key=e,o&&(i.pathname?"/"!==i.pathname.charAt(0)&&(i.pathname=(0,a.default)(i.pathname,o.pathname)):i.pathname=o.pathname),i},n.locationsAreEqual=function(t,n){return t.pathname===n.pathname&&t.search===n.search&&t.hash===n.hash&&t.key===n.key&&(0,u.default)(t.state,n.state)}},function(t,n,e){"use strict";var o=function(){};t.exports=o},function(t,n,e){"use strict";function o(t){return t&&t.__esModule?t:{default:t}}n.__esModule=!0;var r=e(3),i=(o(r),function(){var t=null,n=function(n){return t=n,function(){t===n&&(t=null)}},e=function(n,e,o,r){if(null!=t){var i="function"==typeof t?t(n,e):t;"string"==typeof i?"function"==typeof o?o(i,r):r(!0):r(i!==!1)}else r(!0)},o=[],r=function(t){var n=!0,e=function(){n&&t.apply(void 0,arguments)};return o.push(e),function(){n=!1,o=o.filter(function(t){return t!==e})}},i=function(){for(var t=arguments.length,n=Array(t),e=0;e<t;e++)n[e]=arguments[e];o.forEach(function(t){return t.apply(void 0,n)})};return{setPrompt:n,confirmTransitionTo:e,appendListener:r,notifyListeners:i}});n.default=i},function(t,n){"use strict";n.__esModule=!0;n.canUseDOM=!("undefined"==typeof window||!window.document||!window.document.createElement),n.addEventListener=function(t,n,e){return t.addEventListener?t.addEventListener(n,e,!1):t.attachEvent("on"+n,e)},n.removeEventListener=function(t,n,e){return t.removeEventListener?t.removeEventListener(n,e,!1):t.detachEvent("on"+n,e)},n.getConfirmation=function(t,n){return n(window.confirm(t))},n.supportsHistory=function(){var t=window.navigator.userAgent;return(t.indexOf("Android 2.")===-1&&t.indexOf("Android 4.0")===-1||t.indexOf("Mobile Safari")===-1||t.indexOf("Chrome")!==-1||t.indexOf("Windows Phone")!==-1)&&(window.history&&"pushState"in window.history)},n.supportsPopStateOnHashChange=function(){return window.navigator.userAgent.indexOf("Trident")===-1},n.supportsGoWithoutReloadUsingHash=function(){return window.navigator.userAgent.indexOf("Firefox")===-1},n.isExtraneousPopstateEvent=function(t){return void 0===t.state&&navigator.userAgent.indexOf("CriOS")===-1}},function(t,n,e){"use strict";var o=function(t,n,e,o,r,i,a,c){if(!t){var u;if(void 0===n)u=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var s=[e,o,r,i,a,c],f=0;u=new Error(n.replace(/%s/g,function(){return s[f++]})),u.name="InLine truncated
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
!function(){function n(n){var t=e.get(this);return t||(t=new Map,e.set(this,t)),1<(t=a(this,t.get(n)||(t.set(n,t=function(n){function t(n){1===u&&(n||(r=r.replace(/^\s*\n\s*|\s*\n\s*$/g,"")))?p.push(0,n,r):3===u&&(n||r)?(p.push(3,n,r),u=2):2===u&&"..."===r&&n?p.push(4,n,0):2===u&&r&&!n?p.push(5,0,!0,r):5<=u&&((r||!n&&5===u)&&(p.push(u,0,r,s),u=6),n&&(p.push(u,n,0,s),u=6)),r=""}for(var e,s,u=1,r="",h="",p=[0],a=0;a<n.length;a++){a&&(1===u&&t(),t(a));for(var o=0;o<n[a].length;o++)e=n[a][o],1===u?"<"===e?(t(),p=[p],u=3):r+=e:4===u?r="--"===r&&">"===e?(u=1,""):e+r[0]:h?e===h?h="":r+=e:'"'===e||"'"===e?h=e:">"===e?(t(),u=1):u&&("="===e?(u=5,s=r,r=""):"/"===e&&(u<5||">"===n[a][o+1])?(t(),3===u&&(p=p[0]),(p=(u=p)[0]).push(2,0,u),u=0):" "===e||"\t"===e||"\n"===e||"\r"===e?(t(),u=2):r+=e),3===u&&"!--"===r&&(u=4,p=p[0])}return t(),p}(n)),t),arguments,[])).length?t:t[0]}var a=function(n,t,e,s){var u;t[0]=0;for(var r=1;r<t.length;r++){var h=t[r++],p=t[r]?(t[0]|=h?1:2,e[t[r++]]):t[++r];3===h?s[0]=p:4===h?s[1]=Object.assign(s[1]||{},p):5===h?(s[1]=s[1]||{})[t[++r]]=p:6===h?s[1][t[++r]]+=p+"":h?(u=n.apply(p,a(n,p,e,["",null])),s.push(u),p[0]?t[0]|=2:(t[r-2]=0,t[r]=u)):s.push(p)}return s},e=new Map;"undefined"!=typeof module?module.exports=n:self.htm=n}();
|
||||||
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
@@ -0,0 +1,19 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>example</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="stylesheet" href="bootstrap.min.css" />
|
||||||
|
<link rel="stylesheet" href="style.css" />
|
||||||
|
<script src="preact.min.js"></script>
|
||||||
|
<script src="preact-router.min.js"></script>
|
||||||
|
<script src="htm.min.js"></script>
|
||||||
|
<script src="history.min.js"></script>
|
||||||
|
<script src="linkstate.min.js"></script>
|
||||||
|
<script src="axios.min.js"></script>
|
||||||
|
<script src="app.js"></script>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
function linkState(component, key, eventPath) {
|
||||||
|
let path = key.split('.'), cache = component.__lsc || (component.__lsc = {});
|
||||||
|
|
||||||
|
return cache[key + eventPath] || (cache[key + eventPath] = function(e) {
|
||||||
|
let t = e && e.target || this, state = {}, obj = state,
|
||||||
|
v = typeof eventPath === 'string' ?
|
||||||
|
delve(e, eventPath) :
|
||||||
|
t.nodeName ? (t.type.match(/^che|rad/) ? t.checked : t.value) :
|
||||||
|
e,
|
||||||
|
i = 0;
|
||||||
|
for (; i < path.length - 1; i++) {
|
||||||
|
obj = obj[path[i]] ||
|
||||||
|
(obj[path[i]] = !i && component.state[path[i]] || {});
|
||||||
|
}
|
||||||
|
obj[path[i]] = v;
|
||||||
|
component.setState(state);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("preact")):"function"==typeof define&&define.amd?define(["preact"],e):t.preactRouter=e(t.preact)}(this,function(p){function i(t,e){for(var n in e)t[n]=e[n];return t}function u(t,e,n){var r,o=/(?:\?([^#]*))?(#.*)?$/,i=t.match(o),u={};if(i&&i[1])for(var a=i[1].split("&"),p=0;p<a.length;p++){var c=a[p].split("=");u[decodeURIComponent(c[0])]=decodeURIComponent(c.slice(1).join("="))}t=y(t.replace(o,"")),e=y(e||"");for(var f=Math.max(t.length,e.length),l=0;l<f;l++)if(e[l]&&":"===e[l].charAt(0)){var s=e[l].replace(/(^:|[+*?]+$)/g,""),h=(e[l].match(/[+*?]+$/)||v)[0]||"",d=~h.indexOf("+"),g=~h.indexOf("*"),m=t[l]||"";if(!m&&!g&&(h.indexOf("?")<0||d)){r=!1;break}if(u[s]=decodeURIComponent(m),d||g){u[s]=t.slice(l).map(decodeURIComponent).join("/");break}}else if(e[l]!==t[l]){r=!1;break}return(!0===n.default||!1!==r)&&u}function e(t,e){return t.rank<e.rank?1:t.rank>e.rank?-1:t.index-e.index}function n(t,e){return t.index=e,t.rank=(n=t).props.default?0:function(t){return y(t).map(r).join("")}(n.props.path),t.props;var n}function y(t){return t.replace(/(^\/+|\/+$)/g,"").split("/")}function r(t){return":"==t.charAt(0)?1+"*+?".indexOf(t.charAt(t.length-1))||4:5}function o(){var t;return""+((t=g&&g.location?g.location:g&&g.getCurrentLocation?g.getCurrentLocation():"undefined"!=typeof location?location:b).pathname||"")+(t.search||"")}function a(t,e){return void 0===e&&(e=!1),"string"!=typeof t&&t.url&&(e=t.replace,t=t.url),function(t){for(var e=m.length;e--;)if(m[e].canRoute(t))return 1;return}(t)&&(n=t,void 0===(r=e?"replace":"push")&&(r="push"),g&&g[r]?g[r](n):"undefined"!=typeof history&&history[r+"State"]&&history[r+"State"](null,null,n)),c(t);var n,r}function c(t){for(var e=!1,n=0;n<m.length;n++)!0===m[n].routeTo(t)&&(e=!0);for(var r=C.length;r--;)C[r](t);return e}function f(t){if(t&&t.getAttribute){var e=t.getAttribute("href"),n=t.getAttribute("target");if(e&&e.match(/^\//g)&&(!n||n.match(/^_?self$/i)))return a(e)}}function l(t){if(!(t.ctrlKey||t.metaKey||t.altKey||t.shiftKey||0!==t.button))return f(t.currentTarget||t.target||this),s(t)}function s(t){return t&&(t.stopImmediatePropagation&&t.stopImmediatePropagation(),t.stopPropagation&&t.stopPropagation(),t.preventDefault()),!1}function h(t){if(!(t.ctrlKey||t.metaKey||t.altKey||t.shiftKey||0!==t.button)){var e=t.target;do{if("A"===(e.nodeName+"").toUpperCase()&&e.getAttribute("href")){if(e.hasAttribute("native"))return;if(f(e))return s(t)}}while(e=e.parentNode)}}var d,v={},g=null,m=[],C=[],b={},U=!1,t=((d=p.Component)&&(k.__proto__=d),((k.prototype=Object.create(d&&d.prototype)).constructor=k).prototype.shouldComponentUpdate=function(t){return!0!==t.static||t.url!==this.props.url||t.onChange!==this.props.onChange},k.prototype.canRoute=function(t){return 0<this.getMatchingChildren(p.toChildArray(this.props.children),t,!1).length},k.prototype.routeTo=function(t){this.setState({url:t});var e=this.canRoute(t);return this.updating||this.forceUpdate(),e},k.prototype.componentWillMount=function(){m.push(this),this.updating=!0},k.prototype.componentDidMount=function(){var e=this;g&&(this.unlisten=g.listen(function(t){e.routeTo(""+(t.pathname||"")+(t.search||""))})),this.updating=!1},k.prototype.componentWillUnmount=function(){"function"==typeof this.unlisten&&this.unlisten(),m.splice(m.indexOf(this),1)},k.prototype.componentWillUpdate=function(){this.updating=!0},k.prototype.componentDidUpdate=function(){this.updating=!1},k.prototype.getMatchingChildren=function(t,r,o){return t.filter(n).sort(e).map(function(t){var e=u(r,t.props.path,t.props);if(e){if(!1===o)return t;var n={url:r,matches:e};return i(n,e),delete n.ref,delete n.key,p.cloneElement(t,n)}}).filter(Boolean)},k.prototype.render=function(t,e){var n=t.children,r=t.onChange,o=e.url,i=this.getMatchingChildren(p.toChildArray(n),o,!0),u=i[0]||null,a=this.previousUrl;return o!==a&&(this.previousUrl=o,"function"==typeof r&&r({router:this,url:o,previous:a,active:i,current:u})),u},k);function k(t){d.call(this,t),t.history&&(g=t.history),this.state={url:t.url||o()},U||("function"==typeof addEventListener&&(g||addEventListener("popstate",function(){c(o())}),addEventListener("click",h)),U=!0)}return t.subscribers=C,t.getCurrentUrl=o,t.route=a,(t.Router=t).Route=function(t){return p.createElement(t.component,t)},t.Link=function(t){return p.createElement("a",i({onClick:l},t))},t.exec=u,t});
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
!function(){var n,l,u,t,i,o,r,e,f={},c=[],a=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;function s(n,l){for(var u in l)n[u]=l[u];return n}function v(n){var l=n.parentNode;l&&l.removeChild(n)}function h(n,l,u){var t,i=arguments,o={};for(t in l)"key"!==t&&"ref"!==t&&(o[t]=l[t]);if(arguments.length>3)for(u=[u],t=3;t<arguments.length;t++)u.push(i[t]);if(null!=u&&(o.children=u),"function"==typeof n&&null!=n.defaultProps)for(t in n.defaultProps)void 0===o[t]&&(o[t]=n.defaultProps[t]);return y(n,o,l&&l.key,l&&l.ref,null)}function y(l,u,t,i,o){var r={type:l,props:u,key:t,ref:i,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,constructor:void 0,__v:o};return null==o&&(r.__v=r),n.vnode&&n.vnode(r),r}function p(n){return n.children}function d(n,l){this.props=n,this.context=l}function _(n,l){if(null==l)return n.__?_(n.__,n.__.__k.indexOf(n)+1):null;for(var u;l<n.__k.length;l++)if(null!=(u=n.__k[l])&&null!=u.__e)return u.__e;return"function"==typeof n.type?_(n):null}function m(n){var l,u;if(null!=(n=n.__)&&null!=n.__c){for(n.__e=n.__c.base=null,l=0;l<n.__k.length;l++)if(null!=(u=n.__k[l])&&null!=u.__e){n.__e=n.__c.base=u.__e;break}return m(n)}}function k(l){(!l.__d&&(l.__d=!0)&&u.push(l)&&!w.__r++||i!==n.debounceRendering)&&((i=n.debounceRendering)||t)(w)}function w(){for(var n;w.__r=u.length;)n=u.sort(function(n,l){return n.__v.__b-l.__v.__b}),u=[],n.some(function(n){var l,u,t,i,o,r,e;n.__d&&(r=(o=(l=n).__v).__e,(e=l.__P)&&(u=[],(t=s({},o)).__v=t,i=N(e,o,t,l.__n,void 0!==e.ownerSVGElement,null,u,null==r?_(o):r),z(u,o),i!=r&&m(o)))})}function g(n,l,u,t,i,o,r,e,a,s){var h,d,m,k,w,g,x,C=t&&t.__k||c,A=C.length;for(a==f&&(a=null!=r?r[0]:A?_(t,0):null),u.__k=[],h=0;h<l.length;h++)if(null!=(k=u.__k[h]=null==(k=l[h])||"boolean"==typeof k?null:"string"==typeof k||"number"==typeof k?y(null,k,null,null,k):Array.isArray(k)?y(p,{children:k},null,null,null):null!=k.__e||null!=k.__c?y(k.type,k.props,k.key,null,k.__v):k)){if(k.__=u,k.__b=u.__b+1,null===(m=C[h])||m&&k.key==m.key&&k.type===m.type)C[h]=void 0;else for(d=0;d<A;d++){if((m=C[d])&&k.key==m.key&&k.type===m.type){C[d]=void 0;break}m=null}w=N(n,k,m=m||f,i,o,r,e,a,s),(d=k.ref)&&m.ref!=d&&(x||(x=[]),m.ref&&x.push(m.ref,null,k),x.push(d,k.__c||w,k)),null!=w?(null==g&&(g=w),a=b(n,k,m,C,r,w,a),"option"==u.type?n.value="":"function"==typeof u.type&&(u.__d=a)):a&&m.__e==a&&a.parentNode!=n&&(a=_(m))}if(u.__e=g,null!=r&&"function"!=typeof u.type)for(h=r.length;h--;)null!=r[h]&&v(r[h]);for(h=A;h--;)null!=C[h]&&j(C[h],C[h]);if(x)for(h=0;h<x.length;h++)$(x[h],x[++h],x[++h])}function b(n,l,u,t,i,o,r){var e,f,c;if(void 0!==l.__d)e=l.__d,l.__d=void 0;else if(i==u||o!=r||null==o.parentNode)n:if(null==r||r.parentNode!==n)n.appendChild(o),e=null;else{for(f=r,c=0;(f=f.nextSibling)&&c<t.length;c+=2)if(f==o)break n;n.insertBefore(o,r),e=r}return void 0!==e?e:o.nextSibling}function x(n,l,u,t,i){var o;for(o in u)"children"===o||"key"===o||o in l||A(n,o,null,u[o],t);for(o in l)i&&"function"!=typeof l[o]||"children"===o||"key"===o||"value"===o||"checked"===o||u[o]===l[o]||A(n,o,l[o],u[o],t)}function C(n,l,u){"-"===l[0]?n.setProperty(l,u):n[l]="number"==typeof u&&!1===a.test(l)?u+"px":null==u?"":u}function A(n,l,u,t,i){var o,r,e,f,c;if(i?"className"===l&&(l="class"):"class"===l&&(l="className"),"style"===l)if(o=n.style,"string"==typeof u)o.cssText=u;else{if("string"==typeof t&&(o.cssText="",t=null),t)for(f in t)u&&f in u||C(o,f,"");if(u)for(c in u)t&&u[c]===t[c]||C(o,c,u[c])}else"o"===l[0]&&"n"===l[1]?(r=l!==(l=l.replace(/Capture$/,"")),e=l.toLowerCase(),l=(e in n?e:l).slice(2),u?(t||n.addEventListener(l,P,r),(n.l||(n.l={}))[l]=u):n.removeEventListener(l,P,r)):"list"!==l&&"tagName"!==l&&"form"!==l&&"type"!==l&&"size"!==l&&!i&&l in n?n[l]=null==u?"":u:"function"!=typeof u&&"dangerouslySetInnerHTML"!==l&&(l!==(l=l.replace(/^xlink:?/,""))?null==u||!1===u?n.removeAttributeNS("http://www.w3.org/1999/xlink",l.toLowerCase()):n.setAttributeNS("http://www.w3.org/1999/xlink",l.toLowerCase(),u):null==u||!1===u&&!/^ar/.test(l)?n.removeAttribute(l):n.setAttribute(l,u))}function P(l){this.l[l.type](n.event?n.event(l):l)}function E(n,l,u){var t,i;for(t=0;t<n.__k.length;t++)(i=n.__k[t])&&(i.__=n,i.__e&&("function"==typeof i.type&&i.__k.length>1&&E(i,l,u),l=b(u,i,i,n.__k,null,i.__e,l),"function"==typeof n.type&&(n.__d=l)))}function N(l,u,t,i,o,r,e,f,c){var a,v,h,y,_,m,k,w,b,x,C,A=u.type;if(void 0!==u.constructor)return null;(a=n.__b)&&a(u);try{n:if("function"==typeof A){if(w=u.props,b=(a=A.contextType)&&i[a.__c],x=a?b?b.props.value:a.__:i,t.__c?k=(v=u.__c=t.__c).__=v.__E:("prototype"in A&&A.prototype.render?u.__c=v=new A(w,x):(u.__c=v=new d(w,x),v.constructor=A,v.render=F),b&&b.sub(v),v.props=w,v.state||(v.state={}),v.context=x,v.__n=i,h=v.__d=!0,v.__h=[]),null==v.__s&&(v.__s=v.state),null!=A.getDerivedStateFromProps&&(v.__s==v.state&&(v.__s=s({},v.__s)),s(v.__s,A.getDerivedStateFromProps(w,v.__s))),y=v.props,_=v.state,h)null==A.getDerivedStateFromProps&&null!=v.componentWillMount&&v.componenLine truncated
|
||||||
|
//# sourceMappingURL=preact.min.js.map
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
html, body { margin: 0; padding: 0; height: 100%; }
|
||||||
|
select, input, label::before, textarea { outline: none; box-shadow:none !important; border: 1px solid #ccc !important; }
|
||||||
|
.btn:focus,.btn:active:focus,.btn.active:focus,
|
||||||
|
.btn.focus,.btn:active.focus,.btn.active.focus { outline: none; box-shadow:none !important; }
|
||||||
|
.dropdown.autoexpand:hover>.dropdown-menu { display: block; }
|
||||||
|
.pointer { cursor: pointer; }
|
||||||
|
.log { max-height: 10em; overflow: auto; height: 100%; }
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
PROG ?= example
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(DEBUGGER) ./$(PROG)
|
||||||
|
|
||||||
|
$(PROG):
|
||||||
|
$(CC) ../../mongoose.c -I../.. $(CFLAGS) $(EXTRA) -o $(PROG) main.c mjson.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb log.txt
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
// Copyright (c) 2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
|
||||||
|
#include "mjson.h" // JSON parsing and printing
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
// This is a configuration structure we're going to show on a dashboard
|
||||||
|
static struct config {
|
||||||
|
int value1;
|
||||||
|
char *value2;
|
||||||
|
} s_config = {123, NULL};
|
||||||
|
|
||||||
|
// Stringifies the config. A caller must free() it.
|
||||||
|
static char *stringify_config(struct config *cfg) {
|
||||||
|
char *s = NULL;
|
||||||
|
mjson_printf(mjson_print_dynamic_buf, &s, "{%Q:%d,%Q:%Q}", "value1",
|
||||||
|
cfg->value1, "value2", cfg->value2);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update config structure. Return true if changed, false otherwise
|
||||||
|
static bool update_config(struct mg_http_message *hm, struct config *cfg) {
|
||||||
|
bool changed = false;
|
||||||
|
char buf[256];
|
||||||
|
double dv;
|
||||||
|
if (mjson_get_number(hm->body.ptr, hm->body.len, "$.value1", &dv)) {
|
||||||
|
s_config.value1 = dv;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (mjson_get_string(hm->body.ptr, hm->body.len, "$.value2", buf,
|
||||||
|
sizeof(buf)) > 0) {
|
||||||
|
free(s_config.value2);
|
||||||
|
s_config.value2 = strdup(buf);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify all config watchers about the config change
|
||||||
|
static void notify_config_change(struct mg_mgr *mgr) {
|
||||||
|
struct mg_connection *c;
|
||||||
|
char *s = stringify_config(&s_config);
|
||||||
|
for (c = mgr->conns; c != NULL; c = c->next) {
|
||||||
|
if (c->label[0] == 'W') mg_http_printf_chunk(c, "%s\n", s);
|
||||||
|
}
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTP request handler function. It implements the following endpoints:
|
||||||
|
// /api/config/get - returns current config
|
||||||
|
// /api/config/set - updates current config
|
||||||
|
// /api/config/watch - does not return. Sends config as it changes in
|
||||||
|
// chunks all other URI - serves web_root/ directory
|
||||||
|
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
if (mg_http_match_uri(hm, "/api/config/get")) {
|
||||||
|
char *s = stringify_config(&s_config);
|
||||||
|
mg_printf(c, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s\n",
|
||||||
|
(int) strlen(s) + 1, s);
|
||||||
|
free(s);
|
||||||
|
} else if (mg_http_match_uri(hm, "/api/config/set")) {
|
||||||
|
if (update_config(hm, &s_config)) notify_config_change(fn_data);
|
||||||
|
mg_printf(c, "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
|
||||||
|
} else if (mg_http_match_uri(hm, "/api/config/watch")) {
|
||||||
|
c->label[0] = 'W'; // Mark ourselves as a config watcher
|
||||||
|
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||||
|
} else {
|
||||||
|
mg_http_serve_dir(c, ev_data, "web_root");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_mgr mgr;
|
||||||
|
mg_mgr_init(&mgr);
|
||||||
|
mg_http_listen(&mgr, "http://localhost:8000", cb, &mgr);
|
||||||
|
for (;;) mg_mgr_poll(&mgr, 1000);
|
||||||
|
mg_mgr_free(&mgr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,981 @@
|
|||||||
|
// Copyright (c) 2018-2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
#include "mjson.h"
|
||||||
|
|
||||||
|
#if !defined(_MSC_VER) || _MSC_VER >= 1700
|
||||||
|
#else
|
||||||
|
#define va_copy(x, y) (x) = (y)
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#define alloca _alloca
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int mjson_esc(int c, int esc) {
|
||||||
|
const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\"";
|
||||||
|
for (p = esc ? esc1 : esc2; *p != '\0'; p++) {
|
||||||
|
if (*p == c) return esc ? esc2[p - esc1] : esc1[p - esc2];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mjson_pass_string(const char *s, int len) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (s[i] == '\\' && i + 1 < len && mjson_esc(s[i + 1], 1)) {
|
||||||
|
i++;
|
||||||
|
} else if (s[i] == '\0') {
|
||||||
|
return MJSON_ERROR_INVALID_INPUT;
|
||||||
|
} else if (s[i] == '"') {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MJSON_ERROR_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson(const char *s, int len, mjson_cb_t cb, void *ud) {
|
||||||
|
enum { S_VALUE, S_KEY, S_COLON, S_COMMA_OR_EOO } expecting = S_VALUE;
|
||||||
|
unsigned char nesting[MJSON_MAX_DEPTH];
|
||||||
|
int i, depth = 0;
|
||||||
|
#define MJSONCALL(ev) \
|
||||||
|
if (cb != NULL && cb(ev, s, start, i - start + 1, ud)) return i + 1;
|
||||||
|
|
||||||
|
// In the ascii table, the distance between `[` and `]` is 2.
|
||||||
|
// Ditto for `{` and `}`. Hence +2 in the code below.
|
||||||
|
#define MJSONEOO() \
|
||||||
|
do { \
|
||||||
|
if (c != nesting[depth - 1] + 2) return MJSON_ERROR_INVALID_INPUT; \
|
||||||
|
depth--; \
|
||||||
|
if (depth == 0) { \
|
||||||
|
MJSONCALL(tok); \
|
||||||
|
return i + 1; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
int start = i;
|
||||||
|
unsigned char c = ((unsigned char *) s)[i];
|
||||||
|
int tok = c;
|
||||||
|
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue;
|
||||||
|
// printf("- %c [%.*s] %d %d\n", c, i, s, depth, expecting);
|
||||||
|
switch (expecting) {
|
||||||
|
case S_VALUE:
|
||||||
|
if (c == '{') {
|
||||||
|
if (depth >= (int) sizeof(nesting)) return MJSON_ERROR_TOO_DEEP;
|
||||||
|
nesting[depth++] = c;
|
||||||
|
expecting = S_KEY;
|
||||||
|
break;
|
||||||
|
} else if (c == '[') {
|
||||||
|
if (depth >= (int) sizeof(nesting)) return MJSON_ERROR_TOO_DEEP;
|
||||||
|
nesting[depth++] = c;
|
||||||
|
break;
|
||||||
|
} else if (c == ']' && depth > 0) { // Empty array
|
||||||
|
MJSONEOO();
|
||||||
|
} else if (c == 't' && i + 3 < len && memcmp(&s[i], "true", 4) == 0) {
|
||||||
|
i += 3;
|
||||||
|
tok = MJSON_TOK_TRUE;
|
||||||
|
} else if (c == 'n' && i + 3 < len && memcmp(&s[i], "null", 4) == 0) {
|
||||||
|
i += 3;
|
||||||
|
tok = MJSON_TOK_NULL;
|
||||||
|
} else if (c == 'f' && i + 4 < len && memcmp(&s[i], "false", 5) == 0) {
|
||||||
|
i += 4;
|
||||||
|
tok = MJSON_TOK_FALSE;
|
||||||
|
} else if (c == '-' || ((c >= '0' && c <= '9'))) {
|
||||||
|
char *end = NULL;
|
||||||
|
strtod(&s[i], &end);
|
||||||
|
if (end != NULL) i += end - &s[i] - 1;
|
||||||
|
tok = MJSON_TOK_NUMBER;
|
||||||
|
} else if (c == '"') {
|
||||||
|
int n = mjson_pass_string(&s[i + 1], len - i - 1);
|
||||||
|
if (n < 0) return n;
|
||||||
|
i += n + 1;
|
||||||
|
tok = MJSON_TOK_STRING;
|
||||||
|
} else {
|
||||||
|
return MJSON_ERROR_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
if (depth == 0) {
|
||||||
|
MJSONCALL(tok);
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
expecting = S_COMMA_OR_EOO;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_KEY:
|
||||||
|
if (c == '"') {
|
||||||
|
int n = mjson_pass_string(&s[i + 1], len - i - 1);
|
||||||
|
if (n < 0) return n;
|
||||||
|
i += n + 1;
|
||||||
|
tok = MJSON_TOK_KEY;
|
||||||
|
expecting = S_COLON;
|
||||||
|
} else if (c == '}') { // Empty object
|
||||||
|
MJSONEOO();
|
||||||
|
expecting = S_COMMA_OR_EOO;
|
||||||
|
} else {
|
||||||
|
return MJSON_ERROR_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_COLON:
|
||||||
|
if (c == ':') {
|
||||||
|
expecting = S_VALUE;
|
||||||
|
} else {
|
||||||
|
return MJSON_ERROR_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_COMMA_OR_EOO:
|
||||||
|
if (depth <= 0) return MJSON_ERROR_INVALID_INPUT;
|
||||||
|
if (c == ',') {
|
||||||
|
expecting = (nesting[depth - 1] == '{') ? S_KEY : S_VALUE;
|
||||||
|
} else if (c == ']' || c == '}') {
|
||||||
|
MJSONEOO();
|
||||||
|
} else {
|
||||||
|
return MJSON_ERROR_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
MJSONCALL(tok);
|
||||||
|
}
|
||||||
|
return MJSON_ERROR_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct msjon_get_data {
|
||||||
|
const char *path; // Lookup json path
|
||||||
|
int pos; // Current path index
|
||||||
|
int d1; // Current depth of traversal
|
||||||
|
int d2; // Expected depth of traversal
|
||||||
|
int i1; // Index in an array
|
||||||
|
int i2; // Expected index in an array
|
||||||
|
int obj; // If the value is array/object, offset where it starts
|
||||||
|
const char **tokptr; // Destination
|
||||||
|
int *toklen; // Destination length
|
||||||
|
int tok; // Returned token
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mjson_plen(const char *s) {
|
||||||
|
int i = 0;
|
||||||
|
while (s[i] != '\0' && s[i] != '.' && s[i] != '[') i++;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mjson_get_cb(int tok, const char *s, int off, int len, void *ud) {
|
||||||
|
struct msjon_get_data *data = (struct msjon_get_data *) ud;
|
||||||
|
// printf("--> %2x %2d %2d %2d %2d\t'%s'\t'%.*s'\t\t'%.*s'\n", tok, data->d1,
|
||||||
|
// data->d2, data->i1, data->i2, data->path + data->pos, off, s, len,
|
||||||
|
// s + off);
|
||||||
|
if (data->tok != MJSON_TOK_INVALID) return 1; // Found
|
||||||
|
|
||||||
|
if (tok == '{') {
|
||||||
|
if (!data->path[data->pos] && data->d1 == data->d2) data->obj = off;
|
||||||
|
data->d1++;
|
||||||
|
} else if (tok == '[') {
|
||||||
|
if (data->d1 == data->d2 && data->path[data->pos] == '[') {
|
||||||
|
data->i1 = 0;
|
||||||
|
data->i2 = (int) strtod(&data->path[data->pos + 1], NULL);
|
||||||
|
if (data->i1 == data->i2) {
|
||||||
|
data->d2++;
|
||||||
|
data->pos += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!data->path[data->pos] && data->d1 == data->d2) data->obj = off;
|
||||||
|
data->d1++;
|
||||||
|
} else if (tok == ',') {
|
||||||
|
if (data->d1 == data->d2 + 1) {
|
||||||
|
data->i1++;
|
||||||
|
if (data->i1 == data->i2) {
|
||||||
|
while (data->path[data->pos] != ']') data->pos++;
|
||||||
|
data->pos++;
|
||||||
|
data->d2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (tok == MJSON_TOK_KEY && data->d1 == data->d2 + 1 &&
|
||||||
|
data->path[data->pos] == '.' && s[off] == '"' &&
|
||||||
|
s[off + len - 1] == '"' &&
|
||||||
|
mjson_plen(&data->path[data->pos + 1]) == len - 2 &&
|
||||||
|
!memcmp(s + off + 1, &data->path[data->pos + 1], len - 2)) {
|
||||||
|
data->d2++;
|
||||||
|
data->pos += len - 1;
|
||||||
|
} else if (tok == MJSON_TOK_KEY && data->d1 == data->d2) {
|
||||||
|
return 1; // Exhausted path, not found
|
||||||
|
} else if (tok == '}' || tok == ']') {
|
||||||
|
data->d1--;
|
||||||
|
// data->d2--;
|
||||||
|
if (!data->path[data->pos] && data->d1 == data->d2 && data->obj != -1) {
|
||||||
|
data->tok = tok - 2;
|
||||||
|
if (data->tokptr) *data->tokptr = s + data->obj;
|
||||||
|
if (data->toklen) *data->toklen = off - data->obj + 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if (MJSON_TOK_IS_VALUE(tok)) {
|
||||||
|
// printf("TOK --> %d\n", tok);
|
||||||
|
if (data->d1 == data->d2 && !data->path[data->pos]) {
|
||||||
|
data->tok = tok;
|
||||||
|
if (data->tokptr) *data->tokptr = s + off;
|
||||||
|
if (data->toklen) *data->toklen = len;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum mjson_tok mjson_find(const char *s, int len, const char *jp,
|
||||||
|
const char **tokptr, int *toklen) {
|
||||||
|
struct msjon_get_data data = {jp, 1, 0, 0, 0,
|
||||||
|
0, -1, tokptr, toklen, MJSON_TOK_INVALID};
|
||||||
|
if (jp[0] != '$') return MJSON_TOK_INVALID;
|
||||||
|
if (mjson(s, len, mjson_get_cb, &data) < 0) return MJSON_TOK_INVALID;
|
||||||
|
return (enum mjson_tok) data.tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_get_number(const char *s, int len, const char *path, double *v) {
|
||||||
|
const char *p;
|
||||||
|
int tok, n;
|
||||||
|
if ((tok = mjson_find(s, len, path, &p, &n)) == MJSON_TOK_NUMBER) {
|
||||||
|
if (v != NULL) *v = strtod(p, NULL);
|
||||||
|
}
|
||||||
|
return tok == MJSON_TOK_NUMBER ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_get_bool(const char *s, int len, const char *path, int *v) {
|
||||||
|
int tok = mjson_find(s, len, path, NULL, NULL);
|
||||||
|
if (tok == MJSON_TOK_TRUE && v != NULL) *v = 1;
|
||||||
|
if (tok == MJSON_TOK_FALSE && v != NULL) *v = 0;
|
||||||
|
return tok == MJSON_TOK_TRUE || tok == MJSON_TOK_FALSE ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mjson_unescape(const char *s, int len, char *to, int n) {
|
||||||
|
int i, j;
|
||||||
|
for (i = 0, j = 0; i < len && j < n; i++, j++) {
|
||||||
|
if (s[i] == '\\' && i + 1 < len) {
|
||||||
|
int c = mjson_esc(s[i + 1], 0);
|
||||||
|
if (c == 0) return -1;
|
||||||
|
to[j] = c;
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
to[j] = s[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j >= n) return -1;
|
||||||
|
if (n > 0) to[j] = '\0';
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_get_string(const char *s, int len, const char *path, char *to,
|
||||||
|
int n) {
|
||||||
|
const char *p;
|
||||||
|
int sz;
|
||||||
|
if (mjson_find(s, len, path, &p, &sz) != MJSON_TOK_STRING) return -1;
|
||||||
|
return mjson_unescape(p + 1, sz - 2, to, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_get_hex(const char *s, int len, const char *x, char *to, int n) {
|
||||||
|
const char *p;
|
||||||
|
int i, j, sz;
|
||||||
|
if (mjson_find(s, len, x, &p, &sz) != MJSON_TOK_STRING) return -1;
|
||||||
|
for (i = j = 0; i < sz - 3 && j < n; i += 2, j++) {
|
||||||
|
#define HEXTOI(x) (x >= '0' && x <= '9' ? x - '0' : x - 'W')
|
||||||
|
unsigned char a = *(const unsigned char *) (p + i + 1);
|
||||||
|
unsigned char b = *(const unsigned char *) (p + i + 2);
|
||||||
|
((unsigned char *) to)[j] = (HEXTOI(a) << 4) | HEXTOI(b);
|
||||||
|
}
|
||||||
|
if (j < n) to[j] = '\0';
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_BASE64
|
||||||
|
static int mjson_base64rev(int c) {
|
||||||
|
if (c >= 'A' && c <= 'Z') {
|
||||||
|
return c - 'A';
|
||||||
|
} else if (c >= 'a' && c <= 'z') {
|
||||||
|
return c + 26 - 'a';
|
||||||
|
} else if (c >= '0' && c <= '9') {
|
||||||
|
return c + 52 - '0';
|
||||||
|
} else if (c == '+') {
|
||||||
|
return 62;
|
||||||
|
} else if (c == '/') {
|
||||||
|
return 63;
|
||||||
|
} else {
|
||||||
|
return 64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_base64_dec(const char *src, int n, char *dst, int dlen) {
|
||||||
|
const char *end = src + n;
|
||||||
|
int len = 0;
|
||||||
|
while (src + 3 < end && len < dlen) {
|
||||||
|
int a = mjson_base64rev(src[0]), b = mjson_base64rev(src[1]),
|
||||||
|
c = mjson_base64rev(src[2]), d = mjson_base64rev(src[3]);
|
||||||
|
dst[len++] = (a << 2) | (b >> 4);
|
||||||
|
if (src[2] != '=' && len < dlen) {
|
||||||
|
dst[len++] = (b << 4) | (c >> 2);
|
||||||
|
if (src[3] != '=' && len < dlen) {
|
||||||
|
dst[len++] = (c << 6) | d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
src += 4;
|
||||||
|
}
|
||||||
|
if (len < dlen) dst[len] = '\0';
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_get_base64(const char *s, int len, const char *path, char *to,
|
||||||
|
int n) {
|
||||||
|
const char *p;
|
||||||
|
int sz;
|
||||||
|
if (mjson_find(s, len, path, &p, &sz) != MJSON_TOK_STRING) return 0;
|
||||||
|
return mjson_base64_dec(p + 1, sz - 2, to, n);
|
||||||
|
}
|
||||||
|
#endif // MJSON_ENABLE_BASE64
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_NEXT
|
||||||
|
struct nextdata {
|
||||||
|
int off, len, depth, t, vo, arrayindex;
|
||||||
|
int *koff, *klen, *voff, *vlen, *vtype;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int next_cb(int tok, const char *s, int off, int len, void *ud) {
|
||||||
|
struct nextdata *d = (struct nextdata *) ud;
|
||||||
|
// int i;
|
||||||
|
switch (tok) {
|
||||||
|
case '{':
|
||||||
|
case '[':
|
||||||
|
if (d->depth == 0 && tok == '[') d->arrayindex = 0;
|
||||||
|
if (d->depth == 1 && off > d->off) {
|
||||||
|
d->vo = off;
|
||||||
|
d->t = tok == '{' ? MJSON_TOK_OBJECT : MJSON_TOK_ARRAY;
|
||||||
|
if (d->voff) *d->voff = off;
|
||||||
|
if (d->vtype) *d->vtype = d->t;
|
||||||
|
}
|
||||||
|
d->depth++;
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
case ']':
|
||||||
|
d->depth--;
|
||||||
|
if (d->depth == 1 && d->vo) {
|
||||||
|
d->len = off + len;
|
||||||
|
if (d->vlen) *d->vlen = d->len - d->vo;
|
||||||
|
if (d->arrayindex >= 0) {
|
||||||
|
if (d->koff) *d->koff = d->arrayindex; // koff holds array index
|
||||||
|
if (d->klen) *d->klen = 0; // klen holds 0
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (d->depth == 1 && d->arrayindex >= 0) d->arrayindex++;
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
case ':':
|
||||||
|
break;
|
||||||
|
case MJSON_TOK_KEY:
|
||||||
|
if (d->depth == 1 && d->off < off) {
|
||||||
|
if (d->koff) *d->koff = off; // And report back to the user
|
||||||
|
if (d->klen) *d->klen = len; // If we have to
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (d->depth != 1) break;
|
||||||
|
// If we're iterating over the array
|
||||||
|
if (off > d->off) {
|
||||||
|
d->len = off + len;
|
||||||
|
if (d->vlen) *d->vlen = len; // value length
|
||||||
|
if (d->voff) *d->voff = off; // value offset
|
||||||
|
if (d->vtype) *d->vtype = tok; // value type
|
||||||
|
if (d->arrayindex >= 0) {
|
||||||
|
if (d->koff) *d->koff = d->arrayindex; // koff holds array index
|
||||||
|
if (d->klen) *d->klen = 0; // klen holds 0
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (d->arrayindex >= 0) d->arrayindex++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
(void) s;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_next(const char *s, int n, int off, int *koff, int *klen, int *voff,
|
||||||
|
int *vlen, int *vtype) {
|
||||||
|
struct nextdata d = {off, 0, 0, 0, 0, -1, koff, klen, voff, vlen, vtype};
|
||||||
|
mjson(s, n, next_cb, &d);
|
||||||
|
return d.len;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_PRINT
|
||||||
|
int mjson_print_fixed_buf(const char *ptr, int len, void *fndata) {
|
||||||
|
struct mjson_fixedbuf *fb = (struct mjson_fixedbuf *) fndata;
|
||||||
|
int i, left = fb->size - 1 - fb->len;
|
||||||
|
if (left < len) len = left;
|
||||||
|
for (i = 0; i < len; i++) fb->ptr[fb->len + i] = ptr[i];
|
||||||
|
fb->len += len;
|
||||||
|
fb->ptr[fb->len] = '\0';
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_print_dynamic_buf(const char *ptr, int len, void *fndata) {
|
||||||
|
char *s, *buf = *(char **) fndata;
|
||||||
|
int curlen = buf == NULL ? 0 : strlen(buf);
|
||||||
|
if ((s = (char *) realloc(buf, curlen + len + 1)) == NULL) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
memcpy(s + curlen, ptr, len);
|
||||||
|
s[curlen + len] = '\0';
|
||||||
|
*(char **) fndata = s;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_print_null(const char *ptr, int len, void *userdata) {
|
||||||
|
(void) ptr;
|
||||||
|
(void) userdata;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_print_file(const char *ptr, int len, void *userdata) {
|
||||||
|
return fwrite(ptr, 1, len, (FILE *) userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_print_buf(mjson_print_fn_t fn, void *fndata, const char *buf,
|
||||||
|
int len) {
|
||||||
|
return fn(buf, len, fndata);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_print_int(mjson_print_fn_t fn, void *fndata, int value,
|
||||||
|
int is_signed) {
|
||||||
|
char buf[20];
|
||||||
|
int len = snprintf(buf, sizeof(buf), is_signed ? "%d" : "%u", value);
|
||||||
|
return fn(buf, len, fndata);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_print_long(mjson_print_fn_t fn, void *fndata, long value,
|
||||||
|
int is_signed) {
|
||||||
|
char buf[20];
|
||||||
|
const char *fmt = (is_signed ? "%ld" : "%lu");
|
||||||
|
int len = snprintf(buf, sizeof(buf), fmt, value);
|
||||||
|
return fn(buf, len, fndata);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_print_dbl(mjson_print_fn_t fn, void *fndata, double d,
|
||||||
|
const char *fmt) {
|
||||||
|
char buf[40];
|
||||||
|
int n = snprintf(buf, sizeof(buf), fmt, d);
|
||||||
|
return fn(buf, n, fndata);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_print_str(mjson_print_fn_t fn, void *fndata, const char *s, int len) {
|
||||||
|
int i, n = fn("\"", 1, fndata);
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
char c = mjson_esc(s[i], 1);
|
||||||
|
if (c) {
|
||||||
|
n += fn("\\", 1, fndata);
|
||||||
|
n += fn(&c, 1, fndata);
|
||||||
|
} else {
|
||||||
|
n += fn(&s[i], 1, fndata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n + fn("\"", 1, fndata);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_BASE64
|
||||||
|
int mjson_print_b64(mjson_print_fn_t fn, void *fndata, const unsigned char *s,
|
||||||
|
int n) {
|
||||||
|
const char *t =
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
int i, len = fn("\"", 1, fndata);
|
||||||
|
for (i = 0; i < n; i += 3) {
|
||||||
|
int a = s[i], b = i + 1 < n ? s[i + 1] : 0, c = i + 2 < n ? s[i + 2] : 0;
|
||||||
|
char buf[4] = {t[a >> 2], t[(a & 3) << 4 | (b >> 4)], '=', '='};
|
||||||
|
if (i + 1 < n) buf[2] = t[(b & 15) << 2 | (c >> 6)];
|
||||||
|
if (i + 2 < n) buf[3] = t[c & 63];
|
||||||
|
len += fn(buf, sizeof(buf), fndata);
|
||||||
|
}
|
||||||
|
return len + fn("\"", 1, fndata);
|
||||||
|
}
|
||||||
|
#endif /* MJSON_ENABLE_BASE64 */
|
||||||
|
|
||||||
|
int mjson_vprintf(mjson_print_fn_t fn, void *fndata, const char *fmt,
|
||||||
|
va_list xap) {
|
||||||
|
int i = 0, n = 0;
|
||||||
|
va_list ap;
|
||||||
|
va_copy(ap, xap);
|
||||||
|
while (fmt[i] != '\0') {
|
||||||
|
if (fmt[i] == '%') {
|
||||||
|
char fc = fmt[++i];
|
||||||
|
int is_long = 0;
|
||||||
|
if (fc == 'l') {
|
||||||
|
is_long = 1;
|
||||||
|
fc = fmt[i + 1];
|
||||||
|
}
|
||||||
|
if (fc == 'Q') {
|
||||||
|
char *buf = va_arg(ap, char *);
|
||||||
|
n += mjson_print_str(fn, fndata, buf ? buf : "", buf ? strlen(buf) : 0);
|
||||||
|
} else if (strncmp(&fmt[i], ".*Q", 3) == 0) {
|
||||||
|
int len = va_arg(ap, int);
|
||||||
|
char *buf = va_arg(ap, char *);
|
||||||
|
n += mjson_print_str(fn, fndata, buf, len);
|
||||||
|
i += 2;
|
||||||
|
} else if (fc == 'd' || fc == 'u') {
|
||||||
|
int is_signed = (fc == 'd');
|
||||||
|
if (is_long) {
|
||||||
|
long val = va_arg(ap, long);
|
||||||
|
n += mjson_print_long(fn, fndata, val, is_signed);
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
int val = va_arg(ap, int);
|
||||||
|
n += mjson_print_int(fn, fndata, val, is_signed);
|
||||||
|
}
|
||||||
|
} else if (fc == 'B') {
|
||||||
|
const char *s = va_arg(ap, int) ? "true" : "false";
|
||||||
|
n += mjson_print_buf(fn, fndata, s, strlen(s));
|
||||||
|
} else if (fc == 's') {
|
||||||
|
char *buf = va_arg(ap, char *);
|
||||||
|
n += mjson_print_buf(fn, fndata, buf, strlen(buf));
|
||||||
|
} else if (strncmp(&fmt[i], ".*s", 3) == 0) {
|
||||||
|
int len = va_arg(ap, int);
|
||||||
|
char *buf = va_arg(ap, char *);
|
||||||
|
n += mjson_print_buf(fn, fndata, buf, len);
|
||||||
|
i += 2;
|
||||||
|
} else if (fc == 'g') {
|
||||||
|
n += mjson_print_dbl(fn, fndata, va_arg(ap, double), "%g");
|
||||||
|
} else if (fc == 'f') {
|
||||||
|
n += mjson_print_dbl(fn, fndata, va_arg(ap, double), "%f");
|
||||||
|
#if MJSON_ENABLE_BASE64
|
||||||
|
} else if (fc == 'V') {
|
||||||
|
int len = va_arg(ap, int);
|
||||||
|
const char *buf = va_arg(ap, const char *);
|
||||||
|
n += mjson_print_b64(fn, fndata, (unsigned char *) buf, len);
|
||||||
|
#endif
|
||||||
|
} else if (fc == 'H') {
|
||||||
|
const char *hex = "0123456789abcdef";
|
||||||
|
int i, len = va_arg(ap, int);
|
||||||
|
const unsigned char *p = va_arg(ap, const unsigned char *);
|
||||||
|
n += fn("\"", 1, fndata);
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
n += fn(&hex[(p[i] >> 4) & 15], 1, fndata);
|
||||||
|
n += fn(&hex[p[i] & 15], 1, fndata);
|
||||||
|
}
|
||||||
|
n += fn("\"", 1, fndata);
|
||||||
|
} else if (fc == 'M') {
|
||||||
|
mjson_vprint_fn_t vfn = va_arg(ap, mjson_vprint_fn_t);
|
||||||
|
n += vfn(fn, fndata, &ap);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
n += mjson_print_buf(fn, fndata, &fmt[i++], 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
va_end(xap);
|
||||||
|
va_end(ap);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_printf(mjson_print_fn_t fn, void *fndata, const char *fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
int len;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
len = mjson_vprintf(fn, fndata, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
#endif /* MJSON_ENABLE_PRINT */
|
||||||
|
|
||||||
|
#if MJSON_IMPLEMENT_STRTOD
|
||||||
|
static inline int is_digit(int c) {
|
||||||
|
return c >= '0' && c <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTE: strtod() implementation by Yasuhiro Matsumoto. */
|
||||||
|
double strtod(const char *str, char **end) {
|
||||||
|
double d = 0.0;
|
||||||
|
int sign = 1, n = 0;
|
||||||
|
const char *p = str, *a = str;
|
||||||
|
|
||||||
|
/* decimal part */
|
||||||
|
if (*p == '-') {
|
||||||
|
sign = -1;
|
||||||
|
++p;
|
||||||
|
} else if (*p == '+')
|
||||||
|
++p;
|
||||||
|
if (is_digit(*p)) {
|
||||||
|
d = (double) (*p++ - '0');
|
||||||
|
while (*p && is_digit(*p)) {
|
||||||
|
d = d * 10.0 + (double) (*p - '0');
|
||||||
|
++p;
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
a = p;
|
||||||
|
} else if (*p != '.')
|
||||||
|
goto done;
|
||||||
|
d *= sign;
|
||||||
|
|
||||||
|
/* fraction part */
|
||||||
|
if (*p == '.') {
|
||||||
|
double f = 0.0;
|
||||||
|
double base = 0.1;
|
||||||
|
++p;
|
||||||
|
|
||||||
|
if (is_digit(*p)) {
|
||||||
|
while (*p && is_digit(*p)) {
|
||||||
|
f += base * (*p - '0');
|
||||||
|
base /= 10.0;
|
||||||
|
++p;
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d += f * sign;
|
||||||
|
a = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* exponential part */
|
||||||
|
if ((*p == 'E') || (*p == 'e')) {
|
||||||
|
int e = 0;
|
||||||
|
++p;
|
||||||
|
|
||||||
|
sign = 1;
|
||||||
|
if (*p == '-') {
|
||||||
|
sign = -1;
|
||||||
|
++p;
|
||||||
|
} else if (*p == '+')
|
||||||
|
++p;
|
||||||
|
|
||||||
|
if (is_digit(*p)) {
|
||||||
|
while (*p == '0') ++p;
|
||||||
|
e = (int) (*p++ - '0');
|
||||||
|
while (*p && is_digit(*p)) {
|
||||||
|
e = e * 10 + (int) (*p - '0');
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
e *= sign;
|
||||||
|
} else if (!is_digit(*(a - 1))) {
|
||||||
|
a = str;
|
||||||
|
goto done;
|
||||||
|
} else if (*p == 0)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (d == 2.2250738585072011 && e == -308) {
|
||||||
|
d = 0.0;
|
||||||
|
a = p;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (d == 2.2250738585072012 && e <= -308) {
|
||||||
|
d *= 1.0e-308;
|
||||||
|
a = p;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 10; i++) d *= 10;
|
||||||
|
}
|
||||||
|
a = p;
|
||||||
|
} else if (p > str && !is_digit(*(p - 1))) {
|
||||||
|
a = str;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (end) *end = (char *) a;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_MERGE
|
||||||
|
int mjson_merge(const char *s, int n, const char *s2, int n2,
|
||||||
|
mjson_print_fn_t fn, void *userdata) {
|
||||||
|
int koff, klen, voff, vlen, t, t2, k, off = 0, len = 0, comma = 0;
|
||||||
|
if (n < 2) return len;
|
||||||
|
len += fn("{", 1, userdata);
|
||||||
|
while ((off = mjson_next(s, n, off, &koff, &klen, &voff, &vlen, &t)) != 0) {
|
||||||
|
#if !defined(_MSC_VER) || _MSC_VER >= 1700
|
||||||
|
char path[klen + 1];
|
||||||
|
#else
|
||||||
|
char *path = (char *) alloca(klen + 1);
|
||||||
|
#endif
|
||||||
|
const char *val;
|
||||||
|
memcpy(path, "$.", 2);
|
||||||
|
memcpy(path + 2, s + koff + 1, klen - 2);
|
||||||
|
path[klen] = '\0';
|
||||||
|
if ((t2 = mjson_find(s2, n2, path, &val, &k)) != MJSON_TOK_INVALID) {
|
||||||
|
if (t2 == MJSON_TOK_NULL) continue; // null deletes the key
|
||||||
|
} else {
|
||||||
|
val = s + voff; // Key is not found in the update. Copy the old value.
|
||||||
|
}
|
||||||
|
if (comma) len += fn(",", 1, userdata);
|
||||||
|
len += fn(s + koff, klen, userdata);
|
||||||
|
len += fn(":", 1, userdata);
|
||||||
|
if (t == MJSON_TOK_OBJECT && t2 == MJSON_TOK_OBJECT) {
|
||||||
|
len += mjson_merge(s + voff, vlen, val, k, fn, userdata);
|
||||||
|
} else {
|
||||||
|
if (t2 != MJSON_TOK_INVALID) vlen = k;
|
||||||
|
len += fn(val, vlen, userdata);
|
||||||
|
}
|
||||||
|
comma = 1;
|
||||||
|
}
|
||||||
|
// Add missing keys
|
||||||
|
off = 0;
|
||||||
|
while ((off = mjson_next(s2, n2, off, &koff, &klen, &voff, &vlen, &t)) != 0) {
|
||||||
|
#if !defined(_MSC_VER) || _MSC_VER >= 1700
|
||||||
|
char path[klen + 1];
|
||||||
|
#else
|
||||||
|
char *path = (char *) alloca(klen + 1);
|
||||||
|
#endif
|
||||||
|
const char *val;
|
||||||
|
if (t == MJSON_TOK_NULL) continue;
|
||||||
|
memcpy(path, "$.", 2);
|
||||||
|
memcpy(path + 2, s2 + koff + 1, klen - 2);
|
||||||
|
path[klen] = '\0';
|
||||||
|
if (mjson_find(s, n, path, &val, &vlen) != MJSON_TOK_INVALID) continue;
|
||||||
|
if (comma) len += fn(",", 1, userdata);
|
||||||
|
len += fn(s2 + koff, klen, userdata);
|
||||||
|
len += fn(":", 1, userdata);
|
||||||
|
len += fn(s2 + voff, vlen, userdata);
|
||||||
|
comma = 1;
|
||||||
|
}
|
||||||
|
len += fn("}", 1, userdata);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
#endif // MJSON_ENABLE_MERGE
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_PRETTY
|
||||||
|
struct prettydata {
|
||||||
|
int level;
|
||||||
|
int len;
|
||||||
|
int prev;
|
||||||
|
const char *pad;
|
||||||
|
int padlen;
|
||||||
|
mjson_print_fn_t fn;
|
||||||
|
void *userdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pretty_cb(int ev, const char *s, int off, int len, void *ud) {
|
||||||
|
struct prettydata *d = (struct prettydata *) ud;
|
||||||
|
int i;
|
||||||
|
switch (ev) {
|
||||||
|
case '{':
|
||||||
|
case '[':
|
||||||
|
d->level++;
|
||||||
|
d->len += d->fn(s + off, len, d->userdata);
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
case ']':
|
||||||
|
d->level--;
|
||||||
|
if (d->prev != '[' && d->prev != '{' && d->padlen > 0) {
|
||||||
|
d->len += d->fn("\n", 1, d->userdata);
|
||||||
|
for (i = 0; i < d->level; i++)
|
||||||
|
d->len += d->fn(d->pad, d->padlen, d->userdata);
|
||||||
|
}
|
||||||
|
d->len += d->fn(s + off, len, d->userdata);
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
d->len += d->fn(s + off, len, d->userdata);
|
||||||
|
if (d->padlen > 0) {
|
||||||
|
d->len += d->fn("\n", 1, d->userdata);
|
||||||
|
for (i = 0; i < d->level; i++)
|
||||||
|
d->len += d->fn(d->pad, d->padlen, d->userdata);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ':':
|
||||||
|
d->len += d->fn(s + off, len, d->userdata);
|
||||||
|
if (d->padlen > 0) d->len += d->fn(" ", 1, d->userdata);
|
||||||
|
break;
|
||||||
|
case MJSON_TOK_KEY:
|
||||||
|
if (d->prev == '{' && d->padlen > 0) {
|
||||||
|
d->len += d->fn("\n", 1, d->userdata);
|
||||||
|
for (i = 0; i < d->level; i++)
|
||||||
|
d->len += d->fn(d->pad, d->padlen, d->userdata);
|
||||||
|
}
|
||||||
|
d->len += d->fn(s + off, len, d->userdata);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (d->prev == '[' && d->padlen > 0) {
|
||||||
|
d->len += d->fn("\n", 1, d->userdata);
|
||||||
|
for (i = 0; i < d->level; i++)
|
||||||
|
d->len += d->fn(d->pad, d->padlen, d->userdata);
|
||||||
|
}
|
||||||
|
d->len += d->fn(s + off, len, d->userdata);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
d->prev = ev;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mjson_pretty(const char *s, int n, const char *pad, mjson_print_fn_t fn,
|
||||||
|
void *userdata) {
|
||||||
|
struct prettydata d = {0, 0, 0, pad, strlen(pad), fn, userdata};
|
||||||
|
if (mjson(s, n, pretty_cb, &d) < 0) return -1;
|
||||||
|
return d.len;
|
||||||
|
}
|
||||||
|
#endif // MJSON_ENABLE_PRETTY
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_RPC
|
||||||
|
struct jsonrpc_ctx jsonrpc_default_context;
|
||||||
|
struct jsonrpc_userdata {
|
||||||
|
mjson_print_fn_t fn;
|
||||||
|
void *fndata;
|
||||||
|
};
|
||||||
|
|
||||||
|
int mjson_globmatch(const char *s1, int n1, const char *s2, int n2) {
|
||||||
|
int i = 0, j = 0, ni = 0, nj = 0;
|
||||||
|
while (i < n1 || j < n2) {
|
||||||
|
if (i < n1 && j < n2 && (s1[i] == '?' || s2[j] == s1[i])) {
|
||||||
|
i++, j++;
|
||||||
|
} else if (i < n1 && (s1[i] == '*' || s1[i] == '#')) {
|
||||||
|
ni = i, nj = j + 1, i++;
|
||||||
|
} else if (nj > 0 && nj <= n2 && (s1[i - 1] == '#' || s2[j] != '/')) {
|
||||||
|
i = ni, j = nj;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jsonrpc_printer(const char *buf, int len, void *userdata) {
|
||||||
|
struct jsonrpc_userdata *u = (struct jsonrpc_userdata *) userdata;
|
||||||
|
return u->fn(buf, len, u->fndata);
|
||||||
|
}
|
||||||
|
|
||||||
|
void jsonrpc_return_errorv(struct jsonrpc_request *r, int code,
|
||||||
|
const char *message, const char *data_fmt,
|
||||||
|
va_list ap) {
|
||||||
|
if (r->id_len == 0) return;
|
||||||
|
mjson_printf(r->fn, r->fndata,
|
||||||
|
"{\"id\":%.*s,\"error\":{\"code\":%d,\"message\":%Q", r->id_len,
|
||||||
|
r->id, code, message == NULL ? "" : message);
|
||||||
|
if (data_fmt != NULL) {
|
||||||
|
mjson_printf(r->fn, r->fndata, ",\"data\":");
|
||||||
|
mjson_vprintf(r->fn, r->fndata, data_fmt, ap);
|
||||||
|
}
|
||||||
|
mjson_printf(r->fn, r->fndata, "}}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void jsonrpc_return_error(struct jsonrpc_request *r, int code,
|
||||||
|
const char *message, const char *data_fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, data_fmt);
|
||||||
|
jsonrpc_return_errorv(r, code, message, data_fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void jsonrpc_return_successv(struct jsonrpc_request *r, const char *result_fmt,
|
||||||
|
va_list ap) {
|
||||||
|
if (r->id_len == 0) return;
|
||||||
|
mjson_printf(r->fn, r->fndata, "{\"id\":%.*s,\"result\":", r->id_len, r->id);
|
||||||
|
if (result_fmt != NULL) {
|
||||||
|
mjson_vprintf(r->fn, r->fndata, result_fmt, ap);
|
||||||
|
} else {
|
||||||
|
mjson_printf(r->fn, r->fndata, "%s", "null");
|
||||||
|
}
|
||||||
|
mjson_printf(r->fn, r->fndata, "}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void jsonrpc_return_success(struct jsonrpc_request *r, const char *result_fmt,
|
||||||
|
...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, result_fmt);
|
||||||
|
jsonrpc_return_successv(r, result_fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void jsonrpc_ctx_process(struct jsonrpc_ctx *ctx, const char *req, int req_sz,
|
||||||
|
mjson_print_fn_t fn, void *fndata) {
|
||||||
|
const char *result = NULL, *error = NULL;
|
||||||
|
int result_sz = 0, error_sz = 0;
|
||||||
|
struct jsonrpc_method *m = NULL;
|
||||||
|
struct jsonrpc_userdata d;
|
||||||
|
struct jsonrpc_request r = {req, req_sz, 0, 0, 0, 0, 0,
|
||||||
|
0, &jsonrpc_printer, NULL, NULL};
|
||||||
|
|
||||||
|
d.fn = fn;
|
||||||
|
d.fndata = fndata;
|
||||||
|
r.fndata = &d;
|
||||||
|
|
||||||
|
// Is is a response frame?
|
||||||
|
mjson_find(req, req_sz, "$.result", &result, &result_sz);
|
||||||
|
if (result == NULL) mjson_find(req, req_sz, "$.error", &error, &error_sz);
|
||||||
|
if (result_sz > 0 || error_sz > 0) {
|
||||||
|
if (ctx->response_cb != NULL) ctx->response_cb(req, req_sz, ctx->userdata);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method must exist and must be a string
|
||||||
|
if (mjson_find(req, req_sz, "$.method", &r.method, &r.method_len) !=
|
||||||
|
MJSON_TOK_STRING) {
|
||||||
|
mjson_printf(fn, fndata, "{\"error\":{\"code\":-32700,\"message\":%.*Q}}\n",
|
||||||
|
req_sz, req);
|
||||||
|
ctx->in_len = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// id and params are optional
|
||||||
|
mjson_find(req, req_sz, "$.id", &r.id, &r.id_len);
|
||||||
|
mjson_find(req, req_sz, "$.params", &r.params, &r.params_len);
|
||||||
|
|
||||||
|
for (m = ctx->methods; m != NULL; m = m->next) {
|
||||||
|
if (mjson_globmatch(m->method, m->method_sz, r.method + 1,
|
||||||
|
r.method_len - 2) > 0) {
|
||||||
|
if (r.params == NULL) r.params = "";
|
||||||
|
r.userdata = m->cbdata;
|
||||||
|
m->cb(&r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m == NULL) {
|
||||||
|
jsonrpc_return_error(&r, JSONRPC_ERROR_NOT_FOUND, "method not found", NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jsonrpc_print_methods(mjson_print_fn_t fn, void *fndata,
|
||||||
|
va_list *ap) {
|
||||||
|
struct jsonrpc_ctx *ctx = va_arg(*ap, struct jsonrpc_ctx *);
|
||||||
|
struct jsonrpc_method *m;
|
||||||
|
int len = 0;
|
||||||
|
for (m = ctx->methods; m != NULL; m = m->next) {
|
||||||
|
if (m != ctx->methods) len += mjson_print_buf(fn, fndata, ",", 1);
|
||||||
|
len += mjson_print_str(fn, fndata, m->method, strlen(m->method));
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rpclist(struct jsonrpc_request *r) {
|
||||||
|
jsonrpc_return_success(r, "[%M]", jsonrpc_print_methods, r->userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
void jsonrpc_ctx_init(struct jsonrpc_ctx *ctx, mjson_print_fn_t response_cb,
|
||||||
|
void *userdata) {
|
||||||
|
ctx->response_cb = response_cb;
|
||||||
|
ctx->userdata = userdata;
|
||||||
|
jsonrpc_ctx_export(ctx, MJSON_RPC_LIST_NAME, rpclist, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void jsonrpc_ctx_process_byte(struct jsonrpc_ctx *ctx, unsigned char ch,
|
||||||
|
mjson_print_fn_t fn, void *p) {
|
||||||
|
if (ctx->in_len >= (int) sizeof(ctx->in)) ctx->in_len = 0; // Overflow
|
||||||
|
if (ch == '\n') { // If new line, parse frame
|
||||||
|
if (ctx->in_len > 1) jsonrpc_ctx_process(ctx, ctx->in, ctx->in_len, fn, p);
|
||||||
|
ctx->in_len = 0;
|
||||||
|
} else {
|
||||||
|
ctx->in[ctx->in_len] = ch; // Append to the buffer
|
||||||
|
ctx->in_len++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void jsonrpc_init(mjson_print_fn_t response_cb, void *userdata) {
|
||||||
|
jsonrpc_ctx_init(&jsonrpc_default_context, response_cb, userdata);
|
||||||
|
}
|
||||||
|
#endif // MJSON_ENABLE_RPC
|
||||||
@@ -0,0 +1,220 @@
|
|||||||
|
// Copyright (c) 2018-2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef MJSON_H
|
||||||
|
#define MJSON_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifndef MJSON_ENABLE_PRINT
|
||||||
|
#define MJSON_ENABLE_PRINT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MJSON_ENABLE_RPC
|
||||||
|
#define MJSON_ENABLE_RPC 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MJSON_ENABLE_BASE64
|
||||||
|
#define MJSON_ENABLE_BASE64 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MJSON_ENABLE_MERGE
|
||||||
|
#define MJSON_ENABLE_MERGE 0
|
||||||
|
#elif MJSON_ENABLE_MERGE
|
||||||
|
#define MJSON_ENABLE_NEXT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MJSON_ENABLE_PRETTY
|
||||||
|
#define MJSON_ENABLE_PRETTY 0
|
||||||
|
#elif MJSON_ENABLE_PRETTY
|
||||||
|
#define MJSON_ENABLE_NEXT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MJSON_ENABLE_NEXT
|
||||||
|
#define MJSON_ENABLE_NEXT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef MJSON_RPC_IN_BUF_SIZE
|
||||||
|
#define MJSON_RPC_IN_BUF_SIZE 256
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MJSON_RPC_LIST_NAME
|
||||||
|
#define MJSON_RPC_LIST_NAME "rpc.list"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MJSON_ERROR_INVALID_INPUT = -1,
|
||||||
|
MJSON_ERROR_TOO_DEEP = -2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum mjson_tok {
|
||||||
|
MJSON_TOK_INVALID = 0,
|
||||||
|
MJSON_TOK_KEY = 1,
|
||||||
|
MJSON_TOK_STRING = 11,
|
||||||
|
MJSON_TOK_NUMBER = 12,
|
||||||
|
MJSON_TOK_TRUE = 13,
|
||||||
|
MJSON_TOK_FALSE = 14,
|
||||||
|
MJSON_TOK_NULL = 15,
|
||||||
|
MJSON_TOK_ARRAY = 91,
|
||||||
|
MJSON_TOK_OBJECT = 123,
|
||||||
|
};
|
||||||
|
#define MJSON_TOK_IS_VALUE(t) ((t) > 10 && (t) < 20)
|
||||||
|
|
||||||
|
typedef int (*mjson_cb_t)(int ev, const char *s, int off, int len, void *ud);
|
||||||
|
|
||||||
|
#ifndef MJSON_MAX_DEPTH
|
||||||
|
#define MJSON_MAX_DEPTH 20
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int mjson(const char *s, int len, mjson_cb_t cb, void *ud);
|
||||||
|
enum mjson_tok mjson_find(const char *s, int len, const char *jp,
|
||||||
|
const char **tokptr, int *toklen);
|
||||||
|
int mjson_get_number(const char *s, int len, const char *path, double *v);
|
||||||
|
int mjson_get_bool(const char *s, int len, const char *path, int *v);
|
||||||
|
int mjson_get_string(const char *s, int len, const char *path, char *to, int n);
|
||||||
|
int mjson_get_hex(const char *s, int len, const char *path, char *to, int n);
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_NEXT
|
||||||
|
int mjson_next(const char *s, int n, int off, int *koff, int *klen, int *voff,
|
||||||
|
int *vlen, int *vtype);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_BASE64
|
||||||
|
int mjson_get_base64(const char *s, int len, const char *path, char *to, int n);
|
||||||
|
int mjson_base64_dec(const char *src, int n, char *dst, int dlen);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_PRINT
|
||||||
|
typedef int (*mjson_print_fn_t)(const char *buf, int len, void *userdata);
|
||||||
|
typedef int (*mjson_vprint_fn_t)(mjson_print_fn_t, void *, va_list *);
|
||||||
|
|
||||||
|
struct mjson_fixedbuf {
|
||||||
|
char *ptr;
|
||||||
|
int size, len;
|
||||||
|
};
|
||||||
|
|
||||||
|
int mjson_printf(mjson_print_fn_t, void *, const char *fmt, ...);
|
||||||
|
int mjson_vprintf(mjson_print_fn_t, void *, const char *fmt, va_list ap);
|
||||||
|
int mjson_print_str(mjson_print_fn_t, void *, const char *s, int len);
|
||||||
|
int mjson_print_int(mjson_print_fn_t, void *, int value, int is_signed);
|
||||||
|
int mjson_print_long(mjson_print_fn_t, void *, long value, int is_signed);
|
||||||
|
int mjson_print_buf(mjson_print_fn_t fn, void *, const char *buf, int len);
|
||||||
|
|
||||||
|
int mjson_print_null(const char *ptr, int len, void *userdata);
|
||||||
|
int mjson_print_file(const char *ptr, int len, void *userdata);
|
||||||
|
int mjson_print_fixed_buf(const char *ptr, int len, void *userdata);
|
||||||
|
int mjson_print_dynamic_buf(const char *ptr, int len, void *userdata);
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_PRETTY
|
||||||
|
int mjson_pretty(const char *, int, const char *, mjson_print_fn_t, void *);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_MERGE
|
||||||
|
int mjson_merge(const char *, int, const char *, int, mjson_print_fn_t, void *);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // MJSON_ENABLE_PRINT
|
||||||
|
|
||||||
|
#if MJSON_ENABLE_RPC
|
||||||
|
|
||||||
|
void jsonrpc_init(mjson_print_fn_t, void *userdata);
|
||||||
|
int mjson_globmatch(const char *s1, int n1, const char *s2, int n2);
|
||||||
|
|
||||||
|
struct jsonrpc_request {
|
||||||
|
const char *frame; // Points to the whole frame
|
||||||
|
int frame_len; // Frame length
|
||||||
|
const char *params; // Points to the "params" in the request frame
|
||||||
|
int params_len; // Length of the "params"
|
||||||
|
const char *id; // Points to the "id" in the request frame
|
||||||
|
int id_len; // Length of the "id"
|
||||||
|
const char *method; // Points to the "method" in the request frame
|
||||||
|
int method_len; // Length of the "method"
|
||||||
|
mjson_print_fn_t fn; // Printer function
|
||||||
|
void *fndata; // Printer function data
|
||||||
|
void *userdata; // Callback's user data as specified at export time
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jsonrpc_method {
|
||||||
|
const char *method;
|
||||||
|
int method_sz;
|
||||||
|
void (*cb)(struct jsonrpc_request *);
|
||||||
|
void *cbdata;
|
||||||
|
struct jsonrpc_method *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Main RPC context, stores current request information and a list of
|
||||||
|
// exported RPC methods.
|
||||||
|
struct jsonrpc_ctx {
|
||||||
|
struct jsonrpc_method *methods;
|
||||||
|
void *userdata;
|
||||||
|
mjson_print_fn_t response_cb;
|
||||||
|
int in_len;
|
||||||
|
char in[MJSON_RPC_IN_BUF_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Registers function fn under the given name within the given RPC context
|
||||||
|
#define jsonrpc_ctx_export(ctx, name, fn, ud) \
|
||||||
|
do { \
|
||||||
|
static struct jsonrpc_method m = {(name), sizeof(name) - 1, (fn), 0, 0}; \
|
||||||
|
m.cbdata = (ud); \
|
||||||
|
m.next = (ctx)->methods; \
|
||||||
|
(ctx)->methods = &m; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
void jsonrpc_ctx_init(struct jsonrpc_ctx *ctx, mjson_print_fn_t, void *);
|
||||||
|
void jsonrpc_return_error(struct jsonrpc_request *r, int code,
|
||||||
|
const char *message, const char *data_fmt, ...);
|
||||||
|
void jsonrpc_return_success(struct jsonrpc_request *r, const char *result_fmt,
|
||||||
|
...);
|
||||||
|
void jsonrpc_ctx_process(struct jsonrpc_ctx *ctx, const char *req, int req_sz,
|
||||||
|
mjson_print_fn_t fn, void *fndata);
|
||||||
|
void jsonrpc_ctx_process_byte(struct jsonrpc_ctx *ctx, unsigned char ch,
|
||||||
|
mjson_print_fn_t fn, void *fndata);
|
||||||
|
|
||||||
|
extern struct jsonrpc_ctx jsonrpc_default_context;
|
||||||
|
|
||||||
|
#define jsonrpc_export(name, fn, ud) \
|
||||||
|
jsonrpc_ctx_export(&jsonrpc_default_context, (name), (fn), (ud))
|
||||||
|
|
||||||
|
#define jsonrpc_process(buf, len, fn, data) \
|
||||||
|
jsonrpc_ctx_process(&jsonrpc_default_context, (buf), (len), (fn), (data))
|
||||||
|
|
||||||
|
#define jsonrpc_process_byte(x, fn, data) \
|
||||||
|
jsonrpc_ctx_process_byte(&jsonrpc_default_context, (x), (fn), (data))
|
||||||
|
|
||||||
|
#define JSONRPC_ERROR_INVALID -32700 /* Invalid JSON was received */
|
||||||
|
#define JSONRPC_ERROR_NOT_FOUND -32601 /* The method does not exist */
|
||||||
|
#define JSONRPC_ERROR_BAD_PARAMS -32602 /* Invalid params passed */
|
||||||
|
#define JSONRPC_ERROR_INTERNAL -32603 /* Internal JSON-RPC error */
|
||||||
|
|
||||||
|
#endif // MJSON_ENABLE_RPC
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif // MJSON_H
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
const {h, render, Component} = preact;
|
||||||
|
const html = htm.bind(h);
|
||||||
|
|
||||||
|
const Info = () => html`<div id="info">
|
||||||
|
This dashboard shows values kept in server memory. Many clients
|
||||||
|
can open this page. As soon as any client changes any value,
|
||||||
|
all clients update automatically.
|
||||||
|
<br/><br/>
|
||||||
|
The JS code that watches state changes, reconnects on network failures.
|
||||||
|
That means if server restarts, dashboard on all connected clients
|
||||||
|
refresh automatically.
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
You can use <code>curl</code> command-line utility:
|
||||||
|
<br/><code>curl localhost:8000/api/config/get</code>
|
||||||
|
<br/><code>curl localhost:8000/api/config/watch</code>
|
||||||
|
<br/><code>curl localhost:8000/api/config/set -d '{"a":123}'</code>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
class Dashboard extends Component {
|
||||||
|
state = {value1: null, value2: null};
|
||||||
|
componentDidMount() {
|
||||||
|
axios.get('/api/config/get')
|
||||||
|
.then(r => this.setState(r.data))
|
||||||
|
.catch(e => console.log(e));
|
||||||
|
var self = this;
|
||||||
|
var f = function(reader) {
|
||||||
|
return reader.read().then(function(result) {
|
||||||
|
var data = String.fromCharCode.apply(null, result.value);
|
||||||
|
self.setState(JSON.parse(data));
|
||||||
|
// console.log(JSON.parse(data));
|
||||||
|
if (!result.done) return f(reader);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
fetch('/api/config/watch')
|
||||||
|
.then(r => r.body.getReader())
|
||||||
|
.then(f)
|
||||||
|
.catch(e => setTimeout(x => self.componentDidMount(), 1000));
|
||||||
|
}
|
||||||
|
render(props, state) {
|
||||||
|
return html
|
||||||
|
`<div id="dashboard" style="display: flex; justify-content: flex-evenly;">
|
||||||
|
<div style="width:50%;text-align:center;">Value 1 (number):
|
||||||
|
<div style="font-size:140%;"><b>${state.value1}</b></div></div>
|
||||||
|
<div style="width:50%;text-align:center;">Value 2 (string):
|
||||||
|
<div style="font-size:140%;"><b>${state.value2}</b></div></div>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Form extends Component {
|
||||||
|
render(props, state) {
|
||||||
|
const onclick = ev => axios.post(
|
||||||
|
'/api/config/set', {value1: +state.value1, value2: state.value2});
|
||||||
|
// alert(JSON.stringify(state));
|
||||||
|
return html`<div id="form">
|
||||||
|
<div><b>Change values</b></div>
|
||||||
|
<table>
|
||||||
|
<tr><td>Value 1 (number):</td><td><input value=${state.value1}
|
||||||
|
onInput=${linkState(this, 'value1')} /></td></tr>
|
||||||
|
<tr><td>Value 2 (string):</td><td><input value=${state.value2}
|
||||||
|
onInput=${linkState(this, 'value2')}/></td></tr>
|
||||||
|
<tr><td></td>
|
||||||
|
<td><button onClick=${onclick}>Save values</button></td></tr>
|
||||||
|
</table>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const App = () => html`<div id="container">
|
||||||
|
<${Info} />
|
||||||
|
<${Dashboard} />
|
||||||
|
<${Form} />
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
window.onload = () => render(h(App), document.body);
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
/* axios v0.19.0-beta.1 | (c) 2018 by Matt Zabriskie */
|
||||||
|
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function r(e){var t=new i(e),n=s(i.prototype.request,t);return o.extend(n,i.prototype,t),o.extend(n,t),n}var o=n(2),s=n(3),i=n(5),a=n(22),u=n(11),c=r(u);c.Axios=i,c.create=function(e){return r(a(c.defaults,e))},c.Cancel=n(23),c.CancelToken=n(24),c.isCancel=n(10),c.all=function(e){return Promise.all(e)},c.spread=n(25),e.exports=c,e.exports.default=c},function(e,t,n){"use strict";function r(e){return"[object Array]"===j.call(e)}function o(e){return"[object ArrayBuffer]"===j.call(e)}function s(e){return"undefined"!=typeof FormData&&e instanceof FormData}function i(e){var t;return t="undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function a(e){return"string"==typeof e}function u(e){return"number"==typeof e}function c(e){return"undefined"==typeof e}function f(e){return null!==e&&"object"==typeof e}function p(e){return"[object Date]"===j.call(e)}function d(e){return"[object File]"===j.call(e)}function l(e){return"[object Blob]"===j.call(e)}function h(e){return"[object Function]"===j.call(e)}function m(e){return f(e)&&h(e.pipe)}function y(e){return"undefined"!=typeof URLSearchParams&&e instanceof URLSearchParams}function g(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function x(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product&&"NativeScript"!==navigator.product&&"NS"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)}function v(e,t){if(null!==e&&"undefined"!=typeof e)if("object"!=typeof e&&(e=[e]),r(e))for(var n=0,o=e.length;n<o;n++)t.call(null,e[n],n,e);else for(var s in e)Object.prototype.hasOwnProperty.call(e,s)&&t.call(null,e[s],s,e)}function w(){function e(e,n){"object"==typeof t[n]&&"object"==typeof e?t[n]=w(t[n],e):t[n]=e}for(var t={},n=0,r=arguments.length;n<r;n++)v(arguments[n],e);return t}function b(){function e(e,n){"object"==typeof t[n]&&"object"==typeof e?t[n]=b(t[n],e):"object"==typeof e?t[n]=b({},e):t[n]=e}for(var t={},n=0,r=arguments.length;n<r;n++)v(arguments[n],e);return t}function E(e,t,n){return v(t,function(t,r){n&&"function"==typeof t?e[r]=S(t,n):e[r]=t}),e}var S=n(3),R=n(4),j=Object.prototype.toString;e.exports={isArray:r,isArrayBuffer:o,isBuffer:R,isFormData:s,isArrayBufferView:i,isString:a,isNumber:u,isObject:f,isUndefined:c,isDate:p,isFile:d,isBlob:l,isFunction:h,isStream:m,isURLSearchParams:y,isStandardBrowserEnv:x,forEach:v,merge:w,deepMerge:b,extend:E,trim:g}},function(e,t){"use strict";e.exports=function(e,t){return function(){for(var n=new Array(arguments.length),r=0;r<n.length;r++)n[r]=arguments[r];return e.apply(t,n)}}},function(e,t){/*!
|
||||||
|
* Determine if an object is a Buffer
|
||||||
|
*
|
||||||
|
* @author Feross Aboukhadijeh <https://feross.org>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
e.exports=function(e){return null!=e&&null!=e.constructor&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}},function(e,t,n){"use strict";function r(e){this.defaults=e,this.interceptors={request:new i,response:new i}}var o=n(2),s=n(6),i=n(7),a=n(8),u=n(22);r.prototype.request=function(e){"string"==typeof e?(e=arguments[1]||{},e.url=arguments[0]):e=e||{},e=u(this.defaults,e),e.method=e.method?e.method.toLowerCase():"get";var t=[a,void 0],n=Promise.resolve(e);for(this.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),this.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)n=n.then(t.shift(),t.shift());return n},r.prototype.getUri=function(e){return e=u(this.defaults,e),s(e.url,e.params,e.paramsSerializer).replace(/^\?/,"")},o.forEach(["delete","get","head","options"],function(e){r.prototype[e]=function(t,n){return this.request(o.merge(n||{},{method:e,url:t}))}}),o.forEach(["post","put","patch"],function(e){r.prototype[e]=function(t,n,r){return this.request(o.merge(r||{},{method:e,url:t,data:n}))}}),e.exports=r},function(e,t,n){"use strict";function r(e){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var o=n(2);e.exports=function(e,t,n){if(!t)return e;var s;if(n)s=n(t);else if(o.isURLSearchParams(t))s=t.toString();else{var i=[];o.forEach(t,function(e,t){null!==e&&"undefined"!=typeof e&&(o.isArray(e)?t+="[]":e=[e],o.forEach(e,function(e){o.isDate(e)?e=e.toISOString():o.isObject(e)&&(e=JSON.stringify(e)),i.push(r(t)+"="+r(e))}))}),s=i.join("&")}return s&&(e+=(e.indexOf("?")===-1?"?":"&")+s),e}},function(e,t,n){"use strict";function r(){this.handlers=[]}var o=n(2);r.prototype.use=function(e,t){return this.handlers.push({fulfilled:e,rejected:t}),this.handlers.length-1},r.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)},r.prototype.forEach=function(e){o.forEach(this.handlers,function(t){null!==t&&e(t)})},e.exports=r},function(e,t,n){"use strict";function r(e){e.cancelToken&&e.cancelToken.throwIfRequested()}var o=n(2),s=n(9),i=n(10),a=n(11),u=n(20),c=n(21);e.exports=function(e){r(e),e.baseURL&&!u(e.url)&&(e.url=c(e.baseURL,e.url)),e.headers=e.headers||{},e.data=s(e.data,e.headers,e.transformRequest),e.headers=o.merge(e.headers.common||{},e.headers[e.method]||{},e.headers||{}),o.forEach(["delete","get","head","post","put","patch","common"],function(t){delete e.headers[t]});var t=e.adapter||a.adapter;return t(e).then(function(t){return r(e),t.data=s(t.data,t.headers,e.transformResponse),t},function(t){return i(t)||(r(e),t&&t.response&&(t.response.data=s(t.response.data,t.response.headers,e.transformResponse))),Promise.reject(t)})}},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t,n){return r.forEach(n,function(n){e=n(e,t)}),e}},function(e,t){"use strict";e.exports=function(e){return!(!e||!e.__CANCEL__)}},function(e,t,n){"use strict";function r(e,t){!s.isUndefined(e)&&s.isUndefined(e["Content-Type"])&&(e["Content-Type"]=t)}function o(){var e;return"undefined"!=typeof process&&"[object process]"===Object.prototype.toString.call(process)?e=n(13):"undefined"!=typeof XMLHttpRequest&&(e=n(13)),e}var s=n(2),i=n(12),a={"Content-Type":"application/x-www-form-urlencoded"},u={adapter:o(),transformRequest:[function(e,t){return i(t,"Accept"),i(t,"Content-Type"),s.isFormData(e)||s.isArrayBuffer(e)||s.isBuffer(e)||s.isStream(e)||s.isFile(e)||s.isBlob(e)?e:s.isArrayBufferView(e)?e.buffer:s.isURLSearchParams(e)?(r(t,"application/x-www-form-urlencoded;charset=utf-8"),e.toString()):s.isObject(e)?(r(t,"application/json;charset=utf-8"),JSON.stringify(e)):e}],transformResponse:[function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(e){}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,validateStatus:function(e){return e>=200&&e<300}};u.headers={common:{Accept:"application/json, text/plain, */*"}},s.forEach(["delete","get","head"],function(e){u.headers[e]={}}),s.forEach(["post","put","patch"],function(e){u.headers[e]=s.merge(a)}),e.exports=u},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t){r.forEach(e,function(n,r){r!==t&&r.toUpperCase()===t.toUpperCase()&&(e[t]=n,delete e[r])})}},function(e,t,n){"use strict";var r=n(2),o=n(14),s=n(6),i=n(17),a=n(18),u=n(15);e.exports=function(e){return new Promise(function(t,c){var f=e.data,p=e.headers;r.isFormData(f)&&delete p["Content-Type"];var d=new XMLHttpRequest;if(e.auth){var l=e.auth.username||"",h=e.auth.password||"";p.Authorization="Basic "+btoa(l+":"+h)}if(d.open(e.method.toUpperCase(),s(e.url,e.params,e.paramsSerializer),!0),d.timeout=e.timeout,d.onreadystatechange=function(){if(d&&4===d.readyState&&(0!==d.status||d.responseURL&&0===d.responseURL.indexOf("file:"))){var n="getAllResponseHeaders"in d?i(d.getAllResponseHeaders()):null,r=e.responseType&&"text"!==e.responseType?d.response:Line truncated
|
||||||
|
//# sourceMappingURL=axios.min.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
!function(){function n(n){var t=e.get(this);return t||(t=new Map,e.set(this,t)),1<(t=a(this,t.get(n)||(t.set(n,t=function(n){function t(n){1===u&&(n||(r=r.replace(/^\s*\n\s*|\s*\n\s*$/g,"")))?p.push(0,n,r):3===u&&(n||r)?(p.push(3,n,r),u=2):2===u&&"..."===r&&n?p.push(4,n,0):2===u&&r&&!n?p.push(5,0,!0,r):5<=u&&((r||!n&&5===u)&&(p.push(u,0,r,s),u=6),n&&(p.push(u,n,0,s),u=6)),r=""}for(var e,s,u=1,r="",h="",p=[0],a=0;a<n.length;a++){a&&(1===u&&t(),t(a));for(var o=0;o<n[a].length;o++)e=n[a][o],1===u?"<"===e?(t(),p=[p],u=3):r+=e:4===u?r="--"===r&&">"===e?(u=1,""):e+r[0]:h?e===h?h="":r+=e:'"'===e||"'"===e?h=e:">"===e?(t(),u=1):u&&("="===e?(u=5,s=r,r=""):"/"===e&&(u<5||">"===n[a][o+1])?(t(),3===u&&(p=p[0]),(p=(u=p)[0]).push(2,0,u),u=0):" "===e||"\t"===e||"\n"===e||"\r"===e?(t(),u=2):r+=e),3===u&&"!--"===r&&(u=4,p=p[0])}return t(),p}(n)),t),arguments,[])).length?t:t[0]}var a=function(n,t,e,s){var u;t[0]=0;for(var r=1;r<t.length;r++){var h=t[r++],p=t[r]?(t[0]|=h?1:2,e[t[r++]]):t[++r];3===h?s[0]=p:4===h?s[1]=Object.assign(s[1]||{},p):5===h?(s[1]=s[1]||{})[t[++r]]=p:6===h?s[1][t[++r]]+=p+"":h?(u=n.apply(p,a(n,p,e,["",null])),s.push(u),p[0]?t[0]|=2:(t[r-2]=0,t[r]=u)):s.push(p)}return s},e=new Map;"undefined"!=typeof module?module.exports=n:self.htm=n}();
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>example</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="stylesheet" href="style.css" />
|
||||||
|
<script src="preact.min.js"></script>
|
||||||
|
<script src="htm.min.js"></script>
|
||||||
|
<script src="linkstate.min.js"></script>
|
||||||
|
<script src="axios.min.js"></script>
|
||||||
|
<script src="app.js"></script>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
function linkState(component, key, eventPath) {
|
||||||
|
let path = key.split('.'), cache = component.__lsc || (component.__lsc = {});
|
||||||
|
|
||||||
|
return cache[key + eventPath] || (cache[key + eventPath] = function(e) {
|
||||||
|
let t = e && e.target || this, state = {}, obj = state,
|
||||||
|
v = typeof eventPath === 'string' ?
|
||||||
|
delve(e, eventPath) :
|
||||||
|
t.nodeName ? (t.type.match(/^che|rad/) ? t.checked : t.value) :
|
||||||
|
e,
|
||||||
|
i = 0;
|
||||||
|
for (; i < path.length - 1; i++) {
|
||||||
|
obj = obj[path[i]] ||
|
||||||
|
(obj[path[i]] = !i && component.state[path[i]] || {});
|
||||||
|
}
|
||||||
|
obj[path[i]] = v;
|
||||||
|
component.setState(state);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
!function(){var n,l,u,t,i,o,r,e,f={},c=[],a=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;function s(n,l){for(var u in l)n[u]=l[u];return n}function v(n){var l=n.parentNode;l&&l.removeChild(n)}function h(n,l,u){var t,i=arguments,o={};for(t in l)"key"!==t&&"ref"!==t&&(o[t]=l[t]);if(arguments.length>3)for(u=[u],t=3;t<arguments.length;t++)u.push(i[t]);if(null!=u&&(o.children=u),"function"==typeof n&&null!=n.defaultProps)for(t in n.defaultProps)void 0===o[t]&&(o[t]=n.defaultProps[t]);return y(n,o,l&&l.key,l&&l.ref,null)}function y(l,u,t,i,o){var r={type:l,props:u,key:t,ref:i,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,constructor:void 0,__v:o};return null==o&&(r.__v=r),n.vnode&&n.vnode(r),r}function p(n){return n.children}function d(n,l){this.props=n,this.context=l}function _(n,l){if(null==l)return n.__?_(n.__,n.__.__k.indexOf(n)+1):null;for(var u;l<n.__k.length;l++)if(null!=(u=n.__k[l])&&null!=u.__e)return u.__e;return"function"==typeof n.type?_(n):null}function m(n){var l,u;if(null!=(n=n.__)&&null!=n.__c){for(n.__e=n.__c.base=null,l=0;l<n.__k.length;l++)if(null!=(u=n.__k[l])&&null!=u.__e){n.__e=n.__c.base=u.__e;break}return m(n)}}function k(l){(!l.__d&&(l.__d=!0)&&u.push(l)&&!w.__r++||i!==n.debounceRendering)&&((i=n.debounceRendering)||t)(w)}function w(){for(var n;w.__r=u.length;)n=u.sort(function(n,l){return n.__v.__b-l.__v.__b}),u=[],n.some(function(n){var l,u,t,i,o,r,e;n.__d&&(r=(o=(l=n).__v).__e,(e=l.__P)&&(u=[],(t=s({},o)).__v=t,i=N(e,o,t,l.__n,void 0!==e.ownerSVGElement,null,u,null==r?_(o):r),z(u,o),i!=r&&m(o)))})}function g(n,l,u,t,i,o,r,e,a,s){var h,d,m,k,w,g,x,C=t&&t.__k||c,A=C.length;for(a==f&&(a=null!=r?r[0]:A?_(t,0):null),u.__k=[],h=0;h<l.length;h++)if(null!=(k=u.__k[h]=null==(k=l[h])||"boolean"==typeof k?null:"string"==typeof k||"number"==typeof k?y(null,k,null,null,k):Array.isArray(k)?y(p,{children:k},null,null,null):null!=k.__e||null!=k.__c?y(k.type,k.props,k.key,null,k.__v):k)){if(k.__=u,k.__b=u.__b+1,null===(m=C[h])||m&&k.key==m.key&&k.type===m.type)C[h]=void 0;else for(d=0;d<A;d++){if((m=C[d])&&k.key==m.key&&k.type===m.type){C[d]=void 0;break}m=null}w=N(n,k,m=m||f,i,o,r,e,a,s),(d=k.ref)&&m.ref!=d&&(x||(x=[]),m.ref&&x.push(m.ref,null,k),x.push(d,k.__c||w,k)),null!=w?(null==g&&(g=w),a=b(n,k,m,C,r,w,a),"option"==u.type?n.value="":"function"==typeof u.type&&(u.__d=a)):a&&m.__e==a&&a.parentNode!=n&&(a=_(m))}if(u.__e=g,null!=r&&"function"!=typeof u.type)for(h=r.length;h--;)null!=r[h]&&v(r[h]);for(h=A;h--;)null!=C[h]&&j(C[h],C[h]);if(x)for(h=0;h<x.length;h++)$(x[h],x[++h],x[++h])}function b(n,l,u,t,i,o,r){var e,f,c;if(void 0!==l.__d)e=l.__d,l.__d=void 0;else if(i==u||o!=r||null==o.parentNode)n:if(null==r||r.parentNode!==n)n.appendChild(o),e=null;else{for(f=r,c=0;(f=f.nextSibling)&&c<t.length;c+=2)if(f==o)break n;n.insertBefore(o,r),e=r}return void 0!==e?e:o.nextSibling}function x(n,l,u,t,i){var o;for(o in u)"children"===o||"key"===o||o in l||A(n,o,null,u[o],t);for(o in l)i&&"function"!=typeof l[o]||"children"===o||"key"===o||"value"===o||"checked"===o||u[o]===l[o]||A(n,o,l[o],u[o],t)}function C(n,l,u){"-"===l[0]?n.setProperty(l,u):n[l]="number"==typeof u&&!1===a.test(l)?u+"px":null==u?"":u}function A(n,l,u,t,i){var o,r,e,f,c;if(i?"className"===l&&(l="class"):"class"===l&&(l="className"),"style"===l)if(o=n.style,"string"==typeof u)o.cssText=u;else{if("string"==typeof t&&(o.cssText="",t=null),t)for(f in t)u&&f in u||C(o,f,"");if(u)for(c in u)t&&u[c]===t[c]||C(o,c,u[c])}else"o"===l[0]&&"n"===l[1]?(r=l!==(l=l.replace(/Capture$/,"")),e=l.toLowerCase(),l=(e in n?e:l).slice(2),u?(t||n.addEventListener(l,P,r),(n.l||(n.l={}))[l]=u):n.removeEventListener(l,P,r)):"list"!==l&&"tagName"!==l&&"form"!==l&&"type"!==l&&"size"!==l&&!i&&l in n?n[l]=null==u?"":u:"function"!=typeof u&&"dangerouslySetInnerHTML"!==l&&(l!==(l=l.replace(/^xlink:?/,""))?null==u||!1===u?n.removeAttributeNS("http://www.w3.org/1999/xlink",l.toLowerCase()):n.setAttributeNS("http://www.w3.org/1999/xlink",l.toLowerCase(),u):null==u||!1===u&&!/^ar/.test(l)?n.removeAttribute(l):n.setAttribute(l,u))}function P(l){this.l[l.type](n.event?n.event(l):l)}function E(n,l,u){var t,i;for(t=0;t<n.__k.length;t++)(i=n.__k[t])&&(i.__=n,i.__e&&("function"==typeof i.type&&i.__k.length>1&&E(i,l,u),l=b(u,i,i,n.__k,null,i.__e,l),"function"==typeof n.type&&(n.__d=l)))}function N(l,u,t,i,o,r,e,f,c){var a,v,h,y,_,m,k,w,b,x,C,A=u.type;if(void 0!==u.constructor)return null;(a=n.__b)&&a(u);try{n:if("function"==typeof A){if(w=u.props,b=(a=A.contextType)&&i[a.__c],x=a?b?b.props.value:a.__:i,t.__c?k=(v=u.__c=t.__c).__=v.__E:("prototype"in A&&A.prototype.render?u.__c=v=new A(w,x):(u.__c=v=new d(w,x),v.constructor=A,v.render=F),b&&b.sub(v),v.props=w,v.state||(v.state={}),v.context=x,v.__n=i,h=v.__d=!0,v.__h=[]),null==v.__s&&(v.__s=v.state),null!=A.getDerivedStateFromProps&&(v.__s==v.state&&(v.__s=s({},v.__s)),s(v.__s,A.getDerivedStateFromProps(w,v.__s))),y=v.props,_=v.state,h)null==A.getDerivedStateFromProps&&null!=v.componentWillMount&&v.componenLine truncated
|
||||||
|
//# sourceMappingURL=preact.min.js.map
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#container { margin-right: auto; margin-left: auto; max-width: 480px; }
|
||||||
|
#info { background: #d0f0f0; border-radius: .5em; padding: 2em; }
|
||||||
|
#dashboard { background: #f0f0f0; border-radius: .5em; padding: 0.5em; max-height: 10em; overflow: auto; height: 100%; margin-top: 1em; }
|
||||||
|
#form { background: #d0c0f0; border-radius: .5em; padding: 0.5em; max-height: 10em; overflow: auto; height: 100%; margin-top: 1em; }
|
||||||
|
button { width: 100%; }
|
||||||
|
button, select, input, label::before, textarea { outline: none; box-shadow:none !important; border: 1px solid #ccc !important; }
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
PROG ?= example
|
||||||
|
ROOT ?= $(realpath $(CURDIR)/../..)
|
||||||
|
DEFS ?= -DMG_ENABLE_LINES=1 -DMG_ENABLE_DIRECTORY_LISTING=1
|
||||||
|
CFLAGS ?= -I../.. -W -Wall -DMG_ENABLE_IPV6=1 $(DEFS) $(EXTRA)
|
||||||
|
VCFLAGS = /nologo /W3 /O2 /I../.. $(DEFS) $(EXTRA)
|
||||||
|
VC98 = docker run --rm -e WINEDEBUG=-all -v $(ROOT):$(ROOT) -w $(CURDIR) docker.io/mdashnet/vc98
|
||||||
|
GCC = docker run --rm -v $(ROOT):$(ROOT) -w $(CURDIR) mdashnet/cc2
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(DEBUGGER) ./$(PROG)
|
||||||
|
|
||||||
|
$(PROG):
|
||||||
|
$(CC) ../../mongoose.c main.c -I../.. $(CFLAGS) $(EXTRA) -o $@
|
||||||
|
|
||||||
|
mongoose_mac: $(PROG)
|
||||||
|
cp $(PROG) $@
|
||||||
|
|
||||||
|
mongoose_linux: main.c
|
||||||
|
$(GCC) $(CC) ../../mongoose.c main.c $(CFLAGS) -o $@
|
||||||
|
|
||||||
|
mongoose.exe: main.c
|
||||||
|
$(VC98) wine cl ../../mongoose.c main.c $(VCFLAGS) ws2_32.lib /Fe$@
|
||||||
|
|
||||||
|
zip: mongoose.exe mongoose_linux mongoose_mac
|
||||||
|
rm -rf mongoose; mkdir mongoose
|
||||||
|
cp mongoose.exe mongoose_mac mongoose_linux mongoose
|
||||||
|
zip -r mongoose.zip mongoose
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb mongoose mongoose_* mongoose.*
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
// Copyright (c) 2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static const char *s_debug_level = "2";
|
||||||
|
static const char *s_web_root_dir = ".";
|
||||||
|
static const char *s_listening_address = "http://localhost:8000";
|
||||||
|
static const char *s_enable_hexdump = "no";
|
||||||
|
static const char *s_rewrites = "";
|
||||||
|
|
||||||
|
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
// struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
mg_http_serve_dir(c, ev_data, s_web_root_dir);
|
||||||
|
}
|
||||||
|
(void) fn_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usage(const char *prog) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Mongoose v.%s, built " __DATE__ " " __TIME__
|
||||||
|
"\nUsage: %s OPTIONS\n"
|
||||||
|
" -D LEVEL - debug level, from 0 to 4, default: '%s'\n"
|
||||||
|
" -H yes|no - enable traffic hexdump, default: '%s'\n"
|
||||||
|
" -d DIR - directory to serve, default: '%s'\n"
|
||||||
|
" -l ADDR - listening address, default: '%s'\n"
|
||||||
|
" -r LIST - list of URI=DIR,... URI rewrites, default: '%s'\n",
|
||||||
|
MG_VERSION, prog, s_debug_level, s_enable_hexdump, s_web_root_dir,
|
||||||
|
s_listening_address, s_rewrites);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
struct mg_mgr mgr;
|
||||||
|
struct mg_connection *c;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Parse command-line flags
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
if (strcmp(argv[i], "-d") == 0) {
|
||||||
|
s_web_root_dir = argv[++i];
|
||||||
|
} else if (strcmp(argv[i], "-D") == 0) {
|
||||||
|
s_debug_level = argv[++i];
|
||||||
|
} else if (strcmp(argv[i], "-H") == 0) {
|
||||||
|
s_enable_hexdump = argv[++i];
|
||||||
|
} else if (strcmp(argv[i], "-l") == 0) {
|
||||||
|
s_listening_address = argv[++i];
|
||||||
|
} else if (strcmp(argv[i], "-r") == 0) {
|
||||||
|
s_rewrites = argv[++i];
|
||||||
|
} else {
|
||||||
|
usage(argv[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise stuff
|
||||||
|
mg_log_set(s_debug_level);
|
||||||
|
mg_mgr_init(&mgr);
|
||||||
|
if ((c = mg_http_listen(&mgr, s_listening_address, cb, &mgr)) == NULL) {
|
||||||
|
LOG(LL_ERROR, ("Cannot listen on %s. Use http://ADDR:PORT or :PORT",
|
||||||
|
s_listening_address));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (mg_casecmp(s_enable_hexdump, "yes") == 0) c->is_hexdumping = 1;
|
||||||
|
|
||||||
|
// Start infinite event loop
|
||||||
|
LOG(LL_INFO, ("Starting Mongoose web server v%s", MG_VERSION));
|
||||||
|
for (;;) mg_mgr_poll(&mgr, 1000);
|
||||||
|
mg_mgr_free(&mgr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
PROG ?= example
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(DEBUGGER) ./$(PROG)
|
||||||
|
|
||||||
|
$(PROG):
|
||||||
|
$(CC) ../../mongoose.c -I../.. $(CFLAGS) $(EXTRA) -o $(PROG) main.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb log.txt
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (c) 2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
// HTTP request handler function. It implements the following endpoints:
|
||||||
|
// /upload - Saves the next file chunk
|
||||||
|
// all other URI - serves web_root/ directory
|
||||||
|
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
if (mg_http_match_uri(hm, "/upload")) {
|
||||||
|
mg_http_upload(c, hm, "/tmp");
|
||||||
|
} else {
|
||||||
|
mg_http_serve_dir(c, ev_data, "web_root");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_mgr mgr;
|
||||||
|
struct mg_timer t1;
|
||||||
|
|
||||||
|
mg_mgr_init(&mgr);
|
||||||
|
mg_log_set("3");
|
||||||
|
mg_http_listen(&mgr, "http://localhost:8000", cb, NULL);
|
||||||
|
|
||||||
|
for (;;) mg_mgr_poll(&mgr, 50);
|
||||||
|
mg_mgr_free(&mgr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
// Copyright (c) 2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
|
||||||
|
// Helper function to display upload status
|
||||||
|
var setStatus = function(text) {
|
||||||
|
document.getElementById('el3').innerText = text;
|
||||||
|
};
|
||||||
|
|
||||||
|
// When user clicks on a button, trigger file selection dialog
|
||||||
|
var button = document.getElementById('el2');
|
||||||
|
button.onclick = function(ev) {
|
||||||
|
input.click();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send a large blob of data chunk by chunk
|
||||||
|
var sendFileData = function(name, data, chunkSize) {
|
||||||
|
var sendChunk = function(offset) {
|
||||||
|
var chunk = data.subarray(offset, offset + chunkSize) || '';
|
||||||
|
var opts = {method: 'POST', body: chunk};
|
||||||
|
var url = '/upload?offset=' + offset + '&name=' + encodeURIComponent(name);
|
||||||
|
setStatus(
|
||||||
|
'sending bytes ' + offset + '..' + (offset + chunk.length) + ' of ' +
|
||||||
|
data.length);
|
||||||
|
fetch(url, opts).then(function(res) {
|
||||||
|
if (chunk.length > 0) sendChunk(offset + chunk.length);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
sendChunk(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
// If user selected a file, read it into memory and trigger sendFileData()
|
||||||
|
var input = document.getElementById('el1');
|
||||||
|
input.onchange = function(ev) {
|
||||||
|
if (!ev.target.files[0]) return;
|
||||||
|
var f = ev.target.files[0], r = new FileReader();
|
||||||
|
r.readAsArrayBuffer(f);
|
||||||
|
r.onload = function() {
|
||||||
|
ev.target.value = '';
|
||||||
|
sendFileData(f.name, new Uint8Array(r.result), 4096);
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>example</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<style>
|
||||||
|
#container { margin-right: auto; margin-left: auto; max-width: 480px; }
|
||||||
|
#info { background: #e0f0f0; border-radius: .5em; padding: 2em; }
|
||||||
|
#wrapper { margin-top: 1em; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="container">
|
||||||
|
<div id="info">
|
||||||
|
Mongoose always buffers a full HTTP message before invoking
|
||||||
|
MG_EV_HTTP_MSG event. Big POST request require of lot
|
||||||
|
of RAM to buffer everything. Therefore, in order to upload large
|
||||||
|
files on memory-constrained system, a large file should be send
|
||||||
|
in small chunks.
|
||||||
|
<br/><br/>
|
||||||
|
In this example, JavaScript code on this page sends uploaded
|
||||||
|
file in 2k chunks using an <code>/upload</code> endpoint.
|
||||||
|
Uploaded file is stored in <code>/tmp</code> directory by the helper
|
||||||
|
API function <code>mg_http_upload()</code>
|
||||||
|
</div>
|
||||||
|
<div id="wrapper">
|
||||||
|
<input type="file" id="el1" style="display: none"/>
|
||||||
|
<button id="el2">choose file...</button>
|
||||||
|
<div id="el3"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<script src="app.js"></script>
|
||||||
|
</html>
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
#include "mongoose.h"
|
|
||||||
|
|
||||||
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
|
||||||
switch (ev) {
|
|
||||||
case MG_REQUEST:
|
|
||||||
mg_send_file(conn, "file.c");
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "mongoose.h"
|
|
||||||
|
|
||||||
static int static_value = 123; // Exposed and changeable via the form
|
|
||||||
|
|
||||||
static void print_html_form(struct mg_connection *conn) {
|
|
||||||
mg_send_header(conn, "Content-Type", "text/html");
|
|
||||||
mg_send_header(conn, "Cache-Control", "max-age=0, post-check=0, "
|
|
||||||
"pre-check=0, no-store, no-cache, must-revalidate");
|
|
||||||
|
|
||||||
// Note that all the following normally should reside in static HTML page
|
|
||||||
mg_printf_data(conn, "%s", "<html><head>");
|
|
||||||
// It is better to use local copy though
|
|
||||||
mg_printf_data(conn, "<script src=\"%s\"></script>",
|
|
||||||
"http://code.jquery.com/jquery-1.11.0.min.js");
|
|
||||||
mg_printf_data(conn, "%s", "<script> jQuery(function() {\n");
|
|
||||||
// Here is the ajax call that fetches data from the device and
|
|
||||||
// updates the form
|
|
||||||
mg_printf_data(conn, "%s", "$.ajax({ url: '/get_value', dataType: 'json', "
|
|
||||||
"success: function(d) { $('#val').val(d.value); }});\n");
|
|
||||||
// This ajax call is triggered when submit button is pressed. It sends new
|
|
||||||
// value to the device.
|
|
||||||
mg_printf_data(conn, "%s", "$(document).on('click', '#button', function() {"
|
|
||||||
" $.ajax({ url: '/set_value', dataType: 'json', "
|
|
||||||
" data: { new_value: $('#val').val() } });\n"
|
|
||||||
" return false; });\n");
|
|
||||||
mg_printf_data(conn, "%s", "});</script>");
|
|
||||||
mg_printf_data(conn, "%s", "</head><body>");
|
|
||||||
mg_printf_data(conn, "%s", "<h1>Ajax form submission example</h1>");
|
|
||||||
mg_printf_data(conn, "%s", "<form>");
|
|
||||||
mg_printf_data(conn, "%s", "Device value: <input type=text id=val />");
|
|
||||||
mg_printf_data(conn, "%s", "<input type=submit id=button />");
|
|
||||||
mg_printf_data(conn, "%s", "</form>");
|
|
||||||
mg_printf_data(conn, "%s", "</body></html>");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
|
||||||
if (ev == MG_REQUEST) {
|
|
||||||
if (strcmp(conn->uri, "/get_value") == 0) {
|
|
||||||
mg_printf_data(conn, "{\"value\": %d}", static_value);
|
|
||||||
} else if (strcmp(conn->uri, "/set_value") == 0) {
|
|
||||||
// This Ajax endpoint sets the new value for the device variable
|
|
||||||
char buf[100] = "";
|
|
||||||
mg_get_var(conn, "new_value", buf, sizeof(buf)); // Get form variable
|
|
||||||
static_value = atoi(buf); // Set new value
|
|
||||||
mg_printf_data(conn, "%s", "{\"success\": true}");
|
|
||||||
printf("Setting value to [%d]\n", static_value); // Debug trace
|
|
||||||
} else {
|
|
||||||
// Better way is to set "document_root" option, put "index.html" file
|
|
||||||
// into document_root and return MG_FALSE here. We're printing HTML
|
|
||||||
// page by hands just to keep everything in one C file.
|
|
||||||
print_html_form(conn);
|
|
||||||
}
|
|
||||||
return MG_TRUE;
|
|
||||||
} else if (ev == MG_AUTH) {
|
|
||||||
return MG_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "mongoose.h"
|
|
||||||
|
|
||||||
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
|
||||||
int result = MG_FALSE;
|
|
||||||
|
|
||||||
if (ev == MG_REQUEST) {
|
|
||||||
mg_printf_data(conn, "Hello! Requested URI is [%s]", conn->uri);
|
|
||||||
result = MG_TRUE;
|
|
||||||
} else if (ev == MG_AUTH) {
|
|
||||||
result = MG_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
<? 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>
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
PROG ?= example
|
||||||
|
ARGS ?= http://www.ladyada.net/
|
||||||
|
MBEDTLS_DIR ?=
|
||||||
|
|
||||||
|
ifeq "$(MBEDTLS_DIR)" ""
|
||||||
|
else
|
||||||
|
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS_DIR)/include -I/usr/include
|
||||||
|
CFLAGS += -L$(MBEDTLS_DIR)/lib -lmbedtls -lmbedcrypto -lmbedx509
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(DEBUGGER) ./$(PROG) $(ARGS)
|
||||||
|
|
||||||
|
|
||||||
|
$(PROG): main.c
|
||||||
|
$(CC) ../../mongoose.c -I../.. -W -Wall $(CFLAGS) -o $(PROG) main.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb
|
||||||
@@ -0,0 +1,507 @@
|
|||||||
|
Subject: O=Digital Signature Trust Co., CN=DST Root CA X3
|
||||||
|
Not Before: Sep 30 21:12:19 2000 GMT
|
||||||
|
Not After : Sep 30 14:01:15 2021 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
|
||||||
|
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
||||||
|
DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
|
||||||
|
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
|
||||||
|
Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||||
|
AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
|
||||||
|
rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
|
||||||
|
OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
|
||||||
|
xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
|
||||||
|
7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
|
||||||
|
aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
|
||||||
|
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
|
||||||
|
SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
|
||||||
|
ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
|
||||||
|
AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
|
||||||
|
R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
|
||||||
|
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
|
||||||
|
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root
|
||||||
|
Not Before: May 12 18:46:00 2000 GMT
|
||||||
|
Not After : May 12 23:59:00 2025 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
|
||||||
|
RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
|
||||||
|
VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
|
||||||
|
DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
|
||||||
|
ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
|
||||||
|
VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
|
||||||
|
mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
|
||||||
|
IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
|
||||||
|
mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
|
||||||
|
XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
|
||||||
|
dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
|
||||||
|
jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
|
||||||
|
BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
|
||||||
|
DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
|
||||||
|
9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
|
||||||
|
jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
|
||||||
|
Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
|
||||||
|
ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
|
||||||
|
R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA
|
||||||
|
Not Before: May 21 04:00:00 2002 GMT
|
||||||
|
Not After : May 21 04:00:00 2022 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
|
||||||
|
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
|
||||||
|
YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
|
||||||
|
EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
|
||||||
|
R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
|
||||||
|
9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
|
||||||
|
fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
|
||||||
|
iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
|
||||||
|
1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
|
||||||
|
bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
|
||||||
|
MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
|
||||||
|
ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
|
||||||
|
uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
|
||||||
|
Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
|
||||||
|
tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
|
||||||
|
PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
|
||||||
|
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
|
||||||
|
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=Symantec Corporation, OU=Symantec Trust Network, CN=Symantec Class 3 ECC 256 bit SSL CA - G2
|
||||||
|
Not Before: May 12 00:00:00 2015 GMT
|
||||||
|
Not After : May 11 23:59:59 2025 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEajCCA1KgAwIBAgIQP5KHvp0dpKN6nfYoLndaxDANBgkqhkiG9w0BAQsFADCB
|
||||||
|
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||||
|
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
|
||||||
|
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
|
||||||
|
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
|
||||||
|
aG9yaXR5IC0gRzUwHhcNMTUwNTEyMDAwMDAwWhcNMjUwNTExMjM1OTU5WjCBgDEL
|
||||||
|
MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD
|
||||||
|
VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMTEwLwYDVQQDEyhTeW1hbnRlYyBD
|
||||||
|
bGFzcyAzIEVDQyAyNTYgYml0IFNTTCBDQSAtIEcyMFkwEwYHKoZIzj0CAQYIKoZI
|
||||||
|
zj0DAQcDQgAEDxukkdfnrOfRTk63ZFvhj39uBNOrONtEt0Bcbb2WljffeYmGZ/ex
|
||||||
|
Hwie/WM7RoyfvVPoFdyXPiuBRq2Gfw4BOaOCAV0wggFZMC4GCCsGAQUFBwEBBCIw
|
||||||
|
IDAeBggrBgEFBQcwAYYSaHR0cDovL3Muc3ltY2QuY29tMBIGA1UdEwEB/wQIMAYB
|
||||||
|
Af8CAQAwZQYDVR0gBF4wXDBaBgpghkgBhvhFAQc2MEwwIwYIKwYBBQUHAgEWF2h0
|
||||||
|
dHBzOi8vZC5zeW1jYi5jb20vY3BzMCUGCCsGAQUFBwICMBkaF2h0dHBzOi8vZC5z
|
||||||
|
eW1jYi5jb20vcnBhMC8GA1UdHwQoMCYwJKAioCCGHmh0dHA6Ly9zLnN5bWNiLmNv
|
||||||
|
bS9wY2EzLWc1LmNybDAOBgNVHQ8BAf8EBAMCAQYwKwYDVR0RBCQwIqQgMB4xHDAa
|
||||||
|
BgNVBAMTE1NZTUMtRUNDLUNBLXAyNTYtMjIwHQYDVR0OBBYEFCXwiuFLetkBlQrt
|
||||||
|
xlPxjHgf2fP4MB8GA1UdIwQYMBaAFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG
|
||||||
|
SIb3DQEBCwUAA4IBAQAMMGUXBaWTdaLxsTGtcB/naqjIQrLvoV9NG+7MoHpGd/69
|
||||||
|
dZ/h2zOy7sGFUHoG/0HGRA9rxT/5w5GkEVIVkxtWyIWWq6rs4CTZt8Bej/KHYRbo
|
||||||
|
jtEDUkCTZSTLiCvguPyvinXgxy+LHT+PmdtEfXsvcdbeBSWUYpOsDYvD2hNtz9dw
|
||||||
|
Od5nBosMApmdxt+z7LQyZu8wMnfI1U6IMO+RWowxZ8uy0oswdFYd32l9xe+aAE/k
|
||||||
|
y9alLu/M9pvxiUKufqHJRgDBKA6uDjHLMPX+/nxXaNCPX3SI4KVZ1stHQ/U5oNlM
|
||||||
|
dHN9umAvlU313g0IgJrjsQ2nIdf9dsdP+6lrmP7s
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5
|
||||||
|
Not Before: Nov 8 00:00:00 2006 GMT
|
||||||
|
Not After : Jul 16 23:59:59 2036 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
|
||||||
|
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||||
|
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
|
||||||
|
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
|
||||||
|
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
|
||||||
|
aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
|
||||||
|
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
|
||||||
|
ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
|
||||||
|
biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
|
||||||
|
U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
|
||||||
|
aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
|
||||||
|
nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
|
||||||
|
t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
|
||||||
|
SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
|
||||||
|
BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
|
||||||
|
rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
|
||||||
|
NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
|
||||||
|
BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
|
||||||
|
BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
|
||||||
|
aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
|
||||||
|
MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
|
||||||
|
p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
|
||||||
|
5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
|
||||||
|
WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
|
||||||
|
4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
|
||||||
|
hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority
|
||||||
|
Not Before: Jun 29 17:06:20 2004 GMT
|
||||||
|
Not After : Jun 29 17:06:20 2034 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
|
||||||
|
MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
|
||||||
|
YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
|
||||||
|
MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
|
||||||
|
ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
|
||||||
|
MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
|
||||||
|
ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
|
||||||
|
PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
|
||||||
|
wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
|
||||||
|
EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
|
||||||
|
avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
|
||||||
|
YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
|
||||||
|
sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
|
||||||
|
/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
|
||||||
|
IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
|
||||||
|
YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
|
||||||
|
ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
|
||||||
|
OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
|
||||||
|
TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
|
||||||
|
HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
|
||||||
|
dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
|
||||||
|
ReYNnyicsbkqWletNw+vHX/bvZ8=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
# Note: Amazon ATS endpoint uses this (2018/12/18)
|
||||||
|
Subject: C=US, O=Starfield Technologies, Inc., OU=Starfield Class 2 Certification Authority
|
||||||
|
Not Before: Jun 29 17:39:16 2004 GMT
|
||||||
|
Not After : Jun 29 17:39:16 2034 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
|
||||||
|
MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
|
||||||
|
U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
|
||||||
|
NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
|
||||||
|
ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
|
||||||
|
ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
|
||||||
|
DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
|
||||||
|
8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
|
||||||
|
+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
|
||||||
|
X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
|
||||||
|
K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
|
||||||
|
1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
|
||||||
|
A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
|
||||||
|
zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
|
||||||
|
YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
|
||||||
|
bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
|
||||||
|
DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
|
||||||
|
L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
|
||||||
|
eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
|
||||||
|
xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
|
||||||
|
VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
|
||||||
|
WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Sep 1 00:00:00 2009 GMT
|
||||||
|
Not After : Dec 31 23:59:59 2037 GMT
|
||||||
|
Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Root Certificate Authority - G2
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx
|
||||||
|
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
|
||||||
|
HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs
|
||||||
|
ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw
|
||||||
|
MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
|
||||||
|
b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj
|
||||||
|
aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp
|
||||||
|
Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||||
|
ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg
|
||||||
|
nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1
|
||||||
|
HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N
|
||||||
|
Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN
|
||||||
|
dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0
|
||||||
|
HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
|
||||||
|
BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G
|
||||||
|
CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU
|
||||||
|
sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3
|
||||||
|
4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg
|
||||||
|
8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
|
||||||
|
pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1
|
||||||
|
mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Services Root Certificate Authority - G2
|
||||||
|
Not Before: Sep 1 00:00:00 2009 GMT
|
||||||
|
Not After : Dec 31 23:59:59 2037 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
|
||||||
|
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
|
||||||
|
HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs
|
||||||
|
ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
|
||||||
|
MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD
|
||||||
|
VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy
|
||||||
|
ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy
|
||||||
|
dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
|
||||||
|
hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p
|
||||||
|
OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2
|
||||||
|
8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K
|
||||||
|
Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe
|
||||||
|
hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk
|
||||||
|
6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw
|
||||||
|
DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q
|
||||||
|
AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI
|
||||||
|
bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB
|
||||||
|
ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z
|
||||||
|
qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
|
||||||
|
iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn
|
||||||
|
0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN
|
||||||
|
sSi6
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign
|
||||||
|
Not Before: Dec 15 08:00:00 2006 GMT
|
||||||
|
Not After : Dec 15 08:00:00 2021 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
|
||||||
|
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
|
||||||
|
Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
|
||||||
|
MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
|
||||||
|
A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
|
||||||
|
hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
|
||||||
|
v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
|
||||||
|
eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
|
||||||
|
tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
|
||||||
|
C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
|
||||||
|
zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
|
||||||
|
mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
|
||||||
|
V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
|
||||||
|
bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
|
||||||
|
3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
|
||||||
|
J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
|
||||||
|
291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
|
||||||
|
ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
|
||||||
|
AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
|
||||||
|
TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA
|
||||||
|
Not Before: Nov 10 00:00:00 2006 GMT
|
||||||
|
Not After : Nov 10 00:00:00 2031 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||||
|
ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
|
||||||
|
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
||||||
|
LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
|
||||||
|
RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
|
||||||
|
+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
|
||||||
|
PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
|
||||||
|
xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
|
||||||
|
Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
|
||||||
|
hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
|
||||||
|
EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
|
||||||
|
MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
|
||||||
|
FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
|
||||||
|
nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
|
||||||
|
eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
|
||||||
|
hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
|
||||||
|
Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
|
||||||
|
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
|
||||||
|
+OkuE6N36B9K
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA
|
||||||
|
Not Before: Nov 10 00:00:00 2006 GMT
|
||||||
|
Not After : Nov 10 00:00:00 2031 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||||
|
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||||
|
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||||
|
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||||
|
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||||
|
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||||
|
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||||
|
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||||
|
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||||
|
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||||
|
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||||
|
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||||
|
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||||
|
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||||
|
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||||
|
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||||
|
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||||
|
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
# *.azure-devices.de use this root.
|
||||||
|
Subject: C = DE, O = D-Trust GmbH, CN = D-TRUST Root Class 3 CA 2 2009
|
||||||
|
Not Before: Nov 5 08:35:58 2009 GMT
|
||||||
|
Not After : Nov 5 08:35:58 2029 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF
|
||||||
|
MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD
|
||||||
|
bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha
|
||||||
|
ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM
|
||||||
|
HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB
|
||||||
|
BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03
|
||||||
|
UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42
|
||||||
|
tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R
|
||||||
|
ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM
|
||||||
|
lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp
|
||||||
|
/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G
|
||||||
|
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G
|
||||||
|
A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj
|
||||||
|
dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy
|
||||||
|
MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl
|
||||||
|
cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js
|
||||||
|
L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL
|
||||||
|
BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni
|
||||||
|
acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
|
||||||
|
o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K
|
||||||
|
zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8
|
||||||
|
PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y
|
||||||
|
Johw1+qRzT65ysCQblrGXnRl11z+o+I=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
# https://www.amazontrust.com/repository/
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 1
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : Jan 17 00:00:00 2038 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
|
||||||
|
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
|
||||||
|
b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
|
||||||
|
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
|
||||||
|
b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
|
||||||
|
ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
|
||||||
|
9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
|
||||||
|
IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
|
||||||
|
VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
|
||||||
|
93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
|
||||||
|
jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
|
||||||
|
AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
|
||||||
|
A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
|
||||||
|
U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
|
||||||
|
N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
|
||||||
|
o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
|
||||||
|
5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
|
||||||
|
rqXRfboQnoZsG4q5WTP468SQvvG5
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 2
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : May 26 00:00:00 2040 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF
|
||||||
|
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
|
||||||
|
b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL
|
||||||
|
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
|
||||||
|
b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK
|
||||||
|
gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ
|
||||||
|
W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg
|
||||||
|
1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K
|
||||||
|
8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r
|
||||||
|
2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me
|
||||||
|
z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR
|
||||||
|
8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj
|
||||||
|
mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz
|
||||||
|
7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6
|
||||||
|
+XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI
|
||||||
|
0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB
|
||||||
|
Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm
|
||||||
|
UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2
|
||||||
|
LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY
|
||||||
|
+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS
|
||||||
|
k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl
|
||||||
|
7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm
|
||||||
|
btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl
|
||||||
|
urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+
|
||||||
|
fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63
|
||||||
|
n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE
|
||||||
|
76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H
|
||||||
|
9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT
|
||||||
|
4PsJYGw=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : May 26 00:00:00 2040 GMT
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 3
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5
|
||||||
|
MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
|
||||||
|
Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
|
||||||
|
A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
|
||||||
|
Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl
|
||||||
|
ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j
|
||||||
|
QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr
|
||||||
|
ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr
|
||||||
|
BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM
|
||||||
|
YyRIHN8wfdVoOw==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : May 26 00:00:00 2040 GMT
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 4
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5
|
||||||
|
MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
|
||||||
|
Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
|
||||||
|
A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
|
||||||
|
Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi
|
||||||
|
9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk
|
||||||
|
M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB
|
||||||
|
/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB
|
||||||
|
MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw
|
||||||
|
CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW
|
||||||
|
1KyLa2tJElMzrdfkviT8tQp21KW8EA==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Nov 10 00:00:00 2006 GMT
|
||||||
|
Not After : Nov 10 00:00:00 2031 GMT
|
||||||
|
Subject: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||||
|
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||||
|
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||||
|
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||||
|
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||||
|
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||||
|
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||||
|
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||||
|
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||||
|
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||||
|
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||||
|
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||||
|
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||||
|
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||||
|
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||||
|
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||||
|
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||||
|
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Nov 13 00:00:00 2012 GMT
|
||||||
|
Not After : Jan 19 03:14:07 2038 GMT
|
||||||
|
Subject: OU = GlobalSign ECC Root CA - R4, O = GlobalSign, CN = GlobalSign
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk
|
||||||
|
MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH
|
||||||
|
bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
|
||||||
|
DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
|
||||||
|
QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
|
||||||
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ
|
||||||
|
FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw
|
||||||
|
DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F
|
||||||
|
uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX
|
||||||
|
kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs
|
||||||
|
ewv4n4Q=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Nov 1 00:00:42 2018 GMT
|
||||||
|
Not After : Nov 1 00:00:42 2042 GMT
|
||||||
|
Subject: C = US, O = Google Trust Services LLC, CN = GTS LTSR
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBxTCCAWugAwIBAgINAfD3nVndblD3QnNxUDAKBggqhkjOPQQDAjBEMQswCQYD
|
||||||
|
VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzERMA8G
|
||||||
|
A1UEAxMIR1RTIExUU1IwHhcNMTgxMTAxMDAwMDQyWhcNNDIxMTAxMDAwMDQyWjBE
|
||||||
|
MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
|
||||||
|
QzERMA8GA1UEAxMIR1RTIExUU1IwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATN
|
||||||
|
8YyO2u+yCQoZdwAkUNv5c3dokfULfrA6QJgFV2XMuENtQZIG5HUOS6jFn8f0ySlV
|
||||||
|
eORCxqFyjDJyRn86d+Iko0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUw
|
||||||
|
AwEB/zAdBgNVHQ4EFgQUPv7/zFLrvzQ+PfNA0OQlsV+4u1IwCgYIKoZIzj0EAwID
|
||||||
|
SAAwRQIhAPKuf/VtBHqGw3TUwUIq7TfaExp3bH7bjCBmVXJupT9FAiBr0SmCtsuk
|
||||||
|
miGgpajjf/gFigGM34F9021bCWs1MbL0SA==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
// Copyright (c) 2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// Example HTTP client. Usage:
|
||||||
|
// make
|
||||||
|
// ./example http://www.ladyada.net/
|
||||||
|
//
|
||||||
|
// To enable SSL/TLS for this client, build it like this:
|
||||||
|
// make MBEDTLS_DIR=/path/to/your/mbedtls/installation
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
// Print HTTP response and signal that we're done
|
||||||
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
printf("%.*s", (int) hm->message.len, hm->message.ptr);
|
||||||
|
c->is_closing = 1;
|
||||||
|
*(bool *) fn_data = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
struct mg_mgr mgr; // Event manager
|
||||||
|
mg_mgr_init(&mgr); // Initialise event manager
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
fprintf(stderr, "Usage: %s URL\n", argv[0]); // Print error
|
||||||
|
} else {
|
||||||
|
bool done = false; // Event handler flips it to true
|
||||||
|
struct mg_connection *c = mg_http_connect(&mgr, argv[1], fn, &done);
|
||||||
|
if (c != NULL) {
|
||||||
|
mg_printf(c, "GET %s HTTP/1.0\r\n\r\n", mg_url_uri(argv[1]));
|
||||||
|
// If target URL is SSL/TLS, command client connection to use TLS
|
||||||
|
if (mg_url_is_ssl(argv[1])) {
|
||||||
|
struct mg_tls_opts opts = {.ca = "ca.pem"};
|
||||||
|
mg_tls_init(c, &opts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (done == false) mg_mgr_poll(&mgr, 1000); // Event loop
|
||||||
|
}
|
||||||
|
|
||||||
|
mg_mgr_free(&mgr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
PROG ?= example
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(DEBUGGER) ./$(PROG) $(ARGS)
|
||||||
|
|
||||||
|
$(PROG): main.c
|
||||||
|
$(CC) ../../mongoose.c -I../.. -W -Wall -DMG_ENABLE_LINES=1 -DMG_ENABLE_DIRECTORY_LISTING=1 $(CFLAGS) -o $(PROG) main.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// Copyright (c) 2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static const char *s_listen_on = "http://localhost:8000";
|
||||||
|
static const char *s_web_directory = ".";
|
||||||
|
|
||||||
|
// This RESTful server implements the following endpoints:
|
||||||
|
// /api/f1 - respond with JSON string {"result": 123}
|
||||||
|
// /api/f2/:id - wildcard example, respond with JSON string {"result": "URI"}
|
||||||
|
// any other URI serves static files from s_web_directory
|
||||||
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
if (mg_http_match_uri(hm, "/api/f1")) {
|
||||||
|
mg_http_reply(c, 200, "{\"result\": %d}\n", 123); // Serve REST response
|
||||||
|
} else if (mg_http_match_uri(hm, "/api/f2/*")) {
|
||||||
|
mg_http_reply(c, 200, "{\"result\": \"%.*s\"}\n", (int) hm->uri.len,
|
||||||
|
hm->uri.ptr);
|
||||||
|
} else {
|
||||||
|
mg_http_serve_dir(c, ev_data, s_web_directory); // Serve static files
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void) fn_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_mgr mgr; // Event manager
|
||||||
|
mg_mgr_init(&mgr); // Initialise event manager
|
||||||
|
mg_http_listen(&mgr, s_listen_on, fn, NULL); // Create HTTP listener
|
||||||
|
for (;;) mg_mgr_poll(&mgr, 1000); // Infinite event loop
|
||||||
|
mg_mgr_free(&mgr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
LOCAL_PATH := $(call my-dir)/../..
|
|
||||||
include $(CLEAR_VARS)
|
|
||||||
|
|
||||||
# To build with lua support, uncomment two lines below:
|
|
||||||
#LUA_SOURCES := build/lua_5.2.1.c build/sqlite3.c build/lsqlite3.c
|
|
||||||
#LUA_FLAGS := -I$(LOCAL_PATH)/build -DTHREADSAFE=1 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DUSE_LUA -DUSE_LUA_SQLITE3 -DLUA_COMPAT_ALL -D"getlocaledecpoint() ='.'"
|
|
||||||
|
|
||||||
LOCAL_CFLAGS := -std=c99 -O2 -W -Wall -pthread -pipe $(LUA_FLAGS) $(COPT)
|
|
||||||
LOCAL_MODULE := mongoose
|
|
||||||
LOCAL_SRC_FILES := examples/server.c mongoose.c $(LUA_SOURCES)
|
|
||||||
|
|
||||||
include $(BUILD_EXECUTABLE)
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
PROG ?= example
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(DEBUGGER) ./$(PROG)
|
||||||
|
|
||||||
|
$(PROG):
|
||||||
|
$(CC) ../../mongoose.c -I../.. $(CFLAGS) $(EXTRA) -o $(PROG) main.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb log.txt
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
// Copyright (c) 2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
// HTTP request handler function. It implements the following endpoints:
|
||||||
|
// /api/log/static - returns contents of log.txt file
|
||||||
|
// /api/log/live - hangs forever, and returns live log messages
|
||||||
|
// all other URI - serves web_root/ directory
|
||||||
|
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
if (mg_http_match_uri(hm, "/api/log/static")) {
|
||||||
|
mg_http_serve_file(c, hm, "log.txt", "text/plain");
|
||||||
|
} else if (mg_http_match_uri(hm, "/api/log/live")) {
|
||||||
|
c->label[0] = 'L'; // Mark that connection as live log listener
|
||||||
|
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||||
|
} else {
|
||||||
|
mg_http_serve_dir(c, ev_data, "web_root");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void log_message(const char *filename, const char *message) {
|
||||||
|
FILE *fp = fopen(filename, "a");
|
||||||
|
if (fp != NULL) {
|
||||||
|
fprintf(fp, "%s", message);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void broadcast_message(struct mg_mgr *mgr, const char *message) {
|
||||||
|
struct mg_connection *c;
|
||||||
|
for (c = mgr->conns; c != NULL; c = c->next) {
|
||||||
|
if (c->label[0] == 'L') mg_http_printf_chunk(c, "%s", message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timer function - called periodically.
|
||||||
|
// Prepare log message. Save it to a file, and broadcast.
|
||||||
|
static void timer_fn(void *arg) {
|
||||||
|
char buf[64];
|
||||||
|
snprintf(buf, sizeof(buf), "Time is: %lu\n", (unsigned long) time(NULL));
|
||||||
|
log_message("log.txt", buf);
|
||||||
|
broadcast_message(arg, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_mgr mgr;
|
||||||
|
struct mg_timer t1;
|
||||||
|
|
||||||
|
mg_mgr_init(&mgr);
|
||||||
|
mg_http_listen(&mgr, "http://localhost:8000", cb, NULL);
|
||||||
|
mg_timer_init(&t1, 1000, MG_TIMER_REPEAT, timer_fn, &mgr);
|
||||||
|
|
||||||
|
for (;;) mg_mgr_poll(&mgr, 50);
|
||||||
|
mg_timer_free(&t1);
|
||||||
|
mg_mgr_free(&mgr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>example</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<style>
|
||||||
|
#container { margin-right: auto; margin-left: auto; max-width: 480px; }
|
||||||
|
#info { background: #e0f0f0; border-radius: .5em; padding: 2em; }
|
||||||
|
#static, #live { background: #f0f0f0; border-radius: .5em; padding: 0.5em; max-height: 10em; overflow: auto; height: 100%; }
|
||||||
|
#wrapper { display: flex; justify-content: flex-evenly; margin-top: 1em; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="container">
|
||||||
|
<div id="info">
|
||||||
|
A div below shows file log.txt, which is produced by the server.
|
||||||
|
The server appends a new log message to that file every second,
|
||||||
|
and a div below also shows that, implementing a "live log" feature.
|
||||||
|
JS code on this page first fetches /api/log/static that returns
|
||||||
|
log.txt contents, then fetches /api/log/live that does not return,
|
||||||
|
but feeds chunks of data as they arrive (live log).
|
||||||
|
<br/><br/>
|
||||||
|
You can also use <code>curl</code> command-line utility to see
|
||||||
|
live logs:
|
||||||
|
<br/><code>curl localhost:8000/api/log/live</code>
|
||||||
|
</div>
|
||||||
|
<div id="wrapper">
|
||||||
|
<div style="width: 50%"><b>Static</b><pre id="static"></pre></div>
|
||||||
|
<div style="width: 1em;"></div>
|
||||||
|
<div style="width: 50%"><b>Live</b><pre id="live"></pre></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
var f = function(r) {
|
||||||
|
return r.read().then(function(result) {
|
||||||
|
var data = String.fromCharCode.apply(null, result.value);
|
||||||
|
document.getElementById('live').innerText += data; // Append live log
|
||||||
|
if (!result.done) f(r); // Read next chunk
|
||||||
|
});
|
||||||
|
};
|
||||||
|
window.onload = ev => fetch('/api/log/static')
|
||||||
|
.then(r => r.text())
|
||||||
|
.then(r => { document.getElementById('static').innerText = r; })
|
||||||
|
.then(r => fetch('/api/log/live'))
|
||||||
|
.then(r => r.body.getReader())
|
||||||
|
.then(f);
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
#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, "--myboundary\r\nContent-Type: image/jpeg\r\n"
|
|
||||||
"Content-Length: %llu\r\n\r\n", (unsigned long 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;
|
|
||||||
int result = MG_FALSE;
|
|
||||||
|
|
||||||
if (ev == MG_REQUEST) {
|
|
||||||
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=--myboundary\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);
|
|
||||||
result = MG_MORE;
|
|
||||||
|
|
||||||
} else if (ev == MG_POLL) {
|
|
||||||
|
|
||||||
time_t now = time(NULL);
|
|
||||||
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) {
|
|
||||||
result = MG_TRUE; // No more images, close connection
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state->last_poll = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (ev == MG_CLOSE) {
|
|
||||||
free(conn->connection_param);
|
|
||||||
conn->connection_param = NULL;
|
|
||||||
} else if (ev == MG_AUTH) {
|
|
||||||
result = MG_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
# This program is used to embed arbitrary data into a C binary. It takes
|
|
||||||
# a list of files as an input, and produces a .c data file that contains
|
|
||||||
# contents of all these files as collection of char arrays.
|
|
||||||
#
|
|
||||||
# Usage: perl <this_file> <file1> [file2, ...] > embedded_data.c
|
|
||||||
|
|
||||||
foreach my $i (0 .. $#ARGV) {
|
|
||||||
open FD, '<:raw', $ARGV[$i] or die "Cannot open $ARGV[$i]: $!\n";
|
|
||||||
printf("static const unsigned char v%d[] = {", $i);
|
|
||||||
my $byte;
|
|
||||||
my $j = 0;
|
|
||||||
while (read(FD, $byte, 1)) {
|
|
||||||
if (($j % 12) == 0) {
|
|
||||||
print "\n";
|
|
||||||
}
|
|
||||||
printf ' %#04x,', ord($byte);
|
|
||||||
$j++;
|
|
||||||
}
|
|
||||||
print " 0x00\n};\n";
|
|
||||||
close FD;
|
|
||||||
}
|
|
||||||
|
|
||||||
print <<EOS;
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
static const struct embedded_file {
|
|
||||||
const char *name;
|
|
||||||
const unsigned char *data;
|
|
||||||
size_t size;
|
|
||||||
} embedded_files[] = {
|
|
||||||
EOS
|
|
||||||
|
|
||||||
foreach my $i (0 .. $#ARGV) {
|
|
||||||
print " {\"$ARGV[$i]\", v$i, sizeof(v$i) - 1},\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
print <<EOS;
|
|
||||||
{NULL, NULL, 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
const char *find_embedded_file(const char *name, size_t *size) {
|
|
||||||
const struct embedded_file *p;
|
|
||||||
for (p = embedded_files; p->name != NULL; p++) {
|
|
||||||
if (!strcmp(p->name, name)) {
|
|
||||||
if (size != NULL) { *size = p->size; }
|
|
||||||
return (const char *) p->data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
EOS
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
PROG ?= example
|
||||||
|
MBEDTLS_DIR ?=
|
||||||
|
|
||||||
|
ifeq "$(MBEDTLS_DIR)" ""
|
||||||
|
else
|
||||||
|
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS_DIR)/include -I/usr/include
|
||||||
|
CFLAGS += -L$(MBEDTLS_DIR)/lib -lmbedtls -lmbedcrypto -lmbedx509
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(DEBUGGER) ./$(PROG) $(ARGS)
|
||||||
|
|
||||||
|
|
||||||
|
$(PROG): main.c
|
||||||
|
$(CC) ../../mongoose.c -I../.. -W -Wall $(CFLAGS) -o $(PROG) main.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb
|
||||||
@@ -0,0 +1,507 @@
|
|||||||
|
Subject: O=Digital Signature Trust Co., CN=DST Root CA X3
|
||||||
|
Not Before: Sep 30 21:12:19 2000 GMT
|
||||||
|
Not After : Sep 30 14:01:15 2021 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
|
||||||
|
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
||||||
|
DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
|
||||||
|
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
|
||||||
|
Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||||
|
AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
|
||||||
|
rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
|
||||||
|
OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
|
||||||
|
xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
|
||||||
|
7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
|
||||||
|
aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
|
||||||
|
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
|
||||||
|
SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
|
||||||
|
ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
|
||||||
|
AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
|
||||||
|
R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
|
||||||
|
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
|
||||||
|
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root
|
||||||
|
Not Before: May 12 18:46:00 2000 GMT
|
||||||
|
Not After : May 12 23:59:00 2025 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
|
||||||
|
RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
|
||||||
|
VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
|
||||||
|
DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
|
||||||
|
ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
|
||||||
|
VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
|
||||||
|
mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
|
||||||
|
IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
|
||||||
|
mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
|
||||||
|
XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
|
||||||
|
dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
|
||||||
|
jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
|
||||||
|
BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
|
||||||
|
DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
|
||||||
|
9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
|
||||||
|
jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
|
||||||
|
Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
|
||||||
|
ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
|
||||||
|
R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA
|
||||||
|
Not Before: May 21 04:00:00 2002 GMT
|
||||||
|
Not After : May 21 04:00:00 2022 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
|
||||||
|
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
|
||||||
|
YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
|
||||||
|
EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
|
||||||
|
R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
|
||||||
|
9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
|
||||||
|
fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
|
||||||
|
iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
|
||||||
|
1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
|
||||||
|
bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
|
||||||
|
MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
|
||||||
|
ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
|
||||||
|
uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
|
||||||
|
Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
|
||||||
|
tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
|
||||||
|
PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
|
||||||
|
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
|
||||||
|
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=Symantec Corporation, OU=Symantec Trust Network, CN=Symantec Class 3 ECC 256 bit SSL CA - G2
|
||||||
|
Not Before: May 12 00:00:00 2015 GMT
|
||||||
|
Not After : May 11 23:59:59 2025 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEajCCA1KgAwIBAgIQP5KHvp0dpKN6nfYoLndaxDANBgkqhkiG9w0BAQsFADCB
|
||||||
|
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||||
|
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
|
||||||
|
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
|
||||||
|
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
|
||||||
|
aG9yaXR5IC0gRzUwHhcNMTUwNTEyMDAwMDAwWhcNMjUwNTExMjM1OTU5WjCBgDEL
|
||||||
|
MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD
|
||||||
|
VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMTEwLwYDVQQDEyhTeW1hbnRlYyBD
|
||||||
|
bGFzcyAzIEVDQyAyNTYgYml0IFNTTCBDQSAtIEcyMFkwEwYHKoZIzj0CAQYIKoZI
|
||||||
|
zj0DAQcDQgAEDxukkdfnrOfRTk63ZFvhj39uBNOrONtEt0Bcbb2WljffeYmGZ/ex
|
||||||
|
Hwie/WM7RoyfvVPoFdyXPiuBRq2Gfw4BOaOCAV0wggFZMC4GCCsGAQUFBwEBBCIw
|
||||||
|
IDAeBggrBgEFBQcwAYYSaHR0cDovL3Muc3ltY2QuY29tMBIGA1UdEwEB/wQIMAYB
|
||||||
|
Af8CAQAwZQYDVR0gBF4wXDBaBgpghkgBhvhFAQc2MEwwIwYIKwYBBQUHAgEWF2h0
|
||||||
|
dHBzOi8vZC5zeW1jYi5jb20vY3BzMCUGCCsGAQUFBwICMBkaF2h0dHBzOi8vZC5z
|
||||||
|
eW1jYi5jb20vcnBhMC8GA1UdHwQoMCYwJKAioCCGHmh0dHA6Ly9zLnN5bWNiLmNv
|
||||||
|
bS9wY2EzLWc1LmNybDAOBgNVHQ8BAf8EBAMCAQYwKwYDVR0RBCQwIqQgMB4xHDAa
|
||||||
|
BgNVBAMTE1NZTUMtRUNDLUNBLXAyNTYtMjIwHQYDVR0OBBYEFCXwiuFLetkBlQrt
|
||||||
|
xlPxjHgf2fP4MB8GA1UdIwQYMBaAFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG
|
||||||
|
SIb3DQEBCwUAA4IBAQAMMGUXBaWTdaLxsTGtcB/naqjIQrLvoV9NG+7MoHpGd/69
|
||||||
|
dZ/h2zOy7sGFUHoG/0HGRA9rxT/5w5GkEVIVkxtWyIWWq6rs4CTZt8Bej/KHYRbo
|
||||||
|
jtEDUkCTZSTLiCvguPyvinXgxy+LHT+PmdtEfXsvcdbeBSWUYpOsDYvD2hNtz9dw
|
||||||
|
Od5nBosMApmdxt+z7LQyZu8wMnfI1U6IMO+RWowxZ8uy0oswdFYd32l9xe+aAE/k
|
||||||
|
y9alLu/M9pvxiUKufqHJRgDBKA6uDjHLMPX+/nxXaNCPX3SI4KVZ1stHQ/U5oNlM
|
||||||
|
dHN9umAvlU313g0IgJrjsQ2nIdf9dsdP+6lrmP7s
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5
|
||||||
|
Not Before: Nov 8 00:00:00 2006 GMT
|
||||||
|
Not After : Jul 16 23:59:59 2036 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
|
||||||
|
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||||
|
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
|
||||||
|
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
|
||||||
|
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
|
||||||
|
aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
|
||||||
|
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
|
||||||
|
ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
|
||||||
|
biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
|
||||||
|
U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
|
||||||
|
aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
|
||||||
|
nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
|
||||||
|
t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
|
||||||
|
SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
|
||||||
|
BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
|
||||||
|
rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
|
||||||
|
NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
|
||||||
|
BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
|
||||||
|
BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
|
||||||
|
aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
|
||||||
|
MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
|
||||||
|
p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
|
||||||
|
5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
|
||||||
|
WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
|
||||||
|
4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
|
||||||
|
hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority
|
||||||
|
Not Before: Jun 29 17:06:20 2004 GMT
|
||||||
|
Not After : Jun 29 17:06:20 2034 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
|
||||||
|
MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
|
||||||
|
YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
|
||||||
|
MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
|
||||||
|
ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
|
||||||
|
MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
|
||||||
|
ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
|
||||||
|
PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
|
||||||
|
wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
|
||||||
|
EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
|
||||||
|
avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
|
||||||
|
YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
|
||||||
|
sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
|
||||||
|
/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
|
||||||
|
IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
|
||||||
|
YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
|
||||||
|
ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
|
||||||
|
OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
|
||||||
|
TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
|
||||||
|
HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
|
||||||
|
dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
|
||||||
|
ReYNnyicsbkqWletNw+vHX/bvZ8=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
# Note: Amazon ATS endpoint uses this (2018/12/18)
|
||||||
|
Subject: C=US, O=Starfield Technologies, Inc., OU=Starfield Class 2 Certification Authority
|
||||||
|
Not Before: Jun 29 17:39:16 2004 GMT
|
||||||
|
Not After : Jun 29 17:39:16 2034 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
|
||||||
|
MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
|
||||||
|
U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
|
||||||
|
NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
|
||||||
|
ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
|
||||||
|
ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
|
||||||
|
DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
|
||||||
|
8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
|
||||||
|
+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
|
||||||
|
X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
|
||||||
|
K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
|
||||||
|
1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
|
||||||
|
A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
|
||||||
|
zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
|
||||||
|
YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
|
||||||
|
bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
|
||||||
|
DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
|
||||||
|
L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
|
||||||
|
eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
|
||||||
|
xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
|
||||||
|
VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
|
||||||
|
WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Sep 1 00:00:00 2009 GMT
|
||||||
|
Not After : Dec 31 23:59:59 2037 GMT
|
||||||
|
Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Root Certificate Authority - G2
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx
|
||||||
|
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
|
||||||
|
HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs
|
||||||
|
ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw
|
||||||
|
MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
|
||||||
|
b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj
|
||||||
|
aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp
|
||||||
|
Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||||
|
ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg
|
||||||
|
nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1
|
||||||
|
HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N
|
||||||
|
Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN
|
||||||
|
dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0
|
||||||
|
HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
|
||||||
|
BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G
|
||||||
|
CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU
|
||||||
|
sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3
|
||||||
|
4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg
|
||||||
|
8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
|
||||||
|
pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1
|
||||||
|
mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Services Root Certificate Authority - G2
|
||||||
|
Not Before: Sep 1 00:00:00 2009 GMT
|
||||||
|
Not After : Dec 31 23:59:59 2037 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
|
||||||
|
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
|
||||||
|
HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs
|
||||||
|
ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
|
||||||
|
MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD
|
||||||
|
VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy
|
||||||
|
ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy
|
||||||
|
dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
|
||||||
|
hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p
|
||||||
|
OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2
|
||||||
|
8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K
|
||||||
|
Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe
|
||||||
|
hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk
|
||||||
|
6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw
|
||||||
|
DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q
|
||||||
|
AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI
|
||||||
|
bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB
|
||||||
|
ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z
|
||||||
|
qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
|
||||||
|
iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn
|
||||||
|
0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN
|
||||||
|
sSi6
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign
|
||||||
|
Not Before: Dec 15 08:00:00 2006 GMT
|
||||||
|
Not After : Dec 15 08:00:00 2021 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
|
||||||
|
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
|
||||||
|
Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
|
||||||
|
MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
|
||||||
|
A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
|
||||||
|
hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
|
||||||
|
v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
|
||||||
|
eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
|
||||||
|
tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
|
||||||
|
C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
|
||||||
|
zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
|
||||||
|
mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
|
||||||
|
V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
|
||||||
|
bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
|
||||||
|
3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
|
||||||
|
J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
|
||||||
|
291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
|
||||||
|
ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
|
||||||
|
AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
|
||||||
|
TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA
|
||||||
|
Not Before: Nov 10 00:00:00 2006 GMT
|
||||||
|
Not After : Nov 10 00:00:00 2031 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||||
|
ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
|
||||||
|
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
||||||
|
LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
|
||||||
|
RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
|
||||||
|
+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
|
||||||
|
PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
|
||||||
|
xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
|
||||||
|
Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
|
||||||
|
hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
|
||||||
|
EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
|
||||||
|
MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
|
||||||
|
FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
|
||||||
|
nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
|
||||||
|
eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
|
||||||
|
hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
|
||||||
|
Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
|
||||||
|
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
|
||||||
|
+OkuE6N36B9K
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA
|
||||||
|
Not Before: Nov 10 00:00:00 2006 GMT
|
||||||
|
Not After : Nov 10 00:00:00 2031 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||||
|
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||||
|
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||||
|
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||||
|
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||||
|
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||||
|
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||||
|
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||||
|
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||||
|
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||||
|
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||||
|
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||||
|
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||||
|
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||||
|
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||||
|
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||||
|
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||||
|
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
# *.azure-devices.de use this root.
|
||||||
|
Subject: C = DE, O = D-Trust GmbH, CN = D-TRUST Root Class 3 CA 2 2009
|
||||||
|
Not Before: Nov 5 08:35:58 2009 GMT
|
||||||
|
Not After : Nov 5 08:35:58 2029 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF
|
||||||
|
MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD
|
||||||
|
bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha
|
||||||
|
ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM
|
||||||
|
HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB
|
||||||
|
BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03
|
||||||
|
UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42
|
||||||
|
tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R
|
||||||
|
ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM
|
||||||
|
lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp
|
||||||
|
/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G
|
||||||
|
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G
|
||||||
|
A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj
|
||||||
|
dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy
|
||||||
|
MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl
|
||||||
|
cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js
|
||||||
|
L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL
|
||||||
|
BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni
|
||||||
|
acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
|
||||||
|
o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K
|
||||||
|
zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8
|
||||||
|
PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y
|
||||||
|
Johw1+qRzT65ysCQblrGXnRl11z+o+I=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
# https://www.amazontrust.com/repository/
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 1
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : Jan 17 00:00:00 2038 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
|
||||||
|
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
|
||||||
|
b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
|
||||||
|
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
|
||||||
|
b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
|
||||||
|
ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
|
||||||
|
9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
|
||||||
|
IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
|
||||||
|
VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
|
||||||
|
93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
|
||||||
|
jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
|
||||||
|
AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
|
||||||
|
A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
|
||||||
|
U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
|
||||||
|
N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
|
||||||
|
o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
|
||||||
|
5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
|
||||||
|
rqXRfboQnoZsG4q5WTP468SQvvG5
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 2
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : May 26 00:00:00 2040 GMT
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF
|
||||||
|
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
|
||||||
|
b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL
|
||||||
|
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
|
||||||
|
b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK
|
||||||
|
gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ
|
||||||
|
W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg
|
||||||
|
1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K
|
||||||
|
8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r
|
||||||
|
2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me
|
||||||
|
z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR
|
||||||
|
8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj
|
||||||
|
mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz
|
||||||
|
7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6
|
||||||
|
+XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI
|
||||||
|
0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB
|
||||||
|
Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm
|
||||||
|
UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2
|
||||||
|
LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY
|
||||||
|
+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS
|
||||||
|
k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl
|
||||||
|
7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm
|
||||||
|
btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl
|
||||||
|
urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+
|
||||||
|
fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63
|
||||||
|
n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE
|
||||||
|
76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H
|
||||||
|
9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT
|
||||||
|
4PsJYGw=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : May 26 00:00:00 2040 GMT
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 3
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5
|
||||||
|
MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
|
||||||
|
Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
|
||||||
|
A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
|
||||||
|
Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl
|
||||||
|
ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j
|
||||||
|
QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr
|
||||||
|
ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr
|
||||||
|
BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM
|
||||||
|
YyRIHN8wfdVoOw==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: May 26 00:00:00 2015 GMT
|
||||||
|
Not After : May 26 00:00:00 2040 GMT
|
||||||
|
Subject: C = US, O = Amazon, CN = Amazon Root CA 4
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5
|
||||||
|
MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
|
||||||
|
Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
|
||||||
|
A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
|
||||||
|
Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi
|
||||||
|
9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk
|
||||||
|
M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB
|
||||||
|
/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB
|
||||||
|
MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw
|
||||||
|
CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW
|
||||||
|
1KyLa2tJElMzrdfkviT8tQp21KW8EA==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Nov 10 00:00:00 2006 GMT
|
||||||
|
Not After : Nov 10 00:00:00 2031 GMT
|
||||||
|
Subject: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||||
|
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||||
|
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||||
|
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||||
|
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||||
|
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||||
|
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||||
|
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||||
|
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||||
|
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||||
|
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||||
|
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||||
|
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||||
|
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||||
|
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||||
|
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||||
|
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||||
|
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Nov 13 00:00:00 2012 GMT
|
||||||
|
Not After : Jan 19 03:14:07 2038 GMT
|
||||||
|
Subject: OU = GlobalSign ECC Root CA - R4, O = GlobalSign, CN = GlobalSign
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk
|
||||||
|
MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH
|
||||||
|
bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
|
||||||
|
DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
|
||||||
|
QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
|
||||||
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ
|
||||||
|
FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw
|
||||||
|
DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F
|
||||||
|
uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX
|
||||||
|
kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs
|
||||||
|
ewv4n4Q=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
Not Before: Nov 1 00:00:42 2018 GMT
|
||||||
|
Not After : Nov 1 00:00:42 2042 GMT
|
||||||
|
Subject: C = US, O = Google Trust Services LLC, CN = GTS LTSR
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBxTCCAWugAwIBAgINAfD3nVndblD3QnNxUDAKBggqhkjOPQQDAjBEMQswCQYD
|
||||||
|
VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzERMA8G
|
||||||
|
A1UEAxMIR1RTIExUU1IwHhcNMTgxMTAxMDAwMDQyWhcNNDIxMTAxMDAwMDQyWjBE
|
||||||
|
MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
|
||||||
|
QzERMA8GA1UEAxMIR1RTIExUU1IwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATN
|
||||||
|
8YyO2u+yCQoZdwAkUNv5c3dokfULfrA6QJgFV2XMuENtQZIG5HUOS6jFn8f0ySlV
|
||||||
|
eORCxqFyjDJyRn86d+Iko0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUw
|
||||||
|
AwEB/zAdBgNVHQ4EFgQUPv7/zFLrvzQ+PfNA0OQlsV+4u1IwCgYIKoZIzj0EAwID
|
||||||
|
SAAwRQIhAPKuf/VtBHqGw3TUwUIq7TfaExp3bH7bjCBmVXJupT9FAiBr0SmCtsuk
|
||||||
|
miGgpajjf/gFigGM34F9021bCWs1MbL0SA==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
// Copyright (c) 2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// Example MQTT client. It performs the following steps:
|
||||||
|
// 1. Connects to the MQTT server specified by `s_url` variable
|
||||||
|
// 2. When connected, subscribes to the topic `s_topic`
|
||||||
|
// 3. Publishes message `hello` to the `s_topic`
|
||||||
|
// 4. Receives that message back from the subscribed topic and exits
|
||||||
|
//
|
||||||
|
// To enable SSL/TLS for this client, build it like this:
|
||||||
|
// make MBEDTLS_DIR=/path/to/your/mbedtls/installation
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static const char *s_url = "mqtt://broker.hivemq.com:1883";
|
||||||
|
static const char *s_topic = "mg/test";
|
||||||
|
|
||||||
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_ERROR) {
|
||||||
|
// On error, log error message
|
||||||
|
LOG(LL_ERROR, ("%p %s", c->fd, ev_data));
|
||||||
|
} else if (ev == MG_EV_CONNECT) {
|
||||||
|
// If target URL is SSL/TLS, command client connection to use TLS
|
||||||
|
if (mg_url_is_ssl(s_url)) {
|
||||||
|
struct mg_tls_opts opts = {.ca = "ca.pem"};
|
||||||
|
mg_tls_init(c, &opts);
|
||||||
|
}
|
||||||
|
} else if (ev == MG_EV_MQTT_OPEN) {
|
||||||
|
// MQTT connect is successful
|
||||||
|
struct mg_str topic = mg_str(s_topic), data = mg_str("hello");
|
||||||
|
LOG(LL_INFO, ("CONNECTED to %s", s_url));
|
||||||
|
mg_mqtt_sub(c, &topic);
|
||||||
|
LOG(LL_INFO, ("SUBSCRIBED to %.*s", (int) topic.len, topic.ptr));
|
||||||
|
mg_mqtt_pub(c, &topic, &data);
|
||||||
|
LOG(LL_INFO, ("PUBSLISHED %.*s -> %.*s", (int) data.len, data.ptr,
|
||||||
|
(int) topic.len, topic.ptr));
|
||||||
|
} else if (ev == MG_EV_MQTT_MSG) {
|
||||||
|
// When we get echo response, print it
|
||||||
|
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
|
||||||
|
LOG(LL_INFO, ("RECEIVED %.*s <- %.*s", (int) mm->data.len, mm->data.ptr,
|
||||||
|
(int) mm->topic.len, mm->topic.ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev == MG_EV_ERROR || ev == MG_EV_CLOSE || ev == MG_EV_MQTT_MSG) {
|
||||||
|
*(bool *) fn_data = true; // Signal that we're done
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_mgr mgr; // Event manager
|
||||||
|
struct mg_mqtt_opts opts; // MQTT connection options
|
||||||
|
bool done = false; // Event handler flips it to true when done
|
||||||
|
mg_mgr_init(&mgr); // Initialise event manager
|
||||||
|
memset(&opts, 0, sizeof(opts)); // Set MQTT options
|
||||||
|
opts.qos = 1; // Set QoS to 1
|
||||||
|
opts.will_topic = mg_str(s_topic); // Set last will topic
|
||||||
|
opts.will_message = mg_str("goodbye"); // And last will message
|
||||||
|
mg_mqtt_connect(&mgr, s_url, &opts, fn, &done); // Create client connection
|
||||||
|
while (done == false) mg_mgr_poll(&mgr, 1000); // Event loop
|
||||||
|
mg_mgr_free(&mgr); // Finished, cleanup
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
PROG ?= example
|
||||||
|
CFLAGS += -DMG_ENABLE_SOCKETPAIR=1
|
||||||
|
CDIR ?= $(realpath $(CURDIR))
|
||||||
|
ROOT ?= $(realpath $(CURDIR)/../..)
|
||||||
|
VC2017 = docker run --rm -e WINEDEBUG=-all -v $(ROOT):$(ROOT) -w $(CDIR) docker.io/mdashnet/vc2017
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(DEBUGGER) ./$(PROG)
|
||||||
|
|
||||||
|
$(PROG):
|
||||||
|
$(CC) ../../mongoose.c -I../.. -pthread $(CFLAGS) -o $(PROG) main.c
|
||||||
|
|
||||||
|
vc2017:
|
||||||
|
$(VC2017) wine64 cl ../../mongoose.c main.c -I../.. $(CFLAGS) ws2_32.lib /Fe$@.exe
|
||||||
|
$(VC2017) wine64 $@.exe
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb log.txt
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
// Copyright (c) 2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// Multithreading example.
|
||||||
|
// For each incoming request, we spawn a separate thread, that sleeps for
|
||||||
|
// some time to simulate long processing time, produces an output and
|
||||||
|
// hands over that output to the request handler function.
|
||||||
|
//
|
||||||
|
// IMPORTANT: this program must be compiled with -DMG_ENABLE_SOCKETPAIR=1
|
||||||
|
//
|
||||||
|
// The following procedure is used to benchmark the multi-threaded codepath
|
||||||
|
// against the single-threaded codepath on MacOS:
|
||||||
|
// $ make clean all CFLAGS="-DSLEEP_TIME=0 -DMG_ENABLE_SOCKETPAIR=1"
|
||||||
|
// $ siege -c50 -t5s http://localhost:8000/multi
|
||||||
|
// $ siege -c50 -t5s http://localhost:8000/fast
|
||||||
|
//
|
||||||
|
// If, during the test, there are socket errors, increase ephemeral port limit:
|
||||||
|
// $ sysctl -a | grep portrange
|
||||||
|
// $ sudo sysctl -w net.inet.ip.portrange.first=32768
|
||||||
|
// $ sudo sysctl -w net.inet.ip.portrange.hifirst=32768
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
// thread_function() sends this structure back to the request handler
|
||||||
|
struct response {
|
||||||
|
char *data;
|
||||||
|
int len;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef SLEEP_TIME
|
||||||
|
#define SLEEP_TIME 3 // Seconds to sleep to simulate calculation
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void thread_function(void *param) {
|
||||||
|
int sock = (long) param; // Grab our blocking socket
|
||||||
|
struct response r = {strdup("hello"), 5}; // Create response
|
||||||
|
sleep(SLEEP_TIME); // Simulate long execution
|
||||||
|
send(sock, (void *) &r, sizeof(r), 0); // Send to request handler
|
||||||
|
close(sock); // Done, close socket, end thread
|
||||||
|
}
|
||||||
|
|
||||||
|
static void start_thread(void (*f)(void *), void *p) {
|
||||||
|
#ifdef WINCE
|
||||||
|
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) f, p, 0, NULL);
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
_beginthread((void(__cdecl *)(void *)) f, 0, p);
|
||||||
|
#else
|
||||||
|
#include <pthread.h>
|
||||||
|
pthread_t thread_id = (pthread_t) 0;
|
||||||
|
pthread_attr_t attr;
|
||||||
|
(void) pthread_attr_init(&attr);
|
||||||
|
(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||||
|
pthread_create(&thread_id, &attr, (void *(*) (void *) ) f, p);
|
||||||
|
pthread_attr_destroy(&attr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTP request callback
|
||||||
|
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
// Incoming request. Create socket pair.
|
||||||
|
// Pass blocking socket to the thread, and keep the non-blocking socket.
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
|
||||||
|
if (mg_http_match_uri(hm, "/fast")) {
|
||||||
|
// The /fast URI is for performance impact of the multithreading codepath
|
||||||
|
mg_printf(c,
|
||||||
|
"HTTP/1.1 200 OK\r\n" // Reply success
|
||||||
|
"Host: foo\r\n" // Mandatory header
|
||||||
|
"Content-Length: 3\r\n\r\n" // Set to allow keep-alive
|
||||||
|
"hi\n");
|
||||||
|
} else {
|
||||||
|
int blocking, non_blocking;
|
||||||
|
mg_socketpair(&blocking, &non_blocking); // Create connected pair
|
||||||
|
|
||||||
|
// Pass blocking socket to the thread_function.
|
||||||
|
start_thread(thread_function, (void *) (long) blocking);
|
||||||
|
|
||||||
|
// Non-blocking is ours. Store it in the fn_data, in
|
||||||
|
// order to use it in the subsequent invocations
|
||||||
|
c->fn_data = (void *) (long) non_blocking;
|
||||||
|
}
|
||||||
|
} else if (ev == MG_EV_POLL && c->fn_data != NULL) {
|
||||||
|
// On each poll iteration, try to receive response data
|
||||||
|
int sock = (int) c->fn_data;
|
||||||
|
struct response response = {NULL, 0};
|
||||||
|
if (recv(sock, (void *) &response, sizeof(response), 0) ==
|
||||||
|
sizeof(response)) {
|
||||||
|
// Yeah! Got the response.
|
||||||
|
mg_printf(c, "HTTP/1.0 200 OK\r\nContent-Length: %d\r\n\r\n%.*s",
|
||||||
|
response.len, response.len, response.data);
|
||||||
|
free(response.data); // We can free produced data now
|
||||||
|
close(sock); // And close our end of the socket pair
|
||||||
|
c->fn_data = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_mgr mgr;
|
||||||
|
mg_mgr_init(&mgr);
|
||||||
|
mg_http_listen(&mgr, "http://localhost:8000", cb, NULL);
|
||||||
|
for (;;) mg_mgr_poll(&mgr, 50);
|
||||||
|
mg_mgr_free(&mgr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
#include "mongoose.h"
|
|
||||||
|
|
||||||
// Start a browser and hit refresh couple of times. The replies will
|
|
||||||
// come from both server instances.
|
|
||||||
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
|
||||||
if (ev == MG_REQUEST) {
|
|
||||||
mg_send_header(conn, "Content-Type", "text/plain");
|
|
||||||
mg_printf_data(conn, "This is a reply from server instance # %s",
|
|
||||||
(char *) conn->server_param);
|
|
||||||
return MG_TRUE;
|
|
||||||
} else if (ev == MG_AUTH) {
|
|
||||||
return MG_TRUE;
|
|
||||||
} else {
|
|
||||||
return MG_FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *serve(void *server) {
|
|
||||||
for (;;) mg_poll_server((struct mg_server *) server, 1000);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
struct mg_server *server1, *server2;
|
|
||||||
|
|
||||||
server1 = mg_create_server((void *) "1", ev_handler);
|
|
||||||
server2 = mg_create_server((void *) "2", ev_handler);
|
|
||||||
|
|
||||||
// Make both server1 and server2 listen on the same socket
|
|
||||||
mg_set_option(server1, "listening_port", "8080");
|
|
||||||
mg_set_listening_socket(server2, mg_get_listening_socket(server1));
|
|
||||||
|
|
||||||
// server1 goes to separate thread, server 2 runs in main thread.
|
|
||||||
// IMPORTANT: NEVER LET DIFFERENT THREADS HANDLE THE SAME SERVER.
|
|
||||||
mg_start_thread(serve, server1);
|
|
||||||
mg_start_thread(serve, server2);
|
|
||||||
getchar();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
PROG ?= example
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(DEBUGGER) ./$(PROG)
|
||||||
|
|
||||||
|
$(PROG):
|
||||||
|
$(CC) ../../mongoose.c -I../.. $(CFLAGS) $(EXTRA) -o $(PROG) main.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
// Copyright (c) 2020 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
// Authenticated user.
|
||||||
|
// A user can be authenticated by:
|
||||||
|
// - a name:pass pair
|
||||||
|
// - a token
|
||||||
|
// When a user is shown a login screen, she enters a user:pass. If successful,
|
||||||
|
// a server returns user info which includes token. From that point on,
|
||||||
|
// client can use token for authentication. Tokens could be refreshed/changed
|
||||||
|
// on a server side, forcing clients to re-login.
|
||||||
|
struct user {
|
||||||
|
const char *name, *pass, *token;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse HTTP requests, return authenticated user or NULL
|
||||||
|
static struct user *getuser(struct mg_http_message *hm) {
|
||||||
|
// In production, make passwords strong and tokens randomly generated
|
||||||
|
// In this example, user list is kept in RAM. In production, it can
|
||||||
|
// be backed by file, database, or some other method.
|
||||||
|
static struct user users[] = {
|
||||||
|
{"admin", "admin", "admin_token"},
|
||||||
|
{"user1", "pass1", "user1_token"},
|
||||||
|
{"user2", "pass2", "user2_token"},
|
||||||
|
{NULL, NULL, NULL},
|
||||||
|
};
|
||||||
|
char user[256], pass[256];
|
||||||
|
struct user *u;
|
||||||
|
mg_http_creds(hm, user, sizeof(user), pass, sizeof(pass));
|
||||||
|
if (user[0] != '\0' && pass[0] != '\0') {
|
||||||
|
// Both user and password is set, search by user/password
|
||||||
|
for (u = users; u->name != NULL; u++)
|
||||||
|
if (strcmp(user, u->name) == 0 && strcmp(pass, u->pass) == 0) return u;
|
||||||
|
} else if (user[0] == '\0') {
|
||||||
|
// Only password is set, search by token
|
||||||
|
for (u = users; u->name != NULL; u++)
|
||||||
|
if (strcmp(pass, u->token) == 0) return u;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTP request handler function
|
||||||
|
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
struct user *u = getuser(hm);
|
||||||
|
// LOG(LL_INFO, ("[%.*s] auth %s", (int) hm->uri.len, hm->uri.ptr,
|
||||||
|
// u ? u->name : "NULL"));
|
||||||
|
if (u == NULL && mg_http_match_uri(hm, "/api/#")) {
|
||||||
|
// All URIs starting with /api/ must be authenticated
|
||||||
|
mg_printf(c, "%s", "HTTP/1.1 403 Denied\r\nContent-Length: 0\r\n\r\n");
|
||||||
|
} else if (mg_http_match_uri(hm, "/api/user/data")) {
|
||||||
|
// Data visible to both users and administrators
|
||||||
|
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||||
|
mg_http_printf_chunk(c, "{\"data\":\"%s\"}\n", "this is user data");
|
||||||
|
mg_http_printf_chunk(c, "");
|
||||||
|
} else if (mg_http_match_uri(hm, "/api/admin/data")) {
|
||||||
|
// Data visible only to administrators
|
||||||
|
if (strcmp(u->name, "admin") == 0) {
|
||||||
|
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||||
|
mg_http_printf_chunk(c, "{\"data\":\"%s\"}\n", "this is admin data");
|
||||||
|
mg_http_printf_chunk(c, "");
|
||||||
|
} else {
|
||||||
|
mg_printf(c, "%s", "HTTP/1.1 403 Denied\r\nContent-Length: 0\r\n\r\n");
|
||||||
|
}
|
||||||
|
} else if (mg_http_match_uri(hm, "/api/login")) {
|
||||||
|
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||||
|
mg_http_printf_chunk(c, "{\"user\":\"%s\",\"token\":\"%s\"}\n", u->name,
|
||||||
|
u->token);
|
||||||
|
mg_http_printf_chunk(c, "");
|
||||||
|
} else {
|
||||||
|
mg_http_serve_dir(c, ev_data, "web_root");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_mgr mgr;
|
||||||
|
|
||||||
|
mg_mgr_init(&mgr);
|
||||||
|
mg_http_listen(&mgr, "http://localhost:8000", cb, NULL);
|
||||||
|
|
||||||
|
for (;;) mg_mgr_poll(&mgr, 1000);
|
||||||
|
mg_mgr_free(&mgr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
const {h, render, Component} = preact;
|
||||||
|
const html = htm.bind(h);
|
||||||
|
|
||||||
|
class Login extends Component {
|
||||||
|
state = {user: '', pass: ''};
|
||||||
|
onclick = (app) => {
|
||||||
|
const authhdr = 'Basic ' + btoa(this.state.user + ':' + this.state.pass);
|
||||||
|
const headers = {Authorization: authhdr};
|
||||||
|
return axios.get('/api/login', {headers})
|
||||||
|
.then(res => app.setUser(res.data.token))
|
||||||
|
.catch(err => alert('Login failed'));
|
||||||
|
};
|
||||||
|
onpassinput = (ev) => this.setState({pass: ev.target.value});
|
||||||
|
onuserinput = (ev) => this.setState({user: ev.target.value});
|
||||||
|
render({app}, {user, pass, signup}) {
|
||||||
|
return html`
|
||||||
|
<div class='mx-auto bg-light rounded border my-5' style='max-width: 480px;'>
|
||||||
|
<div class='form p-5 rounded form-sm'>
|
||||||
|
<h4 class="text-muted mb-4">Login </h4>
|
||||||
|
<input type='email' placeholder='Email' class='my-2 form-control'
|
||||||
|
oninput=${this.onuserinput} value=${user} />
|
||||||
|
<input type="password" placeholder="Password" class="my-2 form-control"
|
||||||
|
oninput=${this.onpassinput} value=${pass}
|
||||||
|
onchange=${ev => this.onclick(app)} />
|
||||||
|
<div class="mb-4">
|
||||||
|
<button class="btn btn-info btn-block"
|
||||||
|
disabled=${!user || !pass} onclick="${ev => this.onclick(app)}"
|
||||||
|
> Login </button>
|
||||||
|
</div>
|
||||||
|
<div class="text-muted small">
|
||||||
|
Valid logins: admin:admin, user1:pass1, user2:pass2
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Dropdown extends Component {
|
||||||
|
state = {show: false};
|
||||||
|
render(props, state) {
|
||||||
|
const onclick = x => this.setState({show: x});
|
||||||
|
const show = state.show ? 'show' : '';
|
||||||
|
return html`
|
||||||
|
<div class="dropdown autoexpand ${props.cls}">
|
||||||
|
<div type="buttonx" onclick=${() => onclick(!state.show)}
|
||||||
|
class="dropdown-toggle my-0 ${props.bcls}"
|
||||||
|
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
${props.title}
|
||||||
|
</div>
|
||||||
|
<div onclick=${() => onclick(false)} style=${props.dstyle}
|
||||||
|
class="dropdown-menu ${props.dcls} ${show}">
|
||||||
|
${props.children}
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const NavLink = ({href, title, url}) => html`<a class="nav-item nav-link
|
||||||
|
${url == href ? 'active' : ''}"
|
||||||
|
target=${href.match(/^http/) ? '_blank' : ''}
|
||||||
|
href="${href.match(/^http/) ? '' : '#'}${href}">${title}</a>`;
|
||||||
|
|
||||||
|
class Header extends Component {
|
||||||
|
state = {expanded: false};
|
||||||
|
ontoggle = () => this.setState({expanded: !this.state.expanded});
|
||||||
|
render(props, state) {
|
||||||
|
const u = props.app.state.user || {};
|
||||||
|
return html`
|
||||||
|
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
|
||||||
|
<a class="navbar-brand" href="#">
|
||||||
|
<img src="images/logo.png" width="26" height="26" alt="" class="mr-2" />
|
||||||
|
MyProduct
|
||||||
|
</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"
|
||||||
|
onclick=${() => this.ontoggle()} >
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="navbar-collapse ${state.expanded ? '' : 'collapse'}"
|
||||||
|
id="navbarNav">
|
||||||
|
<div class="nav navbar-nav mr-auto">
|
||||||
|
<${NavLink} href="/" title="Dashboard" url=${props.url} />
|
||||||
|
<${NavLink} href="/settings" title="Settings" url=${props.url} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form class="form-inline">
|
||||||
|
<${Dropdown} title="${u.user}" cls="mr-2"
|
||||||
|
bcls="btn btn-sm btn-outline-light pointer" dcls="m-0 dropdown-menu-right">
|
||||||
|
<div onclick=${() => props.app.setUser('')}
|
||||||
|
class="dropdown-item small pointer text-center">logout</div>
|
||||||
|
</${Dropdown}>
|
||||||
|
<img src="images/user.png" class="rounded-circle nav-item mr-2" width="30" />
|
||||||
|
</form>
|
||||||
|
</nav>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class AdminDashboard extends Component {
|
||||||
|
state = {udata: '', adata: ''};
|
||||||
|
componentDidMount() {
|
||||||
|
axios.get('/api/user/data').then(r => this.setState({udata: r.data}));
|
||||||
|
axios.get('/api/admin/data').then(r => this.setState({adata: r.data}));
|
||||||
|
}
|
||||||
|
render(props, state) {
|
||||||
|
console.log('-->', state);
|
||||||
|
return html`<div class="container-fluid">
|
||||||
|
this is admin page
|
||||||
|
<div>admin data, returned by server:
|
||||||
|
<code class="mx-2">${JSON.stringify(state.adata)}</code></div>
|
||||||
|
<div>user data, returned by server:
|
||||||
|
<code class="mx-2">${JSON.stringify(state.udata)}</code></div>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UserDashboard extends Component {
|
||||||
|
state = {udata: ''};
|
||||||
|
componentDidMount() {
|
||||||
|
axios.get('/api/user/data').then(r => this.setState({udata: r.data}));
|
||||||
|
axios.get('/api/admin/data').then(r => this.setState({adata: r.data}));
|
||||||
|
}
|
||||||
|
render(props, state) {
|
||||||
|
return html`<div class="container-fluid">
|
||||||
|
<div>admin data, returned by server (must be empty and dev tools should show 403):
|
||||||
|
<code class="mx-2">${JSON.stringify(state.adata)}</code></div>
|
||||||
|
<div>user data, returned by server:
|
||||||
|
<code class="mx-2">${JSON.stringify(state.udata)}</code></div>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Settings extends Component {
|
||||||
|
state = {};
|
||||||
|
render(props, state) {
|
||||||
|
return html`<div class="container-fluid">settings page</div>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class App extends Component {
|
||||||
|
state = {user: null, url: '/'};
|
||||||
|
setUser(token) {
|
||||||
|
const maxAge = token ? 86400 : 0;
|
||||||
|
document.cookie = `access_token=${token};path=/;max-age=${maxAge}`;
|
||||||
|
// this.setState({token});
|
||||||
|
return axios.get('/api/login')
|
||||||
|
.then(res => this.setState({user: res.data}))
|
||||||
|
.catch(err => this.setState({user: {}}));
|
||||||
|
}
|
||||||
|
componentDidMount() {
|
||||||
|
const getCookie = name => {
|
||||||
|
var v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');
|
||||||
|
return v ? v[2] : '';
|
||||||
|
};
|
||||||
|
this.setUser(getCookie('access_token')); // Move from state1 to 2 or 3
|
||||||
|
}
|
||||||
|
render(props, state) {
|
||||||
|
// We have three states:
|
||||||
|
// 1. Beginning. We don't know if we have a valid auth token or not
|
||||||
|
// 2. We sent an /api/login request, and failed to login
|
||||||
|
// 3. We sent an /api/login request, and succeeded to login
|
||||||
|
|
||||||
|
if (!state.user) return ''; // State 1
|
||||||
|
if (!state.user.user) return h(Login, {app: this}); // State 2
|
||||||
|
return h( // State 3
|
||||||
|
'div', {}, h(Header, {url: state.url, app: this}),
|
||||||
|
h(preactRouter.Router, {
|
||||||
|
history: History.createHashHistory(),
|
||||||
|
onChange: ev => this.setState({url: ev.url}),
|
||||||
|
},
|
||||||
|
h(state.user.user == 'admin' ? AdminDashboard : UserDashboard,
|
||||||
|
{default: true, app: this}),
|
||||||
|
h(Settings, {path: 'settings', app: this})));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onload = () => render(h(App), document.body);
|
||||||