Compare commits

..
648 Commits
Author SHA1 Message Date
Sergey Lyubka a5e10450dd Mongoose 6.0 -> 6.1
PUBLISHED_FROM=22408f9340bbbbf186bd551dd30564efe0c253e3
2015-11-30 12:27:59 +00:00
Sergey Lyubka e9d79b130d Add documentation for the mongoose binary
PUBLISHED_FROM=71a01298c9bbff9a748ea33e0d148d549e5e6437
2015-11-30 12:27:59 +00:00
Deomid Ryabkov 7951dac9d5 Put getting local/remote address behinf net_if
PUBLISHED_FROM=f88056e79b632d9eee288dacf61c2f87ff3ceca5
2015-11-30 12:27:58 +00:00
Alexander Alashkin 6c77351c58 Verify settings before apply
PUBLISHED_FROM=ca7b6a9814b88b45d893d8e1386faded27305e9c
2015-11-30 12:27:58 +00:00
Sergey Lyubka 7c4cda622f Implement port based redirect
PUBLISHED_FROM=798a8bc38cb385027d3caae9b954002c1a10d39c
2015-11-30 12:27:57 +00:00
Deomid Ryabkov d8f8c1cb99 I fail at math
PUBLISHED_FROM=c45da0cf83e9573a9fa8234f4dee1b9e4e5b977a
2015-11-30 12:27:57 +00:00
Deomid Ryabkov d2b9ad570f Add a custom linker script for 4m flash
PUBLISHED_FROM=a92b86588923fb54075b1c3ed8ca8112164c36c5
2015-11-25 12:06:28 +00:00
Deomid Ryabkov 5b36f32996 Add ESP8266 RTOS example
PUBLISHED_FROM=892d01b09f5801d3d19e6db1ce22b7916d2f83d5
2015-11-24 00:42:27 +00:00
Deomid Ryabkov 3298030b8e Changes to make Mongoose compile on ESP RTOS SDK
PUBLISHED_FROM=863a47416ee5e30f20f6523374ebd510cc022d99
2015-11-24 00:42:27 +00:00
Sergey Lyubka 6cfc696439 Add helper function mg_send_head()
PUBLISHED_FROM=5c9d11d21d34fa72974a021f0342068d87159634
2015-11-24 00:42:26 +00:00
Sergey Lyubka a93b3a06dd Change binary download link
PUBLISHED_FROM=bc1a39dc8c11bab83c20da2c6e9477da0d17f993
2015-11-20 12:07:52 +00:00
Deomid Ryabkov 79e8d77ea0 Shave the debug yak
PUBLISHED_FROM=402d26b6a2797bfe9fb70e48cbde97f3960ef5d4
2015-11-20 12:07:51 +00:00
Sergey Lyubka d68fab9ee5 Enable threads on Win by default
PUBLISHED_FROM=cc4070d618f079ccd1e02e62bba87247e75c74aa
2015-11-20 12:07:51 +00:00
Sergey Lyubka bda470245e Support for multiple listeners
PUBLISHED_FROM=ad00f31ae8732be2d7fdc7f0968fd04edfd76bb6
2015-11-20 12:07:51 +00:00
Sergey Lyubka 0c95290f93 Add extra headers support (allows CORS)
PUBLISHED_FROM=2279e31315bba4d19e2ae568cba94ea5dea3ef6a
2015-11-18 07:44:23 +00:00
Deomid Ryabkov 8989739d32 Use mg_call to invoke user handler
PUBLISHED_FROM=cefd472946dfe77ec262c1980eab983a919b6220
2015-11-18 07:44:23 +00:00
Sergey Lyubka 1112981e6e Fix mg_if_not_modified() logic
PUBLISHED_FROM=3eb1455eacc66af83904f56397c0e24b1d4f13bf
2015-11-18 07:44:23 +00:00
Sergey Lyubka 0cf82744ce Unbreak macos tests
PUBLISHED_FROM=a9521579223cfbb68e2b7bcd221335d25dacbb87
2015-11-18 07:44:22 +00:00
Deomid Ryabkov 5cdf838325 Fix error handling in async resolver
PUBLISHED_FROM=1e8558ec08f8e72d70163d34e0920f80f74372d1
2015-11-18 07:44:22 +00:00
Sergey Lyubka 6418cad39f Disable HTTP keep-alive on embedded
PUBLISHED_FROM=63bb1ca0f307a4332006d6cd13a35f0be6359174
2015-11-18 07:44:22 +00:00
Sergey Lyubka 46529fd51e Remove unused MG_F_DONT_SEND
PUBLISHED_FROM=beaec58b808fb767b7e491d8b5d6b23a6d5e4e0c
2015-11-18 07:44:21 +00:00
Marko Mikulicic c09ba40a48 Cleanup make format target
PUBLISHED_FROM=5f856af633ca9a10161769caac130fc6452f137f
2015-11-18 07:44:20 +00:00
Sergey Lyubka 47d52896a1 s/uri/url, to conform to nodejs HTTP API
PUBLISHED_FROM=32ba0c859ad9df3cf7dc3af8e379e49543e77843
2015-11-18 07:44:19 +00:00
Deomid Ryabkov d60c99b01c Make MG debug go to stderr
PUBLISHED_FROM=11618b6b2a50c62dd612d241c6b13a9aab357909
2015-11-18 07:44:19 +00:00
Sergey Lyubka b8aeba06a2 Add unit test for mg_parse_date_string
PUBLISHED_FROM=aec7d5e6c6598fbc5141c40c9638cc96d288c8dc
2015-11-18 07:44:18 +00:00
Sergey Lyubka 8a0bc2d614 Mongoose binary - GUI version fix
PUBLISHED_FROM=94c2b4c5a40c3519df6caa7561c3935bdf505575
2015-11-18 07:44:18 +00:00
Deomid Ryabkov e34747d1ad Handle case of malloc failure in mbuf_resize
PUBLISHED_FROM=0cb98ac520b8aeb8bbeb2f23b8c65c62ab256021
2015-10-30 18:38:43 +01:00
Deomid Ryabkov 1a6bc7c514 Fix mbuf_resize(0)
PUBLISHED_FROM=7cab7543db990f7f67b53edca4f65ba45b219711
2015-10-30 18:38:42 +01:00
Deomid Ryabkov ffa0ddfdbf Make mg_call usable in protocol handlers
PUBLISHED_FROM=63ad74b31750a851db090d2f2995ecf5f275538b
2015-10-30 18:38:42 +01:00
Alexander Alashkin ca55bff1cf Fix mg compilation
PUBLISHED_FROM=ce7fdfebd3ebbf88688514be501b33ad1241743c
2015-10-30 18:38:42 +01:00
Deomid Ryabkov cfee5c4fdb Mongoose TCP listener for ESP LWIP
PUBLISHED_FROM=e88b17d21ee78a4c2c1c4832db322e19b314206d
2015-10-30 18:38:42 +01:00
Marko Mikulicic e46185068b Avoid inlining of esp gcc bug workaround
PUBLISHED_FROM=f02283b42d842246c75df848061a80b754a97013
2015-10-30 18:38:42 +01:00
Marko Mikulicic 6ef2fea45e Workaround lx106 gcc bug stack frame size rounding
PUBLISHED_FROM=66906d0e5f6d97b135bd157f5f82dc13bef2fb1a
2015-10-30 18:38:41 +01:00
Deomid Ryabkov e244dd84a9 Mongoose and LWIP fixes
PUBLISHED_FROM=c63992029098108ae62234176d4334207b43dd7b
2015-10-30 18:38:41 +01:00
Deomid Ryabkov 5034937a15 Set more reasonable WS buffer size
PUBLISHED_FROM=ecfc284747f1b3eef5c40dd74b4af19f4618edcc
2015-10-30 18:38:41 +01:00
Deomid Ryabkov 060045be65 Un-static a bunch of structs to save ram when idle
PUBLISHED_FROM=1a994be80dd46ffd410f88db28816c85b2c2bf79
2015-10-30 18:38:41 +01:00
Deomid Ryabkov 9adfe8d484 espconn is out, Mongoose + LWIP is in
PUBLISHED_FROM=c67ea324058d70070f89420c40e57b9df87964b1
2015-10-30 18:38:41 +01:00
Deomid Ryabkov 799cc369e0 Reduce stack usage when parsing HTTP URL
PUBLISHED_FROM=682f59e58d8335352cc09987a91e85cc264cf0f8
2015-10-30 18:38:41 +01:00
Deomid Ryabkov b97d3fea4b strnlen should return size_t
PUBLISHED_FROM=545c7d80380c48332803ef00981763b130a1c1c6
2015-10-30 18:38:40 +01:00
Deomid Ryabkov 2a4ca9d5c3 Introduce a network interface API, refactor UDP
PUBLISHED_FROM=6e961e2760b2b64e211978ede5df8ca353ea5512
2015-10-30 18:38:40 +01:00
Deomid Ryabkov 747e40e74e Fix size_t printing on CC3200
PUBLISHED_FROM=65b068a7620e7117c0dffc762d710e08dfbad037
2015-10-30 18:38:40 +01:00
Marko Mikulicic cf279e7885 Address ignored return values of read and write
PUBLISHED_FROM=d76b6b9d91d7af0e916cd81e1213c463757bf924
2015-10-30 18:38:39 +01:00
Marko Mikulicic cbf968735a Fix MG_SEND_FUNC/MG_RECV_FUNC rename fail
PUBLISHED_FROM=da28a75111abb5fb49b122133a66ae9bdf63f474
2015-10-30 18:38:39 +01:00
Sergey Lyubka 57b35e6007 Add JS HTTP server to smartjs
PUBLISHED_FROM=13210e55d9434917549dcbf9a39a5377181f8387
2015-10-21 17:34:55 +02:00
Deomid Ryabkov 1eaabdd8e5 s/dmg/dns/g
PUBLISHED_FROM=96dc8b0b4001f2206749a401c615f043fc5f6131
2015-10-21 15:17:11 +02:00
Sergey Lyubka dcd4e660a3 Serve current dir by default in mg_serve_http()
PUBLISHED_FROM=421b4256629b2bccd20ceb127ece02be57085b40
2015-10-21 15:17:11 +02:00
Deomid Ryabkov 96409e74e5 Fix ALL the leaks!
PUBLISHED_FROM=0adf7c6c903075d6705693829f8758f8ff67d579
2015-10-21 15:17:11 +02:00
Sergey Lyubka e28ee097a1 Move mongoose binary to dev repo
PUBLISHED_FROM=224a216abc4a7cca50d80f762dca602f54470105
2015-10-21 15:17:11 +02:00
Deomid Ryabkov 2b4e544867 Move "connect done" logic from mg_read_from_socket
PUBLISHED_FROM=318cc110d8b012cf75cb02dfc68a8215faa93fe7
2015-10-21 15:17:11 +02:00
Deomid Ryabkov ee042a3481 Fix SSI parsing
PUBLISHED_FROM=c918da948354def5815dfd6b832053f170212c6f
2015-10-16 12:57:02 +01:00
Alexander Alashkin 63075f6846 Add restful_client & restful_server VC projects
PUBLISHED_FROM=5ee78f5c907401c93a04f89d6b25b99515aa809a
2015-10-16 10:31:23 +01:00
Alexander Alashkin 7f2e42a06d Fix MSVC2015 build and add VC project
PUBLISHED_FROM=d071ecd0bdcc871cdd18a65c1ebb8b546ff61941
2015-10-16 10:31:23 +01:00
Sergey Lyubka 3fbfa33b9a Minor nitpicks for big_upload
PUBLISHED_FROM=55d4270916f32ce4645965fbd7a031d7f8e1907b
2015-10-13 10:38:36 +01:00
Maxim Ignatenko 179aa75047 Add big_upload example
PUBLISHED_FROM=58dfd3cfdbc5f908e5fa10171274f0d5dd256404
2015-10-13 10:38:36 +01:00
Maxim Ignatenko 4658194d08 Properly populate mg_connection.sa field
PUBLISHED_FROM=a305c720aee1b159847e10c962b6de7fe08bc787
2015-10-12 12:48:35 +01:00
Marko Mikulicic b35657814c Factor our LWIP enabling flag
PUBLISHED_FROM=d080ccb2d0daef1103ff7487b5c3f4b65ab97b99
2015-10-12 11:05:33 +01:00
Marko Mikulicic a2322c77c6 Fix mongoose build
PUBLISHED_FROM=ec4a774dfd690876201080ff55bdbec5bd865670
2015-10-12 11:05:33 +01:00
Marko Mikulicic b50c183c19 Simplify and abstract C func arg access
PUBLISHED_FROM=c174439a2d22794497dc35fd46ceb1f6c4e553a2
2015-10-12 11:05:32 +01:00
Maxim Ignatenko a941687db0 Fix mongoose build
PUBLISHED_FROM=aec35861339d336697649fd2020766439b3814ad
2015-10-12 11:05:32 +01:00
Marko Mikulicic c2eef52b65 Add CLA to mongoose README
PUBLISHED_FROM=9987c788e55bc949c06ebf355d51d38ef2d109d6
2015-10-12 11:05:32 +01:00
Claudiu 3e6cbbde04 Fix static function prototype
PUBLISHED_FROM=d90d06593ec4531f479053243c72601ee27a3141
2015-10-05 22:27:10 +02:00
Sergey Lyubka 6400536282 Rename v7_get_global_object() -> v7_get_global()
PUBLISHED_FROM=91a306d5dbc55d65505904b1a19cca5bbe9f58cc
2015-10-05 22:27:10 +02:00
Sergey Lyubka 776103068f Add examples for mongoose blog article
PUBLISHED_FROM=54f54211919bb2276e02b4d10306ffa5540a9313
2015-10-02 13:10:47 +01:00
Maxim Ignatenko 93beff3b65 Use select() by default everywhere
PUBLISHED_FROM=474789b0d7f5076434e5c15c079306243f3a8d81
2015-09-25 16:19:50 +01:00
Marko Mikulicic 22f8d86b05 Makes sure send file releases resources on close
PUBLISHED_FROM=451d2dd0b55b9fd7dea441a9279f54d0005c97b1
2015-09-25 16:19:50 +01:00
Marko Mikulicic 3a9a9c7ad0 Enable printf format warnings for mg_printf
PUBLISHED_FROM=61a52651a2542cb89b155623781a5fcbf64779f3
2015-09-25 16:19:50 +01:00
Alexander Alashkin 13238b1ad2 Restore win build
PUBLISHED_FROM=fe072db3dcc5f92f44d91a81596e33e404887951
2015-09-25 16:19:50 +01:00
Marko Mikulicic 56f661e9c6 Make mg send_http_file work for ESP8266 RTOS
PUBLISHED_FROM=10623cfe38e143f7e107a6494baa298c788586f0
2015-09-25 16:19:49 +01:00
Marko Mikulicic 5351f46efb Mongoose send on esp8266 RTOS_SDK
PUBLISHED_FROM=1e97853ebc1c39b01754cf76d875453842e9b36d
2015-09-25 16:19:49 +01:00
Sergey Lyubka 0cd3335b78 Update mongoose download link
PUBLISHED_FROM=70a6e34c6630e3ab95d200b173d22529101b61ea
2015-09-22 10:35:55 +01:00
Marko Mikulicic 0611627448 Serve a http file on quantex
PUBLISHED_FROM=856d2e0bdaddece638d215c252fabeb9ea2d7809
2015-09-22 10:32:02 +01:00
Sergey Lyubka f014918435 Add JS support to Mongoose
PUBLISHED_FROM=5f319c5c6d965432da063ce7ab495ae24e972755
2015-09-22 10:32:01 +01:00
Sergey Lyubka 51e016089e Nitpick README update
PUBLISHED_FROM=28b3a30ad82432e8e3ca194d7e204acf9a998e94
2015-09-22 10:32:01 +01:00
Sergey Lyubka 8a66ff5278 Mongoose rebrand changes
PUBLISHED_FROM=50497043e8d0c10487804263cdcb1cbb260d5a26
2015-09-21 15:19:35 +01:00
Sergey Lyubka e1dd3f06fe Rename Mongoose constants: NS_ -> MG_, NSF_ -> MG_F_
PUBLISHED_FROM=c9cc54df1883aa17606de2b1ffb30f0cd687d037
2015-09-21 15:19:34 +01:00
Deomid Ryabkov 32ab35f61f Rename hmac_sha1 -> cs_hmac_sha1
PUBLISHED_FROM=3d4fbd8192d04add406e304b113ce5ec0b1c1165
2015-09-21 15:19:34 +01:00
Marko Mikulicic 8ab96ec74b Implement binary and incremental clubby client
PUBLISHED_FROM=ba371b8a3d9dd8afcb771144beb8e5c344c7d6c7
2015-09-21 15:19:33 +01:00
Sergey Lyubka 0730590e35 Fix SSL codepath in restful_server example
PUBLISHED_FROM=4cd52839b8d2396f50f94f1ce36fa7b4501dc204
2015-09-21 15:19:33 +01:00
Marko Mikulicic f7e0b1331c Implement incremental UBJSON serializer
PUBLISHED_FROM=fe0936cbf8c16d5b5cfdf674e8e7181f6b2771cc
2015-09-21 15:19:33 +01:00
Marko Mikulicic 17aa2a7092 Implement streaming base64 encoder
PUBLISHED_FROM=af3c6c0e8f9806c1bdc570c06cc6eea9995d6e3d
2015-09-21 15:19:33 +01:00
Alexander Alashkin 7d38d05ca7 Use updated sockets
PUBLISHED_FROM=30231da54720c709ce98cd0ab208cf9b06814eab
2015-09-21 15:19:33 +01:00
TheTypoMaster 33bad047f0 Fix typo recieve
PUBLISHED_FROM=6e2f4fffb91ff18da94d97aba763acbdde496515
2015-09-09 10:21:21 +01:00
Marko Mikulicic 5234b73c29 Add simple core dumper for ESP
PUBLISHED_FROM=ec98516ce6aa1c841344adc7aae20b044b3d349b
2015-09-09 10:21:21 +01:00
Sergey Lyubka c566e2eba5 Mongoose README
PUBLISHED_FROM=f2409461d1ef4eef81b5481914bee5e596e906f8
2015-09-08 14:42:13 +02:00
Marko Mikulicic e565977481 Merge pull request #568 from cesanta/fossamerge
Merge dev branch code named Fossa as next stable Mongoose
2015-09-08 14:39:52 +02:00
Marko Mikulicic 8927c9d22b Merge dev branch code named Fossa as next stable Mongoose 2015-09-08 14:34:30 +02:00
Marko Mikulicic 28eb251ccd Merge pull request #567 from cesanta/move
Fossa merge
2015-09-08 13:28:38 +02:00
Sergey Lyubka b99dc95b1d Fossa merge.
PUBLISHED_FROM=12ccba10358075024a1195cd0b0c1ea132aae6a3
2015-09-08 12:26:25 +01:00
Sergey Lyubka 75aadb3e79 Fix links 2015-08-26 11:23:54 +01:00
Sergey Lyubka b6ecd5fb4c Update readme 2015-08-20 10:20:02 +01:00
Sergey Lyubka 1e7f55ed84 Update readme 2015-08-20 08:56:14 +01:00
Sergey Lyubka eeadc5ecff Updated readme 2015-08-18 12:21:33 +01:00
Sergey Lyubka 568ca42988 Updated readme 2015-08-18 11:26:43 +01:00
Sergey Lyubka 7b758bfc9d Updated readme 2015-08-18 10:47:23 +01:00
Sergey Lyubka 8ef454b75f Updated readme 2015-08-18 09:50:00 +01:00
Marko Mikulicic 0a2f2fda5c Merge pull request #563 from cesanta/sdp
Tweak event handler a bit for clarity
2015-08-13 15:42:45 +02:00
rojer 6b440918ec Tweak event handler a bit for clarity
Put cases in the order we expect them to occur
2015-08-13 14:38:41 +01:00
Marko Mikulicic a73fce945c Merge pull request #562 from cesanta/sdp
Swallow responses to internal pings
2015-08-12 19:45:04 +02:00
rojer d349bb3cc7 Swallow responses to internal pings 2015-08-12 18:35:18 +01:00
Marko Mikulicic 7c4119a287 Merge pull request #561 from cesanta/sdp
Mongoose example for server data push
2015-08-12 18:52:51 +02:00
rojer 8a71ad99e6 Mongoose example for server data push 2015-08-12 17:42:05 +01:00
Sergey Lyubka 41b405d7bf Remove examples/web_server 2015-07-13 11:14:19 +01:00
Sergey Lyubka 30b80dc5ee Update example 2015-07-13 11:11:26 +01:00
Sergey Lyubka 524aa2e586 Merge pull request #556 from nesteroff/vs2013
Fix VS2013 warnings
2015-07-13 11:03:13 +01:00
Yuri Nesterov 990a1b9ae0 Fix VS2013 warnings 2015-07-12 15:43:54 +03:00
Sergey Lyubka 4cb0c6864e Merge pull request #550 from cesanta/fixpolar
Fix ssl close with polarssl
2015-07-02 17:06:30 +01:00
Marko Mikulicic 5183693951 Fix ssl close with polarssl 2015-07-02 16:26:31 +02:00
Sergey Lyubka e47506f957 Fix unauthenticated body handling 2015-06-22 12:05:31 +01:00
Sergey Lyubka 824e4dc0e4 Fix file upload iteration 2015-06-19 19:01:21 +01:00
Sergey Lyubka d033497714 Merge pull request #541 from NickCis/connection_param_fix
Possible fix in order not to loose the reference of connection_param pointer
2015-06-10 15:32:28 +01:00
Nicolas Cisco d8028df29d Quick fix in order not to loose the reference of connection_param pointer 2015-06-10 01:49:37 -03:00
Sergey Lyubka 564683d25a Fix timeout for cookie auth example 2015-06-05 18:09:27 +01:00
Sergey Lyubka 30c0a3f201 Propagate select() and socketpair() errors to the user 2015-06-04 11:27:31 +01:00
Sergey Lyubka 08fe9ac518 Fix examples 2015-05-20 10:53:10 +01:00
Sergey Lyubka 14d6f71f82 Fix unit test 2015-05-20 10:50:32 +01:00
Sergey Lyubka 29454e2296 Merge pull request #524 from NickCis/array_variables
Implementing array varibles
2015-05-20 10:05:48 +01:00
NickCis d6cbf9f77d Fixing C coding style mistakes 2015-05-19 13:54:35 -03:00
Sergey Lyubka b9fead4d6e Merge pull request #525 from NickCis/mg_vprintf
Adding mg_vprintf and mg_vprintf_data.
2015-05-19 15:54:27 +01:00
Sergey Lyubka c6a04e1719 Fix #523 2015-05-18 11:50:56 +01:00
NickCis c839a61fea Adding mg_vprintf and mg_vprintf_data in order to use va_list like functions 2015-05-15 16:20:33 -03:00
NickCis c06abbc5f7 Implementing array varibles 2015-05-15 15:49:35 -03:00
Sergey Lyubka c8e88e1710 Sync fossa struct definitions 2015-05-15 17:20:54 +01:00
Sergey Lyubka bf7a115bf2 Fix url rewrites 2015-05-11 09:13:46 +01:00
Sergey Lyubka b8dfb69cf5 Merge pull request #514 from cesanta/fix_setsize
Fix default windows FD_SETSIZE, closes #506
2015-04-17 07:10:24 +01:00
Marko Mikulicic 1cd9715095 Fix default windows FD_SETSIZE, closes #506
https://support.microsoft.com/en-us/kb/111855 describes
that the user is expected to set the FD_SETSIZE macro
before including winsock2.h
2015-04-17 02:30:22 +02:00
Sergey Lyubka 5c7aeac148 Merge pull request #509 from cesanta/Fix_mjpg_streamer_example
Fix mjpg_streamer example
2015-04-13 23:37:27 +01:00
Alexander Alashkin 09a80628e6 Fix mjpg_streamer example 2015-04-13 16:02:52 +03:00
Sergey Lyubka 2ff2c369f7 Merge pull request #505 from eugoss/master
Inspect POST buffer in mg_get_var() only if first call of get_var() returns -1
2015-04-10 18:31:15 +01:00
Marko Mikulicic eef70aaf74 Merge pull request #507 from gitter-badger/gitter-badge
Add a Gitter chat badge to README.md
2015-04-09 13:04:18 +02:00
The Gitter Badger 89ac97caba Added Gitter badge 2015-04-09 10:58:41 +00:00
Eugene Ossintsev c00b236c8d Fix spelling in docs/ReleaseNotes.md and in comments in mongoose.c 2015-04-09 00:15:40 -04:00
Eugene Ossintsev eacd3f35e0 Inspect POST buffer in mg_get_var() only if first call of get_var() returns -1
In mg_get_var() the first call of get_var() inspects the variables of
the query string. If the requested variable is found but the destination
buffer is too small to hold the variable, return -2 right away. If it's
not found, make the second call of get_var() to inspect the POST buffer.
2015-04-05 23:40:50 -04:00
Marko Mikulicic 8a2aa72571 Merge pull request #504 from himanshupsharma/check_fd-setsize
Reverting (socket < 0) checks to avoid Windows build failure.
2015-04-03 11:22:50 +02:00
p_himanshu 7da8f273d2 Reverting (socket < 0) checks to avoid Windows build failure. 2015-04-02 16:47:07 -07:00
Sergey Lyubka a90a5a2b6a Merge pull request #503 from himanshupsharma/check_fd-setsize
Adding a check to avoid undefined behavior if socket is out of the bound...
2015-04-02 18:28:23 +01:00
p_himanshu b5b819b4a3 Adding a check to avoid undefined behavior if socket is out of the bounds of FD_SETSIZE. 2015-04-01 22:24:29 -07:00
Sergey Lyubka 821e2b3a75 Merge pull request #501 from xant/upstream
safety belt : scan_directory() can return without setting arr to a valid value
2015-04-01 20:22:20 +01:00
Sergey Lyubka 773efb0745 Respect WEBSOCKET_OPCODE_CONNECTION_CLOSE coming from client 2015-04-01 18:37:13 +01:00
Andrea Guzzo ed1904a75d safety belt : scan_directory() can return without setting arr to a valid value 2015-03-31 12:52:08 +02:00
Sergey Lyubka a66663f0f6 Fix non-openssl build 2015-03-31 10:38:14 +01:00
Sergey Lyubka 1104688b02 Fix win32 build no2 2015-03-25 17:29:34 +00:00
Sergey Lyubka 36d95e230e Fix win32 build 2015-03-25 17:10:58 +00:00
Sergey Lyubka 8a27a95a2a Fix #460 2015-03-24 09:32:16 +00:00
Sergey Lyubka 2e63b5a5e5 Fix #441 2015-03-24 08:04:46 +00:00
Sergey Lyubka 4cbd113d01 Upload multiple files 2015-03-24 07:52:49 +00:00
Sergey Lyubka ba5ae74144 Merge pull request #495 from mmicko/master
OS2 and Android NDK fixes
2015-03-22 17:03:28 +00:00
Miodrag Milanovic f2b40e5fae added comment for time_t change 2015-03-22 17:56:22 +01:00
Sergey Lyubka 8ed682930b Fix #448 2015-03-21 13:17:24 +00:00
Miodrag Milanovic 86ad7922b0 OS2 and Android NDK fixes
Note that in Android NDK st_mtime is long unsigned int
2015-03-21 11:04:57 +01:00
Sergey Lyubka f7476f53c7 Merge pull request #493 from RobertDiPaolo/bugfix/Visual_Studios_Build_Issues
Correctly handle _CRT_SECURE_NO_WARNINGS already being set in project se...
2015-03-20 16:29:11 +00:00
Sergey Lyubka 5d6f7ac8ef Merge pull request #494 from RobertDiPaolo/bugfix/Memory_Leak
Fixed Memory Leak
2015-03-20 16:28:15 +00:00
Sergey Lyubka f16fa5ed55 Merge pull request #492 from RobertDiPaolo/feature/Add_PATCH_Method
Added PATCH to list of valid HTTP Methods.
2015-03-20 16:28:11 +00:00
Sergey Lyubka c0ba32f7a6 Set NS_DISABLE_THREADS ifndef MONGOOSE_ENABLE_THREADS 2015-03-20 15:33:02 +00:00
Sergey Lyubka 409c12a851 Better logic for port resolving 2015-03-18 17:25:46 +00:00
Sergey Lyubka bcdcbf20ee Release 5.6 2015-03-18 17:25:31 +00:00
Sergey Lyubka 8fc5b5a55f Add contribution section to readme 2015-03-18 15:45:52 +00:00
Robert Di Paolo 7cf28a5623 The 'char *ip' variable was being allocated and zeroed but not being used or freed. 2015-03-18 10:04:08 +00:00
Robert Di Paolo 6668c456ac Correctly handle _CRT_SECURE_NO_WARNINGS already being set in project settings. 2015-03-18 09:56:01 +00:00
Robert Di Paolo 98f2476751 Added PATCH to list of valid HTTP Methods. 2015-03-18 09:48:17 +00:00
Sergey Lyubka faeedb2930 Sync main 2015-03-18 09:37:52 +00:00
Sergey Lyubka c8e8f94ffe Sync main 2015-03-17 17:35:31 +00:00
Sergey Lyubka 22aeb6111b Update ReleaseNotes 2015-03-17 17:01:16 +00:00
Sergey Lyubka 2d1d2e6534 SIZE_MAX is not defined on MSVC6, use (size_t) ~0 2015-03-17 17:00:59 +00:00
Sergey Lyubka 05c88a98fc Introduce -dav_root option 2015-03-17 15:34:56 +00:00
Marko Mikulicic 5224afb946 Merge pull request #485 from dsrosario/fix_remove_double_dots 2015-03-17 16:07:46 +01:00
Dinis Rosário 3bd79c7cd5 Fix remove_double_dots_and_double_slashes removing all the dots leading http server to serve wrong URI
If the uri is something like '/js/...jquery.js', remove_double_dots_and_double_slashes will remove the 3 dots and the http server will serves the /js/jquery.js file.
remove_double_dots_and_double_slashes should check if a dot or double dots is followed by a slash (or backslash) and only remove this to avoid disclosure attack.
2015-03-17 16:04:59 +01:00
Sergey Lyubka c52e0744cb Squashed warnings after size_t change 2015-03-17 13:18:15 +00:00
Sergey Lyubka 6c09c303d0 Merge pull request #456 from sebgod/fix-win32-examples-using-extra
Enable building of example/Makefile on Win32
2015-03-17 11:45:36 +00:00
Sergey Lyubka b6fde06990 Merge pull request #486 from mmicko/master
Compile fix
2015-03-16 16:52:48 +00:00
Miodrag Milanovic af892c9726 compile fix for visual studio 2015-03-14 09:02:25 +01:00
Miodrag Milanovic df7ad13680 Compile fix 2015-03-13 20:15:19 +01:00
Sergey Lyubka 057c2d4b42 Merge pull request #484 from davidmilligan/master
fix compiler warnings for 64 bit compilation
2015-03-10 18:40:16 +00:00
David Milligan 6c9b43bcf5 fix compiler warnings for 64 bit compilation 2015-03-09 20:01:09 -04:00
Sergey Lyubka a91438acae Fix #477 2015-03-09 16:09:05 +00:00
Sergey Lyubka a6fa51dbc2 Merge pull request #481 from cesanta/web_server_ssl
web_server_ssl
2015-03-06 14:39:50 +00:00
Alexander Alashkin 6ceac6c84c web_server_ssl 2015-03-06 15:08:57 +02:00
Sergey Lyubka 288efe3c23 Add -DMONGOOSE_ENABLE_THREADS to other examples 2015-03-06 09:29:56 +00:00
Sergey Lyubka 5207545a8b Add -DMONGOOSE_ENABLE_THREADS to proxy server example 2015-03-06 09:28:27 +00:00
Sergey Lyubka 716d524f9b Add -DMONGOOSE_ENABLE_THREADS to Makefile 2015-03-06 09:25:30 +00:00
Sergey Lyubka a434bab767 Merge pull request #480 from cesanta/polarssl_examples_1
websocket_ssl_proxy sample for polarsll
2015-03-06 09:03:38 +00:00
Alexander Alashkin e9633a8d2d websocket_ssl_proxy 2015-03-06 09:32:08 +02:00
Sergey Lyubka c7b6a6f0ea Added mg_websocket_printf() 2015-03-05 10:54:51 +00:00
Sergey Lyubka 6cdb9f7ed3 Merge pull request #474 from mmicko/master
OS/2 patches by KO Myung-Hun
2015-03-04 17:18:16 +00:00
Sergey Lyubka 4502dd0c86 s/MONGOOSE_NO_THREADS/MONGOOSE_ENABLE_THREADS 2015-03-03 18:59:23 +00:00
Sergey Lyubka 95055f6048 Add winsock2.h include for win32 2015-03-03 18:32:14 +00:00
Sergey Lyubka 2c36532ec4 Merge pull request #465 from doug16rogers/vs9-compile-ipv6
Allow for compilation in Visual Studio with NS_ENABLE_IPV6.
2015-03-03 18:28:07 +00:00
Sergey Lyubka f2b0b9c737 Fix Win32 build in mg_websocket_write() 2015-02-24 13:32:22 +00:00
Sergey Lyubka b3866439a0 Fix mg_create_server() signature 2015-02-24 13:17:11 +00:00
Miodrag Milanovic 4f2205a667 OS/2 patches by KO Myung-Hun
Upstream patch from MAME project
2015-02-24 11:12:09 +01:00
Sergey Lyubka 6cec1d36a8 Merge pull request #463 from CurlyMoo/patch-1
Replace obsolete gethostbyname by getaddrinfo
2015-02-19 11:48:35 +00:00
CurlyMoo 4238370ae1 Check for getaddrinfo availability. 2015-02-19 12:09:34 +01:00
Sergey Lyubka b4924b715e Merge pull request #473 from mmicko/master
Fix for MINGW builds
2015-02-17 16:19:37 +00:00
Miodrag Milanovic 7a0385dcac Fix for MINGW builds 2015-02-17 11:08:23 +01:00
Sergey Lyubka 44a146faf6 SSL fixes 2015-02-16 18:34:07 +00:00
Sergey Lyubka 53a55da7bc Add type cast in ns_out() 2015-02-16 18:19:15 +00:00
Sergey Lyubka bf44277764 Define _XOPEN_SOURCE for MinGW build 2015-02-16 18:17:30 +00:00
Sergey Lyubka a2e1da6e30 Add overflow checks 2015-02-12 19:12:58 +00:00
Sergey Lyubka bef3f85ba8 Merge pull request #466 from 0-wiz-0/master
Only define _XOPEN_SOURCE on Linux.
2015-02-10 18:07:07 +00:00
Thomas Klausner eb72a63cca Only define _XOPEN_SOURCE on Linux.
Fixes the build on NetBSD.

The comment says it's only needed on Linux, and AFAIK Linux
is the only operating system that only adds symbols when it's defined;
others, like NetBSD or Solaris, also hide symbols.

Signed-off-by: Thomas Klausner <wiz@NetBSD.org>
2015-01-29 15:02:26 +01:00
Doug Rogers f19bbc73cc Allow for compilation in Visual Studio 9 (2008) with NS_ENABLE_IPV6. 2015-01-29 00:12:35 -05:00
Sergey Lyubka 25326b3b12 net skeleton -> fossa 2015-01-28 12:33:48 +00:00
CurlyMoo 10ee430bfd Add debug line and adapt to styling guide
Replaced tabs with spaces.
2015-01-27 22:55:13 +01:00
CurlyMoo 10d0bfdab4 Replace obsolete gethostbyname by getaddrinfo
This also protect against the latest glibc bug
2015-01-27 22:45:34 +01:00
Sergey Lyubka 6b6637c337 Adopt SSL guide to current way of setting SSL cert. 2015-01-21 17:41:45 +00:00
Sergey Lyubka 878acca213 Removed Lua docs 2015-01-21 17:30:30 +00:00
Sergey Lyubka ace9285966 Updated years 2015-01-19 18:25:14 +00:00
Sergey Lyubka cdc167b0cc Merge pull request #459 from joshcriz/patch-1
Update Makefile
2015-01-19 16:32:24 +00:00
Josh Criz a0dd396b95 Update Makefile
Fixing typo in 'clean' section
2015-01-16 17:59:08 -06:00
Sebastian Godelet 8082501b9c Enable building of example/Makefile on Win32
Adding example/.gitignore to ignore *.exe
Appending -lws2_32 at the end of CFLAGS_EXTRA if running make on
Windows to enable easy compiling under that platform.
Obsoletes pull request #454
2015-01-10 16:41:58 +08:00
Sergey Lyubka e4ad3010be Fix #416 2014-12-30 03:56:29 +00:00
Sergey Lyubka 03a82ef848 Merge pull request #452 from CurlyMoo/patch-2
Typo
2014-12-27 18:25:09 +00:00
CurlyMoo 9459d69dcc Typo 2014-12-27 18:35:09 +01:00
Sergey Lyubka b28662362d Merge pull request #449 from ursine/patch-1
64-bit length fields on ARM don't work
2014-12-21 20:54:52 +00:00
Sergey Lyubka 66450bf3d1 Merge pull request #450 from sebgod/master
mongoose.c: using application/javascript for .js
2014-12-21 16:07:12 +00:00
Sebastian Godelet 478ca05e7a mongoose.c: using application/javascript for .js
As of http://www.rfc-editor.org/rfc/rfc4329.txt, the preferred MIME type
for JavaScript is application/javascript.
2014-12-21 22:16:05 +08:00
Gary Coulbourne 8cad0a72f9 64-bit length fields on ARM don't work
ARM only allows aligned accesses.  GCC generated unaligned accesses for the copy buffer, but ARM forces alignment, causing the first two bytes to be trampled.  I changed the mechanism to create two temporaries and memcpy them in.  It now works on ARM (and x86) for large websocket chunks.
2014-12-17 19:14:30 -05:00
Sergey Lyubka 31178f4d48 Typo fixed in the comment 2014-12-15 12:03:50 +00:00
Sergey Lyubka 7a5485493e Added md5 copyright 2014-12-11 18:01:58 +00:00
Sergey Lyubka d3cbb160f5 Removed travis config file 2014-12-01 11:33:16 +00:00
Sergey Lyubka 45ff2c2c19 Removed $Date$ marker 2014-11-28 14:16:49 +00:00
Sergey Lyubka c3db7b141b Removed $Date$ from header 2014-11-28 12:21:36 +00:00
Sergey Lyubka 0a0ea36ace Fix examples/proxy_server build 2014-11-24 19:33:24 +00:00
Sergey Lyubka 72ed954721 Merge pull request #440 from zapline/patch-1
Update ReleaseNotes.md(spell mistake)
2014-11-20 07:35:24 +00:00
zapline 33e035273a Update ReleaseNotes.md
spell mistake
2014-11-20 09:58:29 +08:00
Sergey Lyubka 223f36c130 Updated Readme 2014-11-17 15:50:02 +00:00
Sergey Lyubka 4c0bc5bd03 Updated Readme 2014-11-17 15:49:37 +00:00
Sergey Lyubka 808a5f6f53 Update README.md 2014-11-13 13:48:43 +00:00
Sergey Lyubka 404e635665 Fixed Android build 2014-11-12 22:16:32 +00:00
Sergey Lyubka 9d7a60a63f Merge pull request #433 from jhnwkmn/malloc
Consistent use of NS_MALLOC, NS_FREE and NS_REALLOC
2014-11-10 10:35:07 +00:00
Johan Wikman ba9c74187b Consistent use of NS_MALLOC, NS_FREE and NS_REALLOC
malloc(), free() and realloc() were used in a number of places.
Added NS_CALLOC as well.
2014-11-10 08:29:19 +02:00
Sergey Lyubka e9d4847cbb Merge pull request #432 from jhnwkmn/o_binary
O_BINARY might be defined.
2014-11-09 10:06:16 +00:00
Sergey Lyubka ea76de07ee Merge pull request #436 from jhnwkmn/no-cgi
MONGOOSE_NO_CGI needs special handling.
2014-11-09 10:04:54 +00:00
Sergey Lyubka 5a8c468ff7 Merge pull request #435 from jhnwkmn/size-macros
Added size macros.
2014-11-09 10:01:59 +00:00
Sergey Lyubka 5b143a6237 Merge pull request #434 from jhnwkmn/no-user
Added MONGOOSE_NO_USER configuration define.
2014-11-09 09:56:31 +00:00
Sergey Lyubka d244a7fdfd Merge pull request #437 from jhnwkmn/nsf-close-immediately
If socket is about to be closed do not add to [read|write]_set.
2014-11-09 09:55:13 +00:00
Johan Wikman 300a27de99 If socket is about to be closed do not add to [read|write]_set.
If NSG_CLOSE_IMMEDIATELY is on, then the socket will be closed,
which means that (if the socket was added to either read_set or
write_set) the subsequent select will in turn be performed on a
socket that has been closed.

Standard socket implementations seem to ignore a descriptor
referring to a closed socket but LWIP
(http://savannah.nongnu.org/projects/lwip/) crashes. So better
not to add to the sets.
2014-11-07 15:48:23 +02:00
Johan Wikman 04a15a0c10 MONGOOSE_NO_CGI needs special handling.
MONGOOSE_NO_CGI is implied by both NS_DISABLE_SOCKETPAIR and
MONGOOSE_NO_FILESYSTEM. Thus, so as not to get complaints about
the same define being defined twice, some extra checks are needed.
2014-11-07 15:29:25 +02:00
Johan Wikman f0f6ae05aa Added size macros.
On very resource constraind devices you need to be able to
control the size of all buffers and structures placed on the
stack.
2014-11-07 14:31:44 +02:00
Johan Wikman 8a7d535d92 Added MONGOOSE_NO_USER configuration define.
Low-end systems, not running a proper OS, may not have the
concept of a user.
2014-11-07 14:01:13 +02:00
Sergey Lyubka e7ac6024de Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-11-07 10:05:51 +00:00
Sergey Lyubka 9981b99ac8 Extra NULL check in iter2(). Fix #430 2014-11-07 10:05:42 +00:00
Johan Wikman 87a36c0c30 O_BINARY might be defined.
Some unix environments defines O_BINARY.
2014-11-07 12:02:11 +02:00
Sergey Lyubka f2b13761c0 Merge pull request #431 from jhnwkmn/reduce-includes
Conditionally include dirent.h and dlfcn.h
2014-11-07 09:51:30 +00:00
Johan Wikman 9786478a31 Conditionally include dirent.h and dlfcn.h
If you do not have a filesystem or do not support dav or
dynamic loading, the corresponding header files need not
be included (some environments might not have them).
2014-11-07 11:05:51 +02:00
Sergey Lyubka 7d236d7f33 Merge pull request #429 from AlexAltea/master
Added #define's for deprecated POSIX names
2014-11-01 20:39:34 +00:00
Alexandro Sánchez Bach e098a7292d Added #define's for deprecated POSIX names 2014-10-30 23:07:48 +01:00
Sergey Lyubka 632b3a38a9 5.5 -> 5.6 2014-10-28 11:43:51 +00:00
Sergey Lyubka 23141c2fef Added 5.5 release notes 2014-10-28 11:42:47 +00:00
Sergey Lyubka c8ba652f1c 5.4 -> 5.5 2014-10-28 11:20:44 +00:00
Sergey Lyubka 6ac2fa2ae6 Updated listening_port for SSL option 2014-10-28 11:20:10 +00:00
Sergey Lyubka 0322ec5647 Include query_string when proxying requests 2014-10-22 12:14:21 +01:00
Sergey Lyubka a5223a9850 Squashed ARM warnings 2014-10-21 15:51:42 +01:00
Sergey Lyubka 016968ada1 Removed net_skeleton dependency from examples/proxy_server 2014-10-17 20:29:39 +01:00
Sergey Lyubka 710b888122 Added -pthread to test/Makefile::CFLAGS 2014-10-17 20:12:29 +01:00
Sergey Lyubka cf53959f34 Fix broken push (type cast) 2014-10-17 20:03:15 +01:00
Sergey Lyubka 30d29fb77f Merge pull request #425 from mpromonet/master
make compile with g++ (fix invalid cast from ‘void*’)
2014-10-17 19:49:59 +01:00
MPR c05b51bbfc make compile with g++ (fix invalid conversion from ‘void*’ to ‘ns_connection*’) 2014-10-16 23:57:14 +02:00
Sergey Lyubka 1ab704ac92 Fixed -DMONGOOSE_NO_DIRECTORY_LISTING build 2014-10-16 10:46:33 +01:00
Sergey Lyubka 2bc77e065c Fixed build 2014-10-15 14:29:22 +01:00
Sergey Lyubka 790daabf7d Enhanced RESTful API example 2014-10-15 11:58:47 +01:00
Sergey Lyubka a6598a1278 Added #define close(x) _close(x) for WIN32 to squash warning 4996 that VS2013 gives 2014-10-15 08:30:49 +01:00
Sergey Lyubka 0af5502b74 Removed redundant #defines for -D_WIN32 case 2014-10-15 08:28:17 +01:00
Sergey Lyubka f059e41cac Removed mg_set_listening_socket() and mg_get_listening_socket(), added mg_copy_listeners() 2014-10-14 15:25:56 +01:00
Sergey Lyubka 2cce91de9a Refactored code for multiple listeners 2014-10-14 14:22:26 +01:00
Sergey Lyubka 0ff5b5b044 Added support for multiple listeners 2014-10-14 13:59:22 +01:00
Sergey Lyubka 0c5d9a98c2 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-10-14 11:10:47 +01:00
Sergey Lyubka c9fbdfc1b5 mg_open() accepts 3rd param: mode 2014-10-14 11:10:42 +01:00
Sergey Lyubka 6193b5171c Merge pull request #421 from mpromonet/master
transmit http answer code using http_client
2014-10-14 11:10:03 +01:00
Sergey Lyubka 911115ccc0 Added -pthread to CFLAGS for linux 2014-10-14 10:05:12 +00:00
Sergey Lyubka 2f3ddeccc5 Properly trim whitespaces from the hashbang CGI interpreter path 2014-10-13 15:57:34 +01:00
MPR ca3f5a3257 follow Google style 2014-10-12 13:58:06 +02:00
MPR df206bc05a transmit http answer code using http_client 2014-10-11 17:56:35 +02:00
Sergey Lyubka 531fec34fd Added missing files 2014-10-10 14:35:39 +01:00
Sergey Lyubka 4c10d1f356 mongoose_server -> web_server 2014-10-10 13:58:45 +01:00
Sergey Lyubka 94dccdd6f4 c# -> csharp 2014-10-10 10:02:58 +01:00
Sergey Lyubka 544352b7d3 moved jni to android_build 2014-10-10 09:51:57 +01:00
Sergey Lyubka 29c2ae4886 moved multi_threaded to separate dir 2014-10-10 09:51:02 +01:00
Sergey Lyubka 1a2e2ec2fd moved proxy to separate dir 2014-10-10 09:48:43 +01:00
Sergey Lyubka 3e780d21fc moved form.c example to separate dir 2014-10-10 09:44:45 +01:00
Sergey Lyubka 63fcea0159 moved form_submit to separate dir 2014-10-10 09:40:07 +01:00
Sergey Lyubka e5d21225be moved big_upload to separate dir 2014-10-10 09:39:12 +01:00
Sergey Lyubka 0c9caf3120 Moved server.c to separate dir 2014-10-10 09:37:18 +01:00
Sergey Lyubka 54ba36c1c9 check_login_form_submission() factored in separate function 2014-10-09 11:44:12 +01:00
Sergey Lyubka 5077350589 Added cookie based auth example 2014-10-09 11:29:39 +01:00
Sergey Lyubka 2d880c4f5c Moved auth.c to separate dir 2014-10-09 09:42:07 +01:00
Sergey Lyubka 4ca4c862a5 Updated net_skeleton, added extra_headers param to mg_send_file() 2014-10-09 09:26:45 +01:00
Sergey Lyubka 0918df1566 Removed reference to chat.c 2014-10-05 17:29:33 +01:00
Sergey Lyubka aa2583cc26 Added enable_proxy 2014-10-03 11:54:00 +01:00
Sergey Lyubka e1b1d39635 Removed conflicting MIT-related comment block 2014-10-01 12:11:04 +01:00
Sergey Lyubka 3bf82dd541 Merge pull request #419 from grodansparadis/master
connection_data -> user_data
2014-09-22 15:03:19 +01:00
Sergey Lyubka 2896965c97 Fixed link to examples 2014-09-20 08:32:29 +01:00
Ake Hedman 53b784b143 connection_data -> user_data 2014-09-19 08:20:37 +02:00
Sergey Lyubka 8e91e3a305 Timeout only non-listening connections 2014-09-16 07:47:40 +01:00
Sergey Lyubka dbc07c8b00 Moved mjpg_streamer to a separate dir 2014-09-15 19:05:30 +01:00
Sergey Lyubka ce953575e2 Not closing listening connections 2014-09-15 13:48:55 +01:00
Sergey Lyubka 80db048578 Added more dependencies in test/Makefile 2014-09-15 01:28:03 +01:00
Sergey Lyubka 382d165574 Added MONGOOSE_NO_MMAP conditional 2014-09-15 01:18:38 +01:00
Sergey Lyubka 0fb2f38cb7 Fixed mg_connect() call 2014-09-14 15:06:09 +01:00
Sergey Lyubka aa007f1285 Updated travis config 2014-09-11 15:55:18 +01:00
Sergey Lyubka 8752910330 Better UDP support 2014-09-11 15:52:42 +01:00
Sergey Lyubka 2a5a8eec49 removed chat_server dir in examples 2014-09-10 00:59:31 +01:00
Sergey Lyubka ceca52de30 Moved file send_file example to separate dir 2014-09-09 23:23:29 +01:00
Sergey Lyubka 8a3691055c Moved file upload example to separate dir 2014-09-09 23:20:23 +01:00
Sergey Lyubka 56d12c89da Typo in hello_world.c fixed 2014-09-09 22:47:07 +01:00
Sergey Lyubka 2cfce4d8b2 Added copyright 2014-09-09 22:46:24 +01:00
Sergey Lyubka f372faf614 Moved hello.c example to its own dir 2014-09-09 22:44:57 +01:00
Sergey Lyubka 882f3b3ac3 removed hello.lp 2014-09-09 18:26:03 +01:00
Sergey Lyubka fac0e9b0ac Moved unit test to dedicated dir 2014-09-09 18:23:48 +01:00
Sergey Lyubka a3cf67c380 Moved examples/mkdata.pl -> scripts/embed_binary_files.pl 2014-09-09 18:11:57 +01:00
Sergey Lyubka 2987cbdb5c ws_ssl -> websocket_ssl_proxy 2014-09-09 18:09:33 +01:00
Sergey Lyubka 6083b9c5c5 Updated to the recent skeleton. SSL address format changed 2014-09-09 18:07:55 +01:00
Sergey Lyubka 83237a02d9 Made local copies of dependencies 2014-09-09 17:03:50 +01:00
Sergey Lyubka 965188bac9 removed chat.c 2014-09-09 17:01:06 +01:00
Sergey Lyubka 66da41d401 Adopted to the recent net_skeleton 2014-09-09 17:00:49 +01:00
Sergey Lyubka cfd334ac6c Moved websocket echo server example 2014-09-09 09:27:35 +01:00
Sergey Lyubka b5f6254c1e Added date marker 2014-09-08 23:30:52 +01:00
Sergey Lyubka dcbd1cbbd1 Moved pubsub example to websocket_chat 2014-09-08 23:29:34 +01:00
Sergey Lyubka a3b568f460 removed lua_ddl.c 2014-09-08 23:22:46 +01:00
Sergey Lyubka 75770aec80 Merge pull request #415 from mmicko/master
Added mg_mmap and mg_munmap utility functions for memory mapping files
2014-09-07 11:55:27 +01:00
Sergey Lyubka 3a8ae7ac17 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-09-06 10:11:43 +01:00
Sergey Lyubka b116b2fa82 mg_poll_server doc corrected 2014-09-06 10:10:22 +01:00
m.milanovic@levi9.com 7806609773 Added mg_mmap and mg_munmap utility functions for memory mapping files 2014-09-04 15:05:42 +02:00
Sergey Lyubka 72f45aa7e2 Merge pull request #414 from mmicko/master
Fixed compile on varois MINGW versions
2014-09-02 12:34:58 +01:00
m.milanovic@levi9.com 5e3e6a6dce Fixed compile on MINGW so it is confirmed working on versions 4.6.x till 4.9.x 2014-09-02 12:11:21 +02:00
Sergey Lyubka 1388bb1db4 Fixed line endings 2014-09-01 21:02:16 +01:00
Sergey Lyubka 3cc0d16f65 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-09-01 20:55:37 +01:00
Sergey Lyubka b50095fa61 Added $Date$ markers 2014-09-01 20:54:12 +01:00
Sergey Lyubka 7ad85219d8 Merge pull request #413 from mcallegari/master
Fixed build warning of signed/unsigned conditional expression
2014-08-30 12:42:09 +01:00
Massimo Callegari 347a249d10 Fixed build warning of signed/unsigned conditional expression 2014-08-30 13:04:11 +02:00
Sergey Lyubka 07d982129a Passing NS events together with the NC pointer 2014-08-29 23:28:34 +01:00
Sergey Lyubka 73f2602ba0 Updated due to ssl_wrapper.h refactoring 2014-08-26 14:42:24 +01:00
Sergey Lyubka 44561d163a updated travis config 2014-08-22 22:39:48 +01:00
Sergey Lyubka c941a1a39a Proper struct mg_connection cleanup in close_local_endpoint() 2014-08-22 16:26:30 +01:00
Sergey Lyubka bee22312bc removed dead code 2014-08-21 04:13:33 +01:00
Sergey Lyubka bdb16c624c Added MG_RECV event and mg_send_file_data() func 2014-08-21 04:09:06 +01:00
Sergey Lyubka e389e70d05 squashed warn in mg_terminate_ssl() 2014-08-20 21:54:09 +01:00
Sergey Lyubka 695559f691 Updated to the latest SSL wrapper 2014-08-13 09:17:20 +01:00
Sergey Lyubka 13be74b4c6 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-08-11 16:20:25 +01:00
Sergey Lyubka 02a1032fd4 updated ssl_wrapper 2014-08-11 16:19:25 +01:00
Sergey Lyubka 788f35b19c Merge pull request #411 from mmicko/master
Make mongoose compile on mingw environment
2014-08-11 15:01:33 +01:00
Miodrag Milanovic 3721efe1e9 Make mongoose compile on mingw environment 2014-08-11 15:27:23 +02:00
Sergey Lyubka e0822ffb78 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-08-08 14:25:58 +01:00
Sergey Lyubka ae7d5a8f94 Bumping up default timeout from 30 to 300 sec 2014-08-08 14:25:44 +01:00
Sergey Lyubka ced7a2e0b5 Merge pull request #410 from zinosat/avoid_largefile_redefinition
Avoid unconditional definition of _LARGEFILE_SOURCE
2014-08-07 22:13:09 +01:00
Davide Viti 5ed6708468 Avoid unconditional definition of _LARGEFILE_SOURCE
On some build systems (i.e. Buildroot), _LARGEFILE_SOURCE is defined
at "higher level" as default CFLAG definition.
This fix avoids the following compilation warning:

mongoose-5.4/mongoose.c:52:0: warning: "_LARGEFILE_SOURCE" redefined [enabled by default]
 #define _LARGEFILE_SOURCE       // Enable fseeko() and ftello() functions
 ^
<command-line>:0:0: note: this is the location of the previous definition
2014-08-07 22:08:12 +02:00
Sergey Lyubka 9fe53f307b Added http client example 2014-08-05 17:14:41 +01:00
Sergey Lyubka c64d30e1f6 removed make_settings.mak 2014-08-05 16:41:14 +01:00
Sergey Lyubka b4c25fc7ba Added ALL_PROGS 2014-08-05 16:40:51 +01:00
Sergey Lyubka b67b618811 Added guard for MONGOOSE_NO_FILESYSTEM 2014-08-04 22:32:24 +01:00
Sergey Lyubka 5a19438f70 Added guard for MONGOOSE_NO_FILESYSTEM 2014-08-04 22:31:59 +01:00
Sergey Lyubka 860addf1e3 MONGOOSE_NO_SOCKETPAIR -> NS_DISABLE_SOCKETPAIR 2014-08-03 18:56:19 +01:00
Sergey Lyubka 03d571a119 Merge pull request #407 from kuiash/master
Populate HTTP warning codes
2014-08-03 18:29:15 +01:00
Sergey Lyubka 0d9ecffc53 Do not dealloc conn->request in mg_forward() 2014-08-03 12:41:15 +01:00
Daniel O'Connell d4c8384b85 ws_ssl example 2014-08-03 12:40:10 +01:00
Sergey Lyubka bd40145301 moved hex dumping to skeleton 2014-08-01 17:35:59 +01:00
Sergey Lyubka 9b42494316 Added general example makefile settings 2014-08-01 13:30:05 +01:00
Sergey Lyubka 2daff6959f Added #define matrix 2014-08-01 09:11:00 +01:00
Sergey Lyubka e9c434a6a1 updated net skeleton 2014-08-01 09:05:50 +01:00
Sergey Lyubka d6fba7e45d Added travis file 2014-08-01 08:08:54 +01:00
Sergey Lyubka 0a0130b90c removed 2014-08-01 07:53:51 +01:00
Sergey Lyubka facf2af66e Clearing off HTTP headers in close_local_endpoint() 2014-07-31 20:05:25 +01:00
Sergey Lyubka cc54195f59 Added mg_forward() 2014-07-31 20:04:59 +01:00
Sergey Lyubka e2fb707d9f Added SSL_CTX_set_mode() 2014-07-30 11:27:37 +01:00
kuiash 7dfff935d6 Populate HTTP warning codes
Includes changing 201 "Server Error" to "Internal Server Error"
List mostly borrowed from here http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
418 and 451 also added
Local testing showed a problem with 202 reported as "Server Error" instead of "Accepted"
2014-07-29 12:48:22 +01:00
Sergey Lyubka 5727a5c0ed Removed lua examples 2014-07-29 07:39:20 +01:00
Sergey Lyubka 268d2e9cbe better explanation for websocket2.c example 2014-07-28 12:19:00 +01:00
Sergey Lyubka 1e7da874a4 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-07-28 12:15:23 +01:00
Sergey Lyubka 7875a8c2bd release notes for 5.4 2014-07-28 12:15:13 +01:00
Sergey Lyubka b0355d45ae Merge pull request #403 from pavel-pimenov/fix-cache-call-stat
stat - function result cache
2014-07-27 11:13:26 +01:00
Sergey Lyubka 91136d7731 Merge pull request #406 from Cykey/master
Set the correct json content-type
2014-07-27 11:12:52 +01:00
Pavel Pimenov 01a058d29b Remove file_stat_t st_cgi; 2014-07-27 13:10:49 +04:00
Pavel Pimenov e6eca1738f 80 characters limit + remove tabs 2014-07-27 12:53:37 +04:00
Pavel Pimenov 2108ec5a0c Fix style for pointer 2014-07-27 12:44:08 +04:00
David M. bc4e47630a Set the correct json content-type
Chance text/json to application/json to comply with the RFC.

See http://www.ietf.org/rfc/rfc4627.txt for more information.
2014-07-26 20:55:59 -04:00
Pavel Pimenov f41c9a2a1f stat - function result cache 2014-07-23 11:26:20 +04:00
Sergey Lyubka 6c77208236 release notes dates 2014-07-21 21:38:45 +01:00
Sergey Lyubka 386d2e5cd4 fix leak in handle_propfind() 2014-07-18 13:00:43 +01:00
Sergey Lyubka b738fdbffa updated net skeleton 2014-07-08 11:28:03 +01:00
Sergey Lyubka b5704850db Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-07-08 11:10:17 +01:00
Sergey Lyubka 9c67e8960e updated certs 2014-07-08 11:10:08 +01:00
Sergey Lyubka d3dff4e1d5 Merge pull request #391 from pavel-pimenov/pvs-studio-fix-zu
Change printf mask %zu -> %lu
2014-07-07 08:58:23 +01:00
Pavel Pimenov 82872e86fd Change printf mask %zu -> %lu
for MS VC++ compatibility http://stackoverflow.com/questions/15610053/correct-printf-format-specifier-for-size-t-zu-or-iu
2014-07-07 09:24:48 +04:00
Sergey Lyubka ac229b6606 Merge pull request #387 from Z-Wave-Me/master
Disallow WebDAV MKCOL/PUT/DELETE requests to protected files
2014-06-28 21:40:11 +01:00
Alex Skalozub a6bf2bcbf4 Should also disallow PROPFIND as well 2014-06-29 00:03:52 +04:00
Alex Skalozub b0cf8304cb Disallow WebDAV MKCOL/PUT/DELETE requests to protected files (like .htpasswd) 2014-06-28 23:14:21 +04:00
Sergey Lyubka 0d9fe39dbb ns_read_from_socket(): calling recv() in a loop until failure 2014-06-25 11:43:07 +01:00
Sergey Lyubka 708af6d9c5 more comments in big_upload.c 2014-06-24 17:09:00 +01:00
Sergey Lyubka e4c71425c9 Added big_upload.c 2014-06-24 17:04:26 +01:00
Sergey Lyubka 6e07215c1c Using Multiple inputs for upload example 2014-06-24 16:35:59 +01:00
Sergey Lyubka ca9603301e removed trailing newline 2014-06-24 16:35:26 +01:00
Sergey Lyubka d6c388042c QNX SSL upload fix 2014-06-23 13:52:07 +01:00
Sergey Lyubka 6f66d794e8 Refactor NS_POLL case in mg_ev_handler 2014-06-20 11:41:13 +01:00
Sergey Lyubka 1389eec784 Added comment for mg_terminate_ssl() call 2014-06-19 09:55:10 +01:00
Sergey Lyubka 6ef795e082 manual mitm for oracle.com 2014-06-19 09:53:38 +01:00
Sergey Lyubka 1e5d258e9e Wording for licensing clarified 2014-06-18 11:30:57 +01:00
Sergey Lyubka 70eb4c4bbc exported mg_terminate_ssl 2014-06-18 10:59:29 +01:00
Sergey Lyubka a639e10a4d squash QNX warning about execle() call 2014-06-17 13:28:45 +01:00
Sergey Lyubka 48750e67f6 ENABLE_PROXY is visible with MONGOOSE_NO_FILESYSTEM 2014-06-17 10:50:47 +01:00
Sergey Lyubka ce60379af6 sending 405 for proxy request if connect is not allowed 2014-06-16 11:27:17 +01:00
Sergey Lyubka e0b9e4abfd Added enable_proxy 2014-06-16 11:06:57 +01:00
Sergey Lyubka 665f205527 squash warning under mingw 2014-06-16 10:46:50 +01:00
Sergey Lyubka 030daaf5d5 squash warning under mingw 2014-06-16 10:44:56 +01:00
Sergey Lyubka 760511ec49 squashed warning around NS_STACK_SIZE 2014-06-16 10:21:31 +01:00
Sergey Lyubka 203688a34b Added comment for Win32 SO_RESUSEADDR 2014-06-13 10:19:46 +01:00
Sergey Lyubka 29f4703e4f Adding zero-length chunk for long-running requests 2014-06-13 07:57:27 +01:00
Sergey Lyubka 3cec6f6745 keeping alive long-lived connections 2014-06-12 10:58:49 +01:00
Sergey Lyubka abcea07641 Fix #373 2014-06-11 20:37:35 +01:00
Sergey Lyubka 6a54704b29 mg_set_option(): always set correct actual listening port 2014-06-11 20:12:23 +01:00
Sergey Lyubka 8a2fbac4c0 Calling event handler in MITM mode before making connection to the target host 2014-06-11 09:56:34 +01:00
Sergey Lyubka 96ce6bac69 ns_server_poll(): setting current_time to now after select() 2014-06-11 09:44:18 +01:00
Sergey Lyubka 50c0b958ff Added -root cmd line flag to proxy example 2014-06-10 12:22:50 +01:00
Sergey Lyubka 44416902d6 Changed debug in do_proxy() 2014-06-10 12:22:30 +01:00
Sergey Lyubka 25e646c1a1 Squashed warnings for MONGOOSE_NO_FILESYSTEM 2014-06-10 10:26:58 +01:00
Sergey Lyubka bd723bdc38 Removed dead code in websocket2.c 2014-06-09 17:33:26 +01:00
Sergey Lyubka 5e57031724 Added pubsub example 2014-06-09 17:26:22 +01:00
Sergey Lyubka c583913290 Added pubsub example 2014-06-09 17:25:08 +01:00
Sergey Lyubka 870ca615de Added mg_next() 2014-06-09 17:24:51 +01:00
Sergey Lyubka 64b51699f8 Added MG_WS_CONNECT 2014-06-09 16:32:56 +01:00
Sergey Lyubka 50a889dac0 Inlined parse_url() 2014-06-04 12:32:47 +01:00
Sergey Lyubka 0ff0788458 Formatting change for mg_send_file() 2014-06-04 12:32:31 +01:00
Sergey Lyubka fec6009edb mg_send_file() doc changed 2014-06-03 18:49:17 +01:00
Sergey Lyubka c4f172a120 Documented mg_send_file() 2014-06-03 18:45:37 +01:00
Sergey Lyubka 464c77314d Amended file sending example 2014-06-03 18:03:13 +01:00
Sergey Lyubka f51ca8d5d1 Added mg_send_file(). Changed sending function to return send_iobuf length. 2014-06-03 18:02:55 +01:00
Sergey Lyubka 7b37e0cb8b Added simplistic flow control in transfer_file_data() 2014-06-03 17:00:52 +01:00
Sergey Lyubka c7925353e7 Added parens around expression to squash warning under QNX SDP 6.6.0 2014-06-03 14:25:54 +01:00
Sergey Lyubka bd23ec4323 Removed a bit of dead code. Added more comments in proxy_event_handler() 2014-05-29 17:40:06 +01:00
Daniel O'Connell 3671b2632d proxy unit test reference implementation 2014-05-29 17:04:28 +01:00
Daniel O'Connell 25115a694c proxy support changes 2014-05-29 17:04:13 +01:00
Sergey Lyubka 2436f9d6c3 squashed win32 warnings 2014-05-22 07:31:19 +01:00
Sergey Lyubka 2238951c18 Integrated Dans net skeleton changes 2014-05-21 16:18:21 +01:00
Daniel O'Connell f266dd2c94 Removed noisy debug messages 2014-05-20 16:40:47 +01:00
Daniel O'Connell b03358cb03 Fixes for the proxy code 2014-05-19 19:08:02 +01:00
Sergey Lyubka 1bede7e28b Added test for parse_url() 2014-05-19 12:56:07 +01:00
Sergey Lyubka 3536670b82 re-worded FAQ section 2014-05-18 16:13:04 +01:00
Daniel O'Connell 3235c05fd6 Added proxy functionality 2014-05-18 13:22:33 +01:00
Daniel O'Connell 63db54e7b5 Added AV faq 2014-05-18 10:53:54 +01:00
Daniel O'Connell 1db51eb788 Moved sse.html to proxy_web_root/index.html 2014-05-13 14:51:16 +01:00
Daniel O'Connell 0e640ae885 Made setopt() wrapper around mg_set_option() 2014-05-13 13:02:08 +01:00
Daniel O'Connell 1bff6df2a7 Enabled SSL for proxy example 2014-05-13 12:33:27 +01:00
Daniel O'Connell d0e66de225 Re-added ssl_ca_certificate option 2014-05-13 12:30:30 +01:00
Daniel O'Connell f537670ce2 Synced net skeleton 2014-05-13 12:28:39 +01:00
Daniel O'Connell 4cb3341a15 Added proxy example, with SSE html page 2014-05-13 11:22:31 +01:00
Daniel O'Connell d52d9a4a6f Added pem files 2014-05-13 11:08:18 +01:00
Daniel O'Connell 4a076c7ea4 Added proxy to the clean target 2014-05-13 10:56:32 +01:00
Sergey Lyubka db6e883c22 Added mg_wakeup_server_ex(), removed mg_wakeup_server() and mg_iterate_over_connections() 2014-05-13 09:33:10 +01:00
Sergey Lyubka 804da054b5 Removed extra line in the comment 2014-05-12 23:24:03 +01:00
Sergey Lyubka fb4e701545 Added mg_wakeup_server_ex() for pushing data 2014-05-12 23:22:57 +01:00
Sergey Lyubka ccff4abf13 Added proxy target 2014-05-12 10:47:08 +01:00
Sergey Lyubka 24a7936907 Squashed warning for non-ssl case in ns_set_ssl_ca_cert() 2014-05-11 16:05:07 +01:00
Sergey Lyubka 0993994139 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-05-11 13:43:10 +01:00
Sergey Lyubka 8b740536de Added ssl_ca_certificate option 2014-05-11 13:42:59 +01:00
Sergey Lyubka e851aac853 Merge pull request #371 from cry-inc/master
Fixed wrong behavior of mg_set_option() with option "listening_port" caused by SO_REUSEADDR when using Windows
2014-05-07 17:00:36 +01:00
cry-inc a39861b7bf Fixed wrong behavior of mg_set_option() with option "listening_port" caused by SO_REUSEADDR when using Windows 2014-05-07 16:38:23 +02:00
Sergey Lyubka 63490249ba Merge pull request #368 from cry-inc/master
Fixed wrong MIME type for .rar files
2014-04-30 10:45:09 +01:00
cry-inc 704f057384 Fixed wrong MIME type for .rar files 2014-04-30 10:30:35 +02:00
Sergey Lyubka 40968bc496 Moved other products in a different section 2014-04-30 09:18:55 +01:00
Sergey Lyubka 6873f3c5f6 Removed idle_timeout_ms 2014-04-29 18:01:25 +01:00
Sergey Lyubka ba5cd7267a Added MONGOOSE_SEND_NS_EVENTS to the embedding doc 2014-04-28 15:04:39 +01:00
Sergey Lyubka 1bb98e5e8e Exported mg_websocket_printf(), mg_url_encode(). Added unit test for mg_url_encode() 2014-04-25 18:04:24 +01:00
Sergey Lyubka a7774d0f1a Added mg_websocket_printf(). added MONGOOSE_SEND_NS_EVENTS 2014-04-24 14:09:54 +01:00
Sergey Lyubka f52c756fbb Calling SSL_free() in ns_close_conn() 2014-04-16 16:45:31 +01:00
Sergey Lyubka cc586c6ba2 php->basic 2014-04-15 14:13:38 +01:00
Sergey Lyubka 606eab7f4f Passing PUT content to the event handler 2014-04-14 16:14:13 +01:00
Sergey Lyubka 872b85b5f2 more on -access_control_list 2014-04-14 13:03:47 +01:00
Sergey Lyubka 35bd2b6032 Added form.c 2014-04-10 22:18:01 +01:00
Sergey Lyubka c5287b9044 iobuf_append() refactored: allocating exactly as many bytes as needed 2014-04-09 23:52:16 +01:00
Sergey Lyubka 223f6d960e README message changed 2014-04-09 18:10:49 +01:00
Sergey Lyubka 464b895116 Added enum for websocket opcodes 2014-04-09 15:16:03 +01:00
Sergey Lyubka 05d7b7c8bc Added MG_WS_HANDSHAKE 2014-04-09 11:55:36 +01:00
Sergey Lyubka d8b4db37a0 Squashed warnings 2014-04-09 11:37:08 +01:00
Sergey Lyubka 6bb49c780c Updated net skeleton code 2014-04-09 11:32:23 +01:00
Sergey Lyubka 3a60c5764d Unit test target corrected 2014-04-07 19:07:41 +01:00
Sergey Lyubka a8b38e4ab9 mg_set_option() sets NULL if value is empty 2014-03-31 15:02:20 +01:00
Sergey Lyubka 8750f8af1f Added cast in try_parse() 2014-03-31 09:51:47 +01:00
Sergey Lyubka e94a02dc12 Added more in 5.4 release notes 2014-03-31 09:49:42 +01:00
Sergey Lyubka 5680b0fcc5 Removed redundant cast in try_parse() 2014-03-31 09:34:31 +01:00
Sergey Lyubka 33c56b0edc Init local_ip and local_port properly in mg_connection 2014-03-30 22:50:10 +01:00
Sergey Lyubka e62e48397d Keeping absolute path for config file 2014-03-30 16:00:03 +01:00
Sergey Lyubka 8be30350be mg_set_option(): allow NULL as value. Fast success if old_value == new_value. 2014-03-30 15:59:39 +01:00
Sergey Lyubka 2609a2ab72 Fixed comment for mg_template() 2014-03-30 12:47:27 +01:00
Sergey Lyubka 5a04ab2c56 Added mg_template() function 2014-03-30 12:45:48 +01:00
Sergey Lyubka 4739de6c28 Removed DLL interface and Lua conditional 2014-03-30 12:34:32 +01:00
Sergey Lyubka 639d7a2fd8 Fixing MinGW compilation: pid_t -> process_id_t 2014-03-28 09:18:38 +00:00
Sergey Lyubka 8115ce1d82 Handling SSL_write() error 2014-03-27 11:18:20 +00:00
Sergey Lyubka 3558b587b7 Fixed linking problem for -DMONGOOSE_NO_FILESYSTEM 2014-03-27 10:13:34 +00:00
Sergey Lyubka e21ec58ea8 dav fixes: using auth if auth file is set 2014-03-26 23:13:14 +00:00
Sergey Lyubka 74135bca7d link fixed 2014-03-26 18:58:58 +00:00
Sergey Lyubka d369f31608 return 404 for non-existent propfind URIs 2014-03-26 16:34:55 +00:00
Sergey Lyubka d4b14ca3c1 Better API documentation 2014-03-26 14:13:30 +00:00
Sergey Lyubka f0994896d5 FileSharing doc nitpick 2014-03-26 12:27:44 +00:00
Sergey Lyubka cfdd430b98 Added hexdump_file option 2014-03-26 12:20:02 +00:00
Sergey Lyubka a6c05a9e83 changed handle_propfind() to report only dir entry when listing dir 2014-03-24 20:39:32 +00:00
Sergey Lyubka 94f63787bb Restored void * parameter for iterate_over_connections() 2014-03-24 16:01:45 +00:00
Sergey Lyubka 367f5df328 match_prefix -> mg_match_prefix 2014-03-24 16:00:17 +00:00
Sergey Lyubka f096138d6e Added release note 2014-03-23 20:02:41 +00:00
Sergey Lyubka 0d00cd51e6 Fix #356 2014-03-23 19:59:03 +00:00
Sergey Lyubka b216210a13 Moving lua server side to server.c 2014-03-23 15:33:39 +00:00
Sergey Lyubka 166833f330 Added release notes 2014-03-21 11:47:52 +00:00
Sergey Lyubka 4d6bedfd4e Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-03-20 15:01:18 +00:00
Sergey Lyubka ace8c1736c Added mg_load_dll() 2014-03-20 15:01:05 +00:00
Sergey Lyubka c658a54d18 changed set_absolute_path() signature 2014-03-20 14:58:37 +00:00
Sergey Lyubka 781a1dc25e Merge pull request #352 from ranzhengyuan/some-idea
I think that when the socket invalid, the return value should be -1.
2014-03-20 10:34:18 +00:00
冉正源 3ea3b8dfa4 I think that the socket is invalid, the return should be -1. 2014-03-19 22:32:41 +08:00
Sergey Lyubka a514e143ff updated faw and tutorials 2014-03-19 11:41:01 +00:00
Sergey Lyubka e1486a79e3 Merge pull request #350 from solomonhuang/nodav
Remove MONGOOSE_NO_DAV on DAV_AUTH_FILE options
2014-03-19 11:25:15 +00:00
Sergey Lyubka ee615248e3 Merge pull request #351 from da4089/master
Tyop fix.
2014-03-19 09:33:58 +00:00
David Arnold 687e0e2ee8 Tyop fix. 2014-03-19 04:49:47 +00:00
Solomon Huang 19aefcb7dd Remove MONGOOSE_NO_DAV on DAV_AUTH_FILE options
Building with -DMONGOOSE_NO_DAV will fail.
2014-03-19 01:53:02 +08:00
Sergey Lyubka 6a46244a21 embedding guide for MG_POLL fixed 2014-03-14 08:19:54 +00:00
Sergey Lyubka 60674c11c9 API docs regarding MG_POLL changed 2014-03-13 12:23:53 +00:00
Sergey Lyubka 91c9ab807b Forwarding POST data to the CGI process 2014-03-12 22:43:04 +00:00
Sergey Lyubka 9231c7346c match_prefix -> mg_match_prefix 2014-03-12 18:35:36 +00:00
Sergey Lyubka 20cb3a823a Added ecos & qnx 2014-03-12 14:19:36 +00:00
Sergey Lyubka cbd8d69e6d Added hello world for Lua 2014-03-12 12:47:41 +00:00
Sergey Lyubka f7fcfa6a42 Fixed C# example to work with 5.3 2014-03-12 12:31:53 +00:00
Sergey Lyubka 293c5e5852 Moved screenshots down 2014-03-11 16:59:17 +00:00
Sergey Lyubka ceb866b4ee Using img tags for screenshots 2014-03-11 16:57:38 +00:00
Sergey Lyubka 2f9166e96e Added screenshots for mongoose 2014-03-11 16:51:54 +00:00
Sergey Lyubka fe0e0e69e5 File sharing tutorial wording 2014-03-11 15:36:23 +00:00
Sergey Lyubka db96641c10 Added logo 2014-03-11 06:13:59 +00:00
Sergey Lyubka fe83928ca4 Added logo 2014-03-11 06:11:56 +00:00
Sergey Lyubka 014414f17f Docs links made separate 2014-03-11 06:07:06 +00:00
Sergey Lyubka 6ffe2d7f7a Typo fixed in readme 2014-03-11 06:04:44 +00:00
Sergey Lyubka 30c82d7efe Wording in README changed 2014-03-11 06:03:20 +00:00
Sergey Lyubka 999c4ad26c 5.3 -> 5.4 2014-03-10 17:02:00 +00:00
Sergey Lyubka 30a7965135 added lsp link 2014-03-10 11:21:52 +00:00
Sergey Lyubka a8a017a048 docs updated 2014-03-10 09:23:06 +00:00
Sergey Lyubka eac8ffabc4 docs updated 2014-03-10 09:19:01 +00:00
Sergey Lyubka a7a17711ec Resetting endpoint_type in open_local_endpoint() 2014-03-10 08:35:41 +00:00
Sergey Lyubka 18e28ef879 Added lua includes 2014-03-09 20:22:51 +00:00
Sergey Lyubka ce7515fca9 Merge pull request #349 from jhorneman/master
Exposing Lua support functions
2014-03-09 20:18:49 +00:00
Jurie Horneman d5a78fb664 Fixed bug. 2014-03-09 21:12:34 +01:00
Jurie Horneman 1b3a1b74ac Exposed Lua support functions. 2014-03-09 21:11:06 +01:00
Sergey Lyubka 8dd76e6ef4 Using ns_start_thread() 2014-03-09 19:50:34 +00:00
Sergey Lyubka 976b5f37c1 Added Lua callback 2014-03-09 19:30:41 +00:00
Sergey Lyubka 31489ab7b1 Lua fixes 2014-03-09 19:26:58 +00:00
Sergey Lyubka 1eb59940a4 Re-init rewrites var in convert_uri_to_file_name() 2014-03-09 13:27:39 +00:00
Sergey Lyubka 576d769b56 Corrected links in tutorials 2014-03-09 13:13:25 +00:00
Sergey Lyubka afaba7ee17 Lua calls, birth_time fixed 2014-03-09 13:13:13 +00:00
Sergey Lyubka 40f257ef2b lua build instructions fixed 2014-03-09 13:12:49 +00:00
Sergey Lyubka 5840dc8153 Links updated 2014-03-07 17:08:23 +00:00
Sergey Lyubka 5ed3dafb56 Added warning about PHP 5.5 2014-03-07 14:46:24 +00:00
Sergey Lyubka b99bf306ec fixed image links 2014-03-07 14:40:34 +00:00
Sergey Lyubka 89fae72aa7 added 2014-03-07 14:24:37 +00:00
Sergey Lyubka ab147e8f19 Added MONGOOSE_NO_SSI to MONGOOSE_NO_FILESYSTEM 2014-03-06 13:37:23 +00:00
Sergey Lyubka 81a78f9c8b Added query string to access log 2014-03-05 11:22:23 +00:00
Sergey Lyubka 370aeefdde Added error pages and vhosts to readme 2014-03-05 11:19:18 +00:00
Sergey Lyubka c5407a75f4 #define EV_HANDLER NULL in server.c 2014-03-05 10:12:43 +00:00
Sergey Lyubka 7217aa22f1 Embedded guide 2014-03-05 02:53:19 +00:00
Sergey Lyubka 69bd5f7aa2 SSL_accept logic fix 2014-03-05 02:19:05 +00:00
Sergey Lyubka 41b3c1b23e warning squashed in convert_uri_to_file_name() 2014-03-05 01:59:58 +00:00
Sergey Lyubka f639409533 warning squashed in convert_uri_to_file_name() 2014-03-05 01:59:32 +00:00
Sergey Lyubka 67c44799c8 SSL_accept() error handling fix 2014-03-05 01:57:09 +00:00
Sergey Lyubka 4646e2ad55 Added mjpg example 2014-03-04 20:23:37 +00:00
Sergey Lyubka b77532ea3f Added mjpg example 2014-03-04 20:22:46 +00:00
Sergey Lyubka ed8168e8a1 Added virtual hosts support via url_rewrites 2014-03-04 16:15:02 +00:00
Sergey Lyubka 39e2d2ad55 Appending query_string to the URI when redirecting on HTTP error 2014-03-04 15:01:05 +00:00
Sergey Lyubka 27c6656398 SSL_accept fixes 2014-03-04 13:23:40 +00:00
Sergey Lyubka ffe83051fe build fixed 2014-03-04 13:15:56 +00:00
Sergey Lyubka 93cd77ffad Changed links 2014-03-03 21:18:57 +00:00
Sergey Lyubka 279c06c64c Cleaned up cruft from mongoose.h 2014-03-03 10:56:17 +00:00
Sergey Lyubka 570c8213b6 Cleaned unit test 2014-03-03 10:54:35 +00:00
Sergey Lyubka f521999ea6 Calling EP_CLIENT on close 2014-03-03 10:27:56 +00:00
Sergey Lyubka e41df3cf9c MG_REQ_BEGIN -> MG_REQUEST, killed MG_REQ_END, add MG_REPLY. Restored server test 2014-03-03 10:26:27 +00:00
Sergey Lyubka 65f484291f got rid of multiline comment 2014-03-03 09:45:00 +00:00
Sergey Lyubka 77db89961b mg_stat() fix for paths like X:\ 2014-03-03 01:00:38 +00:00
Sergey Lyubka ad50310bb6 Added index.shtml to index files 2014-03-02 19:49:15 +00:00
Sergey Lyubka 66ec3d1f1e Added defines for popen and pclose, for SSI under Win32 2014-03-02 18:50:02 +00:00
Sergey Lyubka a9da86d05c Mentioned SSI 2014-03-02 18:28:40 +00:00
Sergey Lyubka 5f25a88821 Restored SSI functionality 2014-03-02 18:27:51 +00:00
Sergey Lyubka fd7dc33645 unbroke unit test 2014-03-02 17:20:24 +00:00
Sergey Lyubka 9c22771a43 Merge pull request #345 from nielsegberts/master
Also clean up multi_threaded and websocket_html.c on make clean
2014-03-02 15:48:25 +00:00
Niels Egberts 11640cc3c6 Also clean up multi_threaded and websocket_html.c on make clean 2014-03-02 14:55:34 +00:00
Sergey Lyubka 2264520a2f Example changed to evented API 2014-03-02 13:05:00 +00:00
Sergey Lyubka 2f0b411ddd Added -pthread flag to unix compilation example 2014-03-02 13:00:44 +00:00
Sergey Lyubka e0aceb4f3a Fixed windows build for examples 2014-03-02 12:23:53 +00:00
Sergey Lyubka ea9a60a59a Updated examples to conform to the evented API 2014-03-02 12:16:09 +00:00
Sergey Lyubka 458320cffb Fixed #343 in conn2() for Lua 2014-03-02 10:12:12 +00:00
Sergey Lyubka e0214af422 Using private ns_avprintf() in mg_printf_data() 2014-03-02 10:07:30 +00:00
Sergey Lyubka df5e997ea7 ns_server_poll() waking up by ns_server_wakeup() 2014-03-01 01:55:40 +00:00
Sergey Lyubka 0a3cb63c73 Added mg_wakeup_server() 2014-03-01 01:47:01 +00:00
Sergey Lyubka 37f7f3fb12 Merge pull request #339 from nenioscio/master
Fix issue #338
2014-03-01 01:19:31 +00:00
Sergey Lyubka 2ac970fa16 Moving to event-based API, temporary breaking tests 2014-03-01 01:17:39 +00:00
Sergey Lyubka de35a353d4 pphp -> php 2014-02-27 22:02:18 +00:00
Klaus Wagner dbbda02f70 Fix issue #338 2014-02-27 22:12:46 +01:00
Sergey Lyubka 725c30446c more docs 2014-02-25 20:39:34 +00:00
Sergey Lyubka 60473ae41a more docs 2014-02-25 20:39:00 +00:00
Sergey Lyubka 951d20f904 Added coniditional to use net_skeleton separately 2014-02-25 18:52:23 +00:00
Sergey Lyubka 85a6abd58b Clearing flags in close_local_endpoint() 2014-02-25 12:02:45 +00:00
Sergey Lyubka 2fbe09ad7c Restored jni build dir for Android 2014-02-25 08:12:42 +00:00
Sergey Lyubka 23325efab2 Added time.h 2014-02-25 08:10:19 +00:00
Sergey Lyubka 107902bae4 add_to_set(): fix around non-negative SOCKET on Windows 2014-02-24 08:22:40 +00:00
Sergey Lyubka 9bbf4c8384 Fixed problem with mg_printf_data() 2014-02-22 16:11:47 +00:00
Sergey Lyubka c39a712540 Win32 build fix 2014-02-21 14:13:06 +00:00
Sergey Lyubka e9f6111ba1 re-added signal.h 2014-02-20 17:47:07 +00:00
Sergey Lyubka ba267a32fd squashed warning in read_from_socket 2014-02-20 17:44:47 +00:00
Sergey Lyubka f64ebbe0b1 Guarded on_cgi_data() call by ifdef, thanks to Pavel Pimenov 2014-02-20 12:33:46 +00:00
Sergey Lyubka 8865dd5e84 Moved unit_test.c to examples 2014-02-20 12:13:59 +00:00
Sergey Lyubka ce57f47de0 Added missing signal.h 2014-02-20 09:49:42 +00:00
Sergey Lyubka 48be2dbc2a Added conditional for handling idle websocket conns 2014-02-20 07:32:33 +00:00
Sergey Lyubka 8905522a94 Setting last_io_time in ns_add_sock() 2014-02-20 06:26:44 +00:00
Sergey Lyubka eea1680cf9 open_cgi_endpoint() strrchr fix 2014-02-19 16:44:01 +00:00
Sergey Lyubka d5004cb7eb PF_INET -> AF_INET, unbreaks FreeBSD 2014-02-19 16:39:30 +00:00
Sergey Lyubka 1d1a05bf39 Embedded net_skeleton 2014-02-19 16:38:53 +00:00
Sergey Lyubka 2009069037 merge 2014-02-19 16:36:27 +00:00
Sergey Lyubka 8f7703c2a9 moved to net_skeleton 2014-02-19 16:34:51 +00:00
Sergey Lyubka 8e87c4f013 Merge pull request #329 from abimaelmartell/fix/freebsd-compilation
fix compilation under FreeBSD
2014-02-14 23:46:07 +00:00
Abimael Martell 639a6dc2a8 fix compilation under FreeBSD 2014-02-14 13:21:14 -08:00
Sergey Lyubka cead9a04ca Typo fixed 2014-02-11 15:21:54 +00:00
Sergey Lyubka e528093027 Formatted example 2014-02-11 15:20:19 +00:00
Sergey Lyubka c432b783fb Formatted example 2014-02-11 15:19:18 +00:00
Sergey Lyubka e06976836f Typo fixed 2014-02-11 15:18:20 +00:00
Sergey Lyubka c9f7407573 More comments in example 2014-02-11 15:16:55 +00:00
Sergey Lyubka a40e59dbe6 URL corrected 2014-02-11 09:56:10 +00:00
Sergey Lyubka 61ee3d36d0 Merge pull request #324 from eichin/patch-1
doc typos
2014-02-11 09:55:47 +00:00
Mark Eichin 94dbf21ffb doc typos
just saw them while reading...
2014-02-11 03:41:09 -05:00
Sergey Lyubka 998425b14b Styling changes for hexdump 2014-02-10 10:21:57 +00:00
Sergey Lyubka 6900dd733a Merge pull request #322 from pavel-pimenov/master
Fix copy-paste for MONGOOSE_HEXDUMP feature
2014-02-10 09:48:26 +00:00
Pavel Pimenov 9e4cd054c8 Fix copy-paste for MONGOOSE_HEXDUMP feature 2014-02-10 12:00:51 +04:00
Sergey Lyubka 5dc317fcb0 Added -DMONGOOSE_HEXDUMP feature 2014-02-09 20:57:11 +00:00
Sergey Lyubka fbd5d77ce8 Added note about CGI env vars 2014-02-07 20:23:37 +00:00
Sergey Lyubka 6f8751b479 chat server is going to be in its own dir 2014-02-07 13:04:02 +00:00
Sergey Lyubka 877c4dc698 websocket example responses: 15 times -> 3 times 2014-02-07 13:03:28 +00:00
Sergey Lyubka 2dfc79129a better lua build 2014-02-07 13:03:11 +00:00
Sergey Lyubka 416f4bf10f Merge pull request #321 from pavel-pimenov/master
Add #ifndef MONGOOSE_NO_FILESYSTEM
2014-02-07 07:45:20 +00:00
Pavel Pimenov f9a99530ff Add #ifndef MONGOOSE_NO_FILESYSTEM 2014-02-07 11:02:12 +04:00
Sergey Lyubka 940b65e4db Merge pull request #320 from xant/upstream
added a new handler callback to be used when the http connection is being closed
2014-02-06 21:00:17 +00:00
Andrea Guzzo b22f7d3a49 added a new handler callback to be used when the http connection is being closed
so that in case of connections closed prematurely, the user can clear resources
eventually bound to the connection using the 'connection_param' member of the
mg_connection structure
2014-02-06 11:22:13 +01:00
Sergey Lyubka eaa0e26a85 Starting to rebuild chat example on Lua 2014-02-06 10:18:30 +00:00
Sergey Lyubka a3a63f7e56 Using mg_connection::callback_param for mg_iterate_over_connection() 2014-02-06 10:00:20 +00:00
Sergey Lyubka c9036f3ac0 Added workaround for non-compliant runtimes in alloc_vprintf() 2014-02-05 12:33:36 +00:00
Sergey Lyubka 60858d7fe5 NO_WEBSOCKET -> MONGOOSE_NO_WEBSOCKET 2014-02-04 19:57:00 +00:00
Sergey Lyubka 1c914bde1d Merge pull request #316 from To1ne/master
use `mg_set_request_handler`
2014-02-04 11:55:52 -08:00
Toon Claes a487332aa0 use mg_set_request_handler 2014-02-04 20:48:38 +01:00
Sergey Lyubka 3987d4d560 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-02-04 18:13:10 +00:00
Sergey Lyubka 8d3181e0bf examples/html -> examples/chat_html_root 2014-02-04 18:13:02 +00:00
Sergey Lyubka 0f1a59aeb4 Increased env buf size 4096 -> 8192. Passing TMPDIR to CGI. 2014-02-04 18:11:56 +00:00
Sergey Lyubka 2cdf259940 Merge pull request #315 from To1ne/patch-1
Correct return values: PROCESSED or CALL_AGAIN
2014-02-04 06:51:41 -08:00
Toon Claes 0187fe943a Correct return values: PROCESSED or CALL_AGAIN 2014-02-04 15:24:32 +01:00
Sergey Lyubka a34d1ec00a Better handling of MONGOOSE_NO_SOCKETPAIR 2014-02-04 14:04:54 +00:00
Sergey Lyubka e70d98b7b0 Added fixes for eCos 2014-02-04 09:59:53 +00:00
Sergey Lyubka bea012a3c1 Removed redundant addenv call 2014-02-04 08:06:49 +00:00
Sergey Lyubka eb2d470f65 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-02-03 17:54:46 +00:00
Sergey Lyubka 652c352394 Passing SERVER_NAME, TMP and TEMP env vars to CGI. 2014-02-03 17:54:31 +00:00
Sergey Lyubka f1b37b3101 Merge pull request #313 from xant/upstream
bugfix: set the correct status if we still have pending data
2014-02-03 04:52:10 -08:00
Sergey Lyubka 81b9876af8 5.2 -> 5.3 2014-02-01 16:53:09 +00:00
xant 9e118c8a31 bugfix: set the correct status if we still have pending data 2014-01-31 19:09:12 +01:00
154 changed files with 165770 additions and 7377 deletions

No files matched your search

+6 -6
View File
@@ -1,16 +1,16 @@
Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
Copyright (c) 2013 Cesanta Software Limited
Copyright (c) 2013-2015 Cesanta Software Limited
All rights reserved
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
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
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
Alternatively, you can license this code under a commercial
license, as set out in http://cesanta.com/products.html.
Alternatively, you can license this software under a commercial
license, as set out in <https://www.cesanta.com/license>.
+96 -49
View File
@@ -1,60 +1,107 @@
# Mongoose Web Server
# <img src="http://www.cesanta.com/hubfs/www.cesanta.com/Images/mongoose_library.png" width="64" height="64"> Mongoose - Embedded Web Server
[![Join the chat at https://gitter.im/cesanta/mongoose](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/cesanta/mongoose?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
![](https://img.shields.io/badge/license-GPL_2-green.svg "License")
Mongoose is ideal for embedded environments, it has been designed as an open
source platform for connecting devices and bringing them online.
[Mongoose](https://www.cesanta.com/products)
has been on the market since 2004 and attracted
over 1 million cumulative downloads.
It provides easy to use event-driven interface that allows to implement
network protocols or scalable network applications with little effort.
Mongoose helps developers to manage the complexity of network programming
and let them concentrate on the logic, saving time and money.
[Download Mongoose Source Code here](http://hubs.ly/H01bWvx0)
> Nothing overdone. Nothing less. So unbelievably easy to use.
> Just how good software should be! -- Pritin Tyagaraj, SAP
Mongoose is easy to use, powerful, embeddable web server.
* [Downloads](http://cesanta.com/downloads.html)
* [Documentation](http://cesanta.com/docs.html)
* [Mailing list](http://groups.google.com/group/mongoose-users)
# Features
- Works on Windows, Mac, UNIX/Linux, iPhone, Android, and many other platforms
- CGI, SSL, Digest auth, Websocket, WEbDAV, Resumed download, URL rewrite, file blacklist, IP-based ACL, Windows service
- Scripting and database support ([Lua](http://lua.org) +
[Sqlite](http://sqlite.org), see
[dirscan.lp](https://github.com/cesanta/mongoose/blob/master/examples/lua/dirscan.lp) ),
which provides ready to go, powerful web development platform in
one single-click executable with no dependencies
- Simple and clean
[embedding API](https://github.com/cesanta/mongoose/blob/master/mongoose.h).
The source is in single
[mongoose.c](https://github.com/cesanta/mongoose/blob/master/mongoose.c) file
to make embedding easy
- Extremely lightweight, has a core of under 40kB and tiny runtime footprint
- Asyncronouns, non-blocking core supporting single- or multi-threaded usage
- On the market since 2004, stable, mature and tested,
has several man-years invested in continuous improvement and refinement
- Professional support and consultancy available from
[Cesanta Software](http://cesanta.com), developer of Mongoose
* Cross-platform: works on Linux/UNIX, QNX, eCos, Windows, Android, iPhone, etc
* Single-threaded, asynchronous, non-blocking core with simple event-based API
* Builtin protocols:
- plain TCP, plain UDP, SSL/TLS (over TCP, one-way or two-way)
- HTTP client, HTTP server
- Websocket client, Websocket server
- JSON-RPC client, JSON-RPC server
- MQTT client, MQTT broker
- CoAP client, CoAP server
- DNS client, DNS server, async DNS resolver
* Tiny static and run-time footprint
* Source code is both ISO C and ISO C++ compliant
* Very easy to integrate: just copy
[mongoose.c](https://raw.githubusercontent.com/cesanta/mongoose/master/mongoose.c) and
[mongoose.h](https://raw.githubusercontent.com/cesanta/mongoose/master/mongoose.h)
files to your build tree
* Extensively tested and production-ready, trusted by many blue chip businesses
# Acknowledgements
# Examples & Documentation
Mongoose made better thanks to the contribution of following people:
- [User Guide](https://docs.cesanta.com/mongoose) - Detailed User Guide and API reference
- [examples](examples) - Collection of well-commented examples. To build any example,
go into respective directory and type `make`
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.
# Dashboard Example
Mongoose is often used to implement device dashboards and real-time
data exchange over Websocket. Here is a dashboard example that illustrates
the functionality:
![](http://www.cesanta.com/hubfs/www.cesanta.com/diagrams/dash_mongoose_diagram.png)
[Developing a new product? Contact us today to discuss how Mongoose can help
](https://www.cesanta.com/contact)
# Contributions
People who have agreed to the
[Cesanta CLA](https://docs.cesanta.com/contributors_la.shtml)
can make contributions. Note that the CLA isn't a copyright
_assigment_ but rather a copyright _license_.
You retain the copyright on your contributions.
# Licensing
Mongoose is released under
[GNU GPL v.2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html).
Businesses have an option to get non-restrictive, royalty-free commercial
license and professional support from
[Cesanta Software](http://cesanta.com).
You are using Mongoose under
[GPLv2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
and until you commercialize your
application, can continue to use Mongoose free of charge.
[Frozen JSON parser](https://github.com/cesanta/frozen),
[Super Light Regular Expression library](https://github.com/cesanta/slre),
[Super Light DNS Resolver](https://github.com/cesanta/sldr)
are other projects by Cesanta Software, developed with the same philosophy
of functionality and simplicity.
Once you commercialize your product, in order to comply with GPLv2
you need to either open the source code of your product fully or
alternatively purchase a commercial license.
We offer [three levels of commercial licensing](https://www.cesanta.com/products):
- Mongoose Lite: cross platform integration, SSL/TLS, HTTP support
- Mongoose: Mongoose Lite + HTTP CGI, HTTP SSI, HTTP Digest Auth,
WebSocket support
- Mongoose Premium: Mongoose + Plain TCP, UDP, JSON-RPC, MQTT, DNS,
CoAP support
[Enquire about commercial licensing here](https://www.cesanta.com/contact)
# Mongoose Binary
This is our easy to use web server for web developers (PHP, Ruby, Python, etc)
and web designers. Available in three editions to suit your needs: free, pro
(USD 5) and dev edition (from USD 8). To install, simply download, double-click
to start and run browser - that's all!
[Download Mongoose Binary here](https://www.cesanta.com/products#binary)
# Other products by Cesanta
- [Smart.js](https://github.com/cesanta/smart.js) -
Generic, hardware independent, full-stack IoT software platform
- [V7](https://github.com/cesanta/v7) - Embedded JavaScript engine
- [Frozen](https://github.com/cesanta/frozen) - JSON parser and generator
- [SLRE](https://github.com/cesanta/slre) - Super Light Regular Expression
library
-208
View File
@@ -1,208 +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, initially empty. It has a list of URI handlers,
initially empty, and configuration parameters. Configuration can be
altered by `mg_set_option()`, and new URI handlers could be added by
`mg_add_uri_handler()`.
Side-effect: on UNIX, `mg_create_server()` ignores SIGPIPE signals. If custom
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. Please refer to a separate documentation page
that lists all available option names. 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. This function 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()` (an IO 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);
This function performs one iteration of IO loop by iterating over all
active connections, performing `select()` syscall on all sockets with a timeout
of `milliseconds` 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. 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).
void mg_set_auth_handler(struct mg_server *, mg_handler_t handler);
Sets authorization handler. Called by Mongoose on each request, before
performing any other action. Handler can return either `MG_AUTH_OK` or
`MG_AUTH_FAIL`. If `handler` returns `MG_AUTH_FAIL`, then Mongoose sends
digest authorization request to the client. If `handler returns `MG_AUTH_OK`,
then mongoose proceeds with handling the request. Handler function can use
`mg_authorize_digest()` function to verify authorization, or implement any other
custom authorization mechanism.
void mg_set_request_handler(struct mg_server *, mg_handler_t handler);
Sets a request handler. When set, `handler` will be called for each request.
Possible return values from a handler function are `MG_REQUEST_NOT_PROCESSED`,
`MG_REQUEST_PROCESSED` and `MG_REQUEST_CALL_AGAIN`. If handler returns
`MG_REQUEST_NOT_PROCESSED`, mongoose will proceed with handling the request.
If handler returns `MG_REQUEST_PROCESSED`, that signals mongoose that handler
has already processed the connection, and mongoose will skip to the next
request. `MG_REQUEST_CALL_AGAIN` tells mongoose to call request handler
again and again on each `mg_poll_server()` iteration.
When mongoose buffers in HTTP request and successfully parses it, it calls
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_data()` should be used. Note that
websocket handler must return either `MG_CLIENT_CLOSE` or `MG_CLIENT_CONTINUE`
value.
void mg_set_http_error_handler(struct mg_server *, mg_handler_t);
Adds HTTP error handler. An actual HTTP error is passed as
`struct mg_connection::status_code` parameter.
Hanlder should return either `MG_ERROR_PROCESSED` or `MG_ERROR_NOT_PROCESSED`.
If handler returns `MG_ERROR_NOT_PROCESSED`, it
means a handler has not processed the connection, and mongoose proceeds
with sending HTTP error to the client. Otherwise, mongoose does nothing.
const char **mg_get_valid_option_names(void);
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.
int mg_iterate_over_connections(struct mg_server *,
void (*func)(struct mg_connection *, void *),
void *param);
This is an interface primarily designed to push arbitrary data to websocket
connections at any time. This function could be called from any thread. When
it returns, an IO thread called `func()` on each active connection,
passing `param` as an extra parameter. It is allowed to call `mg_send_data()` or
`mg_websocket_write()` within a callback, cause `func` is executed in the
context of the IO thread.
void mg_send_status(struct mg_connection *, int status_code);
void mg_send_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.
<!-- -->
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.
-27
View File
@@ -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/build`
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.
![screenshot](https://a248.e.akamai.net/camo.github.com/b88428bf009a2b6141000937ab684e04cc8586af/687474703a2f2f692e696d6775722e636f6d2f62676f6b702e706e67)
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.
-108
View File
@@ -1,108 +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);
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;
}
To compile it, put `mongoose.c`, `mongoose.h` and `minimal.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 -o app # on Unix
cl 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.
Mongoose can call user-defined functions when certain URIs are requested.
These functions are _called uri handlers_. `mg_add_uri_handler()` registers
an URI handler, and there is no restriction exist on the number of URI handlers.
Also, mongoose can call a user-defined function when it is about to send
HTTP error back to client. That function is called _http error handler_ and
can be registered by `mg_set_http_error_handler()`. Handlers are called
by Mongoose with `struct mg_connection *` pointer as a parameter, which
has all information about the request: HTTP headers, POST or websocket
data buffer, etcetera.
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 handle_hello(struct mg_connection *conn) {
static const char *reply = "Hello world!\n";
mg_write_data(conn, reply, strlen(reply));
return 1;
}
int main(void) {
struct mg_server *server = mg_create_server(NULL);
mg_set_option(server, "document_root", ".");
mg_set_option(server, "listening_port", "8080");
mg_add_uri_handler(server, "/hello", &handle_hello);
for (;;) mg_poll_server(server, 1000); // Infinite loop, Ctrl-C to stop
mg_destroy_server(&server);
return 0;
}
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.
-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_IPV6 Enable IPv6 support
-DMONGOOSE_USE_LUA Enable Lua scripting
-DMONGOOSE_USE_LUA_SQLITE3 Enable sqlite3 binding for Lua
-DMONGOOSE_USE_SSL Enable SSL
-DMONGOOSE_USE_POST_SIZE_LIMIT=X POST requests larger than X will be
rejected, not set by default
-DMONGOOSE_USE_EXTRA_HTTP_HEADERS=X Append X to the HTTP headers
for static files, empty by default
-DMONGOOSE_USE_STACK_SIZE=X Let mg_start_thread() use stack
size X, default is OS default
-DMONGOOSE_ENABLE_DEBUG Enables debug messages on stdout, very noisy
Mongoose source code contains a well-commented example code, listed below:
* [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/websocket.c) demonstrates API-controlled Digest authorization
-23
View File
@@ -1,23 +0,0 @@
# Mongoose FAQ
### 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.
-44
View File
@@ -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.
-59
View File
@@ -1,59 +0,0 @@
# Mongoose Lua Server Pages
Pre-built Windows and Mac mongoose binaries support Lua Server Pages
functionality.
That means it is possible to write PHP-like scripts with mongoose
using Lua programming language instead of PHP. Lua is known
for it's speed and small size. Mongoose uses Lua version 5.2.1, the
documentation for it can be found at
[Lua 5.2 reference manual](http://www.lua.org/manual/5.2/).
To create a Lua Page, make a file that is called `<something>.lp`. For example,
let's say it is going to be `my_page.lp`. It is important to have a file
name that ends up with `.lp`, cause this is the way mongoose recognises
Lua Page file. The contents of the file, just like
with PHP, is HTML with embedded Lua code. Lua code must be enclosed within
`<? ?>` blocks, and can appear anywhere on the page.
Mongoose does not send HTTP headers for Lua pages. Therefore,
every Lua Page must begin with HTTP status line and headers, like this:
<? mg.write('HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n') ?>
<html><body>
<span>Today is:</span> <? mg.write(os.date("%A")) ?>
</body></html>
Note that this example uses function `mg.write()`, which prints data to the
web page. Using function `mg.write()` is the way to generate web content from
inside Lua code. In addition to `mg.write()`, all standard library functions
are accessible from the Lua code (please check reference manual for details).
Information about the request is available in `mg.request_info` object.
I contains request method, all headers, etcetera. Please refer to
`struct mg_request_info` definition in
[mongoose.h](https://github.com/cesanta/mongoose/blob/master/mongoose.h)
to see what is available in `mg.request_info`. Also,
[page.lp](https://github.com/cesanta/mongoose/blob/master/test/page.lp) and
[prime_numbers.lp](https://github.com/cesanta/mongoose/blob/master/examples/lua/prime_numbers.lp)
contain some example code that uses `request_info` and other functions,
like form submission.
Mongoose exports the following to the Lua server page:
mg.write(str) -- writes string to the client
mg.onerror(msg) -- error handler, can be overridden
mg.request_info -- a table with request information
sqlite3 -- Sqlite3 interface
slite3 functions are documented at [lua.sqlite.org](http://lua.sqlite.org/),
and usage example is at
[page.lp](https://github.com/cesanta/mongoose/blob/master/test/page.lp).
Using Lua scripting it is easy to emulate SSI functionality. For example,
to include the content of another file, one can write:
<? mg.write(io.open('MY_FILE.TXT'):read('*all')) ?>
To serve a Lua Page, mongoose creates Lua context. That context is used for
all Lua blocks within the page. That means, all Lua blocks on the same page
share the same context. If one block defines a variable, for example, that
variable is visible in the block that follows.
-140
View File
@@ -1,140 +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 from 192.168/16 subnet. 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 use as CGI interpreter for __all__ CGI scripts
regardless script extension.
for an interpreter. 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 server 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 that PHP scripts must use `php-cgi.exe` executable, 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 pattern. Note that full file path is
matched against the pattern, not the URI. Note: if `MONGOOSE_CGI` environment
variable is set, then Mongoose passes it to the CGI script.
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`.
### error\_log\_file
Path to a file for error logs. Either full path, or relative to the
mongoose executable. Default: not set, no errors are logged.
### 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.
### idle\_timeout\_ms
Timeout for idle connections. Default: 30000 (30 seconds)
### 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_ports 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. Insted,
`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_patters`
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, appending two parameters:
`?code=<http_error_code&orig_uri=<original_uri>`.
This makes it possible to serve many directories outside from `document_root`,
redirect all requests to scripts, and do other tricky things. 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
Default: not set.
-75
View File
@@ -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.
-85
View File
@@ -1,85 +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 file 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 pops 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:
**.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
View File
@@ -0,0 +1 @@
*.exe
+118
View File
@@ -0,0 +1,118 @@
#############################################################
# Required variables for each makefile
# Discard this section from all parent makefiles
# Expected variables (with automatic defaults):
# CSRCS (all "C" files in the dir)
# SUBDIRS (all subdirs with a Makefile)
# GEN_LIBS - list of libs to be generated ()
# GEN_IMAGES - list of object file images to be generated ()
# GEN_BINS - list of binaries to be generated ()
# COMPONENTS_xxx - a list of libs/objs in the form
# subdir/lib to be extracted and rolled up into
# a generated lib/image xxx.a ()
#
TARGET = eagle
#FLAVOR = release
FLAVOR = debug
EXTRA_CCFLAGS += -Wall -Werror
ifndef PDIR # {
GEN_IMAGES= eagle.app.v6.out
GEN_BINS= eagle.app.v6.bin
SPECIAL_MKTARGETS=$(APP_MKTARGETS)
SUBDIRS=user
endif # } PDIR
LDDIR = $(SDK_PATH)/ld
CCFLAGS += -Os
TARGET_LDFLAGS = \
-nostdlib \
-Wl,-EL \
--longcalls \
--text-section-literals
ifeq ($(FLAVOR),debug)
TARGET_LDFLAGS += -g -O2
endif
ifeq ($(FLAVOR),release)
TARGET_LDFLAGS += -g -O0
endif
COMPONENTS_eagle.app.v6 = \
user/libuser.a
LINKFLAGS_eagle.app.v6 = \
-L$(SDK_PATH)/lib \
-Wl,--gc-sections \
-nostdlib \
-T$(LD_FILE) \
-Wl,--no-check-sections \
-u call_user_start \
-Wl,-static \
-Wl,--start-group \
-lcirom \
-lgcc \
-lhal \
-lphy \
-lpp \
-lnet80211 \
-lwpa \
-lcrypto \
-lmain \
-lfreertos \
-llwip \
$(DEP_LIBS_eagle.app.v6) \
-Wl,--end-group
DEPENDS_eagle.app.v6 = \
$(LD_FILE) \
$(LDDIR)/eagle.rom.addr.v6.ld
#############################################################
# Configuration i.e. compile options etc.
# Target specific stuff (defines etc.) goes in here!
# Generally values applying to a tree are captured in the
# makefile at its root level - these are then overridden
# for a subtree within the makefile rooted therein
#
#UNIVERSAL_TARGET_DEFINES = \
# Other potential configuration flags include:
# -DTXRX_TXBUF_DEBUG
# -DTXRX_RXBUF_DEBUG
# -DWLAN_CONFIG_CCX
CONFIGURATION_DEFINES = -DICACHE_FLASH
DEFINES += \
$(UNIVERSAL_TARGET_DEFINES) \
$(CONFIGURATION_DEFINES)
DDEFINES += \
$(UNIVERSAL_TARGET_DEFINES) \
$(CONFIGURATION_DEFINES)
#############################################################
# Recursion Magic - Don't touch this!!
#
# Each subtree potentially has an include directory
# corresponding to the common APIs applicable to modules
# rooted at that subtree. Accordingly, the INCLUDE PATH
# of a module can only contain the include directories up
# its parent path, and not its siblings
#
# Required for each makefile to inherit from the parent
#
INCLUDES := $(INCLUDES) -I $(PDIR)include
sinclude $(SDK_PATH)/Makefile
.PHONY: FORCE
FORCE:
+36
View File
@@ -0,0 +1,36 @@
This is a Mongoose "Hello, world" that can be compiled under ESP8266 RTOS SDK.
It sets up an AP (SSID `Mongoose`) and serves a "hello world" page on http://192.168.4.1/
Most of the the boilerplate comes from [project_template](https://github.com/espressif/ESP8266_RTOS_SDK/tree/master/examples/project_template) (@ [3ca6af5](https://github.com/espressif/ESP8266_RTOS_SDK/tree/3ca6af5da68678d809b34c7cd98bee71e0235039/examples/project_template)) with minimal changes.
To build with no changes to the SDK, you will need a module with 1MB (8Mb) flash or more.
Compile (for NodeMCU 1.0):
```
$ export SDK_PATH=/path/to/ESP8266_RTOS_SDK
$ export BIN_PATH=./bin
$ make clean; make BOOT=new APP=1 SPI_SPEED=40 SPI_MODE=dio SPI_SIZE_MAP=6
```
Flash (using [esptool](https://github.com/themadinventor/esptool)):
```
$ esptool.py --port /dev/ttyUSB0 --baud 230400 \
write_flash --flash_mode=dio --flash_size=32m \
0x00000 ${SDK_PATH}/bin/boot_v1.4\(b1\).bin \
0x01000 ${BIN_PATH}/upgrade/user1.4096.new.6.bin
```
The output can be made to fit in 512KB (4Mb), but stock linker scripts do not reserve enough space for code.
Custom linker script is provided for that, so you can use it for smaller devices like so (example that will work with ESP-01):
```
$ make clean; make BOOT=none APP=0 SPI_SPEED=40 SPI_MODE=qio SPI_SIZE_MAP=0 LD_FILE=ld/eagle.app.v6.512.compact.ld
$ esptool.py --port /dev/ttyUSB0 --baud 230400 \
write_flash --flash_mode=qio --flash_size=4m \
0x00000 ${BIN_PATH}/eagle.flash.bin \
0x10000 ${BIN_PATH}/eagle.irom0text.bin
```
+173
View File
@@ -0,0 +1,173 @@
#!/bin/bash
:<<!
******NOTICE******
MUST set SDK_PATH & BIN_PATH firstly!!!
example:
export SDK_PATH=~/ESP8266_RTOS_SDK
export BIN_PATH=~/esp8266_bin
!
echo "gen_misc.sh version 20150911"
echo ""
if [ $SDK_PATH ]; then
echo "SDK_PATH:"
echo "$SDK_PATH"
echo ""
else
echo "ERROR: Please export SDK_PATH in gen_misc.sh firstly, exit!!!"
exit
fi
if [ $BIN_PATH ]; then
echo "BIN_PATH:"
echo "$BIN_PATH"
echo ""
else
echo "ERROR: Please export BIN_PATH in gen_misc.sh firstly, exit!!!"
exit
fi
echo "Please check SDK_PATH & BIN_PATH, enter (Y/y) to continue:"
read input
if [[ $input != Y ]] && [[ $input != y ]]; then
exit
fi
echo ""
echo "Please follow below steps(1-5) to generate specific bin(s):"
echo "STEP 1: use boot_v1.2+ by default"
boot=new
echo "boot mode: $boot"
echo ""
echo "STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin)"
echo "enter (0/1/2, default 0):"
read input
if [ -z "$input" ]; then
if [ $boot != none ]; then
boot=none
echo "ignore boot"
fi
app=0
echo "generate bin: eagle.flash.bin+eagle.irom0text.bin"
elif [ $input == 1 ]; then
if [ $boot == none ]; then
app=0
echo "choose no boot before"
echo "generate bin: eagle.flash.bin+eagle.irom0text.bin"
else
app=1
echo "generate bin: user1.bin"
fi
elif [ $input == 2 ]; then
if [ $boot == none ]; then
app=0
echo "choose no boot before"
echo "generate bin: eagle.flash.bin+eagle.irom0text.bin"
else
app=2
echo "generate bin: user2.bin"
fi
else
if [ $boot != none ]; then
boot=none
echo "ignore boot"
fi
app=0
echo "generate bin: eagle.flash.bin+eagle.irom0text.bin"
fi
echo ""
echo "STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz)"
echo "enter (0/1/2/3, default 2):"
read input
if [ -z "$input" ]; then
spi_speed=40
elif [ $input == 0 ]; then
spi_speed=20
elif [ $input == 1 ]; then
spi_speed=26.7
elif [ $input == 3 ]; then
spi_speed=80
else
spi_speed=40
fi
echo "spi speed: $spi_speed MHz"
echo ""
echo "STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT)"
echo "enter (0/1/2/3, default 0):"
read input
if [ -z "$input" ]; then
spi_mode=QIO
elif [ $input == 1 ]; then
spi_mode=QOUT
elif [ $input == 2 ]; then
spi_mode=DIO
elif [ $input == 3 ]; then
spi_mode=DOUT
else
spi_mode=QIO
fi
echo "spi mode: $spi_mode"
echo ""
echo "STEP 5: choose spi size and map"
echo " 0= 512KB( 256KB+ 256KB)"
echo " 2=1024KB( 512KB+ 512KB)"
echo " 3=2048KB( 512KB+ 512KB)"
echo " 4=4096KB( 512KB+ 512KB)"
echo " 5=2048KB(1024KB+1024KB)"
echo " 6=4096KB(1024KB+1024KB)"
echo "enter (0/2/3/4/5/6, default 0):"
read input
if [ -z "$input" ]; then
spi_size_map=0
echo "spi size: 512KB"
echo "spi ota map: 256KB + 256KB"
elif [ $input == 2 ]; then
spi_size_map=2
echo "spi size: 1024KB"
echo "spi ota map: 512KB + 512KB"
elif [ $input == 3 ]; then
spi_size_map=3
echo "spi size: 2048KB"
echo "spi ota map: 512KB + 512KB"
elif [ $input == 4 ]; then
spi_size_map=4
echo "spi size: 4096KB"
echo "spi ota map: 512KB + 512KB"
elif [ $input == 5 ]; then
spi_size_map=5
echo "spi size: 2048KB"
echo "spi ota map: 1024KB + 1024KB"
elif [ $input == 6 ]; then
spi_size_map=6
echo "spi size: 4096KB"
echo "spi ota map: 1024KB + 1024KB"
else
spi_size_map=0
echo "spi size: 512KB"
echo "spi ota map: 256KB + 256KB"
fi
echo ""
echo "start..."
echo ""
make clean
make BOOT=$boot APP=$app SPI_SPEED=$spi_speed SPI_MODE=$spi_mode SPI_SIZE_MAP=$spi_size_map
@@ -0,0 +1,20 @@
/* eagle.flash.bin @ 0x00000 */
/* eagle.irom0text.bin @ 0x10000 */
/*
* Flash map for 512KB flash.
*
* There is 0x8000 (32KB) available between 0x8000 and 0x10000.
*
* Note: IROM images starts at 0x10000 (ignore Makefile output which says 0x40000.
*/
MEMORY
{
dport0_0_seg : org = 0x3FF00000, len = 0x10
dram0_0_seg : org = 0x3FFE8000, len = 0x18000
iram1_0_seg : org = 0x40100000, len = 0x8000
irom0_0_seg : org = 0x40210000, len = 0x6C000
}
INCLUDE "../ld/eagle.app.v6.common.ld"
+56
View File
@@ -0,0 +1,56 @@
This is a simple project template.
sample_lib is an example for multi-level folder Makefile, notice the folder structure and each Makefile, you can get the clue.
HOWTO:
1. Copy this folder to anywhere.
Example:
Copy to ~/workspace/project_template
You can rename this folder as you like.
2. Export SDK_PATH and BIN_PATH.
Example:
Your SDK path is ~/esp_iot_rtos_sdk, and want generate bin at ~/esp8266_bin.
Do follow steps:
1>. export SDK_PATH=~/esp_iot_rtos_sdk
2>. export BIN_PATH=~/esp8266_bin
SDK and project are seperate, you can update SDK without change your project.
3. Enter project_template folder, run ./gen_misc.sh, and follow the tips and steps.
Compile Options:
(1) COMPILE
Possible value: xcc
Default value:
If not set, use gcc by default.
(2) BOOT
Possible value: none/old/new
none: no need boot
old: use boot_v1.1
new: use boot_v1.2
Default value: new
(3) APP
Possible value: 0/1/2
0: original mode, generate eagle.app.v6.flash.bin and eagle.app.v6.irom0text.bin
1: generate user1
2: generate user2
Default value: 0
(3) SPI_SPEED
Possible value: 20/26.7/40/80
Default value: 40
(4) SPI_MODE
Possible value: QIO/QOUT/DIO/DOUT
Default value: QIO
(4) SPI_SIZE_MAP
Possible value: 0/2/3/4/5/6
Default value: 0
For example:
make COMPILE=gcc BOOT=new APP=1 SPI_SPEED=40 SPI_MODE=QIO SPI_SIZE_MAP=0
+47
View File
@@ -0,0 +1,47 @@
#############################################################
# Required variables for each makefile
# Discard this section from all parent makefiles
# Expected variables (with automatic defaults):
# CSRCS (all "C" files in the dir)
# SUBDIRS (all subdirs with a Makefile)
# GEN_LIBS - list of libs to be generated ()
# GEN_IMAGES - list of images to be generated ()
# COMPONENTS_xxx - a list of libs/objs in the form
# subdir/lib to be extracted and rolled up into
# a generated lib/image xxx.a ()
#
ifndef PDIR
GEN_LIBS = libuser.a
endif
#############################################################
# Configuration i.e. compile options etc.
# Target specific stuff (defines etc.) goes in here!
# Generally values applying to a tree are captured in the
# makefile at its root level - these are then overridden
# for a subtree within the makefile rooted therein
#
DEFINES += -DMG_DISABLE_DAV -DMG_DISABLE_SYNC_RESOLVER -DMG_DISABLE_CGI \
-DMG_DISABLE_SOCKETPAIR -DMG_DISABLE_DIRECTORY_LISTING \
-DMG_MAX_HTTP_HEADERS=20 -DMG_MAX_HTTP_REQUEST_SIZE=1024 \
-DMG_MAX_PATH=40 -DMG_MAX_HTTP_SEND_IOBUF=1024 \
-DMG_ESP8266 -DRTOS_SDK -DMG_LWIP
#############################################################
# Recursion Magic - Don't touch this!!
#
# Each subtree potentially has an include directory
# corresponding to the common APIs applicable to modules
# rooted at that subtree. Accordingly, the INCLUDE PATH
# of a module can only contain the include directories up
# its parent path, and not its siblings
#
# Required for each makefile to inherit from the parent
#
INCLUDES += -I ./
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile
+54
View File
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2015 Cesanta Software Limited
* All rights reserved
*/
#include <ctype.h>
#include <sys/time.h>
#include <stdint.h>
#include <math.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "esp_common.h"
/* Makes fprintf(stdout) and stderr work. */
_ssize_t _write_r(struct _reent *r, int fd, void *buf, size_t len) {
if (fd == 1 || fd == 2) {
size_t i;
for (i = 0; i < len; i++) {
os_putc(((char *) buf)[i]);
}
return len;
}
return -1;
}
/*
* You'll need to implement _open_r and friends if you want file operations. See
* https://github.com/cesanta/smart.js/blob/master/platforms/esp8266/user/esp_fs.c
* for SPIFFS-based implementation.
*/
void abort(void) __attribute__((no_instrument_function));
void abort(void) {
/* cause an unaligned access exception, that will drop you into gdb */
*(int *) 1 = 1;
while (1)
; /* avoid gcc warning because stdlib abort() has noreturn attribute */
}
void _exit(int status) {
printf("_exit(%d)\n", status);
abort();
}
int _gettimeofday_r(struct _reent *r, struct timeval *tp, void *tzp) {
uint32_t time = system_get_time();
tp->tv_sec = time / 1000000;
tp->tv_usec = time % 1000000;
return 0;
}
+1
View File
@@ -0,0 +1 @@
../../../mongoose.c
+1
View File
@@ -0,0 +1 @@
../../../mongoose.h
+108
View File
@@ -0,0 +1,108 @@
/*
* Copyright (c) 2015 Cesanta Software Limited
* All rights reserved
*/
#include "esp_common.h"
#include "mongoose.h"
#define AP_SSID "Mongoose"
#define AP_PASS "Mongoose"
#define AP_CHAN 9
#define MG_LISTEN_ADDR "80"
#define MG_TASK_STACK_SIZE 2048
#define MG_TASK_PRIORITY 1
void uart_div_modify(int uart_no, unsigned int freq);
void ev_handler(struct mg_connection *nc, int ev, void *p) {
static const char *reply_fmt =
"HTTP/1.0 200 OK\r\n"
"Connection: close\r\n"
"Content-Type: text/plain\r\n"
"\r\n"
"Hello %s\n";
LOG(LL_DEBUG, ("conn %p ev %d", nc, ev));
switch (ev) {
case MG_EV_ACCEPT: {
char addr[32];
mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr),
MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT);
LOG(LL_INFO, ("Connection %p from %s", nc, addr));
break;
}
case MG_EV_HTTP_REQUEST: {
char addr[32];
struct http_message *hm = (struct http_message *) p;
mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr),
MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT);
LOG(LL_INFO,
("HTTP request from %s: %.*s %.*s", addr, (int) hm->method.len,
hm->method.p, (int) hm->uri.len, hm->uri.p));
mg_printf(nc, reply_fmt, addr);
nc->flags |= MG_F_SEND_AND_CLOSE;
break;
}
case MG_EV_CLOSE: {
LOG(LL_INFO, ("Connection %p closed", nc));
break;
}
}
}
void setup_ap() {
struct softap_config cfg;
wifi_set_opmode_current(SOFTAP_MODE);
memset(&cfg, 0, sizeof(cfg));
strcpy((char *) cfg.ssid, AP_SSID);
strcpy((char *) cfg.password, AP_PASS);
cfg.ssid_len = strlen((const char *) cfg.ssid);
cfg.authmode =
strlen((const char *) cfg.password) ? AUTH_WPA2_PSK : AUTH_OPEN;
cfg.channel = AP_CHAN;
cfg.ssid_hidden = 0;
cfg.max_connection = 10;
cfg.beacon_interval = 100; /* ms */
LOG(LL_INFO, ("Setting up AP '%s' on channel %d", cfg.ssid, cfg.channel));
wifi_softap_set_config_current(&cfg);
}
static void mg_task(void *arg) {
struct mg_mgr mgr;
struct mg_connection *nc;
cs_log_set_level(LL_INFO);
LOG(LL_INFO, ("SDK version: %s", system_get_sdk_version()));
setup_ap();
mg_mgr_init(&mgr, NULL);
nc = mg_bind(&mgr, MG_LISTEN_ADDR, ev_handler);
if (nc == NULL) {
LOG(LL_ERROR, ("Error setting up listener!"));
return;
}
mg_set_protocol_http_websocket(nc);
while (1) {
mg_mgr_poll(&mgr, 1000);
}
}
xTaskHandle s_mg_task_handle;
void user_init(void) {
uart_div_modify(0, UART_CLK_FREQ / 115200);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
xTaskCreate(mg_task, (const signed char *) "mongoose", MG_TASK_STACK_SIZE,
NULL, MG_TASK_PRIORITY, &s_mg_task_handle);
}
+9 -48
View File
@@ -1,54 +1,15 @@
CFLAGS = -W -Wall -I.. -pthread -g -pipe $(CFLAGS_EXTRA)
DLL_FLAGS = -DLUA_COMPAT_ALL -I../build
RM = rm -rf
# Copyright (c) 2014 Cesanta Software
# All rights reserved
ifeq ($(OS),Windows_NT)
RM = del /q /f
else
UNAME_S := $(shell uname -s)
DLL_FLAGS += -shared
SUBDIRS = $(sort $(dir $(wildcard */)))
X = $(SUBDIRS)
ifeq ($(UNAME_S),Linux)
CFLAGS += -ldl
endif
.PHONY: $(SUBDIRS)
ifeq ($(UNAME_S),Darwin)
# DLL_FLAGS += -bundle -undefined dynamic_lookup -dynamiclib
DLL_FLAGS += -flat_namespace -undefined suppress -dynamiclib
endif
endif
all: $(SUBDIRS)
all: websocket_html.c
$(CC) hello.c ../mongoose.c -o hello $(CFLAGS)
$(CC) websocket.c websocket_html.c ../mongoose.c -o websocket $(CFLAGS)
$(CC) post.c ../mongoose.c -o post $(CFLAGS)
$(CC) multi_threaded.c ../mongoose.c -o multi_threaded $(CFLAGS)
$(CC) upload.c ../mongoose.c -o upload $(CFLAGS)
$(CC) auth.c ../mongoose.c -o auth $(CFLAGS)
$(CC) server.c ../mongoose.c -o server $(CFLAGS)
# $(CC) chat.c ../mongoose.c -o chat $(CFLAGS)
# $(CC) lua_dll.c ../build/lua_5.2.1.c -o $@.so $(CFLAGS) $(DLL_FLAGS)
websocket_html.c: websocket.html
perl mkdata.pl $< > $@
MSVC = ../../vc6
CL = $(MSVC)/bin/cl
CLFLAGS = /MD /TC /nologo $(DBG) /W3 \
/I$(MSVC)/include /I.. /Dsnprintf=_snprintf
LFLAGS = /link /incremental:no /libpath:$(MSVC)/lib /machine:IX86
windows: websocket_html.c
$(CL) hello.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
$(CL) websocket.c websocket_html.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
$(CL) post.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
$(CL) multi_threaded.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
$(CL) upload.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
$(CL) auth.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
$(CL) server.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
#$(CL) lua_dll.c $(CLFLAGS) $(DLL_FLAGS) /DLL $(LFLAGS) /SUBSYSTEM:WINDOWS /ENTRY:luaopen_lua_dll /EXPORT:luaopen_lua_dll /out:lua_dll.dll
$(SUBDIRS):
@$(MAKE) -C $@
clean:
-@$(RM) hello upload post websocket chat *.exe *.dSYM *.obj .*o
for d in $(SUBDIRS) ; do $(MAKE) -C $$d clean ; done
+25
View File
@@ -0,0 +1,25 @@
PROG = api_server
SOURCES = $(PROG).c sqlite3.c db_plugin_sqlite.c ../../mongoose.c
CFLAGS = -W -Wall -pthread $(CFLAGS_EXTRA)
ifeq ($(OS), Windows_NT)
else
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S), Linux)
CFLAGS += -ldl -lm
endif
endif
all: $(PROG)
$(PROG): $(SOURCES)
$(CC) $(SOURCES) -o $@ $(CFLAGS)
$(PROG).exe: $(SOURCES)
cl $(SOURCES) /I.. /MD /Fe$@
test: $(PROG)
sh unit_test.sh $$(pwd)/$(PROG)
clean:
rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG)
+104
View File
@@ -0,0 +1,104 @@
/*
* Copyright (c) 2014 Cesanta Software Limited
* All rights reserved
*/
#include "db_plugin.h"
static const char *s_http_port = "8000";
static struct mg_serve_http_opts s_http_server_opts;
static int s_sig_num = 0;
static void *s_db_handle = NULL;
static const char *s_db_path = "api_server.db";
static const struct mg_str s_get_method = MG_STR("GET");
static const struct mg_str s_put_method = MG_STR("PUT");
static const struct mg_str s_delele_method = MG_STR("DELETE");
static void signal_handler(int sig_num) {
signal(sig_num, signal_handler);
s_sig_num = sig_num;
}
static int has_prefix(const struct mg_str *uri, const struct mg_str *prefix) {
return uri->len > prefix->len && memcmp(uri->p, prefix->p, prefix->len) == 0;
}
static int is_equal(const struct mg_str *s1, const struct mg_str *s2) {
return s1->len == s2->len && memcmp(s1->p, s2->p, s2->len) == 0;
}
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
static const struct mg_str api_prefix = MG_STR("/api/v1");
struct http_message *hm = (struct http_message *) ev_data;
struct mg_str key;
switch (ev) {
case MG_EV_HTTP_REQUEST:
if (has_prefix(&hm->uri, &api_prefix)) {
key.p = hm->uri.p + api_prefix.len;
key.len = hm->uri.len - api_prefix.len;
if (is_equal(&hm->method, &s_get_method)) {
db_op(nc, hm, &key, s_db_handle, API_OP_GET);
} else if (is_equal(&hm->method, &s_put_method)) {
db_op(nc, hm, &key, s_db_handle, API_OP_SET);
} else if (is_equal(&hm->method, &s_delele_method)) {
db_op(nc, hm, &key, s_db_handle, API_OP_DEL);
} else {
mg_printf(nc, "%s",
"HTTP/1.0 501 Not Implemented\r\n"
"Content-Length: 0\r\n\r\n");
}
} else {
mg_serve_http(nc, hm, s_http_server_opts); /* Serve static content */
}
break;
default:
break;
}
}
int main(int argc, char *argv[]) {
struct mg_mgr mgr;
struct mg_connection *nc;
int i;
/* Open listening socket */
mg_mgr_init(&mgr, NULL);
nc = mg_bind(&mgr, s_http_port, ev_handler);
mg_set_protocol_http_websocket(nc);
s_http_server_opts.document_root = "web_root";
/* Parse command line arguments */
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-D") == 0) {
mgr.hexdump_file = argv[++i];
} else if (strcmp(argv[i], "-f") == 0) {
s_db_path = argv[++i];
} else if (strcmp(argv[i], "-r") == 0) {
s_http_server_opts.document_root = argv[++i];
}
}
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
/* Open database */
if ((s_db_handle = db_open(s_db_path)) == NULL) {
fprintf(stderr, "Cannot open DB [%s]\n", s_db_path);
exit(EXIT_FAILURE);
}
/* Run event loop until signal is received */
printf("Starting RESTful server on port %s\n", s_http_port);
while (s_sig_num == 0) {
mg_mgr_poll(&mgr, 1000);
}
/* Cleanup */
mg_mgr_free(&mgr);
db_close(&s_db_handle);
printf("Exiting on signal %d\n", s_sig_num);
return 0;
}
+19
View File
@@ -0,0 +1,19 @@
/*
* Copyright (c) 2014 Cesanta Software Limited
* All rights reserved
*/
#ifndef DB_PLUGIN_HEADER_DEFINED
#define DB_PLUGIN_HEADER_DEFINED
#include "../../mongoose.h"
void *db_open(const char *db_path);
void db_close(void **db_handle);
enum { API_OP_GET, API_OP_SET, API_OP_DEL };
void db_op(struct mg_connection *nc, const struct http_message *hm,
const struct mg_str *key, void *db, int op);
#endif /* DB_PLUGIN_HEADER_DEFINED */
+107
View File
@@ -0,0 +1,107 @@
/*
* Copyright (c) 2014 Cesanta Software Limited
* All rights reserved
*/
#include "db_plugin.h"
#include "sqlite3.h"
void *db_open(const char *db_path) {
sqlite3 *db = NULL;
if (sqlite3_open_v2(db_path, &db, SQLITE_OPEN_READWRITE |
SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL) == SQLITE_OK) {
sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS kv(key PRIMARY KEY, val);",
0, 0, 0);
}
return db;
}
void db_close(void **db_handle) {
if (db_handle != NULL && *db_handle != NULL) {
sqlite3_close(*db_handle);
*db_handle = NULL;
}
}
static void op_set(struct mg_connection *nc, const struct http_message *hm,
const struct mg_str *key, void *db) {
sqlite3_stmt *stmt = NULL;
char value[200];
const struct mg_str *body = hm->query_string.len > 0 ?
&hm->query_string : &hm->body;
mg_get_http_var(body, "value", value, sizeof(value));
if (sqlite3_prepare_v2(db, "INSERT OR REPLACE INTO kv VALUES (?, ?);",
-1, &stmt, NULL) == SQLITE_OK) {
sqlite3_bind_text(stmt, 1, key->p, key->len, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, value, strlen(value), SQLITE_STATIC);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
}
mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
}
static void op_get(struct mg_connection *nc, const struct http_message *hm,
const struct mg_str *key, void *db) {
sqlite3_stmt *stmt = NULL;
const char *data = NULL;
int result;
(void) hm;
if (sqlite3_prepare_v2(db, "SELECT val FROM kv WHERE key = ?;",
-1, &stmt, NULL) == SQLITE_OK) {
sqlite3_bind_text(stmt, 1, key->p, key->len, SQLITE_STATIC);
result = sqlite3_step(stmt);
data = (char *) sqlite3_column_text(stmt, 0);
if ((result == SQLITE_OK || result == SQLITE_ROW) && data != NULL) {
mg_printf(nc, "HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: %d\r\n\r\n%s",
(int) strlen(data), data);
} else {
mg_printf(nc, "%s", "HTTP/1.1 404 Not Found\r\n"
"Content-Length: 0\r\n\r\n");
}
sqlite3_finalize(stmt);
} else {
mg_printf(nc, "%s", "HTTP/1.1 500 Server Error\r\n"
"Content-Length: 0\r\n\r\n");
}
}
static void op_del(struct mg_connection *nc, const struct http_message *hm,
const struct mg_str *key, void *db) {
sqlite3_stmt *stmt = NULL;
int result;
(void) hm;
if (sqlite3_prepare_v2(db, "DELETE FROM kv WHERE key = ?;",
-1, &stmt, NULL) == SQLITE_OK) {
sqlite3_bind_text(stmt, 1, key->p, key->len, SQLITE_STATIC);
result = sqlite3_step(stmt);
if (result == SQLITE_OK || result == SQLITE_ROW) {
mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
} else {
mg_printf(nc, "%s", "HTTP/1.1 404 Not Found\r\n"
"Content-Length: 0\r\n\r\n");
}
sqlite3_finalize(stmt);
} else {
mg_printf(nc, "%s", "HTTP/1.1 500 Server Error\r\n"
"Content-Length: 0\r\n\r\n");
}
}
void db_op(struct mg_connection *nc, const struct http_message *hm,
const struct mg_str *key, void *db, int op) {
switch (op) {
case API_OP_GET: op_get(nc, hm, key, db); break;
case API_OP_SET: op_set(nc, hm, key, db); break;
case API_OP_DEL: op_del(nc, hm, key, db); break;
default:
mg_printf(nc, "%s", "HTTP/1.0 501 Not Implemented\r\n"
"Content-Length: 0\r\n\r\n");
break;
}
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+35
View File
@@ -0,0 +1,35 @@
#!/bin/sh
PROG=$1
PORT=${2:-8000} # If second param is given, this is load balancer port
DB_FILE=/tmp/_$$.db
URL=http://127.0.0.1:$PORT/api/v1
cleanup() {
rm -rf $DB_FILE
kill -9 $PID >/dev/null 2>&1
}
#set -x
trap cleanup EXIT
cleanup
$PROG -f $DB_FILE &
PID=$!
#sleep 1
curl -s -X PUT -d 'value=123' $URL/foo
curl -s -X PUT -d 'value=success' $URL/bar/baz
# Fetch existing key
RESULT=$(curl -s $URL/bar/baz)
test "$RESULT" = "success" || exit 1
# Delete it
curl -s -X DELETE $URL/bar/baz
# Make sure it's deleted - GET must result in 404
RESULT=$(curl -s -i $URL/bar/baz | head -1 | tr -d '\r')
test "$RESULT" = "HTTP/1.1 404 Not Found" || exit 1
exit 0
+38
View File
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>RESTful API demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
* { outline: none; }
body {
background-color: #789; margin: 0;
padding: 0; font: 16px/1.4 Helvetica, Arial, sans-serif;
font: 16px/1.4 Helvetica, Arial, sans-serif;
}
div.content {
width: 800px; margin: 2em auto; padding: 20px 50px;
background-color: #fff; border-radius: 1em;
}
label { display: inline-block; min-width: 7em; }
input { border: 1px solid #ccc; padding: 0.2em; }
a:link, a:visited { color: #69c; text-decoration: none; }
@media (max-width: 700px) {
body { background-color: #fff; }
div.content { width: auto; margin: 0 auto; padding: 1em; }
}
</style>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script language="javascript" type="text/javascript">
jQuery(function() {
});
</script>
</head>
<body>
<div class="content">
<h1>API server</h1>
</div>
</body>
</html>
+2
View File
@@ -0,0 +1,2 @@
# This "makefile" is only intended to prevent errors during main makefile execution
all:
+46
View File
@@ -0,0 +1,46 @@
# Arduino Restful Client
This example demonstrates how to use [Mongoose](https://www.cesanta.com/mongoose) to send HTTP commands from Arduino.
Example sends free memory size and current board uptime, but it can be modified to send any user-specific data.
At the moment this example supports [Arduino Mega 2560](http://arduino.cc/en/Main/ArduinoBoardMega2560) board (and compatible) with either W5100-based
network shield (like [Arduino Ethernet Shield](http://arduino.cc/en/Main/ArduinoEthernetShield)) or [CC3000](http://www.ti.com/product/cc3000)-based WIFI Shield.
## Build and run instructions:
###To run with Arduino Ethernet (W5100) shield:
1. Add (Sketch->Add file...) the following files to sketch:
- /mongoose/mongoose.h
- /mongoose/mongoose.c
- /mongoose/platforms/arduino_ethernet_W5100/avrsupport.h
- /mongoose/platforms/arduino_ethernet_W5100/avrsupport.cpp
3. Buils and start (in console) /Users/alex/Projects/mongoose/examples/restful_server example
4. Make `board_ip` and `board_mac` variables suitable for your network and board
5. Change IP address in `s_target_address` variable to IP address of host running restful_server
6. Uncomment line `#include <Ethernet.h>`
7. Compile and flash sketch
8. restful_server will start to show current uptime and free memory size (with 5 seconds interval)
###To run with Adafruit WiFi (CC3000) shield:
1. Add (Sketch->Add files...) the following files to sketch:
- /mongoose/mongoose.h
- /mongoose/mongoose.c
- /mongoose/platforms/arduino_ethernet_W5100/avrsupport.h
- /mongoose/platforms/arduino_ethernet_W5100/avrsupport.cpp
2. Import Adafruit CC3000 library for mongoose
(select Sketch->Import Library...->Add library... and point
/mongoose/platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_mongoose folder)
3. Buils and start (in console) /Users/alex/Projects/mongoose/examples/restful_server example
4. Make the following variables suitable for your network
- `board_ip`
- `subnet_mask`
- `gateway`
- `dns`
- `wlan_ssid`
- `wlan_pwd`
- `wlan_security`
5. Change IP address in `s_target_address` variable to IP address of host running restful_server
6. Uncomment line `#include <Adafruit_CC3000.h>`
8. Compile and flash sketch
9. restful_server will start to show current uptime and free memory size (with 5 seconds interval)
@@ -0,0 +1,141 @@
/*
* Copyright (c) 2015 Cesanta Software Limited
* All rights reserved
*
* Build and run instructions:
* To run with Arduino Ethernet (W5100) shield:
* -----------------------------------------------------------
* 1. Add (Sketch->Add file...) the following files to sketch:
* - /mongoose/mongoose.h
* - /mongoose/mongoose.c
* - /mongoose/platforms/arduino_ethernet_W5100/avrsupport.h
* - /mongoose/platforms/arduino_ethernet_W5100/avrsupport.cpp
* 2. Buils and run in console /Users/alex/Projects/mongoose/examples/restful_server example
* 3. Make board_ip and board_mac variables suitable for your network and board
* 4. Uncomment line #include <Ethernet.h>
* 5. Change IP address in s_target_address variable to IP address of host running restful_server
* 6. Compile & flash sketch
* 7. restful_server server will start to show current uptime and free memory size (with 5 second interval)
*
* To run with Adafruit WiFi (CC3000) shield:
* -----------------------------------------------------------
* 1. Add (Sketch->Add files...) the following files to sketch:
* - /mongoose/mongoose.h
* - /mongoose/mongoose.c
* - /mongoose/platforms/arduino_ethernet_W5100/avrsupport.h
* - /mongoose/platforms/arduino_ethernet_W5100/avrsupport.cpp
* 2. Import Adafruit CC3000 library for mongoose (select Sketch->Import Library...->Add library... and point
* /mongoose/platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_mongoose folder
* 3. Buils and run in console /Users/alex/Projects/mongoose/examples/restful_server example
* 4. Make the following variables suitable for your network
* - board_ip
* - subnet_mask
* - gateway
* - dns
* - wlan_ssid
* - wlan_pwd
* - wlan_security
* 5. Uncomment line #include <Adafruit_CC3000.h>
* 6. Compile & flash sketch
* 7. restful_server server will start to show current uptime and free memory size (with 5 second interval) *
*
*/
//#include <Ethernet.h>
//#include <Adafruit_CC3000.h>
#include <SPI.h>
#include "mongoose.h"
// CHANGE THESE VARIABLES
// NB: Devices with the same address must not end up on the same network.
// Use MAC address provided by device manufacturer (e.g. on a sticker).
// If there isn't one, use a random one from the locally administered range.
// See http://en.wikipedia.org/wiki/MAC_address for details.
static uint8_t board_mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
static uint8_t board_ip[] = {192, 168, 10, 177};
#ifdef WIFI_CC3000
static uint8_t subnet_mask[] = {255, 255, 255, 0};
static uint8_t gateway[] = {192, 168, 10, 254};
static uint8_t dns_ip[] = {192, 168, 10, 254};
static const char *wlan_ssid = "mynetwork";
static const char *wlan_pwd = "mypassword";
static int wlan_security = WLAN_SEC_WPA2;
#endif
static const char *s_target_address = "192.168.10.3:8000";
/////////////////////////////////////////////
static const char *s_request = "/printcontent";
static uint32_t IP2U32(uint8_t* iparr) {
return ((uint32_t)iparr[0] << 24) | ((uint32_t)iparr[1] << 16) | (iparr[2] << 8) | (iparr[3]);
}
static int get_data_to_send(char* buf, int buf_size) {
// Adding data to send
// It could be any sensor data, now just put uptime & free memory size here
return snprintf(buf, buf_size, "Uptime: %lus Free memory: %db",
millis()/1000, get_freememsize());
}
static void rfc_ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
int connect_status;
switch (ev) {
case NS_CONNECT:
connect_status = * (int *) ev_data;
if (connect_status == 0) {
char buf[100];
int len = get_data_to_send(buf, sizeof(buf));
mg_printf(nc, "POST %s HTTP/1.0\r\nHost: %s\r\nContent-Lenght: %d"
"\r\n\r\n%s", s_request, s_target_address, len, buf);
nc->flags |= MG_F_SEND_AND_CLOSE;
} else {
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
break;
default:
break;
}
}
static struct mg_mgr mgr;
static struct mg_connection *nc;
void setup()
{
Serial.begin(9600);
Serial.println("Initialization...");
#if defined(ETHERNET_W5100)
avr_netinit(board_mac, board_ip);
#elif defined(WIFI_CC3000)
if (avr_netinit(wlan_ssid, wlan_pwd, wlan_security, IP2U32(board_ip),
IP2U32(subnet_mask), IP2U32(gateway), IP2U32(dns_ip)) != 0) {
Serial.println("Initialization error, check network settings");
return;
};
#endif
mg_mgr_init(&mgr, NULL);
Serial.println("Initialization done");
}
void loop() {
nc = mg_connect(&mgr, s_target_address, rfc_ev_handler);
if (nc != NULL) {
mg_set_protocol_http_websocket(nc);
}
uint32_t time_to_finish = millis() + 5000;
while (millis() < time_to_finish) {
mg_mgr_poll(&mgr, 1000);
}
}
+2
View File
@@ -0,0 +1,2 @@
# This "makefile" is only intended to prevent errors during main makefile execution
all:
+45
View File
@@ -0,0 +1,45 @@
# Arduino Restful Server
This example demonstrates how to use [Mongoose](https://www.cesanta.com/mongoose) to control Arduino
using HTTP requests.
Example just blinks by LED when Mongoose receives HTTP command, but it can be modified to execute any user-specific code.
At the moment this example supports [Arduino Mega 2560](http://arduino.cc/en/Main/ArduinoBoardMega2560) board (and compatible) with either W5100-based
network shield (like [Arduino Ethernet Shield](http://arduino.cc/en/Main/ArduinoEthernetShield)) or [CC3000](http://www.ti.com/product/cc3000)-based WIFI Shield.
## Build and run instructions:
###To run with Arduino Ethernet (W5100) shield:
1. Add (Sketch->Add file...) the following files to sketch:
- /mongoose/mongoose.h
- /mongoose/mongoose.c
- /mongoose/platforms/arduino_ethernet_W5100/avrsupport.h
- /mongoose/platforms/arduino_ethernet_W5100/avrsupport.cpp
2. Make `board_ip` and `board_mac` variables suitable for your network and board
3. Uncomment line `#include <Ethernet.h>`
4. Compile and flash sketch
5. Run `curl http://<board_ip/blink`
LED attached to PIN 13 will blink and board free memory size and board uptime will be displayed.
###To run with Adafruit WiFi (CC3000) shield:
1. Add (Sketch->Add files...) the following files to sketch:
- /mongoose/mongoose.h
- /mongoose/mongoose.c
- /mongoose/platforms/arduino_ethernet_W5100/avrsupport.h
- /mongoose/platforms/arduino_ethernet_W5100/avrsupport.cpp
2. Import Adafruit CC3000 library for mongoose
(select Sketch->Import Library...->Add library... and point
/mongoose/platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_mongoose folder)
3. Make the following variables suitable for your network
- `board_ip`
- `subnet_mask`
- `gateway`
- `dns`
- `wlan_ssid`
- `wlan_pwd`
- `wlan_security`
5. Uncomment line `#include <Adafruit_CC3000.h>`
4. Compile and flash sketch
5. Run curl `http://<board_ip/blink`
LED attached to PIN 13 will blink and board free memory size and board uptime will be displayed.
@@ -0,0 +1,133 @@
/*
* Copyright (c) 2015 Cesanta Software Limited
* All rights reserved
*
* Build and run instructions:
* To run with Arduino Ethernet (W5100) shield:
* -----------------------------------------------------------
* 1. Add (Sketch->Add file...) the following files to sketch:
* - /mongoose/mongoose.h
* - /mongoose/mongoose.c
* - /mongoose/platforms/arduino_ethernet_W5100/avrsupport.h
* - /mongoose/platforms/arduino_ethernet_W5100/avrsupport.cpp
* 2. Make board_ip and board_mac variables suitable for your network and board
* 3. Uncomment line #include <Ethernet.h>
* 4. Compile & flash sketch
* 5. Run curl http://<board_ip/blink
* LED attached to PIN 13 will blink and board free memory size and uptime will responsed
*
* To run with Adafruit WiFi (CC3000) shield:
* -----------------------------------------------------------
* 1. Add (Sketch->Add files...) the following files to sketch:
* - /mongoose/mongoose.h
* - /mongoose/mongoose.c
* - /mongoose/platforms/arduino_ethernet_W5100/avrsupport.h
* - /mongoose/platforms/arduino_ethernet_W5100/avrsupport.cpp
* 2. Import Adafruit CC3000 library for mongoose (select Sketch->Import Library...->Add library... and point
* /mongoose/platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_mongoose folder
* 3. Make the following variables suitable for your network
* - board_ip
* - subnet_mask
* - gateway
* - dns
* - wlan_ssid
* - wlan_pwd
* - wlan_security
* 5. Uncomment line #include <Adafruit_CC3000.h>
* 4. Compile & flash sketch
* 5. Run curl http://<board_ip/blink
* LED attached to PIN 13 will blink and board free memory size and uptime will responsed
*
*/
//#include <Ethernet.h>
//#include <Adafruit_CC3000.h>
#include <SPI.h>
#include "mongoose.h"
// CHANGE THESE VARIABLES
// NB: Devices with the same address must not end up on the same network.
// Use MAC address provided by device manufacturer (e.g. on a sticker).
// If there isn't one, use a random one from the locally administered range.
// See http://en.wikipedia.org/wiki/MAC_address for details.
static uint8_t board_mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
static uint8_t board_ip[] = {192, 168, 10, 8};
#ifdef WIFI_CC3000
static uint8_t subnet_mask[] = {255, 255, 255, 0};
static uint8_t gateway[] = {192, 168, 10, 254};
static uint8_t dns_ip[] = {192, 168, 10, 254};
static const char *wlan_ssid = "mynetwork";
static const char *wlan_pwd = "mypassword";
static int wlan_security = WLAN_SEC_WPA2;
#endif
///////////////////////////////////////////////
static const char *s_http_port = "60000";
static uint32_t IP2U32(uint8_t* iparr) {
return ((uint32_t)iparr[0] << 24) | ((uint32_t)iparr[1] << 16) | (iparr[2] << 8) | (iparr[3]);
}
static void rfs_ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
struct http_message *hm = (struct http_message *) ev_data;
char buf[100];
int clen;
switch (ev) {
case NS_HTTP_REQUEST:
if (mg_vcmp(&hm->uri, "/blink") == 0) {
blink(1, 500);
}
clen = snprintf(buf, sizeof(buf),
"Free memory size: %d Uptime: %d",
(int)get_freememsize(), (int)time(NULL));
mg_printf_http_chunk(nc, "HTTP/1.1 200 OK\r\n"
"Content-Length: %d\r\n"
"Transfer-Encoding: chunked\r\n\r\n"
"%s",
clen, buf);
mg_send_http_chunk(nc, "", 0);
break;
case NS_SEND:
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
break;
default:
break;
}
}
static struct mg_connection *nc;
static struct mg_mgr mgr;
void setup() {
Serial.begin(9600);
Serial.println("Initialization...");
#if defined(ETHERNET_W5100)
avr_netinit(board_mac, board_ip);
#elif defined(WIFI_CC3000)
if (avr_netinit(wlan_ssid, wlan_pwd, wlan_security, IP2U32(board_ip),
IP2U32(subnet_mask), IP2U32(gateway), IP2U32(dns_ip)) != 0) {
Serial.println("Initialization error, check network settings");
return;
};
#endif
mg_mgr_init(&mgr, NULL);
nc = mg_bind(&mgr, s_http_port, rfs_ev_handler);
mg_set_protocol_http_websocket(nc);
Serial.println("Initialization done");
}
void loop() {
mg_mgr_poll(&mgr, 1000);
}
-32
View File
@@ -1,32 +0,0 @@
#include <stdio.h>
#include <string.h>
#include "mongoose.h"
static int auth_handler(struct mg_connection *conn) {
int result = MG_AUTH_FAIL; // Not authorized
FILE *fp;
// To populate passwords file, do
// mongoose -A my_passwords.txt mydomain.com admin admin
if ((fp = fopen("my_passwords.txt", "r")) != NULL) {
result = mg_authorize_digest(conn, fp);
fclose(fp);
}
return result;
}
int main(void) {
struct mg_server *server = mg_create_server(NULL);
mg_set_option(server, "listening_port", "8080");
mg_set_option(server, "document_root", ".");
mg_set_auth_handler(server, auth_handler);
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
for (;;) {
mg_poll_server(server, 1000);
}
mg_destroy_server(&server);
return 0;
}
+2
View File
@@ -0,0 +1,2 @@
PROG = big_upload
include ../examples.mk
+153
View File
@@ -0,0 +1,153 @@
// Copyright (c) 2015 Cesanta Software Limited
// All rights reserved
//
// This example demonstrates how to handle very large requests without keeping
// them in memory.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mongoose.h"
static const char *s_http_port = "8000";
struct file_writer_data {
FILE *fp;
size_t bytes_left;
};
static void handle_request(struct mg_connection *nc) {
// This handler gets called only when we don't reset proto_handler in
// handle_recv, so we just return a page unconditionally.
mg_printf(nc, "%s",
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n"
"\r\n"
"<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>");
nc->flags |= MG_F_SEND_AND_CLOSE;
}
static void handle_recv(struct mg_connection *nc) {
struct file_writer_data *data = (struct file_writer_data *) nc->user_data;
if (data == NULL) {
// This is a new connection, try to parse HTTP request.
struct http_message hm;
int req_len = mg_parse_http(nc->recv_mbuf.buf, nc->recv_mbuf.len, &hm,
1 /* is_req */);
if (req_len < 0 ||
(req_len == 0 && nc->recv_mbuf.len >= MG_MAX_HTTP_REQUEST_SIZE)) {
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
} else if (req_len == 0) {
// Request is not complete yet, do nothing.
} else if (mg_vcasecmp(&hm.method, "POST") == 0 &&
mg_vcmp(&hm.uri, "/upload") == 0) {
// This is the request that we don't want to buffer in memory.
if (hm.body.len == (size_t) ~0 || hm.body.len == 0) {
mg_printf(nc, "%s",
"HTTP/1.1 411 Content-Length required\r\n"
"Content-Length: 0\r\n\r\n");
nc->flags |= MG_F_SEND_AND_CLOSE;
return;
}
// Reset proto_handler so Mongoose's http_handler() won't get confused
// once we start removing data from the buffer.
nc->proto_handler = NULL;
// Headers will be inaccessible later, so put everything we need into
// user_data.
data = calloc(1, sizeof(struct file_writer_data));
data->bytes_left = hm.body.len;
data->fp = tmpfile();
if (data->fp == NULL) {
mg_printf(nc, "%s",
"HTTP/1.1 500 Failed to open a file\r\n"
"Content-Length: 0\r\n\r\n");
nc->flags |= MG_F_SEND_AND_CLOSE;
return;
}
nc->user_data = (void *) data;
// Remove the headers from the buffer.
mbuf_remove(&nc->recv_mbuf, hm.body.p - nc->recv_mbuf.buf);
// Invoke itself again to write the piece of the body that is already in
// the buffer.
handle_recv(nc);
}
} else { // data != NULL
size_t to_write = data->bytes_left, written = 0;
if (nc->recv_mbuf.len < to_write) to_write = nc->recv_mbuf.len;
written = fwrite(nc->recv_mbuf.buf, 1, to_write, data->fp);
mbuf_remove(&nc->recv_mbuf, written);
data->bytes_left -= written;
if (data->bytes_left <= 0) {
// Request is complete, do something meaningful here.
mg_printf(nc,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n"
"Written %ld of POST data to a temp file\n\n",
(long) ftell(data->fp));
nc->flags |= MG_F_SEND_AND_CLOSE;
// handle_close will free the resources.
}
}
}
// Make sure we free all allocated resources
static void handle_close(struct mg_connection *nc) {
struct file_writer_data *data = (struct file_writer_data *) nc->user_data;
if (data != NULL) {
fclose(data->fp);
free(data);
nc->user_data = NULL;
}
}
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
(void) ev_data;
switch (ev) {
case MG_EV_HTTP_REQUEST:
// Invoked when the full HTTP request is in the buffer (including body).
handle_request(nc);
break;
case MG_EV_RECV:
// Invoked every time new data arrives.
handle_recv(nc);
break;
case MG_EV_CLOSE:
handle_close(nc);
break;
}
}
int main(void) {
struct mg_mgr mgr;
struct mg_connection *nc;
mg_mgr_init(&mgr, NULL);
nc = mg_bind(&mgr, s_http_port, ev_handler);
// Set up HTTP server parameters
mg_set_protocol_http_websocket(nc);
printf("Starting web server on port %s\n", s_http_port);
for (;;) {
mg_mgr_poll(&mgr, 1000);
}
mg_mgr_free(&mgr);
return 0;
}
-37
View File
@@ -1,37 +0,0 @@
// This file is part of mongoose web server project,
// https://github.com/cesanta/mongoose
using System;
using System.Runtime.InteropServices;
public class Program {
static private int EventHandler(MongooseEvent ev) {
if (ev.type != 1) {
return 0; // Mark as unhandled
}
MongooseRequestInfo request_info = (MongooseRequestInfo)
Marshal.PtrToStructure(ev.request_info, typeof(MongooseRequestInfo));
if (request_info.uri != "/test") {
return 0; // Mark as unhandled
}
Mongoose.write(ev.conn, "HTTP/1.1 200 OK\r\n\r\n");
Mongoose.write(ev.conn, "Hello from C#!\n");
return 1; // Mark as handled
}
static void Main() {
Mongoose web_server = new Mongoose(".", "9000",
new MongooseEventHandler(EventHandler));
Console.WriteLine("Mongoose v." + web_server.version_ + " started.");
Console.WriteLine("Press enter to exit program.");
// Serve requests until user presses "enter" on a keyboard
Console.ReadLine();
web_server.stop();
}
}
-93
View File
@@ -1,93 +0,0 @@
// This file is part of mongoose web server project,
// https://github.com/cesanta/mongoose
using System;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)] public struct MongooseHeader {
[MarshalAs(UnmanagedType.LPTStr)] public IntPtr name;
[MarshalAs(UnmanagedType.LPTStr)] public IntPtr value;
};
// mongoose.h :: struct mg_request_info
[StructLayout(LayoutKind.Sequential)] public struct MongooseRequestInfo {
[MarshalAs(UnmanagedType.LPTStr)] public string request_method;
[MarshalAs(UnmanagedType.LPTStr)] public string uri;
[MarshalAs(UnmanagedType.LPTStr)] public string http_version;
[MarshalAs(UnmanagedType.LPTStr)] public string query_string;
[MarshalAs(UnmanagedType.LPTStr)] public string remote_user;
public int remote_ip;
public int remote_port;
public int is_ssl;
[MarshalAs(UnmanagedType.ByValArray,SizeConst=64)]
public MongooseHeader[] http_headers;
};
[StructLayout(LayoutKind.Sequential)] public struct MongooseEvent {
public int type;
public IntPtr user_data;
public IntPtr conn_data;
public IntPtr event_param;
public IntPtr conn;
public IntPtr request_info;
};
public delegate int MongooseEventHandlerN(ref MongooseEvent ev);
public delegate int MongooseEventHandler(MongooseEvent ev);
public class Mongoose {
public const string dll_name_ = "mongoose";
public string version_ = "??";
// These are here to store a ref to the callbacks
// while they are over in unmanaged code, to prevent garbage collection.
private event MongooseEventHandlerN delegates;
private IntPtr ctx_;
[DllImport(dll_name_)] private static extern
IntPtr mg_start([MarshalAs(UnmanagedType.LPArray,
ArraySubType=UnmanagedType.LPTStr)] string[] options,
MongooseEventHandlerN callback,
IntPtr user_data);
[DllImport(dll_name_)] private static extern void mg_stop(IntPtr ctx);
[DllImport(dll_name_)] private static extern IntPtr mg_version();
[DllImport(dll_name_)] public static extern int mg_write(IntPtr conn,
string data, int length);
public Mongoose(string document_root,
string listening_ports,
MongooseEventHandler event_handler) {
version_ = Marshal.PtrToStringAnsi(mg_version());
string[] options = {
"document_root", document_root,
"listening_ports", listening_ports,
null
};
MongooseEventHandlerN cb = delegate(ref MongooseEvent ev) {
return event_handler(ev);
};
// Prevent garbage collection
delegates += cb;
ctx_ = mg_start(options, cb, IntPtr.Zero);
}
public static int write(IntPtr conn, string data) {
return mg_write(conn, data, data.Length);
}
public void stop() {
if (this.ctx_ != IntPtr.Zero) {
mg_stop(this.ctx_);
}
this.ctx_ = IntPtr.Zero;
}
~Mongoose() {
stop();
}
}
+4
View File
@@ -0,0 +1,4 @@
PROG = captive_dns_server
MODULE_CFLAGS=-DMG_ENABLE_DNS_SERVER
include ../rules.mk
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2014 Cesanta Software Limited
* All rights reserved
*/
/*
* Try it out with:
* $ dig -t A www.google.com -4 @localhost -p 5533
*/
#include "../../mongoose.h"
#include <stdio.h>
static int s_exit_flag = 0;
static in_addr_t s_our_ip_addr;
static const char *s_listening_addr = "udp://:5533";
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
struct mg_dns_message *msg;
struct mg_dns_resource_record *rr;
struct mg_dns_reply reply;
int i;
switch (ev) {
case MG_DNS_MESSAGE:
msg = (struct mg_dns_message *) ev_data;
reply = mg_dns_create_reply(&nc->send_mbuf, msg);
for (i = 0; i < msg->num_questions; i++) {
rr = &msg->questions[i];
if (rr->rtype == MG_DNS_A_RECORD) {
mg_dns_reply_record(&reply, rr, NULL, rr->rtype, 3600,
&s_our_ip_addr, 4);
}
}
/*
* We don't set the error flag even if there were no answers
* maching the MG_DNS_A_RECORD query type.
* This indicates that we have (syntetic) answers for MG_DNS_A_RECORD.
* See http://goo.gl/QWvufr for a distinction between NXDOMAIN and NODATA.
*/
mg_dns_send_reply(nc, &reply);
nc->flags |= MG_F_SEND_AND_CLOSE;
break;
}
}
int main(int argc, char *argv[]) {
struct mg_mgr mgr;
struct mg_connection *nc;
int i;
mg_mgr_init(&mgr, NULL);
s_our_ip_addr = inet_addr("127.0.0.1");
/* Parse command line arguments */
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-D") == 0) {
mgr.hexdump_file = argv[++i];
} else if (strcmp(argv[i], "-l") == 0 && i + 1 < argc) {
s_listening_addr = argv[++i];
} else {
s_our_ip_addr = inet_addr(argv[i]);
}
}
fprintf(stderr, "Listening on '%s'\n", s_listening_addr);
if ((nc = mg_bind(&mgr, s_listening_addr, ev_handler)) == NULL) {
fprintf(stderr, "cannot bind to socket\n");
exit(1);
}
mg_set_protocol_dns(nc);
while (s_exit_flag == 0) {
mg_mgr_poll(&mgr, 1000);
}
mg_mgr_free(&mgr);
return 0;
}
-386
View File
@@ -1,386 +0,0 @@
// This file is part of the Mongoose project, http://code.google.com/p/mongoose
// It implements an online chat server. For more details,
// see the documentation on the project web site.
// To test the application,
// 1. type "make" in the directory where this file lives
// 2. point your browser to http://127.0.0.1:8081
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include <stdarg.h>
#include <pthread.h>
#include "mongoose.h"
#define MAX_USER_LEN 20
#define MAX_MESSAGE_LEN 100
#define MAX_MESSAGES 5
#define MAX_SESSIONS 2
#define SESSION_TTL 120
static const char *authorize_url = "/authorize";
static const char *login_url = "/login.html";
static const char *ajax_reply_start =
"HTTP/1.1 200 OK\r\n"
"Cache: no-cache\r\n"
"Content-Type: application/x-javascript\r\n"
"\r\n";
// Describes single message sent to a chat. If user is empty (0 length),
// the message is then originated from the server itself.
struct message {
long id; // Message ID
char user[MAX_USER_LEN]; // User that have sent the message
char text[MAX_MESSAGE_LEN]; // Message text
time_t timestamp; // Message timestamp, UTC
};
// Describes web session.
struct session {
char session_id[33]; // Session ID, must be unique
char random[20]; // Random data used for extra user validation
char user[MAX_USER_LEN]; // Authenticated user
time_t expire; // Expiration timestamp, UTC
};
static struct message messages[MAX_MESSAGES]; // Ringbuffer for messages
static struct session sessions[MAX_SESSIONS]; // Current sessions
static long last_message_id;
// Protects messages, sessions, last_message_id
static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
// Get session object for the connection. Caller must hold the lock.
static struct session *get_session(const struct mg_connection *conn) {
int i;
const char *cookie = mg_get_header(conn, "Cookie");
char session_id[33];
time_t now = time(NULL);
mg_get_cookie(cookie, "session", session_id, sizeof(session_id));
for (i = 0; i < MAX_SESSIONS; i++) {
if (sessions[i].expire != 0 &&
sessions[i].expire > now &&
strcmp(sessions[i].session_id, session_id) == 0) {
break;
}
}
return i == MAX_SESSIONS ? NULL : &sessions[i];
}
static void get_qsvar(const struct mg_request_info *request_info,
const char *name, char *dst, size_t dst_len) {
const char *qs = request_info->query_string;
mg_get_var(qs, strlen(qs == NULL ? "" : qs), name, dst, dst_len);
}
// Get a get of messages with IDs greater than last_id and transform them
// into a JSON string. Return that string to the caller. The string is
// dynamically allocated, caller must free it. If there are no messages,
// NULL is returned.
static char *messages_to_json(long last_id) {
const struct message *message;
int max_msgs, len;
char buf[sizeof(messages)]; // Large enough to hold all messages
// Read-lock the ringbuffer. Loop over all messages, making a JSON string.
pthread_rwlock_rdlock(&rwlock);
len = 0;
max_msgs = sizeof(messages) / sizeof(messages[0]);
// If client is too far behind, return all messages.
if (last_message_id - last_id > max_msgs) {
last_id = last_message_id - max_msgs;
}
for (; last_id < last_message_id; last_id++) {
message = &messages[last_id % max_msgs];
if (message->timestamp == 0) {
break;
}
// buf is allocated on stack and hopefully is large enough to hold all
// messages (it may be too small if the ringbuffer is full and all
// messages are large. in this case asserts will trigger).
len += snprintf(buf + len, sizeof(buf) - len,
"{user: '%s', text: '%s', timestamp: %lu, id: %lu},",
message->user, message->text, message->timestamp, message->id);
assert(len > 0);
assert((size_t) len < sizeof(buf));
}
pthread_rwlock_unlock(&rwlock);
return len == 0 ? NULL : strdup(buf);
}
// If "callback" param is present in query string, this is JSONP call.
// Return 1 in this case, or 0 if "callback" is not specified.
// Wrap an output in Javascript function call.
static int handle_jsonp(struct mg_connection *conn,
const struct mg_request_info *request_info) {
char cb[64];
get_qsvar(request_info, "callback", cb, sizeof(cb));
if (cb[0] != '\0') {
mg_printf(conn, "%s(", cb);
}
return cb[0] == '\0' ? 0 : 1;
}
// A handler for the /ajax/get_messages endpoint.
// Return a list of messages with ID greater than requested.
static void ajax_get_messages(struct mg_connection *conn,
const struct mg_request_info *request_info) {
char last_id[32], *json;
int is_jsonp;
mg_printf(conn, "%s", ajax_reply_start);
is_jsonp = handle_jsonp(conn, request_info);
get_qsvar(request_info, "last_id", last_id, sizeof(last_id));
if ((json = messages_to_json(strtoul(last_id, NULL, 10))) != NULL) {
mg_printf(conn, "[%s]", json);
free(json);
}
if (is_jsonp) {
mg_printf(conn, "%s", ")");
}
}
// Allocate new message. Caller must hold the lock.
static struct message *new_message(void) {
static int size = sizeof(messages) / sizeof(messages[0]);
struct message *message = &messages[last_message_id % size];
message->id = last_message_id++;
message->timestamp = time(0);
return message;
}
static void my_strlcpy(char *dst, const char *src, size_t len) {
strncpy(dst, src, len);
dst[len - 1] = '\0';
}
// A handler for the /ajax/send_message endpoint.
static void ajax_send_message(struct mg_connection *conn,
const struct mg_request_info *request_info) {
struct message *message;
struct session *session;
char text[sizeof(message->text) - 1];
int is_jsonp;
mg_printf(conn, "%s", ajax_reply_start);
is_jsonp = handle_jsonp(conn, request_info);
get_qsvar(request_info, "text", text, sizeof(text));
if (text[0] != '\0') {
// We have a message to store. Write-lock the ringbuffer,
// grab the next message and copy data into it.
pthread_rwlock_wrlock(&rwlock);
message = new_message();
// TODO(lsm): JSON-encode all text strings
session = get_session(conn);
assert(session != NULL);
my_strlcpy(message->text, text, sizeof(text));
my_strlcpy(message->user, session->user, sizeof(message->user));
pthread_rwlock_unlock(&rwlock);
}
mg_printf(conn, "%s", text[0] == '\0' ? "false" : "true");
if (is_jsonp) {
mg_printf(conn, "%s", ")");
}
}
// Redirect user to the login form. In the cookie, store the original URL
// we came from, so that after the authorization we could redirect back.
static void redirect_to_login(struct mg_connection *conn,
const struct mg_request_info *request_info) {
mg_printf(conn, "HTTP/1.1 302 Found\r\n"
"Set-Cookie: original_url=%s\r\n"
"Location: %s\r\n\r\n",
request_info->uri, login_url);
}
// Return 1 if username/password is allowed, 0 otherwise.
static int check_password(const char *user, const char *password) {
// In production environment we should ask an authentication system
// to authenticate the user.
// Here however we do trivial check that user and password are not empty
return (user[0] && password[0]);
}
// Allocate new session object
static struct session *new_session(void) {
int i;
time_t now = time(NULL);
pthread_rwlock_wrlock(&rwlock);
for (i = 0; i < MAX_SESSIONS; i++) {
if (sessions[i].expire == 0 || sessions[i].expire < now) {
sessions[i].expire = time(0) + SESSION_TTL;
break;
}
}
pthread_rwlock_unlock(&rwlock);
return i == MAX_SESSIONS ? NULL : &sessions[i];
}
// Generate session ID. buf must be 33 bytes in size.
// Note that it is easy to steal session cookies by sniffing traffic.
// This is why all communication must be SSL-ed.
static void generate_session_id(char *buf, const char *random,
const char *user) {
mg_md5(buf, random, user, NULL);
}
static void send_server_message(const char *fmt, ...) {
va_list ap;
struct message *message;
pthread_rwlock_wrlock(&rwlock);
message = new_message();
message->user[0] = '\0'; // Empty user indicates server message
va_start(ap, fmt);
vsnprintf(message->text, sizeof(message->text), fmt, ap);
va_end(ap);
pthread_rwlock_unlock(&rwlock);
}
// A handler for the /authorize endpoint.
// Login page form sends user name and password to this endpoint.
static void authorize(struct mg_connection *conn,
const struct mg_request_info *request_info) {
char user[MAX_USER_LEN], password[MAX_USER_LEN];
struct session *session;
// Fetch user name and password.
get_qsvar(request_info, "user", user, sizeof(user));
get_qsvar(request_info, "password", password, sizeof(password));
if (check_password(user, password) && (session = new_session()) != NULL) {
// Authentication success:
// 1. create new session
// 2. set session ID token in the cookie
// 3. remove original_url from the cookie - not needed anymore
// 4. redirect client back to the original URL
//
// The most secure way is to stay HTTPS all the time. However, just to
// show the technique, we redirect to HTTP after the successful
// authentication. The danger of doing this is that session cookie can
// be stolen and an attacker may impersonate the user.
// Secure application must use HTTPS all the time.
my_strlcpy(session->user, user, sizeof(session->user));
snprintf(session->random, sizeof(session->random), "%d", rand());
generate_session_id(session->session_id, session->random, session->user);
send_server_message("<%s> joined", session->user);
mg_printf(conn, "HTTP/1.1 302 Found\r\n"
"Set-Cookie: session=%s; max-age=3600; http-only\r\n" // Session ID
"Set-Cookie: user=%s\r\n" // Set user, needed by Javascript code
"Set-Cookie: original_url=/; max-age=0\r\n" // Delete original_url
"Location: /\r\n\r\n",
session->session_id, session->user);
} else {
// Authentication failure, redirect to login.
redirect_to_login(conn, request_info);
}
}
// Return 1 if request is authorized, 0 otherwise.
static int is_authorized(const struct mg_connection *conn,
const struct mg_request_info *request_info) {
struct session *session;
char valid_id[33];
int authorized = 0;
// Always authorize accesses to login page and to authorize URI
if (!strcmp(request_info->uri, login_url) ||
!strcmp(request_info->uri, authorize_url)) {
return 1;
}
pthread_rwlock_rdlock(&rwlock);
if ((session = get_session(conn)) != NULL) {
generate_session_id(valid_id, session->random, session->user);
if (strcmp(valid_id, session->session_id) == 0) {
session->expire = time(0) + SESSION_TTL;
authorized = 1;
}
}
pthread_rwlock_unlock(&rwlock);
return authorized;
}
static void redirect_to_ssl(struct mg_connection *conn,
const struct mg_request_info *request_info) {
const char *p, *host = mg_get_header(conn, "Host");
if (host != NULL && (p = strchr(host, ':')) != NULL) {
mg_printf(conn, "HTTP/1.1 302 Found\r\n"
"Location: https://%.*s:8082/%s:8082\r\n\r\n",
(int) (p - host), host, request_info->uri);
} else {
mg_printf(conn, "%s", "HTTP/1.1 500 Error\r\n\r\nHost: header is not set");
}
}
static int event_handler(struct mg_event *event) {
struct mg_request_info *request_info = event->request_info;
struct mg_connection *conn = event->conn;
int result = 1;
if (event->type != MG_REQUEST_BEGIN) return 0;
if (!request_info->is_ssl) {
redirect_to_ssl(conn, request_info);
} else if (!is_authorized(conn, request_info)) {
redirect_to_login(conn, request_info);
} else if (strcmp(request_info->uri, authorize_url) == 0) {
authorize(conn, request_info);
} else if (strcmp(request_info->uri, "/ajax/get_messages") == 0) {
ajax_get_messages(conn, request_info);
} else if (strcmp(request_info->uri, "/ajax/send_message") == 0) {
ajax_send_message(conn, request_info);
} else {
// No suitable handler found, mark as not processed. Mongoose will
// try to serve the request.
result = 0;
}
return result;
}
static const char *options[] = {
"document_root", "html",
"listening_ports", "8081,8082s",
"ssl_certificate", "ssl_cert.pem",
"num_threads", "5",
NULL
};
int main(void) {
struct mg_context *ctx;
// Initialize random number generator. It will be used later on for
// the session identifier creation.
srand((unsigned) time(0));
// Setup and start Mongoose
if ((ctx = mg_start(options, event_handler, NULL)) == NULL) {
printf("%s\n", "Cannot start chat server, fatal exit");
exit(EXIT_FAILURE);
}
// Wait until enter is pressed, then exit
printf("Chat server started on ports %s, press enter to quit.\n",
mg_get_option(ctx, "listening_ports"));
getchar();
mg_stop(ctx);
printf("%s\n", "Chat server stopped.");
return EXIT_SUCCESS;
}
// vim:ts=2:sw=2:et
+14
View File
@@ -0,0 +1,14 @@
PROG = coap_client
SOURCES = $(PROG).c ../../mongoose.c
CFLAGS = -W -Wall -I../.. $(CFLAGS_EXTRA) -DMG_ENABLE_COAP
all: $(PROG)
$(PROG): $(SOURCES)
$(CC) $(SOURCES) -o $@ $(CFLAGS)
$(PROG).exe: $(SOURCES)
cl $(SOURCES) /I../.. /MD /Fe$@
clean:
rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG)
+72
View File
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2015 Cesanta Software Limited
* All rights reserved
*
* This program sends CoAP CON-message to server (coap.me by default)
* and waits for answer.
*/
#include "mongoose.h"
static int s_time_to_exit = 0;
static char* s_default_address = "udp://coap.me:5683";
static void coap_handler(struct mg_connection *nc, int ev, void *p) {
switch (ev) {
case MG_EV_CONNECT: {
struct mg_coap_message cm;
uint32_t res;
memset(&cm, 0, sizeof(cm));
cm.msg_id = 1;
cm.msg_type = MG_COAP_MSG_CON;
printf("Sending CON...\n");
res = mg_coap_send_message(nc, &cm);
if (res == 0) {
printf("Sent CON with msg_id = %d\n", cm.msg_id);
} else {
printf("Error: %d\n", res);
s_time_to_exit = 1;
}
break;
}
case MG_EV_COAP_ACK:
case MG_EV_COAP_RST: {
struct mg_coap_message *cm = (struct mg_coap_message *)p;
printf("ACK/RST for message with msg_id = %d received\n",
cm->msg_id);
s_time_to_exit = 1;
break;
}
}
}
int main(int argc, char* argv[]) {
struct mg_mgr mgr;
struct mg_connection *nc;
char *address = s_default_address;
if (argc > 1) {
address = argv[1];
}
printf("Using %s as CoAP server\n", address);
mg_mgr_init(&mgr, 0);
nc = mg_connect(&mgr, address, coap_handler);
if (nc == NULL) {
printf("Unable to connect to %s\n", address);
return -1;
}
mg_set_protocol_coap(nc);
while (!s_time_to_exit) {
mg_mgr_poll(&mgr, 1);
}
mg_mgr_free(&mgr);
return 0;
}
+14
View File
@@ -0,0 +1,14 @@
PROG = coap_server
SOURCES = $(PROG).c ../../mongoose.c
CFLAGS = -W -Wall -I../.. $(CFLAGS_EXTRA) -DMG_ENABLE_COAP
all: $(PROG)
$(PROG): $(SOURCES)
$(CC) $(SOURCES) -o $@ $(CFLAGS)
$(PROG).exe: $(SOURCES)
cl $(SOURCES) /I../.. /MD /Fe$@
clean:
rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG)
+73
View File
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2015 Cesanta Software Limited
* All rights reserved
*
* This program listens on 5683 for CoAP messages,
* sends ACK is nessesary and dump everything received.
* It is possible to use ../coap_client to send message.
*/
#include "mongoose.h"
static char* s_default_address = "udp://:5683";
static int s_sig_received = 0;
static void signal_handler(int sig_num) {
signal(sig_num, signal_handler);
s_sig_received = sig_num;
}
static void coap_handler(struct mg_connection *nc, int ev, void *p) {
switch (ev) {
case MG_EV_COAP_CON: {
uint32_t res;
struct mg_coap_message *cm = (struct mg_coap_message *)p;
printf("CON with msg_id = %d received\n", cm->msg_id);
res = mg_coap_send_ack(nc, cm->msg_id);
if (res == 0) {
printf("Successfully sent ACK for message with msg_id = %d\n",
cm->msg_id);
} else {
printf("Error: %d\n", res);
}
break;
}
case MG_EV_COAP_NOC:
case MG_EV_COAP_ACK:
case MG_EV_COAP_RST: {
struct mg_coap_message *cm = (struct mg_coap_message *)p;
printf("ACK/RST/NOC with msg_id = %d received\n",
cm->msg_id);
break;
}
}
}
int main() {
struct mg_mgr mgr;
struct mg_connection *nc;
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
mg_mgr_init(&mgr, 0);
nc = mg_bind(&mgr, s_default_address, coap_handler);
if (nc == NULL) {
printf("Unable to start listener at %s\n", s_default_address);
return -1;
}
printf("Listening for CoAP messages at %s\n", s_default_address);
mg_set_protocol_coap(nc);
while (!s_sig_received) {
mg_mgr_poll(&mgr, 1);
}
printf("Exiting on signal %d\n", s_sig_received);
mg_mgr_free(&mgr);
return 0;
}
+2
View File
@@ -0,0 +1,2 @@
PROG = server
include ../examples.mk
+43
View File
@@ -0,0 +1,43 @@
// Copyright (c) 2015 Cesanta Software Limited
// All rights reserved
#include "mongoose.h"
static const char *s_http_port = "8000";
static struct mg_serve_http_opts s_http_server_opts;
static void ev_handler(struct mg_connection *nc, int ev, void *p) {
if (ev == MG_EV_HTTP_REQUEST) {
mg_serve_http(nc, p, s_http_server_opts); // Serves static content
}
}
int main(void) {
struct mg_mgr mgr;
struct mg_connection *nc;
cs_stat_t st;
mg_mgr_init(&mgr, NULL);
nc = mg_bind(&mgr, s_http_port, ev_handler);
if (nc == NULL) {
fprintf(stderr, "Cannot bind to %s\n", s_http_port);
exit(1);
}
// Set up HTTP server parameters
mg_set_protocol_http_websocket(nc);
s_http_server_opts.document_root = "web_root"; // Set up web root directory
if (mg_stat(s_http_server_opts.document_root, &st) != 0) {
fprintf(stderr, "%s", "Cannot find web_root directory, exiting\n");
exit(1);
}
printf("Starting web server on port %s\n", s_http_port);
for (;;) {
mg_mgr_poll(&mgr, 1000);
}
mg_mgr_free(&mgr);
return 0;
}
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Connected device demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="content">
<img src="logo.png" style="float:right; height: 50px; border-radius: 3px;">
<h1>Connected device demo - static content only</h1>
<p>
This page shows initial steps on how to make a device connected.
Mongoose serves static content from the <code>web_root</code>
directory. Images, CSS, HTML, JavaScript files could be dropped into the
<code>web_root</code> directory - and they'll be served happily
by Mongoose.
</p>
<p>
Below is a placeholder for the
settings section, and a real-time dashboard, which will be
implemented in the following examples.
Both settings section, and a dashboard section, could be organised
differently on this UI - for example, in different tabs. But, to
make the demonstration clearer, we show everything on one page.
</p>
<h1>Settings section</h1>
<p>Nothing here yet</p>
<h1>Dashboard section</h1>
<p>Nothing here yet</p>
</div>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

@@ -0,0 +1,31 @@
* {
outline: none;
}
body {
background-color: #36c;
margin: 0;
padding: 0;
font: 16px/1.4 Helvetica, Arial, sans-serif;
}
div.content {
width: 800px;
margin: 1em auto;
padding: 2em;
background-color: #fff;
border-radius: 1em;
}
code {
background: #f0f0f0;
padding: 0 0.3em;
color: #396;
border-radius: 0.3em;
}
a:link, a:visited {
color: #69c;
text-decoration: none;
}
+2
View File
@@ -0,0 +1,2 @@
PROG = server
include ../examples.mk
+81
View File
@@ -0,0 +1,81 @@
// Copyright (c) 2015 Cesanta Software Limited
// All rights reserved
#include "mongoose.h"
struct device_settings {
char setting1[100];
char setting2[100];
};
static const char *s_http_port = "8000";
static struct mg_serve_http_opts s_http_server_opts;
static struct device_settings s_settings = { "value1", "value2" };
static void handle_save(struct mg_connection *nc, struct http_message *hm) {
// Get form variables and store settings values
mg_get_http_var(&hm->body, "setting1", s_settings.setting1,
sizeof(s_settings.setting1));
mg_get_http_var(&hm->body, "setting2", s_settings.setting2,
sizeof(s_settings.setting2));
// Send response
mg_printf(nc, "%s", "HTTP/1.1 302 OK\r\nLocation: /\r\n\r\n");
}
static void handle_ssi_call(struct mg_connection *nc, const char *param) {
if (strcmp(param, "setting1") == 0) {
mg_printf_html_escape(nc, "%s", s_settings.setting1);
} else if (strcmp(param, "setting2") == 0) {
mg_printf_html_escape(nc, "%s", s_settings.setting2);
}
}
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
struct http_message *hm = (struct http_message *) ev_data;
switch (ev) {
case MG_EV_HTTP_REQUEST:
if (mg_vcmp(&hm->uri, "/save") == 0) {
handle_save(nc, hm);
} else {
mg_serve_http(nc, hm, s_http_server_opts); // Serve static content
}
break;
case MG_EV_SSI_CALL:
handle_ssi_call(nc, ev_data);
break;
default:
break;
}
}
int main(void) {
struct mg_mgr mgr;
struct mg_connection *nc;
cs_stat_t st;
mg_mgr_init(&mgr, NULL);
nc = mg_bind(&mgr, s_http_port, ev_handler);
if (nc == NULL) {
fprintf(stderr, "Cannot bind to %s\n", s_http_port);
exit(1);
}
// Set up HTTP server parameters
mg_set_protocol_http_websocket(nc);
s_http_server_opts.document_root = "web_root"; // Set up web root directory
if (mg_stat(s_http_server_opts.document_root, &st) != 0) {
fprintf(stderr, "%s", "Cannot find web_root directory, exiting\n");
exit(1);
}
printf("Starting web server on port %s\n", s_http_port);
for (;;) {
mg_mgr_poll(&mgr, 1000);
}
mg_mgr_free(&mgr);
return 0;
}
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Connected device demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="content">
<img src="logo.png" style="float:right; height: 50px; border-radius: 3px;">
<h1>Connected device demo - settings section</h1>
<p>
This page is one of the series of examples that show how to make
devices connected with Mongoose. Here, we create a settings section
that expose some internal device variables, and allow user to change
them. They could be some stored in a database, in a file, or in
firmware RAM. In this example, we store them in RAM, and use two
variables, one integer and one string. We use SSI
<code>&lt;!--#call parameter_name --&gt;</code> directive to fetch
variable values from Mongoose.
</p>
<h1>Settings section</h1>
<form method="POST" action="/save">
<fieldset>
<legend>Device settings</legend>
<label>Setting 1:</label> <input type="text"
name="setting1" value="<!--#call setting1 -->" >
<label>Setting 2:</label> <input type="text"
name="setting2" value="<!--#call setting2 -->" >
<div>
<button type="submit">Save Settings</button>
</div>
</fieldset>
</form>
<h1>Dashboard section</h1>
<p>Nothing here yet</p>
</div>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

@@ -0,0 +1,67 @@
* {
outline: none;
}
body {
background: #36c;
color: #555;
margin: 0;
padding: 0;
font: 16px/1.4 Helvetica, Arial, sans-serif;
}
div.content {
width: 800px;
margin: 1em auto;
padding: 2em;
background-color: #fff;
border-radius: 1em;
}
fieldset {
border: 1px solid #ccc;
padding: 1em;
}
fieldset legend {
font-style: italic;
color: silver;
}
fieldset label {
text-align: right;
padding: 0 1em;
}
input[type=text] {
font-size: 100%;
padding: 0.2em;
border: 1px solid #ccc;
}
button {
color: #666;
background: #eee;
border: 1px solid #ccc;
padding: 0.2em 2em;
font-size: 100%;
cursor: pointer;
margin-top: 1em;
}
button:hover {
background: #ccc;
}
code {
background: #f0f0f0;
padding: 0 0.3em;
color: #396;
border-radius: 0.3em;
}
a:link, a:visited {
color: #69c;
text-decoration: none;
}
+2
View File
@@ -0,0 +1,2 @@
PROG = server
include ../examples.mk
+98
View File
@@ -0,0 +1,98 @@
// Copyright (c) 2015 Cesanta Software Limited
// All rights reserved
#include "mongoose.h"
struct device_settings {
char setting1[100];
char setting2[100];
};
static const char *s_http_port = "8000";
static struct mg_serve_http_opts s_http_server_opts;
static struct device_settings s_settings = { "value1", "value2" };
static void handle_save(struct mg_connection *nc, struct http_message *hm) {
// Get form variables and store settings values
mg_get_http_var(&hm->body, "setting1", s_settings.setting1,
sizeof(s_settings.setting1));
mg_get_http_var(&hm->body, "setting2", s_settings.setting2,
sizeof(s_settings.setting2));
// Send response
mg_printf(nc, "%s", "HTTP/1.1 302 OK\r\nLocation: /\r\n\r\n");
}
static void handle_get_cpu_usage(struct mg_connection *nc) {
// Generate random value, as an example of changing CPU usage
// Getting real CPU usage depends on the OS.
int cpu_usage = (double) rand() / RAND_MAX * 100.0;
// Use chunked encoding in order to avoid calculating Content-Length
mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
// Output JSON object which holds CPU usage data
mg_printf_http_chunk(nc, "{ \"result\": %d }", cpu_usage);
// Send empty chunk, the end of response
mg_send_http_chunk(nc, "", 0);
}
static void handle_ssi_call(struct mg_connection *nc, const char *param) {
if (strcmp(param, "setting1") == 0) {
mg_printf_html_escape(nc, "%s", s_settings.setting1);
} else if (strcmp(param, "setting2") == 0) {
mg_printf_html_escape(nc, "%s", s_settings.setting2);
}
}
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
struct http_message *hm = (struct http_message *) ev_data;
switch (ev) {
case MG_EV_HTTP_REQUEST:
if (mg_vcmp(&hm->uri, "/save") == 0) {
handle_save(nc, hm);
} else if (mg_vcmp(&hm->uri, "/get_cpu_usage") == 0) {
handle_get_cpu_usage(nc);
} else {
mg_serve_http(nc, hm, s_http_server_opts); // Serve static content
}
break;
case MG_EV_SSI_CALL:
handle_ssi_call(nc, ev_data);
break;
default:
break;
}
}
int main(void) {
struct mg_mgr mgr;
struct mg_connection *nc;
cs_stat_t st;
mg_mgr_init(&mgr, NULL);
nc = mg_bind(&mgr, s_http_port, ev_handler);
if (nc == NULL) {
fprintf(stderr, "Cannot bind to %s\n", s_http_port);
exit(1);
}
// Set up HTTP server parameters
mg_set_protocol_http_websocket(nc);
s_http_server_opts.document_root = "web_root"; // Set up web root directory
if (mg_stat(s_http_server_opts.document_root, &st) != 0) {
fprintf(stderr, "%s", "Cannot find web_root directory, exiting\n");
exit(1);
}
printf("Starting web server on port %s\n", s_http_port);
for (;;) {
mg_mgr_poll(&mgr, 1000);
}
mg_mgr_free(&mgr);
return 0;
}
@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Connected device demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css" href="style.css">
<script type="text/javascript" src="jquery-1.11.3.min.js"></script>
<script type="text/javascript" src="main.js"></script>
</head>
<body>
<div class="content">
<img src="logo.png" style="float:right; height: 50px; border-radius: 3px;">
<h1>Connected device demo - RESTful call</h1>
<p>
This page is one of the series of examples that show how to make
devices connected with Mongoose. Here we add a RESTful call
to the Mongoose to show CPU usage stats on a dashboard.
RESTful call is done using Jquery's <code>ajax</code> call.
</p>
<h1>Settings section</h1>
<form method="POST" action="/save">
<fieldset>
<legend>Device settings</legend>
<label>Setting 1:</label> <input type="text"
name="setting1" value="<!--#call setting1 -->" >
<label>Setting 2:</label> <input type="text"
name="setting2" value="<!--#call setting2 -->" >
<div>
<button type="submit">Save Settings</button>
</div>
</fieldset>
</form>
<h1>Dashboard section</h1>
<label>CPU usage:</label> <span id="cpu_usage">&nbsp;</span>
</div>
</body>
</html>
@@ -0,0 +1,5 @@
/*! jQuery v1.11.3 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */
!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.3",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b="length"in a&&a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^Line truncated
return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?m.queue(this[0],a):void 0===b?this:this.each(function(){var c=m.queue(this,a,b);m._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&m.dequeue(this,a)})},dequeue:function(a){return this.each(function(){m.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=m.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=m._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var S=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=["Top","Right","Bottom","Left"],U=function(a,b){return a=b||a,"none"===m.css(a,"display")||!m.contains(a.ownerDocument,a)},V=m.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===m.type(c)){e=!0;for(h in c)m.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,m.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(m(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav></:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="<input type='radio' checked='checked' name='t'/>",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function aa(){return!0}function ba(){return!1}function ca(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var Line truncated
return new Za.prototype.init(a,b,c,d,e)}m.Tween=Za,Za.prototype={constructor:Za,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(m.cssNumber[c]?"":"px")},cur:function(){var a=Za.propHooks[this.prop];return a&&a.get?a.get(this):Za.propHooks._default.get(this)},run:function(a){var b,c=Za.propHooks[this.prop];return this.options.duration?this.pos=b=m.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Za.propHooks._default.set(this),this}},Za.prototype.init.prototype=Za.prototype,Za.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=m.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){m.fx.step[a.prop]?m.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[m.cssProps[a.prop]]||m.cssHooks[a.prop])?m.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Za.propHooks.scrollTop=Za.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},m.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},m.fx=Za.prototype.init,m.fx.step={};var $a,_a,ab=/^(?:toggle|show|hide)$/,bb=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),cb=/queueHooks$/,db=[ib],eb={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=bb.exec(b),f=e&&e[3]||(m.cssNumber[a]?"":"px"),g=(m.cssNumber[a]||"px"!==f&&+d)&&bb.exec(m.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,m.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function fb(){return setTimeout(function(){$a=void 0}),$a=m.now()}function gb(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=T[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function hb(a,b,c){for(var d,e=(eb[b]||[]).concat(eb["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ib(a,b,c){var d,e,f,g,h,i,j,l,n=this,o={},p=a.style,q=a.nodeType&&U(a),r=m._data(a,"fxshow");c.queue||(h=m._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,n.always(function(){n.always(function(){h.unqueued--,m.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=m.css(a,"display"),l="none"===j?m._data(a,"olddisplay")||Fa(a.nodeName):j,"inline"===l&&"none"===m.css(a,"float")&&(k.inlineBlockNeedsLayout&&"inline"!==Fa(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",k.shrinkWrapBlocks()||n.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],ab.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||m.style(a,d)}else j=void 0;if(m.isEmptyObject(o))"inline"===("none"===j?Fa(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=m._data(a,"fxshow",{}),f&&(r.hidden=!q),q?m(a).show():n.done(function(){m(a).hide()}),n.done(function(){var b;m._removeData(a,"fxshow");for(b in o)m.style(a,b,o[b])});for(d in o)g=hb(q?r[d]:0,d,n),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function jb(a,b){var c,d,e,f,g;for(c in a)if(d=m.camelCase(c),e=b[d],f=a[c],m.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=m.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kb(a,b,c){var d,e,f=0,g=db.length,h=m.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=$a||fb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:m.extend({},b),opts:m.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:$a||fb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=m.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jb(k,j.opts.specialEasing);g>f;f++)if(d=db[f].call(j,a,k,j.opts))return d;return m.map(k,hb,j),m.isFunction(j.opts.start)&&j.opts.start.call(a,j),m.fx.timer(m.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}m.Animation=m.extend(kb,{tweener:function(a,b){m.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],eb[cLine truncated
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

@@ -0,0 +1,12 @@
$(document).ready(function() {
// Start 1-second timer to call RESTful endpoint
setInterval(function() {
$.ajax({
url: '/get_cpu_usage',
dataType: 'json',
success: function(json) {
$('#cpu_usage').text(json.result + '% ');
}
});
}, 1000);
});
@@ -0,0 +1,66 @@
* {
outline: none;
}
body {
background: #36c;
color: #555;
margin: 0;
padding: 0;
font: 16px/1.4 Helvetica, Arial, sans-serif;
}
div.content {
width: 800px;
margin: 1em auto;
padding: 2em;
background-color: #fff;
border-radius: 1em;
}
fieldset {
border: 1px solid #ccc;
padding: 1em;
}
fieldset legend {
font-style: italic;
color: silver;
}
fieldset label {
text-align: right;
padding: 0 1em;
}
input[type=text] {
font-size: 100%;
padding: 0.2em;
border: 1px solid #ccc;
}
button {
color: #666;
background: #eee;
border: 1px solid #ccc;
padding: 0.2em 2em;
font-size: 100%;
cursor: pointer;
margin-top: 1em;
}
button:hover {
background: #ccc;
}
code {
background: #f0f0f0;
padding: 0 0.3em;
color: #396;
border-radius: 0.3em;
}
a:link, a:visited {
color: #69c;
text-decoration: none;
}
+2
View File
@@ -0,0 +1,2 @@
PROG = server
include ../examples.mk
+115
View File
@@ -0,0 +1,115 @@
// Copyright (c) 2015 Cesanta Software Limited
// All rights reserved
#include "mongoose.h"
struct device_settings {
char setting1[100];
char setting2[100];
};
static const char *s_http_port = "8000";
static struct mg_serve_http_opts s_http_server_opts;
static struct device_settings s_settings = { "value1", "value2" };
static void handle_save(struct mg_connection *nc, struct http_message *hm) {
// Get form variables and store settings values
mg_get_http_var(&hm->body, "setting1", s_settings.setting1,
sizeof(s_settings.setting1));
mg_get_http_var(&hm->body, "setting2", s_settings.setting2,
sizeof(s_settings.setting2));
// Send response
mg_printf(nc, "%s", "HTTP/1.1 302 OK\r\nLocation: /\r\n\r\n");
}
static void handle_get_cpu_usage(struct mg_connection *nc) {
// Generate random value, as an example of changing CPU usage
// Getting real CPU usage depends on the OS.
int cpu_usage = (double) rand() / RAND_MAX * 100.0;
// Use chunked encoding in order to avoid calculating Content-Length
mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
// Output JSON object which holds CPU usage data
mg_printf_http_chunk(nc, "{ \"result\": %d }", cpu_usage);
// Send empty chunk, the end of response
mg_send_http_chunk(nc, "", 0);
}
static void handle_ssi_call(struct mg_connection *nc, const char *param) {
if (strcmp(param, "setting1") == 0) {
mg_printf_html_escape(nc, "%s", s_settings.setting1);
} else if (strcmp(param, "setting2") == 0) {
mg_printf_html_escape(nc, "%s", s_settings.setting2);
}
}
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
struct http_message *hm = (struct http_message *) ev_data;
switch (ev) {
case MG_EV_HTTP_REQUEST:
if (mg_vcmp(&hm->uri, "/save") == 0) {
handle_save(nc, hm);
} else if (mg_vcmp(&hm->uri, "/get_cpu_usage") == 0) {
handle_get_cpu_usage(nc);
} else {
mg_serve_http(nc, hm, s_http_server_opts); // Serve static content
}
break;
case MG_EV_SSI_CALL:
handle_ssi_call(nc, ev_data);
break;
default:
break;
}
}
static void push_data_to_all_websocket_connections(struct mg_mgr *m) {
struct mg_connection *c;
int memory_usage = (double) rand() / RAND_MAX * 100.0;
for (c = mg_next(m, NULL); c != NULL; c = mg_next(m, c)) {
if (c->flags & MG_F_IS_WEBSOCKET) {
mg_printf_websocket_frame(c, WEBSOCKET_OP_TEXT, "%d", memory_usage);
}
}
}
int main(void) {
struct mg_mgr mgr;
struct mg_connection *nc;
cs_stat_t st;
mg_mgr_init(&mgr, NULL);
nc = mg_bind(&mgr, s_http_port, ev_handler);
if (nc == NULL) {
fprintf(stderr, "Cannot bind to %s\n", s_http_port);
exit(1);
}
// Set up HTTP server parameters
mg_set_protocol_http_websocket(nc);
s_http_server_opts.document_root = "web_root"; // Set up web root directory
if (mg_stat(s_http_server_opts.document_root, &st) != 0) {
fprintf(stderr, "%s", "Cannot find web_root directory, exiting\n");
exit(1);
}
printf("Starting web server on port %s\n", s_http_port);
for (;;) {
static time_t last_time;
time_t now = time(NULL);
mg_mgr_poll(&mgr, 1000);
if (now - last_time > 0) {
push_data_to_all_websocket_connections(&mgr);
last_time = now;
}
}
mg_mgr_free(&mgr);
return 0;
}
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Connected device demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css" href="style.css">
<script type="text/javascript" src="jquery-1.11.3.min.js"></script>
<script src="jquery.flot.min.js"></script>
<script src="jquery.flot.time.js"></script>
<script type="text/javascript" src="main.js"></script>
</head>
<body>
<div class="content">
<img src="logo.png" style="float:right; height: 50px; border-radius: 3px;">
<h1>Connected device demo - Websocket push</h1>
<p>
This page is one of the series of examples that show how to make
devices connected with Mongoose. Here we add a real-time Websocket
server push, and update dashboard graph as data arrives.
</p>
<h1>Settings section</h1>
<form method="POST" action="/save">
<fieldset>
<legend>Device settings</legend>
<label>Setting 1:</label> <input type="text"
name="setting1" value="<!--#call setting1 -->" >
<label>Setting 2:</label> <input type="text"
name="setting2" value="<!--#call setting2 -->" >
<div>
<button type="submit">Save Settings</button>
</div>
</fieldset>
</form>
<h1>Dashboard section</h1>
<label>CPU usage:</label> <span id="cpu_usage">&nbsp;</span>
<div id="graphs"></div>
</div>
</body>
</html>
@@ -0,0 +1,5 @@
/*! jQuery v1.11.3 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */
!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.3",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b="length"in a&&a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^Line truncated
return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?m.queue(this[0],a):void 0===b?this:this.each(function(){var c=m.queue(this,a,b);m._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&m.dequeue(this,a)})},dequeue:function(a){return this.each(function(){m.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=m.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=m._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var S=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=["Top","Right","Bottom","Left"],U=function(a,b){return a=b||a,"none"===m.css(a,"display")||!m.contains(a.ownerDocument,a)},V=m.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===m.type(c)){e=!0;for(h in c)m.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,m.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(m(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav></:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="<input type='radio' checked='checked' name='t'/>",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function aa(){return!0}function ba(){return!1}function ca(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var Line truncated
return new Za.prototype.init(a,b,c,d,e)}m.Tween=Za,Za.prototype={constructor:Za,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(m.cssNumber[c]?"":"px")},cur:function(){var a=Za.propHooks[this.prop];return a&&a.get?a.get(this):Za.propHooks._default.get(this)},run:function(a){var b,c=Za.propHooks[this.prop];return this.options.duration?this.pos=b=m.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Za.propHooks._default.set(this),this}},Za.prototype.init.prototype=Za.prototype,Za.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=m.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){m.fx.step[a.prop]?m.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[m.cssProps[a.prop]]||m.cssHooks[a.prop])?m.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Za.propHooks.scrollTop=Za.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},m.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},m.fx=Za.prototype.init,m.fx.step={};var $a,_a,ab=/^(?:toggle|show|hide)$/,bb=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),cb=/queueHooks$/,db=[ib],eb={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=bb.exec(b),f=e&&e[3]||(m.cssNumber[a]?"":"px"),g=(m.cssNumber[a]||"px"!==f&&+d)&&bb.exec(m.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,m.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function fb(){return setTimeout(function(){$a=void 0}),$a=m.now()}function gb(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=T[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function hb(a,b,c){for(var d,e=(eb[b]||[]).concat(eb["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ib(a,b,c){var d,e,f,g,h,i,j,l,n=this,o={},p=a.style,q=a.nodeType&&U(a),r=m._data(a,"fxshow");c.queue||(h=m._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,n.always(function(){n.always(function(){h.unqueued--,m.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=m.css(a,"display"),l="none"===j?m._data(a,"olddisplay")||Fa(a.nodeName):j,"inline"===l&&"none"===m.css(a,"float")&&(k.inlineBlockNeedsLayout&&"inline"!==Fa(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",k.shrinkWrapBlocks()||n.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],ab.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||m.style(a,d)}else j=void 0;if(m.isEmptyObject(o))"inline"===("none"===j?Fa(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=m._data(a,"fxshow",{}),f&&(r.hidden=!q),q?m(a).show():n.done(function(){m(a).hide()}),n.done(function(){var b;m._removeData(a,"fxshow");for(b in o)m.style(a,b,o[b])});for(d in o)g=hb(q?r[d]:0,d,n),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function jb(a,b){var c,d,e,f,g;for(c in a)if(d=m.camelCase(c),e=b[d],f=a[c],m.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=m.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kb(a,b,c){var d,e,f=0,g=db.length,h=m.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=$a||fb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:m.extend({},b),opts:m.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:$a||fb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=m.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jb(k,j.opts.specialEasing);g>f;f++)if(d=db[f].call(j,a,k,j.opts))return d;return m.map(k,hb,j),m.isFunction(j.opts.start)&&j.opts.start.call(a,j),m.fx.timer(m.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}m.Animation=m.extend(kb,{tweener:function(a,b){m.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],eb[cLine truncated
@@ -0,0 +1,8 @@
/* Javascript plotting library for jQuery, version 0.8.3.
Copyright (c) 2007-2014 IOLA and Ole Laursen.
Licensed under the MIT license.
*/
(function($){$.color={};$.color.make=function(r,g,b,a){var o={};o.r=r||0;o.g=g||0;o.b=b||0;o.a=a!=null?a:1;o.add=function(c,d){for(var i=0;i<c.length;++i)o[c.charAt(i)]+=d;return o.normalize()};o.scale=function(c,f){for(var i=0;i<c.length;++i)o[c.charAt(i)]*=f;return o.normalize()};o.toString=function(){if(o.a>=1){return"rgb("+[o.r,o.g,o.b].join(",")+")"}else{return"rgba("+[o.r,o.g,o.b,o.a].join(",")+")"}};o.normalize=function(){function clamp(min,value,max){return value<min?min:value>max?max:value}o.r=clamp(0,parseInt(o.r),255);o.g=clamp(0,parseInt(o.g),255);o.b=clamp(0,parseInt(o.b),255);o.a=clamp(0,o.a,1);return o};o.clone=function(){return $.color.make(o.r,o.b,o.g,o.a)};return o.normalize()};$.color.extract=function(elem,css){var c;do{c=elem.css(css).toLowerCase();if(c!=""&&c!="transparent")break;elem=elem.parent()}while(elem.length&&!$.nodeName(elem.get(0),"body"));if(c=="rgba(0, 0, 0, 0)")c="transparent";return $.color.parse(c)};$.color.parse=function(str){var res,m=$.color.make;if(res=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10));if(res=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10),parseFloat(res[4]));if(res=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55);if(res=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55,parseFloat(res[4]));if(res=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))return m(parseInt(res[1],16),parseInt(res[2],16),parseInt(res[3],16));if(res=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))return m(parseInt(res[1]+res[1],16),parseInt(res[2]+res[2],16),parseInt(res[3]+res[3],16));var name=$.trim(str).toLowerCase();if(name=="transparent")return m(255,255,255,0);else{res=lookupColors[name]||[0,0,0];return m(res[0],res[1],res[2])}};var lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);(function($){var hasOwnProperty=Object.prototype.hasOwnProperty;if(!$.fn.detach){$.fn.detach=function(){return this.each(function(){if(this.parentNode){this.parentNode.removeChild(this)}})}}function Canvas(cls,container){var element=container.children("."+cls)[0];if(element==null){element=document.createElement("canvas");element.className=cls;$(element).css({direction:"ltr",position:"absolute",left:0,top:0}).appendTo(container);if(!element.getContext){if(window.G_vmlCanvasManager){element=window.G_vmlCanvasManager.initElement(element)}else{throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode.")}}}this.element=element;var context=this.context=element.getContext("2d");var devicePixelRatio=window.devicePixelRatio||1,backingStoreRatio=context.webkitBackingStorePixelRatio||context.mozBackingStorePixelRatio||context.msBackingStorePixelRatio||context.oBackingStorePixelRatio||context.backingStorePixelRatio||1;this.pixelRatio=devicePixelRatio/backingStoreRatio;this.resize(container.width(),container.height());this.textContainer=null;this.text={};this._textCache={}}Canvas.prototype.resize=function(width,height){if(width<=0||height<=0){throw new Error("Invalid dimensions for plot, width = "+width+", height = "+height)}var element=this.element,context=this.context,pixelRatio=this.pixelRatio;if(this.width!=width){element.width=width*pixelRatio;element.style.width=width+"px";this.width=width}if(this.height!=height){element.height=height*pixelRatio;element.style.height=height+"px";this.height=height}context.restore();context.save();context.scale(pixelRatio,pixelRatio)};Canvas.prototype.clear=function(){this.context.clearRect(0,0,this.width,this.height)};Canvas.prototype.render=function(){vaLine truncated
if(yrange.from==null)yrange.from=yrange.axis.min;if(yrange.to==null)yrange.to=yrange.axis.max;if(xrange.to<xrange.axis.min||xrange.from>xrange.axis.max||yrange.to<yrange.axis.min||yrange.from>yrange.axis.max)continue;xrange.from=Math.max(xrange.from,xrange.axis.min);xrange.to=Math.min(xrange.to,xrange.axis.max);yrange.from=Math.max(yrange.from,yrange.axis.min);yrange.to=Math.min(yrange.to,yrange.axis.max);var xequal=xrange.from===xrange.to,yequal=yrange.from===yrange.to;if(xequal&&yequal){continue}xrange.from=Math.floor(xrange.axis.p2c(xrange.from));xrange.to=Math.floor(xrange.axis.p2c(xrange.to));yrange.from=Math.floor(yrange.axis.p2c(yrange.from));yrange.to=Math.floor(yrange.axis.p2c(yrange.to));if(xequal||yequal){var lineWidth=m.lineWidth||options.grid.markingsLineWidth,subPixel=lineWidth%2?.5:0;ctx.beginPath();ctx.strokeStyle=m.color||options.grid.markingsColor;ctx.lineWidth=lineWidth;if(xequal){ctx.moveTo(xrange.to+subPixel,yrange.from);ctx.lineTo(xrange.to+subPixel,yrange.to)}else{ctx.moveTo(xrange.from,yrange.to+subPixel);ctx.lineTo(xrange.to,yrange.to+subPixel)}ctx.stroke()}else{ctx.fillStyle=m.color||options.grid.markingsColor;ctx.fillRect(xrange.from,yrange.to,xrange.to-xrange.from,yrange.from-yrange.to)}}}axes=allAxes();bw=options.grid.borderWidth;for(var j=0;j<axes.length;++j){var axis=axes[j],box=axis.box,t=axis.tickLength,x,y,xoff,yoff;if(!axis.show||axis.ticks.length==0)continue;ctx.lineWidth=1;if(axis.direction=="x"){x=0;if(t=="full")y=axis.position=="top"?0:plotHeight;else y=box.top-plotOffset.top+(axis.position=="top"?box.height:0)}else{y=0;if(t=="full")x=axis.position=="left"?0:plotWidth;else x=box.left-plotOffset.left+(axis.position=="left"?box.width:0)}if(!axis.innermost){ctx.strokeStyle=axis.options.color;ctx.beginPath();xoff=yoff=0;if(axis.direction=="x")xoff=plotWidth+1;else yoff=plotHeight+1;if(ctx.lineWidth==1){if(axis.direction=="x"){y=Math.floor(y)+.5}else{x=Math.floor(x)+.5}}ctx.moveTo(x,y);ctx.lineTo(x+xoff,y+yoff);ctx.stroke()}ctx.strokeStyle=axis.options.tickColor;ctx.beginPath();for(i=0;i<axis.ticks.length;++i){var v=axis.ticks[i].v;xoff=yoff=0;if(isNaN(v)||v<axis.min||v>axis.max||t=="full"&&(typeof bw=="object"&&bw[axis.position]>0||bw>0)&&(v==axis.min||v==axis.max))continue;if(axis.direction=="x"){x=axis.p2c(v);yoff=t=="full"?-plotHeight:t;if(axis.position=="top")yoff=-yoff}else{y=axis.p2c(v);xoff=t=="full"?-plotWidth:t;if(axis.position=="left")xoff=-xoff}if(ctx.lineWidth==1){if(axis.direction=="x")x=Math.floor(x)+.5;else y=Math.floor(y)+.5}ctx.moveTo(x,y);ctx.lineTo(x+xoff,y+yoff)}ctx.stroke()}if(bw){bc=options.grid.borderColor;if(typeof bw=="object"||typeof bc=="object"){if(typeof bw!=="object"){bw={top:bw,right:bw,bottom:bw,left:bw}}if(typeof bc!=="object"){bc={top:bc,right:bc,bottom:bc,left:bc}}if(bw.top>0){ctx.strokeStyle=bc.top;ctx.lineWidth=bw.top;ctx.beginPath();ctx.moveTo(0-bw.left,0-bw.top/2);ctx.lineTo(plotWidth,0-bw.top/2);ctx.stroke()}if(bw.right>0){ctx.strokeStyle=bc.right;ctx.lineWidth=bw.right;ctx.beginPath();ctx.moveTo(plotWidth+bw.right/2,0-bw.top);ctx.lineTo(plotWidth+bw.right/2,plotHeight);ctx.stroke()}if(bw.bottom>0){ctx.strokeStyle=bc.bottom;ctx.lineWidth=bw.bottom;ctx.beginPath();ctx.moveTo(plotWidth+bw.right,plotHeight+bw.bottom/2);ctx.lineTo(0,plotHeight+bw.bottom/2);ctx.stroke()}if(bw.left>0){ctx.strokeStyle=bc.left;ctx.lineWidth=bw.left;ctx.beginPath();ctx.moveTo(0-bw.left/2,plotHeight+bw.bottom);ctx.lineTo(0-bw.left/2,0);ctx.stroke()}}else{ctx.lineWidth=bw;ctx.strokeStyle=options.grid.borderColor;ctx.strokeRect(-bw/2,-bw/2,plotWidth+bw,plotHeight+bw)}}ctx.restore()}function drawAxisLabels(){$.each(allAxes(),function(_,axis){var box=axis.box,legacyStyles=axis.direction+"Axis "+axis.direction+axis.n+"Axis",layer="flot-"+axis.direction+"-axis flot-"+axis.direction+axis.n+"-axis "+legacyStyles,font=axis.options.font||"flot-tick-label tickLabel",tick,x,y,halign,valign;surface.removeText(layer);if(!axis.show||axis.ticks.length==0)return;for(var i=0;i<axis.ticks.length;++i){tick=axis.ticks[i];if(!tick.label||tick.v<axis.min||tick.v>axis.max)continue;if(axis.direction=="x"){halign="center";x=plotOffset.left+axis.p2c(tick.v);if(axis.position=="bottom"){y=box.top+box.padding}else{y=box.top+box.height-box.padding;valign="bottom"}}else{valign="middle";y=plotOffset.top+axis.p2c(tick.v);if(axis.position=="left"){x=box.left+box.width-box.padding;halign="right"}else{x=box.left+box.padding}}surface.addText(layer,x,y,tick.label,font,null,null,halign,valign)}})}function drawSeries(series){if(series.lines.show)drawSeriesLines(series);if(series.bars.show)drawSeriesBars(series);if(series.points.show)drawSeriesPoints(series)}function drawSeriesLines(series){function plotLine(datapoints,xoffset,yoffset,axisx,axisy){var points=datapoints.points,ps=datapoints.pointsize,prevx=null,prevy=null;ctx.beginPath();for(var i=ps;i<points.length;i+=ps){var x1=points[i-ps],y1=points[i-ps+1],x2=points[i],y2=points[i+1];if(x1==null||x2==null)continue;if(y1<=y2&&y1<axisy.min){if(y2<axLine truncated
@@ -0,0 +1,432 @@
/* Pretty handling of time axes.
Copyright (c) 2007-2014 IOLA and Ole Laursen.
Licensed under the MIT license.
Set axis.mode to "time" to enable. See the section "Time series data" in
API.txt for details.
*/
(function($) {
var options = {
xaxis: {
timezone: null, // "browser" for local to the client or timezone for timezone-js
timeformat: null, // format string to use
twelveHourClock: false, // 12 or 24 time in time mode
monthNames: null // list of names of months
}
};
// round to nearby lower multiple of base
function floorInBase(n, base) {
return base * Math.floor(n / base);
}
// Returns a string with the date d formatted according to fmt.
// A subset of the Open Group's strftime format is supported.
function formatDate(d, fmt, monthNames, dayNames) {
if (typeof d.strftime == "function") {
return d.strftime(fmt);
}
var leftPad = function(n, pad) {
n = "" + n;
pad = "" + (pad == null ? "0" : pad);
return n.length == 1 ? pad + n : n;
};
var r = [];
var escape = false;
var hours = d.getHours();
var isAM = hours < 12;
if (monthNames == null) {
monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
}
if (dayNames == null) {
dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
}
var hours12;
if (hours > 12) {
hours12 = hours - 12;
} else if (hours == 0) {
hours12 = 12;
} else {
hours12 = hours;
}
for (var i = 0; i < fmt.length; ++i) {
var c = fmt.charAt(i);
if (escape) {
switch (c) {
case 'a': c = "" + dayNames[d.getDay()]; break;
case 'b': c = "" + monthNames[d.getMonth()]; break;
case 'd': c = leftPad(d.getDate()); break;
case 'e': c = leftPad(d.getDate(), " "); break;
case 'h': // For back-compat with 0.7; remove in 1.0
case 'H': c = leftPad(hours); break;
case 'I': c = leftPad(hours12); break;
case 'l': c = leftPad(hours12, " "); break;
case 'm': c = leftPad(d.getMonth() + 1); break;
case 'M': c = leftPad(d.getMinutes()); break;
// quarters not in Open Group's strftime specification
case 'q':
c = "" + (Math.floor(d.getMonth() / 3) + 1); break;
case 'S': c = leftPad(d.getSeconds()); break;
case 'y': c = leftPad(d.getFullYear() % 100); break;
case 'Y': c = "" + d.getFullYear(); break;
case 'p': c = (isAM) ? ("" + "am") : ("" + "pm"); break;
case 'P': c = (isAM) ? ("" + "AM") : ("" + "PM"); break;
case 'w': c = "" + d.getDay(); break;
}
r.push(c);
escape = false;
} else {
if (c == "%") {
escape = true;
} else {
r.push(c);
}
}
}
return r.join("");
}
// To have a consistent view of time-based data independent of which time
// zone the client happens to be in we need a date-like object independent
// of time zones. This is done through a wrapper that only calls the UTC
// versions of the accessor methods.
function makeUtcWrapper(d) {
function addProxyMethod(sourceObj, sourceMethod, targetObj, targetMethod) {
sourceObj[sourceMethod] = function() {
return targetObj[targetMethod].apply(targetObj, arguments);
};
};
var utc = {
date: d
};
// support strftime, if found
if (d.strftime != undefined) {
addProxyMethod(utc, "strftime", d, "strftime");
}
addProxyMethod(utc, "getTime", d, "getTime");
addProxyMethod(utc, "setTime", d, "setTime");
var props = ["Date", "Day", "FullYear", "Hours", "Milliseconds", "Minutes", "Month", "Seconds"];
for (var p = 0; p < props.length; p++) {
addProxyMethod(utc, "get" + props[p], d, "getUTC" + props[p]);
addProxyMethod(utc, "set" + props[p], d, "setUTC" + props[p]);
}
return utc;
};
// select time zone strategy. This returns a date-like object tied to the
// desired timezone
function dateGenerator(ts, opts) {
if (opts.timezone == "browser") {
return new Date(ts);
} else if (!opts.timezone || opts.timezone == "utc") {
return makeUtcWrapper(new Date(ts));
} else if (typeof timezoneJS != "undefined" && typeof timezoneJS.Date != "undefined") {
var d = new timezoneJS.Date();
// timezone-js is fickle, so be sure to set the time zone before
// setting the time.
d.setTimezone(opts.timezone);
d.setTime(ts);
return d;
} else {
return makeUtcWrapper(new Date(ts));
}
}
// map of app. size of time units in milliseconds
var timeUnitSize = {
"second": 1000,
"minute": 60 * 1000,
"hour": 60 * 60 * 1000,
"day": 24 * 60 * 60 * 1000,
"month": 30 * 24 * 60 * 60 * 1000,
"quarter": 3 * 30 * 24 * 60 * 60 * 1000,
"year": 365.2425 * 24 * 60 * 60 * 1000
};
// the allowed tick sizes, after 1 year we use
// an integer algorithm
var baseSpec = [
[1, "second"], [2, "second"], [5, "second"], [10, "second"],
[30, "second"],
[1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"],
[30, "minute"],
[1, "hour"], [2, "hour"], [4, "hour"],
[8, "hour"], [12, "hour"],
[1, "day"], [2, "day"], [3, "day"],
[0.25, "month"], [0.5, "month"], [1, "month"],
[2, "month"]
];
// we don't know which variant(s) we'll need yet, but generating both is
// cheap
var specMonths = baseSpec.concat([[3, "month"], [6, "month"],
[1, "year"]]);
var specQuarters = baseSpec.concat([[1, "quarter"], [2, "quarter"],
[1, "year"]]);
function init(plot) {
plot.hooks.processOptions.push(function (plot, options) {
$.each(plot.getAxes(), function(axisName, axis) {
var opts = axis.options;
if (opts.mode == "time") {
axis.tickGenerator = function(axis) {
var ticks = [];
var d = dateGenerator(axis.min, opts);
var minSize = 0;
// make quarter use a possibility if quarters are
// mentioned in either of these options
var spec = (opts.tickSize && opts.tickSize[1] ===
"quarter") ||
(opts.minTickSize && opts.minTickSize[1] ===
"quarter") ? specQuarters : specMonths;
if (opts.minTickSize != null) {
if (typeof opts.tickSize == "number") {
minSize = opts.tickSize;
} else {
minSize = opts.minTickSize[0] * timeUnitSize[opts.minTickSize[1]];
}
}
for (var i = 0; i < spec.length - 1; ++i) {
if (axis.delta < (spec[i][0] * timeUnitSize[spec[i][1]]
+ spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2
&& spec[i][0] * timeUnitSize[spec[i][1]] >= minSize) {
break;
}
}
var size = spec[i][0];
var unit = spec[i][1];
// special-case the possibility of several years
if (unit == "year") {
// if given a minTickSize in years, just use it,
// ensuring that it's an integer
if (opts.minTickSize != null && opts.minTickSize[1] == "year") {
size = Math.floor(opts.minTickSize[0]);
} else {
var magn = Math.pow(10, Math.floor(Math.log(axis.delta / timeUnitSize.year) / Math.LN10));
var norm = (axis.delta / timeUnitSize.year) / magn;
if (norm < 1.5) {
size = 1;
} else if (norm < 3) {
size = 2;
} else if (norm < 7.5) {
size = 5;
} else {
size = 10;
}
size *= magn;
}
// minimum size for years is 1
if (size < 1) {
size = 1;
}
}
axis.tickSize = opts.tickSize || [size, unit];
var tickSize = axis.tickSize[0];
unit = axis.tickSize[1];
var step = tickSize * timeUnitSize[unit];
if (unit == "second") {
d.setSeconds(floorInBase(d.getSeconds(), tickSize));
} else if (unit == "minute") {
d.setMinutes(floorInBase(d.getMinutes(), tickSize));
} else if (unit == "hour") {
d.setHours(floorInBase(d.getHours(), tickSize));
} else if (unit == "month") {
d.setMonth(floorInBase(d.getMonth(), tickSize));
} else if (unit == "quarter") {
d.setMonth(3 * floorInBase(d.getMonth() / 3,
tickSize));
} else if (unit == "year") {
d.setFullYear(floorInBase(d.getFullYear(), tickSize));
}
// reset smaller components
d.setMilliseconds(0);
if (step >= timeUnitSize.minute) {
d.setSeconds(0);
}
if (step >= timeUnitSize.hour) {
d.setMinutes(0);
}
if (step >= timeUnitSize.day) {
d.setHours(0);
}
if (step >= timeUnitSize.day * 4) {
d.setDate(1);
}
if (step >= timeUnitSize.month * 2) {
d.setMonth(floorInBase(d.getMonth(), 3));
}
if (step >= timeUnitSize.quarter * 2) {
d.setMonth(floorInBase(d.getMonth(), 6));
}
if (step >= timeUnitSize.year) {
d.setMonth(0);
}
var carry = 0;
var v = Number.NaN;
var prev;
do {
prev = v;
v = d.getTime();
ticks.push(v);
if (unit == "month" || unit == "quarter") {
if (tickSize < 1) {
// a bit complicated - we'll divide the
// month/quarter up but we need to take
// care of fractions so we don't end up in
// the middle of a day
d.setDate(1);
var start = d.getTime();
d.setMonth(d.getMonth() +
(unit == "quarter" ? 3 : 1));
var end = d.getTime();
d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize);
carry = d.getHours();
d.setHours(0);
} else {
d.setMonth(d.getMonth() +
tickSize * (unit == "quarter" ? 3 : 1));
}
} else if (unit == "year") {
d.setFullYear(d.getFullYear() + tickSize);
} else {
d.setTime(v + step);
}
} while (v < axis.max && v != prev);
return ticks;
};
axis.tickFormatter = function (v, axis) {
var d = dateGenerator(v, axis.options);
// first check global format
if (opts.timeformat != null) {
return formatDate(d, opts.timeformat, opts.monthNames, opts.dayNames);
}
// possibly use quarters if quarters are mentioned in
// any of these places
var useQuarters = (axis.options.tickSize &&
axis.options.tickSize[1] == "quarter") ||
(axis.options.minTickSize &&
axis.options.minTickSize[1] == "quarter");
var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]];
var span = axis.max - axis.min;
var suffix = (opts.twelveHourClock) ? " %p" : "";
var hourCode = (opts.twelveHourClock) ? "%I" : "%H";
var fmt;
if (t < timeUnitSize.minute) {
fmt = hourCode + ":%M:%S" + suffix;
} else if (t < timeUnitSize.day) {
if (span < 2 * timeUnitSize.day) {
fmt = hourCode + ":%M" + suffix;
} else {
fmt = "%b %d " + hourCode + ":%M" + suffix;
}
} else if (t < timeUnitSize.month) {
fmt = "%b %d";
} else if ((useQuarters && t < timeUnitSize.quarter) ||
(!useQuarters && t < timeUnitSize.year)) {
if (span < timeUnitSize.year) {
fmt = "%b";
} else {
fmt = "%b %Y";
}
} else if (useQuarters && t < timeUnitSize.year) {
if (span < timeUnitSize.year) {
fmt = "Q%q";
} else {
fmt = "Q%q %Y";
}
} else {
fmt = "%Y";
}
var rt = formatDate(d, fmt, opts.monthNames, opts.dayNames);
return rt;
};
}
});
});
}
$.plot.plugins.push({
init: init,
options: options,
name: 'time',
version: '1.0'
});
// Time-axis support used to be in Flot core, which exposed the
// formatDate function on the plot object. Various plugins depend
// on the function, so we need to re-expose it here.
$.plot.formatDate = formatDate;
$.plot.dateGenerator = dateGenerator;
})(jQuery);
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

@@ -0,0 +1,75 @@
$(document).ready(function() {
// Start 1-second timer to call RESTful endpoint
setInterval(function() {
$.ajax({
url: '/get_cpu_usage',
dataType: 'json',
success: function(json) {
$('#cpu_usage').text(json.result + '% ');
}
});
}, 1000);
// Initialize graph
var $c = $('<div class="graph"/>').appendTo('#graphs');
var dur = 120;
var past = Date.now() - dur * 1000;
var options = {
lines: {
fill: true,
lineWidth: 0,
fillColor: {colors: [ { opacity: 0 }, { opacity: 1 } ] }
},
grid: { borderWidth: 1, borderColor: '#ccc'},
xaxis: { mode: 'time', ticks: 5 },
legend: { labelBoxBorderColor: '#fff' },
colors: [ '#fec', '#396', '#e39', '9e2' ],
hooks: {
draw: [function(plot, canvas) {
canvas.font = '13px sans-serif';
canvas.fillStyle = '#aaa';
canvas.fillText('Resource Usage', 35, 25);
}]
}
};
var plot = $.plot($c, [], options);
var updateGraph = function(counter) {
var data = plot.getData();
var now = Date.now();
var oldest = now - dur * 1000;
data[0] = {
show: false,
data: [[oldest, null], [now, null]]
};
console.log(data);
// Remove old points
$.each(data, function(di, d) {
while (d.data.length > 0 && d.data[0][0] < oldest) {
d.data.shift();
}
});
// Add new points
var new_datapoint = [now, counter];
if (data[1]) {
data[1].label = 'memory';
data[1].data.push(new_datapoint);
} else {
data[1] = [{ data: [new_datapoint] }];
}
// Redraw the graph
plot.setData(data);
plot.setupGrid();
plot.draw();
};
// Create Websocket connection. For simplicity, no reconnect logic is here.
var ws = new WebSocket('ws://' + location.host);
ws.onmessage = function(ev) {
updateGraph(ev.data);
};
});
@@ -0,0 +1,87 @@
* {
outline: none;
}
body {
background: #36c;
color: #555;
margin: 0;
padding: 0;
font: 16px/1.4 Helvetica, Arial, sans-serif;
}
div.content {
width: 800px;
margin: 1em auto;
padding: 2em;
background-color: #fff;
border-radius: 1em;
}
fieldset {
border: 1px solid #ccc;
padding: 1em;
}
fieldset legend {
font-style: italic;
color: silver;
}
fieldset label {
text-align: right;
padding: 0 1em;
}
input[type=text] {
font-size: 100%;
padding: 0.2em;
border: 1px solid #ccc;
}
button {
color: #666;
background: #eee;
border: 1px solid #ccc;
padding: 0.2em 2em;
font-size: 100%;
cursor: pointer;
margin-top: 1em;
}
button:hover {
background: #ccc;
}
code {
background: #f0f0f0;
padding: 0 0.3em;
color: #396;
border-radius: 0.3em;
}
a:link, a:visited {
color: #69c;
text-decoration: none;
}
#graphs {
margin-top: 1em;
}
.graph {
min-height: 12em;
border: 0px solid #ccc;
position: relative;
margin: 0 1em 1em 0;
width: 36em;
display: inline-block;
}
.graph_title {
position: absolute;
top: 0.5em; left: 1em;
color: #ccc;
font-weight: bold;
z-index: 999;
}
+13
View File
@@ -0,0 +1,13 @@
SOURCES = $(PROG).c ../../mongoose.c
CFLAGS = -W -Wall -I../.. -Wno-unused-function $(CFLAGS_EXTRA) $(MODULE_CFLAGS)
all: $(PROG)
$(PROG): $(SOURCES)
$(CC) $(SOURCES) -o $@ $(CFLAGS)
$(PROG).exe: $(SOURCES)
cl $(SOURCES) /I../.. /MD /Fe$@
clean:
rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG)
-47
View File
@@ -1,47 +0,0 @@
#include <stdio.h>
#include <string.h>
#include "mongoose.h"
static int index_html(struct mg_connection *conn) {
FILE *fp = (FILE *) conn->connection_param;
char buf[200];
size_t n = 0;
if (fp == NULL) {
fp = fopen("../mongoose.c", "r");
conn->connection_param = (void *) fp;
}
if (fp != NULL) {
n = fread(buf, 1, sizeof(buf), fp);
mg_send_data(conn, buf, n);
if (n < sizeof(buf) || conn->wsbits != 0) {
fclose(fp);
conn->connection_param = NULL;
}
}
return n < sizeof(buf) ? 1 : 0;
}
int main(void) {
struct mg_server *server;
// Create and configure the server
server = mg_create_server(NULL);
mg_set_option(server, "listening_port", "8080");
mg_add_uri_handler(server, "/", index_html);
// Serve request. Hit Ctrl-C to terminate the program
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
for (;;) {
mg_poll_server(server, 1000);
}
// Cleanup, and free server instance
mg_destroy_server(&server);
return 0;
}
-29
View File
@@ -1,29 +0,0 @@
#include <stdio.h>
#include <string.h>
#include "mongoose.h"
// This function will be called by mongoose on every new request
static int index_html(struct mg_connection *conn) {
mg_printf_data(conn, "Hello! Requested URI is [%s]", conn->uri);
return MG_REQUEST_PROCESSED;
}
int main(void) {
struct mg_server *server;
// Create and configure the server
server = mg_create_server(NULL);
mg_set_option(server, "listening_port", "8080");
mg_set_request_handler(server, index_html);
// Serve request. Hit Ctrl-C to terminate the program
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
for (;;) {
mg_poll_server(server, 1000);
}
// Cleanup, and free server instance
mg_destroy_server(&server);
return 0;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

-73
View File
@@ -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 &copy; 2004-2010 by Sergey Lyubka
</div>
</body>
</html>
-154
View File
@@ -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);
-43
View File
@@ -1,43 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" dir="ltr">
<!-- This file is part of the Mongoose project,
http://code.google.com/p/mongoose -->
<head>
<title>Mongoose chat: login</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<!--
Note that this page is self-sufficient, it does not load any other
CSS or Javascript file. This is done so because only this page is
allowed for non-authorized users. If we want to load other files
from the frontend, we need to change backend code to allow those
for non-authorized users. See chat.c :: must_authorize() function.
-->
</head>
<script>
window.onload = function() {
// Set correct action for the login form. We assume that the SSL port
// is the next one to insecure one.
var httpsPort = location.protocol.match(/https/) ? location.port :
parseInt(location.port) + 1;
document.forms[0].action = 'https://' + location.hostname + ':' +
httpsPort + '/authorize';
};
</script>
<body>
<center>
<h2>Mongoose chat server login</h2>
<div style="max-width: 30em;">
Username and password can be any non-empty strings.
</div>
<br/>
<form>
<input type="text" name="user"></input><br/>
<input type="text" name="password"></input><br/>
<input type="submit" value="Login"></input>
</form>
</center>
</body>
</html>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

-106
View File
@@ -1,106 +0,0 @@
// This file is part of Mongoose project, http://code.google.com/p/mongoose
var chat = {
// Backend URL, string.
// 'http://backend.address.com' or '' if backend is the same as frontend
backendUrl: '',
maxVisibleMessages: 10,
errorMessageFadeOutTimeoutMs: 2000,
errorMessageFadeOutTimer: null,
lastMessageId: 0,
getMessagesIntervalMs: 1000,
};
chat.normalizeText = function(text) {
return text.replace('<', '&lt;').replace('>', '&gt;');
};
chat.refresh = function(data) {
if (data === undefined) {
return;
}
$.each(data, function(index, entry) {
var row = $('<div>').addClass('message-row').appendTo('#mml');
var timestamp = (new Date(entry.timestamp * 1000)).toLocaleTimeString();
$('<span>')
.addClass('message-timestamp')
.html('[' + timestamp + ']')
.prependTo(row);
$('<span>')
.addClass('message-user')
.addClass(entry.user ? '' : 'message-user-server')
.html(chat.normalizeText((entry.user || '[server]') + ':'))
.appendTo(row);
$('<span>')
.addClass('message-text')
.addClass(entry.user ? '' : 'message-text-server')
.html(chat.normalizeText(entry.text))
.appendTo(row);
chat.lastMessageId = Math.max(chat.lastMessageId, entry.id) + 1;
});
// Keep only chat.maxVisibleMessages, delete older ones.
while ($('#mml').children().length > chat.maxVisibleMessages) {
$('#mml div:first-child').remove();
}
};
chat.getMessages = function(enter_loop) {
$.ajax({
dataType: 'jsonp',
url: chat.backendUrl + '/ajax/get_messages',
data: {last_id: chat.lastMessageId},
success: chat.refresh,
error: function() {
},
});
if (enter_loop) {
window.setTimeout('chat.getMessages(true)', chat.getMessagesIntervalMs);
}
};
chat.handleMenuItemClick = function(ev) {
$('.menu-item').removeClass('menu-item-selected'); // Deselect menu buttons
$(this).addClass('menu-item-selected'); // Select clicked button
$('.main').addClass('hidden'); // Hide all main windows
$('#' + $(this).attr('name')).removeClass('hidden'); // Show main window
};
chat.showError = function(message) {
$('#error').html(message).fadeIn('fast');
window.clearTimeout(chat.errorMessageFadeOutTimer);
chat.errorMessageFadeOutTimer = window.setTimeout(function() {
$('#error').fadeOut('slow');
}, chat.errorMessageFadeOutTimeoutMs);
};
chat.handleMessageInput = function(ev) {
var input = ev.target;
if (ev.keyCode != 13 || !input.value)
return;
//input.disabled = true;
$.ajax({
dataType: 'jsonp',
url: chat.backendUrl + '/ajax/send_message',
data: {text: input.value},
success: function(ev) {
input.value = '';
input.disabled = false;
chat.getMessages(false);
},
error: function(ev) {
chat.showError('Error sending message');
input.disabled = false;
},
});
};
$(document).ready(function() {
$('.menu-item').click(chat.handleMenuItemClick);
$('.message-input').keypress(chat.handleMessageInput);
chat.getMessages(true);
});
// vim:ts=2:sw=2:et
-154
View File
@@ -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;
}
+14
View File
@@ -0,0 +1,14 @@
PROG = http_client
SOURCES = $(PROG).c ../../mongoose.c
CFLAGS = -W -Wall -I../.. -DMG_ENABLE_SSL -lssl -lcrypto -pthread $(CFLAGS_EXTRA)
all: $(PROG)
$(PROG): $(SOURCES)
$(CC) $(SOURCES) -o $@ $(CFLAGS)
$(PROG).exe: $(SOURCES)
cl $(SOURCES) /I../.. /MD /Fe$@
clean:
rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG)
+70
View File
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2014 Cesanta Software Limited
* All rights reserved
*
* This program fetches HTTP URLs.
*/
#include "mongoose.h"
static int s_exit_flag = 0;
static int s_show_headers = 0;
static const char *s_show_headers_opt = "--show-headers";
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
struct http_message *hm = (struct http_message *) ev_data;
switch (ev) {
case MG_EV_CONNECT:
if (* (int *) ev_data != 0) {
fprintf(stderr, "connect() failed: %s\n", strerror(* (int *) ev_data));
s_exit_flag = 1;
}
break;
case MG_EV_HTTP_REPLY:
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
if (s_show_headers) {
fwrite(hm->message.p, 1, hm->message.len, stdout);
} else {
fwrite(hm->body.p, 1, hm->body.len, stdout);
}
putchar('\n');
s_exit_flag = 1;
break;
default:
break;
}
}
int main(int argc, char *argv[]) {
struct mg_mgr mgr;
int i;
mg_mgr_init(&mgr, NULL);
/* Process command line arguments */
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], s_show_headers_opt) == 0) {
s_show_headers = 1;
} else if (strcmp(argv[i], "--hexdump") == 0 && i + 1 < argc) {
mgr.hexdump_file = argv[++i];
} else {
break;
}
}
if (i + 1 != argc) {
fprintf(stderr, "Usage: %s [%s] [--hexdump <file>] <URL>\n",
argv[0], s_show_headers_opt);
exit(EXIT_FAILURE);
}
mg_connect_http(&mgr, ev_handler, argv[i], NULL, NULL);
while (s_exit_flag == 0) {
mg_mgr_poll(&mgr, 1000);
}
mg_mgr_free(&mgr);
return 0;
}
+163
View File
@@ -0,0 +1,163 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\mongoose.c">
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">TurnOffAllWarnings</WarningLevel>
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">TurnOffAllWarnings</WarningLevel>
</ClCompile>
<ClCompile Include="http_client.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\mongoose.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{BDF3FC6F-2658-4A27-846D-6A45FB53C602}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>http_client</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;MG_ENABLE_THREADS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>./../../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;MG_ENABLE_THREADS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>./../../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+14
View File
@@ -0,0 +1,14 @@
PROG = json_rpc_server
SOURCES = $(PROG).c ../../mongoose.c
CFLAGS = -W -Wall -I../.. -pthread $(CFLAGS_EXTRA)
all: $(PROG)
$(PROG): $(SOURCES)
$(CC) $(SOURCES) -o $@ $(CFLAGS)
$(PROG).exe: $(SOURCES)
cl $(SOURCES) /I../.. /MD /Fe$@
clean:
rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG)
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2014 Cesanta Software Limited
* All rights reserved
*
* To test this server, do
* $ curl -d '{"id":1,method:"sum",params:[22,33]}' 127.0.0.1:8000
*/
#include "mongoose.h"
static const char *s_http_port = "8000";
static int rpc_sum(char *buf, int len, struct mg_rpc_request *req) {
double sum = 0;
int i;
if (req->params[0].type != JSON_TYPE_ARRAY) {
return mg_rpc_create_std_error(buf, len, req,
JSON_RPC_INVALID_PARAMS_ERROR);
}
for (i = 0; i < req->params[0].num_desc; i++) {
if (req->params[i + 1].type != JSON_TYPE_NUMBER) {
return mg_rpc_create_std_error(buf, len, req,
JSON_RPC_INVALID_PARAMS_ERROR);
}
sum += strtod(req->params[i + 1].ptr, NULL);
}
return mg_rpc_create_reply(buf, len, req, "f", sum);
}
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
struct http_message *hm = (struct http_message *) ev_data;
static const char *methods[] = { "sum", NULL };
static mg_rpc_handler_t handlers[] = { rpc_sum, NULL };
char buf[100];
switch (ev) {
case MG_EV_HTTP_REQUEST:
mg_rpc_dispatch(hm->body.p, hm->body.len, buf, sizeof(buf),
methods, handlers);
mg_printf(nc, "HTTP/1.0 200 OK\r\nContent-Length: %d\r\n"
"Content-Type: application/json\r\n\r\n%s",
(int) strlen(buf), buf);
nc->flags |= MG_F_SEND_AND_CLOSE;
break;
default:
break;
}
}
int main(void) {
struct mg_mgr mgr;
struct mg_connection *nc;
mg_mgr_init(&mgr, NULL);
nc = mg_bind(&mgr, s_http_port, ev_handler);
mg_set_protocol_http_websocket(nc);
printf("Starting JSON-RPC server on port %s\n", s_http_port);
for (;;) {
mg_mgr_poll(&mgr, 1000);
}
mg_mgr_free(&mgr);
return 0;
}
+10
View File
@@ -0,0 +1,10 @@
FROM cesanta/mongoose
COPY load_balancer.c /mongoose/
WORKDIR /mongoose
RUN mkdir /mongoose/certs; \
sed -i 's:#include "../../mongoose.h":#include "mongoose.h":' load_balancer.c; \
cc load_balancer.c mongoose.c -o load_balancer -W -Wall -pthread -DMG_ENABLE_SSL -lssl -lcrypto
EXPOSE 8000
VOLUME ["/mongoose/certs"]
ENTRYPOINT ["/mongoose/load_balancer"]
+39
View File
@@ -0,0 +1,39 @@
# To build with SSL under windows, do:
# wine make load_balancer.exe SSL=openssl # OpenSSL build
# wine make load_balancer.exe SSL=krypton # Krypton build
PROG = load_balancer
SOURCES = $(PROG).c ../../mongoose.c
CFLAGS = -W -Wall -pthread $(CFLAGS_EXTRA)
ifeq ($(SSL), openssl)
OPENSSL_PATH = ./openssl-0.9.8
CFLAGS_EXTRA += -DMG_ENABLE_SSL -I$(OPENSSL_PATH)/include
CFLAGS_EXTRA += /link /libpath:$(OPENSSL_PATH)/lib ssleay32.lib libeay32.lib
endif
ifeq ($(SSL), krypton)
KRYPTON_PATH = ../../../krypton
CFLAGS_EXTRA += -DMG_ENABLE_SSL $(KRYPTON_PATH)/krypton.c -I$(KRYPTON_PATH)
endif
all: $(PROG)
$(PROG): $(SOURCES)
$(CC) $(SOURCES) -o $@ $(CFLAGS)
$(PROG).exe: $(SOURCES)
cl $(SOURCES) /I.. /MD /Fe$@ /DMG_ENABLE_THREADS advapi32.lib $(CFLAGS_EXTRA)
test: $(PROG)
$(MAKE) -C ../api_server
sh unit_test.sh $$(pwd)/$(PROG)
docker-build:
docker build -t cesanta/load_balancer .
docker-push:
docker push cesanta/load_balancer
clean:
rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG)
+44
View File
@@ -0,0 +1,44 @@
# Mongoose-based HTTP load balancer
## Configuration
Load balancer is configured with command-line flags.
### Global flags
* `-p port` – TCP port to listen on. Default: 8000.
* `-l log_file` – path to the log file. Default: none.
* `-s ssl_cert` – path to SSL certificate. Default: none.
### Backend configuration
Main flag is `-b uri_prefix host_port` – it adds a new backend for a given
URI prefix. Example: `-b /stuff/ 127.0.0.1:8080` will route all requests that
start with '/stuff/' to a backend at port 8080 on localhost. There is a special
syntax for `uri_prefix` that allows you to change the URIs that get passed to
backends:
* `-b /stuff/=/ 127.0.0.1:8080` – for '/stuff/thing' backend will see '/thing'.
* `-b /stuff/=/other/ 127.0.0.1:8080` – '/stuff/thing' => '/other/thing'.
Also there are few per-backend flags that can be placed before `-b` and apply
only to the next backend:
* `-r` – instead of proxying requests load balancer will reply with 302
redirect.
* `-v vhost` – match not only URI prefix but 'Host:' header as well.
### Example
```
load_balancer -s path/to/cert.pem \
-v example.com -b /site/=/ 127.0.0.1:8080 \
-b /static/ 127.0.0.1:8081 \
-b /static/ 127.0.0.1:8082
```
In this example requests to 'example.com/site/' will be forwarded to the
backend on port 8080 with '/site' prefix stripped off and requests to
'/static/' on any virtual host will be balanced in round-robin fashion between
backends on ports 8081 and 8082.
+637
View File
@@ -0,0 +1,637 @@
/*
* Copyright (c) 2014 Cesanta Software Limited
* All rights reserved
*/
#include "../../mongoose.h"
#include <sys/queue.h>
#define MAX_IDLE_CONNS 5
#define CONN_IDLE_TIMEOUT 30
struct http_backend;
struct be_conn {
struct http_backend *be;
struct mg_connection *nc;
time_t idle_deadline;
STAILQ_ENTRY(be_conn) conns;
};
STAILQ_HEAD(be_conn_list_head, be_conn);
struct http_backend {
const char *vhost; /* NULL if any host */
const char *uri_prefix; /* URI prefix, e.g. "/api/v1/", "/static/" */
const char *uri_prefix_replacement; /* if not NULL, will replace uri_prefix in
requests to backends */
const char *host_port; /* Backend address */
int redirect; /* if true redirect instead of proxy */
int usage_counter; /* Number of times this backend was chosen */
struct be_conn_list_head conns;
int num_conns;
};
struct peer {
struct mg_connection *nc;
int64_t body_len; /* Size of the HTTP body to forward */
int64_t body_sent; /* Number of bytes already forwarded */
struct {
/* Headers have been sent, no more headers. */
unsigned int headers_sent : 1;
unsigned int keep_alive : 1;
} flags;
};
struct conn_data {
struct be_conn *be_conn; /* Chosen backend */
struct peer client; /* Client peer */
struct peer backend; /* Backend peer */
time_t last_activity;
};
static const char *s_error_500 = "HTTP/1.1 500 Failed\r\n";
static const char *s_content_len_0 = "Content-Length: 0\r\n";
static const char *s_connection_close = "Connection: close\r\n";
static const char *s_http_port = "8000";
static struct http_backend s_vhost_backends[100], s_default_backends[100];
static int s_num_vhost_backends = 0, s_num_default_backends = 0;
static int s_sig_num = 0;
static int s_backend_keepalive = 0;
static FILE *s_log_file = NULL;
#ifdef MG_ENABLE_SSL
const char *s_ssl_cert = NULL;
#endif
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data);
static void write_log(const char *fmt, ...);
static void signal_handler(int sig_num) {
signal(sig_num, signal_handler);
s_sig_num = sig_num;
}
static void send_http_err(struct mg_connection *nc, const char *err_line) {
mg_printf(nc, "%s%s%s\r\n", err_line, s_content_len_0, s_connection_close);
}
static void respond_with_error(struct conn_data *conn, const char *err_line) {
struct mg_connection *nc = conn->client.nc;
int headers_sent = conn->client.flags.headers_sent;
#ifdef DEBUG
write_log("conn=%p nc=%p respond_with_error %d\n", conn, nc, headers_sent);
#endif
if (nc == NULL) return;
if (!headers_sent) {
send_http_err(nc, err_line);
conn->client.flags.headers_sent = 1;
}
nc->flags |= MG_F_SEND_AND_CLOSE;
}
static int has_prefix(const struct mg_str *uri, const char *prefix) {
size_t prefix_len = strlen(prefix);
return uri->len >= prefix_len && memcmp(uri->p, prefix, prefix_len) == 0;
}
static int matches_vhost(const struct mg_str *host, const char *vhost) {
size_t vhost_len;
if (vhost == NULL) {
return 1;
}
vhost_len = strlen(vhost);
return host->len == vhost_len && memcmp(host->p, vhost, vhost_len) == 0;
}
static void write_log(const char *fmt, ...) {
va_list ap;
if (s_log_file != NULL) {
va_start(ap, fmt);
vfprintf(s_log_file, fmt, ap);
fflush(s_log_file);
va_end(ap);
}
}
static struct http_backend *choose_backend_from_list(
struct http_message *hm, struct http_backend *backends, int num_backends) {
int i;
struct mg_str vhost = {"", 0};
const struct mg_str *host = mg_get_http_header(hm, "host");
if (host != NULL) vhost = *host;
const char *vhost_end = vhost.p;
while (vhost_end < vhost.p + vhost.len && *vhost_end != ':') {
vhost_end++;
}
vhost.len = vhost_end - vhost.p;
struct http_backend *chosen = NULL;
for (i = 0; i < num_backends; i++) {
struct http_backend *be = &backends[i];
if (has_prefix(&hm->uri, be->uri_prefix) &&
matches_vhost(&vhost, be->vhost) &&
(chosen == NULL ||
/* Prefer most specific URI prefixes */
strlen(be->uri_prefix) > strlen(chosen->uri_prefix) ||
/* Among prefixes of the same length chose the least used. */
(strlen(be->uri_prefix) == strlen(chosen->uri_prefix) &&
be->usage_counter < chosen->usage_counter))) {
chosen = be;
}
}
return chosen;
}
static struct http_backend *choose_backend(struct http_message *hm) {
struct http_backend *chosen =
choose_backend_from_list(hm, s_vhost_backends, s_num_vhost_backends);
/* Nothing was chosen for this vhost, look for vhost == NULL backends. */
if (chosen == NULL) {
chosen = choose_backend_from_list(hm, s_default_backends,
s_num_default_backends);
}
if (chosen != NULL) chosen->usage_counter++;
return chosen;
}
static void forward_body(struct peer *src, struct peer *dst) {
struct mbuf *src_io = &src->nc->recv_mbuf;
if (src->body_sent < src->body_len) {
size_t to_send = src->body_len - src->body_sent;
if (src_io->len < to_send) {
to_send = src_io->len;
}
mg_send(dst->nc, src_io->buf, to_send);
src->body_sent += to_send;
mbuf_remove(src_io, to_send);
}
#ifdef DEBUG
write_log("forward_body %p (ka=%d) -> %p sent %d of %d\n", src->nc,
src->flags.keep_alive, dst->nc, src->body_sent, src->body_len);
#endif
}
static void forward(struct conn_data *conn, struct http_message *hm,
struct peer *src_peer, struct peer *dst_peer) {
struct mg_connection *src = src_peer->nc;
struct mg_connection *dst = dst_peer->nc;
struct mbuf *io = &src->recv_mbuf;
int i;
int is_request = (src_peer == &conn->client);
src_peer->body_len = hm->body.len;
struct http_backend *be = conn->be_conn->be;
if (is_request) {
/* Write rewritten request line. */
size_t trim_len = strlen(be->uri_prefix);
mg_printf(dst, "%.*s%s%.*s\r\n", (int) (hm->uri.p - io->buf), io->buf,
be->uri_prefix_replacement,
(int) (hm->proto.p + hm->proto.len - (hm->uri.p + trim_len)),
hm->uri.p + trim_len);
} else {
/* Reply line goes without modification */
mg_printf(dst, "%.*s %d %.*s\r\n", (int) hm->proto.len, hm->proto.p,
(int) hm->resp_code, (int) hm->resp_status_msg.len,
hm->resp_status_msg.p);
}
/* Headers. */
for (i = 0; i < MG_MAX_HTTP_HEADERS && hm->header_names[i].len > 0; i++) {
struct mg_str hn = hm->header_names[i];
struct mg_str hv = hm->header_values[i];
#ifdef MG_ENABLE_SSL
/*
* If we terminate SSL and backend redirects to local HTTP port,
* strip protocol to let client use HTTPS.
* TODO(lsm): web page content may also contain local HTTP references,
* they need to be rewritten too.
*/
if (mg_vcasecmp(&hn, "Location") == 0 && s_ssl_cert != NULL) {
size_t hlen = strlen(be->host_port);
const char *hp = be->host_port, *p = memchr(hp, ':', hlen);
if (p == NULL) {
p = hp + hlen;
}
if (mg_ncasecmp(hv.p, "http://", 7) == 0 &&
mg_ncasecmp(hv.p + 7, hp, (p - hp)) == 0) {
mg_printf(dst, "Location: %.*s\r\n", (int) (hv.len - (7 + (p - hp))),
hv.p + 7 + (p - hp));
continue;
}
}
#endif
/* We always rewrite the connection header depending on the settings. */
if (mg_vcasecmp(&hn, "Connection") == 0) continue;
mg_printf(dst, "%.*s: %.*s\r\n", (int) hn.len, hn.p, (int) hv.len, hv.p);
}
/* Emit the connection header. */
const char *connection_mode = "close";
if (dst_peer == &conn->backend) {
if (s_backend_keepalive) connection_mode = "keep-alive";
} else {
if (conn->client.flags.keep_alive) connection_mode = "keep-alive";
}
mg_printf(dst, "Connection: %s\r\n", connection_mode);
mg_printf(dst, "%s", "\r\n");
mbuf_remove(io, hm->body.p - hm->message.p); /* We've forwarded headers */
dst_peer->flags.headers_sent = 1;
forward_body(src_peer, dst_peer);
}
struct be_conn *get_conn(struct http_backend *be) {
if (STAILQ_EMPTY(&be->conns)) return NULL;
struct be_conn *result = STAILQ_FIRST(&be->conns);
STAILQ_REMOVE_HEAD(&be->conns, conns);
be->num_conns--;
return result;
}
/*
* choose_backend parses incoming HTTP request and routes it to the appropriate
* backend. It assumes that clients don't do HTTP pipelining, handling only
* one request request for each connection. To give a hint to backend about
* this it inserts "Connection: close" header into each forwarded request.
*/
static int connect_backend(struct conn_data *conn, struct http_message *hm) {
struct mg_connection *nc = conn->client.nc;
struct http_backend *be = choose_backend(hm);
write_log("%.*s %.*s backend=%s\n", (int) hm->method.len, hm->method.p,
(int) hm->uri.len, hm->uri.p, be->host_port);
if (be == NULL) return 0;
if (be->redirect != 0) {
mg_printf(nc, "HTTP/1.1 302 Found\r\nLocation: %s\r\n\r\n", be->host_port);
return 1;
}
struct be_conn *bec = get_conn(be);
if (bec != NULL) {
bec->nc->handler = ev_handler;
#ifdef DEBUG
write_log("conn=%p to %p (%s) reusing bec=%p\n", conn, be, be->host_port,
bec);
#endif
} else {
bec = malloc(sizeof(*conn->be_conn));
memset(bec, 0, sizeof(*bec));
bec->nc = mg_connect(nc->mgr, be->host_port, ev_handler);
#ifdef DEBUG
write_log("conn=%p new conn to %p (%s) bec=%p\n", conn, be, be->host_port,
bec);
#endif
if (bec->nc == NULL) {
free(bec);
write_log("Connection to [%s] failed\n", be->host_port);
return 0;
}
}
bec->be = be;
conn->be_conn = bec;
conn->backend.nc = bec->nc;
conn->backend.nc->user_data = conn;
mg_set_protocol_http_websocket(conn->backend.nc);
return 1;
}
static int is_keep_alive(struct http_message *hm) {
const struct mg_str *connection_header = mg_get_http_header(hm, "Connection");
if (connection_header == NULL) {
/* HTTP/1.1 connections are keep-alive by default. */
if (mg_vcasecmp(&hm->proto, "HTTP/1.1") != 0) return 0;
} else if (mg_vcasecmp(connection_header, "keep-alive") != 0) {
return 0;
}
// We must also have Content-Length.
return mg_get_http_header(hm, "Content-Length") != NULL;
}
static void idle_backend_handler(struct mg_connection *nc, int ev,
void *ev_data) {
(void) ev_data; /* Unused. */
struct be_conn *bec = nc->user_data;
const time_t now = time(NULL);
#ifdef DEBUG
write_log("%d idle bec=%p nc=%p ev=%d deadline=%d\n", now, bec, nc, ev,
bec->idle_deadline);
#endif
switch (ev) {
case MG_EV_POLL: {
if (bec->idle_deadline > 0 && now > bec->idle_deadline) {
#ifdef DEBUG
write_log("bec=%p nc=%p closing due to idleness\n", bec, bec->nc);
#endif
bec->nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
break;
}
case MG_EV_CLOSE: {
#ifdef DEBUG
write_log("bec=%p closed\n", bec);
#endif
if (bec->idle_deadline > 0) {
STAILQ_REMOVE(&bec->be->conns, bec, be_conn, conns);
}
free(bec);
break;
}
}
}
void release_backend(struct conn_data *conn) {
/* Disassociate the backend, put back on the pool. */
struct be_conn *bec = conn->be_conn;
conn->be_conn = NULL;
if (bec->nc == NULL) {
free(bec);
memset(&conn->backend, 0, sizeof(conn->backend));
return;
}
struct http_backend *be = bec->be;
bec->nc->user_data = bec;
bec->nc->handler = idle_backend_handler;
if (conn->backend.flags.keep_alive) {
bec->idle_deadline = time(NULL) + CONN_IDLE_TIMEOUT;
STAILQ_INSERT_TAIL(&be->conns, bec, conns);
#ifdef DEBUG
write_log("bec=%p becoming idle\n", bec);
#endif
be->num_conns++;
while (be->num_conns > MAX_IDLE_CONNS) {
bec = STAILQ_FIRST(&be->conns);
STAILQ_REMOVE_HEAD(&be->conns, conns);
be->num_conns--;
bec->idle_deadline = 0;
bec->nc->flags = MG_F_CLOSE_IMMEDIATELY;
#ifdef DEBUG
write_log("bec=%p evicted\n", bec);
#endif
}
} else {
bec->idle_deadline = 0;
bec->nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
memset(&conn->backend, 0, sizeof(conn->backend));
}
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
struct conn_data *conn = (struct conn_data *) nc->user_data;
const time_t now = time(NULL);
#ifdef DEBUG
write_log("%d conn=%p nc=%p ev=%d ev_data=%p bec=%p bec_nc=%p\n", now, conn,
nc, ev, ev_data, conn != NULL ? conn->be_conn : NULL,
conn != NULL && conn->be_conn != NULL ? conn->be_conn->nc : NULL);
#endif
if (conn == NULL) {
if (ev == MG_EV_ACCEPT) {
conn = calloc(1, sizeof(*conn));
if (conn == NULL) {
send_http_err(nc, s_error_500);
} else {
memset(conn, 0, sizeof(*conn));
nc->user_data = conn;
conn->client.nc = nc;
conn->client.body_len = -1;
conn->backend.body_len = -1;
conn->last_activity = now;
}
return;
} else {
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
return;
}
}
if (ev != MG_EV_POLL) conn->last_activity = now;
switch (ev) {
case MG_EV_HTTP_REQUEST: { /* From client */
assert(conn != NULL);
assert(conn->be_conn == NULL);
struct http_message *hm = (struct http_message *) ev_data;
conn->client.flags.keep_alive = is_keep_alive(hm);
if (!connect_backend(conn, hm)) {
respond_with_error(conn, s_error_500);
break;
}
if (conn->backend.nc == NULL) {
/* This is a redirect, we're done. */
conn->client.nc->flags |= MG_F_SEND_AND_CLOSE;
break;
}
forward(conn, hm, &conn->client, &conn->backend);
break;
}
case MG_EV_CONNECT: { /* To backend */
assert(conn != NULL);
assert(conn->be_conn != NULL);
int status = *(int *) ev_data;
if (status != 0) {
write_log("Error connecting to %s: %d (%s)\n",
conn->be_conn->be->host_port, status, strerror(status));
/* TODO(lsm): mark backend as defunct, try it later on */
respond_with_error(conn, s_error_500);
conn->be_conn->nc = NULL;
release_backend(conn);
break;
}
break;
}
case MG_EV_HTTP_REPLY: { /* From backend */
assert(conn != NULL);
struct http_message *hm = (struct http_message *) ev_data;
conn->backend.flags.keep_alive = s_backend_keepalive && is_keep_alive(hm);
forward(conn, hm, &conn->backend, &conn->client);
release_backend(conn);
if (!conn->client.flags.keep_alive) {
conn->client.nc->flags |= MG_F_SEND_AND_CLOSE;
} else {
#ifdef DEBUG
write_log("conn=%p remains open\n", conn);
#endif
}
break;
}
case MG_EV_POLL: {
assert(conn != NULL);
if (now - conn->last_activity > CONN_IDLE_TIMEOUT &&
conn->backend.nc == NULL /* not waiting for backend */) {
#ifdef DEBUG
write_log("conn=%p has been idle for too long\n", conn);
conn->client.nc->flags |= MG_F_SEND_AND_CLOSE;
#endif
}
break;
}
case MG_EV_CLOSE: {
assert(conn != NULL);
if (nc == conn->client.nc) {
#ifdef DEBUG
write_log("conn=%p nc=%p client closed, body_sent=%d\n", conn, nc,
conn->backend.body_sent);
#endif
conn->client.nc = NULL;
if (conn->backend.nc != NULL) {
conn->backend.nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
} else if (nc == conn->backend.nc) {
#ifdef DEBUG
write_log("conn=%p nc=%p backend closed\n", conn, nc);
#endif
conn->backend.nc = NULL;
if (conn->client.nc != NULL &&
(conn->backend.body_len < 0 ||
conn->backend.body_sent < conn->backend.body_len)) {
write_log("Backend %s disconnected.\n", conn->be_conn->be->host_port);
respond_with_error(conn, s_error_500);
}
}
if (conn->client.nc == NULL && conn->backend.nc == NULL) {
free(conn);
}
break;
}
}
}
static void print_usage_and_exit(const char *prog_name) {
fprintf(stderr,
"Usage: %s [-D debug_dump_file] [-p http_port] [-l log] [-k]"
#if MG_ENABLE_SSL
"[-s ssl_cert] "
#endif
"<[-r] [-v vhost] -b uri_prefix[=replacement] host_port> ... \n",
prog_name);
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[]) {
struct mg_mgr mgr;
struct mg_connection *nc;
int i, redirect = 0;
const char *vhost = NULL;
mg_mgr_init(&mgr, NULL);
/* Parse command line arguments */
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-D") == 0) {
mgr.hexdump_file = argv[i + 1];
i++;
} else if (strcmp(argv[i], "-k") == 0) {
s_backend_keepalive = 1;
} else if (strcmp(argv[i], "-l") == 0 && i + 1 < argc) {
if (strcmp(argv[i + 1], "-") == 0) {
s_log_file = stdout;
} else {
s_log_file = fopen(argv[i + 1], "a");
if (s_log_file == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
}
i++;
} else if (strcmp(argv[i], "-p") == 0) {
s_http_port = argv[i + 1];
i++;
} else if (strcmp(argv[i], "-r") == 0 && i + 1 < argc) {
redirect = 1;
} else if (strcmp(argv[i], "-v") == 0 && i + 1 < argc) {
if (strcmp(argv[i + 1], "") == 0) {
vhost = NULL;
} else {
vhost = argv[i + 1];
}
i++;
} else if (strcmp(argv[i], "-b") == 0 && i + 2 < argc) {
struct http_backend *be =
vhost != NULL ? &s_vhost_backends[s_num_vhost_backends++]
: &s_default_backends[s_num_default_backends++];
STAILQ_INIT(&be->conns);
char *r = NULL;
be->vhost = vhost;
be->uri_prefix = argv[i + 1];
be->host_port = argv[i + 2];
be->redirect = redirect;
be->uri_prefix_replacement = be->uri_prefix;
if ((r = strchr(be->uri_prefix, '=')) != NULL) {
*r = '\0';
be->uri_prefix_replacement = r + 1;
}
printf(
"Adding backend for %s%s : %s "
"[redirect=%d,prefix_replacement=%s]\n",
be->vhost == NULL ? "" : be->vhost, be->uri_prefix, be->host_port,
be->redirect, be->uri_prefix_replacement);
vhost = NULL;
redirect = 0;
i += 2;
#ifdef MG_ENABLE_SSL
} else if (strcmp(argv[i], "-s") == 0 && i + 1 < argc) {
s_ssl_cert = argv[++i];
#endif
} else {
print_usage_and_exit(argv[0]);
}
}
/* Open listening socket */
if ((nc = mg_bind(&mgr, s_http_port, ev_handler)) == NULL) {
fprintf(stderr, "mg_bind(%s) failed\n", s_http_port);
exit(EXIT_FAILURE);
}
#if MG_ENABLE_SSL
if (s_ssl_cert != NULL) {
const char *err_str = mg_set_ssl(nc, s_ssl_cert, NULL);
if (err_str != NULL) {
fprintf(stderr, "Error loading SSL cert: %s\n", err_str);
exit(1);
}
}
#endif
mg_set_protocol_http_websocket(nc);
if (s_num_vhost_backends + s_num_default_backends == 0) {
print_usage_and_exit(argv[0]);
}
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
/* Run event loop until signal is received */
printf("Starting LB on port %s\n", s_http_port);
while (s_sig_num == 0) {
mg_mgr_poll(&mgr, 1000);
}
/* Cleanup */
mg_mgr_free(&mgr);
printf("Exiting on signal %d\n", s_sig_num);
return EXIT_SUCCESS;
}
+21
View File
@@ -0,0 +1,21 @@
#!/bin/sh
PROG=$1
PORT=8002
cleanup() {
kill -9 $PID >/dev/null 2>&1
}
#set -x
trap cleanup EXIT
cleanup
$PROG -p $PORT -b /api/ 127.0.0.1:8000 &
PID=$!
# Perform api_server unit test through the load balancer by passing
# load balancer port to the unit test script
(cd ../api_server && make && sh unit_test.sh ./api_server $PORT)
exit $?
-15
View File
@@ -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
?>
-42
View File
@@ -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>&nbsp;') 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>
-17
View File
@@ -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;
}
-53
View File
@@ -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
+14
View File
@@ -0,0 +1,14 @@
PROG = mqtt_broker
SOURCES = $(PROG).c ../../mongoose.c
CFLAGS = -W -Wall -I../.. -pthread -DMG_ENABLE_SSL -DMG_ENABLE_MQTT_BROKER -lssl -lcrypto $(CFLAGS_EXTRA)
all: $(PROG)
$(PROG): $(SOURCES)
$(CC) $(SOURCES) -o $@ $(CFLAGS)
$(PROG).exe: $(SOURCES)
cl $(SOURCES) /I../.. /DMG_ENABLE_SSL /DMG_ENABLE_MQTT_BROKER /MD /Fe$@
clean:
rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG)
Loaded 100 of 154 files, more files were not shown because too many files have changed in this diff. Show more