Bladeren bron

Merge remote-tracking branch 'upstream/master'

Updates from master
Dialga 10 jaren geleden
bovenliggende
commit
9e77ac2c88
50 gewijzigde bestanden met toevoegingen van 1669 en 452 verwijderingen
  1. 7 0
      .gitignore
  2. 11 1
      .travis.yml
  3. 4 0
      CREDITS.md
  4. 94 62
      LICENSE.md
  5. 6 2
      Makefile
  6. 22 0
      Qt/CivetWeb.pro
  7. 25 15
      README.md
  8. 3 2
      RELEASE_NOTES.md
  9. 12 0
      VS2012/civetweb.sln
  10. 1 1
      VS2012/civetweb/civetweb.vcxproj
  11. 4 4
      VS2012/civetweb_lua/civetweb_lua.vcxproj
  12. 5 5
      VS2012/ex_embed_cpp/ex_embed_cpp.vcxproj
  13. 5 5
      VS2012/ex_embedded_c/ex_embedded_c.vcxproj
  14. 5 4
      VS2012/ex_websocket/ex_websocket.vcxproj
  15. 5 4
      VS2012/ex_websocket_client/ex_websocket_client.vcxproj
  16. 5 5
      VS2012/lua_lib/lua_lib.vcxproj
  17. 5 4
      VS2012/unit_test/unit_test.vcxproj
  18. 3 3
      VS2012/upload/upload.vcxproj
  19. 35 0
      ci/test/01_basic/basic_spec.lua
  20. 0 0
      ci/test/01_basic/docroot/01_basic_test_dir/git_keep_empty_dir
  21. 0 0
      ci/test/01_basic/docroot/01_basic_test_file
  22. 34 0
      ci/test/README.md
  23. 42 0
      ci/test/civet.lua
  24. 14 0
      ci/travis/install_rocks.sh
  25. 5 0
      ci/travis/lua_env.sh
  26. 15 0
      ci/travis/platform.sh
  27. 7 0
      ci/travis/run_ci_tests.sh
  28. 61 0
      ci/travis/setup_lua.sh
  29. 1 1
      docs/Embedding.md
  30. 129 8
      examples/embedded_c/embedded_c.c
  31. 18 9
      examples/embedded_cpp/embedded_cpp.cpp
  32. 16 11
      examples/websocket/WebSockCallbacks.c
  33. 3 3
      examples/websocket/WebSockCallbacks.h
  34. 5 0
      examples/websocket/websocket.c
  35. 4 4
      examples/websocket_client/websocket_client.c
  36. 11 8
      include/CivetServer.h
  37. 68 20
      include/civetweb.h
  38. 5 5
      src/CivetServer.cpp
  39. 446 152
      src/civetweb.c
  40. 113 74
      src/main.c
  41. 24 22
      src/md5.inl
  42. 4 2
      src/mod_lua.inl
  43. 8 1
      test/resource_script_demo.lua
  44. 16 6
      test/unit_test.c
  45. 2 0
      test/windows.cgi
  46. 7 0
      test/windows.cgi.cmd
  47. 21 7
      testutils/testclient/testclient.c
  48. 3 2
      testutils/testclient/testclient.vcxproj
  49. 239 0
      testutils/testclient_chunked_linux/testclient.c
  50. 91 0
      testutils/testclient_chunked_linux/testclient2.vcxproj

+ 7 - 0
.gitignore

@@ -1,5 +1,6 @@
 
 
 civetweb
 civetweb
+civetweb_test
 libcivetweb.a
 libcivetweb.a
 libcivetweb.so
 libcivetweb.so
 *-cache
 *-cache
@@ -242,3 +243,9 @@ tags
 ##########################
 ##########################
 *.lo
 *.lo
 .libs
 .libs
+
+##########################
+## Travis Build Dir
+##########################
+ci/lua
+

+ 11 - 1
.travis.yml

@@ -1,5 +1,15 @@
 language: c
 language: c
+sudo: false
+
 compiler:
 compiler:
   - gcc
   - gcc
   - clang
   - clang
-script: make WITH_LUA=1 WITH_DEBUG=1 WITH_IPV6=1 WITH_WEBSOCKET=1
+
+install: make WITH_LUA=1 WITH_DEBUG=1 WITH_IPV6=1 WITH_WEBSOCKET=1
+
+before_script:
+  - ci/travis/setup_lua.sh
+  - ci/travis/install_rocks.sh
+
+script:
+  - ci/travis/run_ci_tests.sh

+ 4 - 0
CREDITS.md

@@ -3,6 +3,7 @@
 * Alex Kozlov
 * Alex Kozlov
 * bel2125
 * bel2125
 * Brian Spratke
 * Brian Spratke
+* cdbishop
 * celeron55
 * celeron55
 * Daniel Oaks
 * Daniel Oaks
 * Danny Al-Gaaf
 * Danny Al-Gaaf
@@ -11,8 +12,11 @@
 * HariKamath Kamath
 * HariKamath Kamath
 * Jordan Shelley
 * Jordan Shelley
 * Keith Kyzivat
 * Keith Kyzivat
+* Kevin Wojniak
 * Kimmo Mustonen
 * Kimmo Mustonen
+* Matt Clarkson
 * Morgan McGuire
 * Morgan McGuire
+* nihildeb
 * No Face Press
 * No Face Press
 * Paul Sokolovsky
 * Paul Sokolovsky
 * Richard Screene
 * Richard Screene

+ 94 - 62
LICENSE.md

@@ -5,11 +5,14 @@ This document includes several copyright licenses for different
 aspects of the software.  Not all licenses may apply depending
 aspects of the software.  Not all licenses may apply depending
 on the features chosen.
 on the features chosen.
 
 
+
 Civetweb License
 Civetweb License
 -----
 -----
 
 
 ### Included with all features.
 ### Included with all features.
 
 
+> Copyright (c) 2013-2015 The CivetWeb developers ([CREDITS.md](https://github.com/bel2125/civetweb/blob/master/CREDITS.md))
+>
 > Copyright (c) 2004-2013 Sergey Lyubka
 > Copyright (c) 2004-2013 Sergey Lyubka
 >
 >
 > Copyright (c) 2013 No Face Press, LLC (Thomas Davis)
 > Copyright (c) 2013 No Face Press, LLC (Thomas Davis)
@@ -22,10 +25,10 @@ Civetweb License
 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 > copies of the Software, and to permit persons to whom the Software is
 > copies of the Software, and to permit persons to whom the Software is
 > furnished to do so, subject to the following conditions:
 > furnished to do so, subject to the following conditions:
-> 
+>
 > The above copyright notice and this permission notice shall be included in
 > The above copyright notice and this permission notice shall be included in
 > all copies or substantial portions of the Software.
 > all copies or substantial portions of the Software.
-> 
+>
 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -34,6 +37,7 @@ Civetweb License
 > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 > THE SOFTWARE.
 > THE SOFTWARE.
 
 
+
 Lua License
 Lua License
 ------
 ------
 
 
@@ -41,18 +45,31 @@ Lua License
 
 
 http://www.lua.org/license.html
 http://www.lua.org/license.html
 
 
-> Copyright � 1994-2013 Lua.org, PUC-Rio.
-> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+> Copyright (C) 1994-2015 Lua.org, PUC-Rio.
 >
 >
-> The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-> 
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+> Permission is hereby granted, free of charge, to any person obtaining a copy
+> of this software and associated documentation files (the "Software"), to deal
+> in the Software without restriction, including without limitation the rights
+> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+> copies of the Software, and to permit persons to whom the Software is
+> furnished to do so, subject to the following conditions:
+>
+> The above copyright notice and this permission notice shall be included in
+> all copies or substantial portions of the Software.
+>
+> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+> THE SOFTWARE.
 
 
 
 
 SQLite3 License
 SQLite3 License
 ------
 ------
 
 
-### Included only if built with Lua support.
+### Included only if built with Lua and SQLite support.
 
 
 http://www.sqlite.org/copyright.html
 http://www.sqlite.org/copyright.html
 
 
@@ -65,36 +82,36 @@ http://www.sqlite.org/copyright.html
 >    May you find forgiveness for yourself and forgive others.
 >    May you find forgiveness for yourself and forgive others.
 >    May you share freely, never taking more than you give.
 >    May you share freely, never taking more than you give.
 
 
+
 lsqlite3 License
 lsqlite3 License
 ------
 ------
 
 
-### Included only if built with Lua support.
+### Included only if built with Lua and SQLite support.
+
+> Copyright (C) 2002-2013 Tiago Dionizio, Doug Currie
+> All rights reserved.
+> Author    : Tiago Dionizio <tiago.dionizio@ist.utl.pt>
+> Author    : Doug Currie <doug.currie@alum.mit.edu>
+> Library   : lsqlite3 - a SQLite 3 database binding for Lua 5
+>
+> Permission is hereby granted, free of charge, to any person obtaining a copy
+> of this software and associated documentation files (the "Software"), to deal
+> in the Software without restriction, including without limitation the rights
+> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+> copies of the Software, and to permit persons to whom the Software is
+> furnished to do so, subject to the following conditions:
+>
+> The above copyright notice and this permission notice shall be included in
+> all copies or substantial portions of the Software.
+>
+> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+> THE SOFTWARE.
 
 
-> lsqlite3                                                              
-> Copyright (C) 2002-2007 Tiago Dionizio, Doug Currie                   
-> All rights reserved.                                                  
-> Author    : Tiago Dionizio <tiago.dionizio@ist.utl.pt>                
-> Author    : Doug Currie <doug.currie@alum.mit.edu>                    
-> Library   : lsqlite3 - a SQLite 3 database binding for Lua 5          
->                                                                      
-> Permission is hereby granted, free of charge, to any person obtaining 
-> a copy of this software and associated documentation files (the       
-> "Software"), to deal in the Software without restriction, including   
-> without limitation the rights to use, copy, modify, merge, publish,   
-> distribute, sublicense, and/or sell copies of the Software, and to    
-> permit persons to whom the Software is furnished to do so, subject to 
-> the following conditions:                                             
->                                                                      
-> The above copyright notice and this permission notice shall be        
-> included in all copies or substantial portions of the Software.       
->                                                                      
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       
-> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    
-> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-> IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  
-> CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  
-> TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     
-> SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                
 
 
 Lua File System License
 Lua File System License
 ------
 ------
@@ -105,37 +122,52 @@ http://keplerproject.github.io/luafilesystem/license.html
 
 
 > Copyright © 2003 Kepler Project.
 > Copyright © 2003 Kepler Project.
 >
 >
-> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+> Permission is hereby granted, free of charge, to any person obtaining a copy
+> of this software and associated documentation files (the "Software"), to deal
+> in the Software without restriction, including without limitation the rights
+> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+> copies of the Software, and to permit persons to whom the Software is
+> furnished to do so, subject to the following conditions:
+>
+> The above copyright notice and this permission notice shall be included in
+> all copies or substantial portions of the Software.
 >
 >
-> The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-> 
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+> THE SOFTWARE.
+
 
 
 LuaXML License
 LuaXML License
 ------
 ------
 
 
-### Included only if built with Lua support.
+### Included only if built with Lua and LuaXML support.
 
 
-LuaXml is licensed under the terms of the MIT license reproduced below,
-the same as Lua itself. This means that LuaXml is free software and can be
-used for both academic and commercial purposes at absolutely no cost.
-
-Copyright (C) 2007-2013 Gerald Franz, eludi.net
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+> LuaXML License
+>
+> LuaXml is licensed under the terms of the MIT license reproduced below,
+> the same as Lua itself. This means that LuaXml is free software and can be
+> used for both academic and commercial purposes at absolutely no cost.
+>
+> Copyright (C) 2007-2013 Gerald Franz, eludi.net
+>
+> Permission is hereby granted, free of charge, to any person obtaining a copy
+> of this software and associated documentation files (the "Software"), to deal
+> in the Software without restriction, including without limitation the rights
+> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+> copies of the Software, and to permit persons to whom the Software is
+> furnished to do so, subject to the following conditions:
+>
+> The above copyright notice and this permission notice shall be included in
+> all copies or substantial portions of the Software.
+>
+> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+> THE SOFTWARE.

+ 6 - 2
Makefile

@@ -60,7 +60,7 @@ BUILD_DIRS += $(BUILD_DIR)/test
 endif
 endif
 
 
 # only set main compile options if none were chosen
 # only set main compile options if none were chosen
-CFLAGS += -W -Wall -O2 -D$(TARGET_OS) -Iinclude $(COPT) -DUSE_STACK_SIZE=102400
+CFLAGS += -Wall -Wextra -O2 -D$(TARGET_OS) -Iinclude $(COPT) -DUSE_STACK_SIZE=102400
 
 
 LIBS = -lpthread -lm
 LIBS = -lpthread -lm
 
 
@@ -93,7 +93,9 @@ ifdef WITH_WEBSOCKET
   CFLAGS += -DUSE_WEBSOCKET
   CFLAGS += -DUSE_WEBSOCKET
   ifdef WITH_LUA
   ifdef WITH_LUA
     CFLAGS += -DUSE_TIMERS
     CFLAGS += -DUSE_TIMERS
-    LIBS += -lrt
+    ifeq ($(TARGET_OS),LINUX)
+      LIBS += -lrt
+    endif
   endif
   endif
 endif
 endif
 
 
@@ -229,6 +231,7 @@ clean:
 	$(RMRF) lib$(CPROG).so
 	$(RMRF) lib$(CPROG).so
 	$(RMRF) lib$(CPROG).so.$(major)
 	$(RMRF) lib$(CPROG).so.$(major)
 	$(RMRF) lib$(CPROG).so.$(version).0
 	$(RMRF) lib$(CPROG).so.$(version).0
+	$(RMRF) $(CPROG)
 
 
 distclean: clean
 distclean: clean
 	@$(RMRF) VS2012/Debug VS2012/*/Debug  VS2012/*/*/Debug
 	@$(RMRF) VS2012/Debug VS2012/*/Debug  VS2012/*/*/Debug
@@ -236,6 +239,7 @@ distclean: clean
 	$(RMF) $(CPROG) lib$(CPROG).so lib$(CPROG).a *.dmg *.msi *.exe lib$(CPROG).dll lib$(CPROG).dll.a
 	$(RMF) $(CPROG) lib$(CPROG).so lib$(CPROG).a *.dmg *.msi *.exe lib$(CPROG).dll lib$(CPROG).dll.a
 	$(RMF) $(UNIT_TEST_PROG)
 	$(RMF) $(UNIT_TEST_PROG)
 
 
+lib$(CPROG).a: CFLAGS += -fPIC
 lib$(CPROG).a: $(LIB_OBJECTS)
 lib$(CPROG).a: $(LIB_OBJECTS)
 	@$(RMF) $@
 	@$(RMF) $@
 	ar cq $@ $(LIB_OBJECTS)
 	ar cq $@ $(LIB_OBJECTS)

+ 22 - 0
Qt/CivetWeb.pro

@@ -0,0 +1,22 @@
+TEMPLATE = app
+CONFIG += console
+CONFIG -= app_bundle
+CONFIG -= qt
+
+SOURCES += \
+    ../src/md5.inl \
+    ../src/mod_lua.inl \
+    ../src/timer.inl \
+    ../src/civetweb.c \
+    ../src/main.c
+
+include(deployment.pri)
+qtcAddDeployment()
+
+HEADERS += \
+    ../include/civetweb.h
+
+INCLUDEPATH +=  \
+    ../include/
+
+LIBS += -lws2_32 -lComdlg32

+ 25 - 15
README.md

@@ -4,13 +4,15 @@
 There is a new home!!!
 There is a new home!!!
 -----------------
 -----------------
 https://github.com/bel2125/civetweb
 https://github.com/bel2125/civetweb
-Bel has been taking the lead on Civetweb, so the official repository
-is being moved under his control for ease of maintenance.
+
+Bel has been taking the lead on Civetweb, so the official repository is being
+moved under his control for ease of maintenance.
 
 
 Project Mission
 Project Mission
 -----------------
 -----------------
 
 
-Project mission is to provide easy to use, powerful, C/C++ embeddable web server with optional CGI, SSL and Lua support.
+Project mission is to provide easy to use, powerful, C/C++ embeddable web
+server with optional CGI, SSL and Lua support.
 Civetweb has a MIT license so you can innovate without restrictions.
 Civetweb has a MIT license so you can innovate without restrictions.
 
 
 Where to find the official version?
 Where to find the official version?
@@ -25,7 +27,7 @@ https://github.com/bel2125/civetweb
 Trouble tickets should be filed on GitHub
 Trouble tickets should be filed on GitHub
 https://github.com/bel2125/civetweb/issues
 https://github.com/bel2125/civetweb/issues
 
 
-Discussion group is at Google Groups
+Discussion/support group and announcements are at Google Groups
 https://groups.google.com/d/forum/civetweb
 https://groups.google.com/d/forum/civetweb
 
 
 Quick start documentation
 Quick start documentation
@@ -46,18 +48,26 @@ simplicity by a carefully selected list of features:
 
 
 - Liberal, commercial-friendly, permissive,
 - Liberal, commercial-friendly, permissive,
   [MIT license](http://en.wikipedia.org/wiki/MIT_License)
   [MIT license](http://en.wikipedia.org/wiki/MIT_License)
-- Free from copy-left licenses, like GPL, because you should innovate without restrictions.
-- Based on [Mongoose](https://code.google.com/p/mongoose/)
-- Works on Windows, Mac, UNIX, iPhone, Android, Buildroot, and many other platforms
-- Scripting and database support (Lua scipts, Lua Server Pages, CGI + SQLite database).
-  This provides a ready to go, powerful web development platform in a
-  one single-click executable with **no dependencies**.
-- Support for CGI, HTTPS/SSL, SSI, HTTP digest (MD5) authorization, Websocket, WEbDAV
-- Resumed download, URL rewrite, file blacklist, IP-based ACL, Windows service
-- Download speed limit based on client subnet or URI pattern
+- Free from copy-left licenses, like GPL, because you should innovate without
+  restrictions.
+- Forked from [Mongoose](https://code.google.com/p/mongoose/) in 2013, before
+  it changed the licence from MIT to commercial + GPL. A lot of enchancements
+  have been added since that time, see
+  [RELEASE_NOTES.md](https://github.com/bel2125/civetweb/blob/master/RELEASE_NOTES.md).
+- Works on Windows, Mac, Linux, UNIX, iPhone, Android, Buildroot, and many
+  other platforms.
+- Scripting and database support (Lua scipts, Lua Server Pages, CGI + SQLite
+  database).
+  This provides a ready to go, powerful web development platform in a one
+  single-click executable with **no dependencies**.
+- Support for CGI, HTTPS/SSL, SSI, HTTP digest (MD5) authorization, Websocket,
+  WEbDAV.
+- Resumed download, URL rewrite, file blacklist, IP-based ACL, Windows service.
+- Download speed limit based on client subnet or URI pattern.
 - Simple and clean embedding API.
 - Simple and clean embedding API.
-  The source is in single file to make things easy. Embedding examples included.
-- HTTP client capable of sending arbitrary HTTP/HTTPS requests
+- The source is in single file to make things easy.
+- Embedding examples included.
+- HTTP client capable of sending arbitrary HTTP/HTTPS requests.
 
 
 
 
 ### Optionally included software
 ### Optionally included software

+ 3 - 2
RELEASE_NOTES.md

@@ -1,11 +1,12 @@
 Release Notes v1.7 (Under Development)
 Release Notes v1.7 (Under Development)
 ===
 ===
-### Objectives: *Examples, documentation, additional API functions, chunked transfer support, rewritten handle_request method, bug fixes and updates*
+### Objectives: *Examples, documentation, additional API functions, rewritten handle_request method, bug fixes and updates*
 
 
 Changes
 Changes
 -------
 -------
 
 
-- Add chunked transfer support
+- URI specific callbacks for websockets
+- Add chunked transfer support (TODO: currently not working)
 - Update LuaFileSystem
 - Update LuaFileSystem
 - Update Lua to 5.2.4
 - Update Lua to 5.2.4
 - Fix build for MinGW-x64, TDM-GCC and clang
 - Fix build for MinGW-x64, TDM-GCC and clang

+ 12 - 0
VS2012/civetweb.sln

@@ -23,6 +23,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testclient", "..\testutils\
 EndProject
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Browser", "..\testutils\Browser\Browser.vcxproj", "{277772B0-D4B3-451E-86B6-261FBC645793}"
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Browser", "..\testutils\Browser\Browser.vcxproj", "{277772B0-D4B3-451E-86B6-261FBC645793}"
 EndProject
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testclient2", "..\testutils\testclient_chunked_linux\testclient2.vcxproj", "{150140C5-2989-4D0D-8714-5A47B78EAD4D}"
+EndProject
 Global
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Mixed Platforms = Debug|Mixed Platforms
 		Debug|Mixed Platforms = Debug|Mixed Platforms
@@ -155,6 +157,16 @@ Global
 		{277772B0-D4B3-451E-86B6-261FBC645793}.Release|Win32.ActiveCfg = Release|Win32
 		{277772B0-D4B3-451E-86B6-261FBC645793}.Release|Win32.ActiveCfg = Release|Win32
 		{277772B0-D4B3-451E-86B6-261FBC645793}.Release|Win32.Build.0 = Release|Win32
 		{277772B0-D4B3-451E-86B6-261FBC645793}.Release|Win32.Build.0 = Release|Win32
 		{277772B0-D4B3-451E-86B6-261FBC645793}.Release|x64.ActiveCfg = Release|Win32
 		{277772B0-D4B3-451E-86B6-261FBC645793}.Release|x64.ActiveCfg = Release|Win32
+		{150140C5-2989-4D0D-8714-5A47B78EAD4D}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+		{150140C5-2989-4D0D-8714-5A47B78EAD4D}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+		{150140C5-2989-4D0D-8714-5A47B78EAD4D}.Debug|Win32.ActiveCfg = Debug|Win32
+		{150140C5-2989-4D0D-8714-5A47B78EAD4D}.Debug|Win32.Build.0 = Debug|Win32
+		{150140C5-2989-4D0D-8714-5A47B78EAD4D}.Debug|x64.ActiveCfg = Debug|Win32
+		{150140C5-2989-4D0D-8714-5A47B78EAD4D}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+		{150140C5-2989-4D0D-8714-5A47B78EAD4D}.Release|Mixed Platforms.Build.0 = Release|Win32
+		{150140C5-2989-4D0D-8714-5A47B78EAD4D}.Release|Win32.ActiveCfg = Release|Win32
+		{150140C5-2989-4D0D-8714-5A47B78EAD4D}.Release|Win32.Build.0 = Release|Win32
+		{150140C5-2989-4D0D-8714-5A47B78EAD4D}.Release|x64.ActiveCfg = Release|Win32
 	EndGlobalSection
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 		HideSolutionNode = FALSE

+ 1 - 1
VS2012/civetweb/civetweb.vcxproj

@@ -39,7 +39,7 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v110_xp</PlatformToolset>
+    <PlatformToolset>v100</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   </PropertyGroup>

+ 4 - 4
VS2012/civetweb_lua/civetweb_lua.vcxproj

@@ -118,7 +118,7 @@
       </PrecompiledHeader>
       </PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>USE_IPV6;LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
@@ -132,7 +132,7 @@
       </PrecompiledHeader>
       </PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;CONSOLE;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>USE_IPV6;LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;CONSOLE;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
@@ -176,7 +176,7 @@
       <Optimization>MaxSpeed</Optimization>
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>USE_IPV6;LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
@@ -235,4 +235,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
   </ImportGroup>
-</Project>
+</Project>

+ 5 - 5
VS2012/ex_embed_cpp/ex_embed_cpp.vcxproj

@@ -28,7 +28,7 @@
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <UseDebugLibraries>true</UseDebugLibraries>
     <PlatformToolset>v100</PlatformToolset>
     <PlatformToolset>v100</PlatformToolset>
-    <CharacterSet>Unicode</CharacterSet>
+    <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
@@ -39,9 +39,9 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v110_xp</PlatformToolset>
+    <PlatformToolset>v100</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
+    <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
@@ -88,7 +88,7 @@
       </PrecompiledHeader>
       </PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
@@ -118,7 +118,7 @@
       <Optimization>MaxSpeed</Optimization>
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>

+ 5 - 5
VS2012/ex_embedded_c/ex_embedded_c.vcxproj

@@ -35,7 +35,7 @@
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <UseDebugLibraries>true</UseDebugLibraries>
     <PlatformToolset>v100</PlatformToolset>
     <PlatformToolset>v100</PlatformToolset>
-    <CharacterSet>Unicode</CharacterSet>
+    <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
@@ -46,9 +46,9 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v110_xp</PlatformToolset>
+    <PlatformToolset>v100</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
+    <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
@@ -95,7 +95,7 @@
       </PrecompiledHeader>
       </PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>USE_WEBSOCKET;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
@@ -125,7 +125,7 @@
       <Optimization>MaxSpeed</Optimization>
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>USE_WEBSOCKET;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>

+ 5 - 4
VS2012/ex_websocket/ex_websocket.vcxproj

@@ -27,7 +27,7 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
+    <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
@@ -39,7 +39,8 @@
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <UseDebugLibraries>false</UseDebugLibraries>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
+    <CharacterSet>MultiByte</CharacterSet>
+    <PlatformToolset>v100</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
@@ -86,7 +87,7 @@
       </PrecompiledHeader>
       </PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>USE_WEBSOCKET;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>USE_WEBSOCKET;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
@@ -116,7 +117,7 @@
       <Optimization>MaxSpeed</Optimization>
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <PreprocessorDefinitions>USE_WEBSOCKET;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>USE_WEBSOCKET;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>

+ 5 - 4
VS2012/ex_websocket_client/ex_websocket_client.vcxproj

@@ -27,7 +27,7 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
+    <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
@@ -39,7 +39,8 @@
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <UseDebugLibraries>false</UseDebugLibraries>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
+    <CharacterSet>MultiByte</CharacterSet>
+    <PlatformToolset>v100</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
@@ -86,7 +87,7 @@
       </PrecompiledHeader>
       </PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>USE_WEBSOCKET;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>USE_WEBSOCKET;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
@@ -116,7 +117,7 @@
       <Optimization>MaxSpeed</Optimization>
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <PreprocessorDefinitions>USE_WEBSOCKET;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>USE_WEBSOCKET;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>

+ 5 - 5
VS2012/lua_lib/lua_lib.vcxproj

@@ -27,7 +27,7 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
+    <CharacterSet>MultiByte</CharacterSet>
     <PlatformToolset>v100</PlatformToolset>
     <PlatformToolset>v100</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
@@ -40,7 +40,7 @@
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <UseDebugLibraries>false</UseDebugLibraries>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
+    <CharacterSet>MultiByte</CharacterSet>
     <PlatformToolset>v100</PlatformToolset>
     <PlatformToolset>v100</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
@@ -84,7 +84,7 @@
       </PrecompiledHeader>
       </PrecompiledHeader>
       <WarningLevel>TurnOffAllWarnings</WarningLevel>
       <WarningLevel>TurnOffAllWarnings</WarningLevel>
       <Optimization>Disabled</Optimization>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>LUA_COMPAT_ALL;THREADSAFE=1;SQLITE_ENABLE_FTS3;SQLITE_ENABLE_FTS3_PARENTHESIS;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>LUA_COMPAT_ALL;THREADSAFE=1;SQLITE_ENABLE_FTS3;SQLITE_ENABLE_FTS3_PARENTHESIS;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
@@ -114,7 +114,7 @@
       <Optimization>MaxSpeed</Optimization>
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <PreprocessorDefinitions>LUA_COMPAT_ALL;THREADSAFE=1;SQLITE_ENABLE_FTS3;SQLITE_ENABLE_FTS3_PARENTHESIS;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>LUA_COMPAT_ALL;THREADSAFE=1;SQLITE_ENABLE_FTS3;SQLITE_ENABLE_FTS3_PARENTHESIS;WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
@@ -187,4 +187,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
   </ImportGroup>
-</Project>
+</Project>

+ 5 - 4
VS2012/unit_test/unit_test.vcxproj

@@ -19,13 +19,14 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
+    <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <UseDebugLibraries>false</UseDebugLibraries>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
+    <CharacterSet>MultiByte</CharacterSet>
+    <PlatformToolset>v100</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
   <ImportGroup Label="ExtensionSettings">
@@ -51,7 +52,7 @@
       </PrecompiledHeader>
       </PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>MEMORY_DEBUGGING;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\src;$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\src;$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
@@ -83,4 +84,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
   </ImportGroup>
-</Project>
+</Project>

+ 3 - 3
VS2012/upload/upload.vcxproj

@@ -35,7 +35,7 @@
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <UseDebugLibraries>true</UseDebugLibraries>
     <PlatformToolset>v100</PlatformToolset>
     <PlatformToolset>v100</PlatformToolset>
-    <CharacterSet>Unicode</CharacterSet>
+    <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
@@ -46,9 +46,9 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v110_xp</PlatformToolset>
+    <PlatformToolset>v100</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
+    <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>

+ 35 - 0
ci/test/01_basic/basic_spec.lua

@@ -0,0 +1,35 @@
+civet = require "ci/test/civet"
+local curl = require "cURL"
+
+describe("civetweb basic", function()
+
+  setup(function()
+    civet.start()
+  end)
+
+  teardown(function()
+    civet.stop()
+  end)
+
+
+  it("should serve a simple get request", function()
+
+    local out = ""
+    function capture(str)
+      out = out .. str
+    end
+
+    local c = curl.easy()
+      :setopt_url('http://localhost:' .. civet.port .. "/")
+      :setopt_writefunction(capture)
+      :perform()
+    :close()
+
+    --print('rescode:' .. c.getinfo(curl.INFO_RESPONSE_CODE))
+
+    assert.are.equal('Index of', string.match(out, 'Index of'))
+    assert.are.equal('01_basic_test_dir', string.match(out, '01_basic_test_dir'))
+    assert.are.equal('01_basic_test_file', string.match(out, '01_basic_test_file'))
+  end)
+
+end)

+ 0 - 0
ci/test/01_basic/docroot/01_basic_test_dir/git_keep_empty_dir


+ 0 - 0
ci/test/01_basic/docroot/01_basic_test_file


+ 34 - 0
ci/test/README.md

@@ -0,0 +1,34 @@
+== Travis CI Tests
+
+Travis is a service which will build your project when you commit or get pull requests on Github.
+
+I have fixed and extended the travis configuration to build on the new sudo-less docker infrastructure.
+
+=== CI Process
+
+* On Check-in or Pull Requests clone the repo
+* Run make WITH_LUA=1 WITH_DEBUG=1 WITH_IPV6=1 WITH_WEBSOCKET=1
+* Build a standalone lua installation (seperate from civetweb or the OS)
+* Build LuaRocks in standalone installation
+* Install a few rocks into the standalone installation
+* Start the test script
+
+=== test/ci_tests/01_basic/basic_spec.lua
+
+On the initial checkin, there is only one test which demonstrates:
+
+* reliably starting civetweb server on travis infrastructure
+* waiting (polling) with lua.socket to establish the server is up and running 
+* using libcurl via lua to test that files in the specified docroot are available
+* kill the civetweb server process
+* waiting (polling) the server port to see that the server has freed it
+
+=== Adding Tests
+
+* Create a directory under ci_tests
+* Add a spec file, so now we have ci_tests/02_my_awesome_test/awesome_spec.lua
+* Any file under ci_tests which ends in _spec.lua will be automatically run
+* Check out the 'busted' and lua-curl3 docs for more info
+* https://github.com/Lua-cURL/Lua-cURLv3
+* http://olivinelabs.com/busted/
+

+ 42 - 0
ci/test/civet.lua

@@ -0,0 +1,42 @@
+socket = require "socket"
+
+local civet = {}
+
+-- default params
+civet.port=12345
+civet.max_retry=100
+civet.start_delay=0.1
+
+function civet.start(docroot)
+  -- TODO: use a property
+  docroot = docroot or 'ci/test/01_basic/docroot'
+  assert(io.popen('./civetweb'
+  .. " -listening_ports " .. civet.port
+  .. " -document_root " .. docroot
+  .. " > /dev/null 2>&1 &"
+  ))
+  -- wait until the server answers
+  for i=1,civet.max_retry do
+    local s = socket.connect('127.0.0.1', civet.port)
+    if s then
+      s:close()
+      break
+    end
+    socket.select(nil, nil, civet.start_delay) -- sleep
+  end
+end
+
+function civet.stop()
+  os.execute('killall civetweb')
+  -- wait until the server port closes
+  for i=1,civet.max_retry do
+    local s = socket.connect('127.0.0.1', civet.port)
+    if not s then
+      break
+    end
+    s:close()
+    socket.select(nil, nil, civet.start_delay) -- sleep
+  end
+end
+
+return civet

+ 14 - 0
ci/travis/install_rocks.sh

@@ -0,0 +1,14 @@
+#!/bin/bash
+set -ev
+
+source ci/travis/lua_env.sh
+
+# add any rocks required for ci_tests to this list
+# lua-curl depends on a libcurl development package (i.e. libcurl4-openssl-dev)
+ROCKS=(lua-curl busted)
+
+for ROCK in ${ROCKS[*]}
+do
+  $LUAROCKS install $ROCK
+done
+

+ 5 - 0
ci/travis/lua_env.sh

@@ -0,0 +1,5 @@
+#!/bin/bash
+
+LUAROCKS=ci/lua/bin/luarocks
+eval $($LUAROCKS path --bin)
+

+ 15 - 0
ci/travis/platform.sh

@@ -0,0 +1,15 @@
+if [ -z "$PLATFORM" ]; then
+  PLATFORM=$TRAVIS_OS_NAME;
+fi
+
+if [ "$PLATFORM" == "osx" ]; then
+  PLATFORM="macosx";
+fi
+
+if [ -z "$PLATFORM" ]; then
+  if [ "$(uname)" == "Linux" ]; then
+    PLATFORM="linux";
+  else
+    PLATFORM="macosx";
+  fi;
+fi

+ 7 - 0
ci/travis/run_ci_tests.sh

@@ -0,0 +1,7 @@
+#!/bin/bash
+set -ev
+
+source ci/travis/lua_env.sh
+busted -o TAP ci/test/
+
+

+ 61 - 0
ci/travis/setup_lua.sh

@@ -0,0 +1,61 @@
+#! /bin/bash
+set -ev
+
+# this script installs a lua / luarocks environment in .travis/lua
+# this is necessary because travis docker architecture (the fast way)
+# does not permit sudo, and does not contain a useful lua installation
+
+# After this script is finished, you can configure your environment to
+# use it by sourcing lua_env.sh
+
+source ci/travis/platform.sh
+
+# The current versions when this script was written
+LUA_VERSION=5.2.4
+LUAROCKS_VERSION=2.2.2
+
+# directory where this script is located
+SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
+
+# civetweb base dir
+PROJECT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../.. && pwd )
+
+# fetch and unpack lua src
+cd $SCRIPT_DIR
+LUA_BASE=lua-$LUA_VERSION
+rm -rf $LUA_BASE
+curl http://www.lua.org/ftp/$LUA_BASE.tar.gz | tar zx
+
+# build lua
+cd $LUA_BASE
+make $PLATFORM
+make local
+
+# mv built lua install to target Lua dir
+LUA_DIR=$PROJECT_DIR/ci/lua
+rm -rf $LUA_DIR
+mv $SCRIPT_DIR/$LUA_BASE/install $LUA_DIR
+
+# add to path required by luarocks installer
+export PATH=$LUA_DIR/bin:$PATH
+
+
+# fetch and unpack luarocks
+cd $SCRIPT_DIR
+LUAROCKS_BASE=luarocks-$LUAROCKS_VERSION
+rm -rf ${LUAROCKS_BASE}
+LUAROCKS_URL=http://luarocks.org/releases/${LUAROCKS_BASE}.tar.gz
+# -L because it's a 302 redirect
+curl -L $LUAROCKS_URL | tar xzp
+cd $LUAROCKS_BASE
+
+# build luarocks
+./configure --prefix=$LUA_DIR
+make build
+make install
+
+# cleanup source dirs
+cd $SCRIPT_DIR
+rm -rf $LUAROCKS_BASE
+rm -rf $LUA_BASE
+

+ 1 - 1
docs/Embedding.md

@@ -52,7 +52,7 @@ By default, the server will automatically serve up files like a normal HTTP serv
 Lua Support
 Lua Support
 ------
 ------
 
 
-Lua is a server side include functionality.  Files ending in .la will be processed with Lua.
+Lua is a server side include functionality.  Files ending in .lua will be processed with Lua.
 
 
 ##### Add the following CFLAGS
 ##### Add the following CFLAGS
 
 

+ 129 - 8
examples/embedded_c/embedded_c.c

@@ -1,4 +1,5 @@
 /*
 /*
+* Copyright (c) 2013-2015 the CivetWeb developers
 * Copyright (c) 2013 No Face Press, LLC
 * Copyright (c) 2013 No Face Press, LLC
 * License http://opensource.org/licenses/mit-license.php MIT License
 * License http://opensource.org/licenses/mit-license.php MIT License
 */
 */
@@ -14,13 +15,13 @@
 #include "civetweb.h"
 #include "civetweb.h"
 
 
 
 
-
 #define DOCUMENT_ROOT "."
 #define DOCUMENT_ROOT "."
 #define PORT "8888"
 #define PORT "8888"
 #define EXAMPLE_URI "/example"
 #define EXAMPLE_URI "/example"
 #define EXIT_URI "/exit"
 #define EXIT_URI "/exit"
 int exitNow = 0;
 int exitNow = 0;
 
 
+
 int ExampleHandler(struct mg_connection *conn, void *cbdata)
 int ExampleHandler(struct mg_connection *conn, void *cbdata)
 {
 {
     mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
     mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
@@ -29,12 +30,14 @@ int ExampleHandler(struct mg_connection *conn, void *cbdata)
     mg_printf(conn, "<p>To see a page from the A handler <a href=\"A\">click here</a></p>");
     mg_printf(conn, "<p>To see a page from the A handler <a href=\"A\">click here</a></p>");
     mg_printf(conn, "<p>To see a page from the A/B handler <a href=\"A/B\">click here</a></p>");
     mg_printf(conn, "<p>To see a page from the A/B handler <a href=\"A/B\">click here</a></p>");
     mg_printf(conn, "<p>To see a page from the *.foo handler <a href=\"xy.foo\">click here</a></p>");
     mg_printf(conn, "<p>To see a page from the *.foo handler <a href=\"xy.foo\">click here</a></p>");
+    mg_printf(conn, "<p>To test websocket handler <a href=\"/websocket\">click here</a></p>");
     mg_printf(conn, "<p>To exit <a href=\"%s\">click here</a></p>",
     mg_printf(conn, "<p>To exit <a href=\"%s\">click here</a></p>",
               EXIT_URI);
               EXIT_URI);
     mg_printf(conn, "</body></html>\n");
     mg_printf(conn, "</body></html>\n");
     return 1;
     return 1;
 }
 }
 
 
+
 int ExitHandler(struct mg_connection *conn, void *cbdata)
 int ExitHandler(struct mg_connection *conn, void *cbdata)
 {
 {
     mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n");
     mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n");
@@ -43,6 +46,7 @@ int ExitHandler(struct mg_connection *conn, void *cbdata)
     return 1;
     return 1;
 }
 }
 
 
+
 int AHandler(struct mg_connection *conn, void *cbdata)
 int AHandler(struct mg_connection *conn, void *cbdata)
 {
 {
     mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
     mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
@@ -52,6 +56,7 @@ int AHandler(struct mg_connection *conn, void *cbdata)
     return 1;
     return 1;
 }
 }
 
 
+
 int ABHandler(struct mg_connection *conn, void *cbdata)
 int ABHandler(struct mg_connection *conn, void *cbdata)
 {
 {
     mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
     mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
@@ -61,10 +66,11 @@ int ABHandler(struct mg_connection *conn, void *cbdata)
     return 1;
     return 1;
 }
 }
 
 
+
 int FooHandler(struct mg_connection *conn, void *cbdata)
 int FooHandler(struct mg_connection *conn, void *cbdata)
 {
 {
     /* Handler may access the request info using mg_get_request_info */
     /* Handler may access the request info using mg_get_request_info */
-    struct mg_request_info * req_info = mg_get_request_info(conn);
+    const struct mg_request_info * req_info = mg_get_request_info(conn);
 
 
     mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
     mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
     mg_printf(conn, "<html><body>");
     mg_printf(conn, "<html><body>");
@@ -76,9 +82,119 @@ int FooHandler(struct mg_connection *conn, void *cbdata)
 }
 }
 
 
 
 
-int main(int argc, char *argv[])
+int WebSocketStartHandler(struct mg_connection *conn, void *cbdata)
+{
+    mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
+
+    mg_printf(conn, "<!DOCTYPE html>\n");
+    mg_printf(conn, "<html>\n<head>\n");
+    mg_printf(conn, "<meta charset=\"UTF-8\">\n");
+    mg_printf(conn, "<title>Embedded websocket example</title>\n");
+#ifdef USE_WEBSOCKET
+    /* mg_printf(conn, "<script type=\"text/javascript\"><![CDATA[\n"); ... xhtml style */
+    mg_printf(conn, "<script>\n");
+    mg_printf(conn,
+    "function load() {\n"
+    "  var wsproto = (location.protocol === 'https:') ? 'wss:' : 'ws:';\n"
+    "  connection = new WebSocket(wsproto + '//' + window.location.host + '/websocket');\n"
+    "  websock_text_field = document.getElementById('websock_text_field');\n"
+    "  connection.onmessage = function (e) {\n"
+    "    websock_text_field.innerHTML=e.data;\n"
+    "  }\n"
+    "  connection.onerror = function (error) {\n"
+    "    alert('WebSocket error');\n"
+    "    connection.close();\n"
+    "  }\n"
+    "}\n"
+    );
+    /* mg_printf(conn, "]]></script>\n"); ... xhtml style */
+    mg_printf(conn, "</script>\n");
+    mg_printf(conn, "</head>\n<body onload=\"load()\">\n");
+    mg_printf(conn, "<div id='websock_text_field'>No websocket connection yet</div>\n");
+#else
+    mg_printf(conn, "</head>\n<body>\n");
+    mg_printf(conn, "Example not compiled with USE_WEBSOCKET\n");
+#endif
+    mg_printf(conn, "</body>\n</html>\n");
+    return 1;
+}
+
+
+#ifdef USE_WEBSOCKET
+#define MAX_WS_CLIENTS 1024
+static struct mg_connection * ws_clients[MAX_WS_CLIENTS];
+static unsigned long cnt;
+
+int WebSocketConnectHandler(const struct mg_connection * conn, void *cbdata)
+{
+    int reject = 0;
+    fprintf(stdout, "Websocket client %s\r\n\r\n", reject ? "rejected" : "accepted");
+    return reject;
+}
+
+void WebSocketReadyHandler(struct mg_connection * conn, void *cbdata)
+{
+    struct mg_context *ctx = mg_get_context(conn);
+    int i;
+
+    const char * text = "Hello from the websocket ready handler";
+    mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, text, strlen(text));
+    fprintf(stdout, "Client added to the set of webserver connections\r\n\r\n");
+    mg_lock_context(ctx);
+    for (i=0; i<MAX_WS_CLIENTS; i++) {
+        if (ws_clients[i] == NULL) {
+            ws_clients[i] = conn;
+            break;
+        }
+    }
+    mg_unlock_context(ctx);
+}
+
+int WebsocketDataHandler(struct mg_connection * conn, int bits, char * data, size_t len, void *cbdata)
 {
 {
+    fprintf(stdout, "Websocket got data:\r\n");
+    fwrite(data, len, 1, stdout);
+    fprintf(stdout, "\r\n\r\n");
+
+    return 1;
+}
 
 
+void WebSocketCloseHandler(const struct mg_connection * conn, void *cbdata)
+{
+    struct mg_context *ctx = mg_get_context((struct mg_connection *) /* TODO: check const_casts */ conn);
+    int i;
+
+    mg_lock_context(ctx);
+    for (i=0; i<MAX_WS_CLIENTS; i++) {
+        if (ws_clients[i] == conn) {
+            ws_clients[i] = NULL;
+            break;
+        }
+    }
+    mg_unlock_context(ctx);
+    fprintf(stdout, "Client droped from the set of webserver connections\r\n\r\n");
+}
+
+void InformWebsockets(struct mg_context *ctx)
+{
+    char text[32];
+    int i;
+
+    sprintf(text, "%lu", ++cnt);
+
+    mg_lock_context(ctx);
+    for (i=0; i<MAX_WS_CLIENTS; i++) {
+        if (ws_clients[i] != NULL) {
+            mg_websocket_write(ws_clients[i], WEBSOCKET_OPCODE_TEXT, text, strlen(text));
+        }
+    }
+    mg_unlock_context(ctx);
+}
+#endif
+
+
+int main(int argc, char *argv[])
+{
     const char * options[] = { "document_root", DOCUMENT_ROOT,
     const char * options[] = { "document_root", DOCUMENT_ROOT,
                                "listening_ports", PORT, 0
                                "listening_ports", PORT, 0
                              };
                              };
@@ -88,11 +204,13 @@ int main(int argc, char *argv[])
     memset(&callbacks, 0, sizeof(callbacks));
     memset(&callbacks, 0, sizeof(callbacks));
     ctx = mg_start(&callbacks, 0, options);
     ctx = mg_start(&callbacks, 0, options);
 
 
-    mg_set_request_handler(ctx,EXAMPLE_URI, ExampleHandler,0);
-    mg_set_request_handler(ctx,EXIT_URI, ExitHandler,0);
-    mg_set_request_handler(ctx,"/a", AHandler,0);
-    mg_set_request_handler(ctx,"/a/b", ABHandler,0);
-    mg_set_request_handler(ctx,"**.foo$", FooHandler,0);
+    mg_set_request_handler(ctx, EXAMPLE_URI, ExampleHandler, 0);
+    mg_set_request_handler(ctx, EXIT_URI, ExitHandler, 0);
+    mg_set_request_handler(ctx, "/a", AHandler, 0);
+    mg_set_request_handler(ctx, "/a/b", ABHandler, 0);
+    mg_set_request_handler(ctx, "**.foo$", FooHandler, 0);
+    mg_set_request_handler(ctx, "/websocket", WebSocketStartHandler, 0);
+    mg_set_websocket_handler(ctx, "/websocket", WebSocketConnectHandler, WebSocketReadyHandler, WebsocketDataHandler, WebSocketCloseHandler, 0);
 
 
     printf("Browse files at http://localhost:%s/\n", PORT);
     printf("Browse files at http://localhost:%s/\n", PORT);
     printf("Run example at http://localhost:%s%s\n", PORT, EXAMPLE_URI);
     printf("Run example at http://localhost:%s%s\n", PORT, EXAMPLE_URI);
@@ -104,6 +222,9 @@ int main(int argc, char *argv[])
 #else
 #else
         sleep(1);
         sleep(1);
 #endif
 #endif
+#ifdef USE_WEBSOCKET
+        InformWebsockets(ctx);
+#endif
     }
     }
 
 
     mg_stop(ctx);
     mg_stop(ctx);

+ 18 - 9
examples/embedded_cpp/embedded_cpp.cpp

@@ -26,9 +26,9 @@ public:
         mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
         mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
         mg_printf(conn, "<html><body>\r\n");
         mg_printf(conn, "<html><body>\r\n");
         mg_printf(conn, "<h2>This is an example text from a C++ handler</h2>\r\n");
         mg_printf(conn, "<h2>This is an example text from a C++ handler</h2>\r\n");
-        mg_printf(conn, "<p>To see a page from the A handler <a href=\"A\">click here</a></p>\r\n");
-        mg_printf(conn, "<p>To see a page from the A handler with a parameter <a href=\"A?param=1\">click here</a></p>\r\n");
-        mg_printf(conn, "<p>To see a page from the A/B handler <a href=\"A/B\">click here</a></p>\r\n");
+        mg_printf(conn, "<p>To see a page from the A handler <a href=\"a\">click here</a></p>\r\n");
+        mg_printf(conn, "<p>To see a page from the A handler with a parameter <a href=\"a?param=1\">click here</a></p>\r\n");
+        mg_printf(conn, "<p>To see a page from the A/B handler <a href=\"a/b\">click here</a></p>\r\n");
         mg_printf(conn, "<p>To see a page from the *.foo handler <a href=\"xy.foo\">click here</a></p>\r\n");
         mg_printf(conn, "<p>To see a page from the *.foo handler <a href=\"xy.foo\">click here</a></p>\r\n");
         mg_printf(conn, "<p>To exit <a href=\"%s\">click here</a></p>\r\n", EXIT_URI);
         mg_printf(conn, "<p>To exit <a href=\"%s\">click here</a></p>\r\n", EXIT_URI);
         mg_printf(conn, "</body></html>\r\n");
         mg_printf(conn, "</body></html>\r\n");
@@ -89,7 +89,7 @@ class FooHandler: public CivetHandler
 public:
 public:
     bool handleGet(CivetServer *server, struct mg_connection *conn) {
     bool handleGet(CivetServer *server, struct mg_connection *conn) {
         /* Handler may access the request info using mg_get_request_info */
         /* Handler may access the request info using mg_get_request_info */
-        struct mg_request_info * req_info = mg_get_request_info(conn);
+        const struct mg_request_info * req_info = mg_get_request_info(conn);
 
 
         mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
         mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
         mg_printf(conn, "<html><body>");
         mg_printf(conn, "<html><body>");
@@ -111,11 +111,20 @@ int main(int argc, char *argv[])
 
 
     CivetServer server(options);
     CivetServer server(options);
 
 
-    server.addHandler(EXAMPLE_URI, new ExampleHandler());
-    server.addHandler(EXIT_URI, new ExitHandler());
-    server.addHandler("/a", new AHandler());
-    server.addHandler("/a/b", new ABHandler());
-    server.addHandler("**.foo$", new FooHandler());
+    ExampleHandler h_ex;
+    server.addHandler(EXAMPLE_URI, h_ex);
+
+    ExitHandler h_exit;
+    server.addHandler(EXIT_URI, h_exit);
+
+    AHandler h_a;
+    server.addHandler("/a", h_a);
+
+    ABHandler h_ab;
+    server.addHandler("/a/b", h_ab);
+
+    FooHandler h_foo;
+    server.addHandler("**.foo$", h_foo);
 
 
     printf("Browse files at http://localhost:%s/\n", PORT);
     printf("Browse files at http://localhost:%s/\n", PORT);
     printf("Run example at http://localhost:%s%s\n", PORT, EXAMPLE_URI);
     printf("Run example at http://localhost:%s%s\n", PORT, EXAMPLE_URI);

+ 16 - 11
examples/websocket/WebSockCallbacks.c

@@ -1,3 +1,8 @@
+/* This example uses deprecated interfaces: global websocket callbacks.
+   They have been superseeded by URI specific callbacks.
+   See examples/embedded_c for an up to date example.
+   */
+
 #include <assert.h>
 #include <assert.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <time.h>
 #include <time.h>
@@ -32,13 +37,13 @@ static void send_to_all_websockets(struct mg_context *ctx, const char * data, in
 void websocket_ready_handler(struct mg_connection *conn) {
 void websocket_ready_handler(struct mg_connection *conn) {
 
 
     int i;
     int i;
-    struct mg_request_info * rq = mg_get_request_info(conn);
+    const struct mg_request_info * rq = mg_get_request_info(conn);
     struct mg_context * ctx = mg_get_context(conn);
     struct mg_context * ctx = mg_get_context(conn);
     tWebSockContext *ws_ctx = (tWebSockContext*) mg_get_user_data(ctx);
     tWebSockContext *ws_ctx = (tWebSockContext*) mg_get_user_data(ctx);
     tWebSockInfo * wsock = malloc(sizeof(tWebSockInfo));
     tWebSockInfo * wsock = malloc(sizeof(tWebSockInfo));
     assert(wsock);
     assert(wsock);
     wsock->webSockState = 0;
     wsock->webSockState = 0;
-    rq->conn_data = wsock;
+    mg_set_user_connection_data(conn, wsock);
 
 
     mg_lock_context(ctx);
     mg_lock_context(ctx);
     for (i=0;i<MAX_NUM_OF_WEBSOCKS;i++) {
     for (i=0;i<MAX_NUM_OF_WEBSOCKS;i++) {
@@ -74,7 +79,7 @@ static void websocket_done(tWebSockContext *ws_ctx, tWebSockInfo * wsock) {
 
 
 int websocket_data_handler(struct mg_connection *conn, int flags, char *data, size_t data_len) {
 int websocket_data_handler(struct mg_connection *conn, int flags, char *data, size_t data_len) {
 
 
-    struct mg_request_info * rq = mg_get_request_info(conn);
+    const struct mg_request_info * rq = mg_get_request_info(conn);
     tWebSockInfo * wsock = (tWebSockInfo*)rq->conn_data;
     tWebSockInfo * wsock = (tWebSockInfo*)rq->conn_data;
     struct mg_context * ctx = mg_get_context(conn);
     struct mg_context * ctx = mg_get_context(conn);
     tWebSockContext *ws_ctx = (tWebSockContext*) mg_get_user_data(ctx);
     tWebSockContext *ws_ctx = (tWebSockContext*) mg_get_user_data(ctx);
@@ -84,7 +89,7 @@ int websocket_data_handler(struct mg_connection *conn, int flags, char *data, si
     if (flags==136) {
     if (flags==136) {
         // close websock
         // close websock
         websocket_done(ws_ctx, wsock);
         websocket_done(ws_ctx, wsock);
-        rq->conn_data = 0;
+        mg_set_user_connection_data(conn, NULL);
         mg_unlock_context(ctx);
         mg_unlock_context(ctx);
         return 1;
         return 1;
     }
     }
@@ -124,16 +129,16 @@ int websocket_data_handler(struct mg_connection *conn, int flags, char *data, si
 }
 }
 
 
 
 
-void connection_close_handler(struct mg_connection *conn) {
+void connection_close_handler(const struct mg_connection *conn) {
 
 
-    struct mg_request_info * rq = mg_get_request_info(conn);
+    const struct mg_request_info * rq = mg_get_request_info(conn);
     tWebSockInfo * wsock = (tWebSockInfo*)rq->conn_data;
     tWebSockInfo * wsock = (tWebSockInfo*)rq->conn_data;
     struct mg_context * ctx = mg_get_context(conn);
     struct mg_context * ctx = mg_get_context(conn);
     tWebSockContext *ws_ctx = (tWebSockContext*) mg_get_user_data(ctx);
     tWebSockContext *ws_ctx = (tWebSockContext*) mg_get_user_data(ctx);
 
 
     mg_lock_context(ctx);
     mg_lock_context(ctx);
     websocket_done(ws_ctx, wsock);
     websocket_done(ws_ctx, wsock);
-    rq->conn_data = 0;
+    mg_set_user_connection_data(conn, NULL);
     mg_unlock_context(ctx);
     mg_unlock_context(ctx);
 }
 }
 
 
@@ -169,15 +174,15 @@ void websock_send_broadcast(struct mg_context *ctx, const char * data, int data_
     }
     }
 }
 }
 
 
-void websock_init_lib(struct mg_context *ctx) {
+void websock_init_lib(const struct mg_context *ctx) {
 
 
     tWebSockContext *ws_ctx = (tWebSockContext*) mg_get_user_data(ctx);
     tWebSockContext *ws_ctx = (tWebSockContext*) mg_get_user_data(ctx);
-    memset(ws_ctx,0,sizeof(*ws_ctx));
+    memset(ws_ctx, 0, sizeof(*ws_ctx));
     /* todo: use mg_start_thread_id instead of mg_start_thread */
     /* todo: use mg_start_thread_id instead of mg_start_thread */
-    mg_start_thread(eventMain, ctx);
+    mg_start_thread(eventMain, (void*)ctx);
 }
 }
 
 
-void websock_exit_lib(struct mg_context *ctx) {
+void websock_exit_lib(const struct mg_context *ctx) {
 
 
     tWebSockContext *ws_ctx = (tWebSockContext*) mg_get_user_data(ctx);
     tWebSockContext *ws_ctx = (tWebSockContext*) mg_get_user_data(ctx);
     ws_ctx->runLoop = 0;
     ws_ctx->runLoop = 0;

+ 3 - 3
examples/websocket/WebSockCallbacks.h

@@ -22,14 +22,14 @@ typedef struct tWebSockContext {
 } tWebSockContext;
 } tWebSockContext;
 
 
 
 
-void websock_init_lib(struct mg_context *ctx);
-void websock_exit_lib(struct mg_context *ctx);
+void websock_init_lib(const struct mg_context *ctx);
+void websock_exit_lib(const struct mg_context *ctx);
 
 
 void websock_send_broadcast(struct mg_context *ctx, const char * data, int data_len);
 void websock_send_broadcast(struct mg_context *ctx, const char * data, int data_len);
 
 
 void websocket_ready_handler(struct mg_connection *conn);
 void websocket_ready_handler(struct mg_connection *conn);
 int websocket_data_handler(struct mg_connection *conn, int flags, char *data, size_t data_len);
 int websocket_data_handler(struct mg_connection *conn, int flags, char *data, size_t data_len);
-void connection_close_handler(struct mg_connection *conn);
+void connection_close_handler(const struct mg_connection *conn);
 
 
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus

+ 5 - 0
examples/websocket/websocket.c

@@ -1,3 +1,8 @@
+/* This example uses deprecated interfaces: global websocket callbacks.
+   They have been superseeded by URI specific callbacks.
+   See examples/embedded_c for an up to date example.
+   */
+
 #include <stdio.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <ctype.h>
 #include <string.h>
 #include <string.h>

+ 4 - 4
examples/websocket_client/websocket_client.c

@@ -1,5 +1,5 @@
 /*
 /*
-* Copyright (c) 2014 the Civetweb developers
+* Copyright (c) 2014-2015 the Civetweb developers
 * Copyright (c) 2014 Jordan Shelley
 * Copyright (c) 2014 Jordan Shelley
 * https://github.com/jshelley
 * https://github.com/jshelley
 * License http://opensource.org/licenses/mit-license.php MIT License
 * License http://opensource.org/licenses/mit-license.php MIT License
@@ -67,7 +67,7 @@ int websocket_server_data(struct mg_connection * conn, int bits, char *data, siz
     return 1; /* return 1 to keep the connetion open */
     return 1; /* return 1 to keep the connetion open */
 }
 }
 
 
-void websocket_server_connection_close(struct mg_connection * conn)
+void websocket_server_connection_close(const struct mg_connection * conn)
 {
 {
     printf("Server: Close connection\n");
     printf("Server: Close connection\n");
 
 
@@ -105,7 +105,7 @@ struct tclient_data {
     int closed;
     int closed;
 };
 };
 
 
-static int websocket_client_data_handler(struct mg_connection *conn, int flags, char *data, size_t data_len)
+static int websocket_client_data_handler(struct mg_connection *conn, int flags, char *data, size_t data_len, void * user_data)
 {
 {
     struct mg_context *ctx = mg_get_context(conn);
     struct mg_context *ctx = mg_get_context(conn);
     struct tclient_data *pclient_data = (struct tclient_data *) mg_get_user_data(ctx);
     struct tclient_data *pclient_data = (struct tclient_data *) mg_get_user_data(ctx);
@@ -122,7 +122,7 @@ static int websocket_client_data_handler(struct mg_connection *conn, int flags,
     return 1;
     return 1;
 }
 }
 
 
-static void websocket_client_close_handler(struct mg_connection *conn)
+static void websocket_client_close_handler(const struct mg_connection *conn, void * user_data)
 {
 {
     struct mg_context *ctx = mg_get_context(conn);
     struct mg_context *ctx = mg_get_context(conn);
     struct tclient_data *pclient_data = (struct tclient_data *) mg_get_user_data(ctx);
     struct tclient_data *pclient_data = (struct tclient_data *) mg_get_user_data(ctx);

+ 11 - 8
include/CivetServer.h

@@ -20,7 +20,7 @@ class CivetServer;
 /**
 /**
  * Exception class for thrown exceptions within the CivetHandler object.
  * Exception class for thrown exceptions within the CivetHandler object.
  */
  */
-class CivetException : public std::runtime_error
+class CIVETWEB_API CivetException : public std::runtime_error
 {
 {
     public:
     public:
     CivetException(const std::string& msg) : std::runtime_error(msg) {}
     CivetException(const std::string& msg) : std::runtime_error(msg) {}
@@ -30,7 +30,7 @@ class CivetException : public std::runtime_error
  * Basic interface for a URI request handler.  Handlers implementations
  * Basic interface for a URI request handler.  Handlers implementations
  * must be reentrant.
  * must be reentrant.
  */
  */
-class CivetHandler
+class CIVETWEB_API CivetHandler
 {
 {
 public:
 public:
 
 
@@ -91,7 +91,7 @@ public:
  *
  *
  * Basic class for embedded web server.  This has an URL mapping built-in.
  * Basic class for embedded web server.  This has an URL mapping built-in.
  */
  */
-class CivetServer
+class CIVETWEB_API CivetServer
 {
 {
 public:
 public:
 
 
@@ -139,11 +139,14 @@ public:
      * URI's are ordered and prefix (REST) URI's are supported.
      * URI's are ordered and prefix (REST) URI's are supported.
      *
      *
      *  @param uri - URI to match.
      *  @param uri - URI to match.
-     *  @param handler - handler instance to use.  This will be free'ed
-     *      when the server closes and instances cannot be reused.
+     *  @param handler - handler instance to use.
      */
      */
     void addHandler(const std::string &uri, CivetHandler *handler);
     void addHandler(const std::string &uri, CivetHandler *handler);
 
 
+    void addHandler(const std::string &uri, CivetHandler &handler) {
+        addHandler(uri, &handler);
+    }
+
     /**
     /**
      * removeHandler(const std::string &)
      * removeHandler(const std::string &)
      *
      *
@@ -160,7 +163,7 @@ public:
      *
      *
      * @return A vector of ports
      * @return A vector of ports
      */
      */
-    
+
     std::vector<int> getListeningPorts();
     std::vector<int> getListeningPorts();
 
 
     /**
     /**
@@ -341,12 +344,12 @@ private:
      *
      *
      * @param conn - the connection information
      * @param conn - the connection information
      */
      */
-    static void closeHandler(struct mg_connection *conn);
+    static void closeHandler(const struct mg_connection *conn);
 
 
     /**
     /**
      * Stores the user provided close handler
      * Stores the user provided close handler
      */
      */
-    void (*userCloseHandler)(struct mg_connection *conn);
+    void (*userCloseHandler)(const struct mg_connection *conn);
 
 
 };
 };
 
 

+ 68 - 20
include/civetweb.h

@@ -23,9 +23,7 @@
 #ifndef CIVETWEB_HEADER_INCLUDED
 #ifndef CIVETWEB_HEADER_INCLUDED
 #define CIVETWEB_HEADER_INCLUDED
 #define CIVETWEB_HEADER_INCLUDED
 
 
-#ifndef CIVETWEB_VERSION
 #define CIVETWEB_VERSION "1.7"
 #define CIVETWEB_VERSION "1.7"
-#endif
 
 
 #ifndef CIVETWEB_API
 #ifndef CIVETWEB_API
     #if defined(_WIN32)
     #if defined(_WIN32)
@@ -120,11 +118,13 @@ struct mg_callbacks {
     /* Called when websocket request is received, before websocket handshake.
     /* Called when websocket request is received, before websocket handshake.
        Return value:
        Return value:
          0: civetweb proceeds with websocket handshake.
          0: civetweb proceeds with websocket handshake.
-         1: connection is closed immediately. */
+         1: connection is closed immediately.
+       This callback is deprecated, use mg_set_websocket_handler instead. */
     int (*websocket_connect)(const struct mg_connection *);
     int (*websocket_connect)(const struct mg_connection *);
 
 
     /* Called when websocket handshake is successfully completed, and
     /* Called when websocket handshake is successfully completed, and
-       connection is ready for data exchange. */
+       connection is ready for data exchange.
+       This callback is deprecated, use mg_set_websocket_handler instead. */
     void (*websocket_ready)(struct mg_connection *);
     void (*websocket_ready)(struct mg_connection *);
 
 
     /* Called when data frame has been received from the client.
     /* Called when data frame has been received from the client.
@@ -134,15 +134,18 @@ struct mg_callbacks {
          data, data_len: payload, with mask (if any) already applied.
          data, data_len: payload, with mask (if any) already applied.
        Return value:
        Return value:
          1: keep this websocket connection open.
          1: keep this websocket connection open.
-         0: close this websocket connection. */
+         0: close this websocket connection.
+       This callback is deprecated, use mg_set_websocket_handler instead. */
     int  (*websocket_data)(struct mg_connection *, int bits,
     int  (*websocket_data)(struct mg_connection *, int bits,
                            char *data, size_t data_len);
                            char *data, size_t data_len);
 
 
     /* Called when civetweb is closing a connection.  The per-context mutex is
     /* Called when civetweb is closing a connection.  The per-context mutex is
        locked when this is invoked.  This is primarily useful for noting when
        locked when this is invoked.  This is primarily useful for noting when
        a websocket is closing and removing it from any application-maintained
        a websocket is closing and removing it from any application-maintained
-       list of clients. */
-    void (*connection_close)(struct mg_connection *);
+       list of clients.
+       Using this callback for websocket connections is deprecated, use
+       mg_set_websocket_handler instead. */
+    void (*connection_close)(const struct mg_connection *);
 
 
     /* Called when civetweb tries to open a file. Used to intercept file open
     /* Called when civetweb tries to open a file. Used to intercept file open
        calls, and serve file data from memory instead.
        calls, and serve file data from memory instead.
@@ -161,7 +164,7 @@ struct mg_callbacks {
        Lua support is enabled.
        Lua support is enabled.
        Parameters:
        Parameters:
          lua_context: "lua_State *" pointer. */
          lua_context: "lua_State *" pointer. */
-    void (*init_lua)(struct mg_connection *, void *lua_context);
+    void (*init_lua)(const struct mg_connection *, void *lua_context);
 
 
     /* Called when civetweb has uploaded a file to a temporary directory as a
     /* Called when civetweb has uploaded a file to a temporary directory as a
        result of mg_upload() call.
        result of mg_upload() call.
@@ -182,12 +185,12 @@ struct mg_callbacks {
        are processed.
        are processed.
        Parameters:
        Parameters:
          ctx: context handle */
          ctx: context handle */
-    void (*init_context)(struct mg_context * ctx);
+    void (*init_context)(const struct mg_context * ctx);
 
 
     /* Called when civetweb context is deleted.
     /* Called when civetweb context is deleted.
        Parameters:
        Parameters:
          ctx: context handle */
          ctx: context handle */
-    void (*exit_context)(struct mg_context * ctx);
+    void (*exit_context)(const struct mg_context * ctx);
 };
 };
 
 
 
 
@@ -264,6 +267,48 @@ typedef int (* mg_request_handler)(struct mg_connection *conn, void *cbdata);
       cbdata: the callback data to give to the handler when it is called. */
       cbdata: the callback data to give to the handler when it is called. */
 CIVETWEB_API void mg_set_request_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata);
 CIVETWEB_API void mg_set_request_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata);
 
 
+/* Callback types for websocket handlers in C/C++.
+
+   mg_websocket_connect_handler
+       Is called when the client intends to establish a websocket connection,
+       before websocket handshake.
+       Return value:
+         0: civetweb proceeds with websocket handshake.
+         1: connection is closed immediately.
+
+   mg_websocket_ready_handler
+       Is called when websocket handshake is successfully completed, and
+       connection is ready for data exchange.
+
+   mg_websocket_data_handler
+       Is called when a data frame has been received from the client.
+       Parameters:
+         bits: first byte of the websocket frame, see websocket RFC at
+               http://tools.ietf.org/html/rfc6455, section 5.2
+         data, data_len: payload, with mask (if any) already applied.
+       Return value:
+         1: keep this websocket connection open.
+         0: close this websocket connection.
+
+   mg_connection_close_handler
+       Is called, when the connection is closed.*/
+typedef int  (*mg_websocket_connect_handler)(const struct mg_connection *, void *);
+typedef void (*mg_websocket_ready_handler)(struct mg_connection *, void *);
+typedef int  (*mg_websocket_data_handler)(struct mg_connection *, int, char *, size_t, void *);
+typedef void (*mg_websocket_close_handler)(const struct mg_connection *, void *);
+
+/* mg_set_websocket_handler
+
+   Set or remove handler functions for websocket connections.
+   This function works similar to mg_set_request_handler - see there. */
+CIVETWEB_API void mg_set_websocket_handler(struct mg_context *ctx,
+                                           const char *uri,
+                                           mg_websocket_connect_handler connect_handler,
+                                           mg_websocket_ready_handler ready_handler,
+                                           mg_websocket_data_handler data_handler,
+                                           mg_websocket_close_handler close_handler,
+                                           void *cbdata
+                                           );
 
 
 /* Get the value of particular configuration parameter.
 /* Get the value of particular configuration parameter.
    The value returned is read-only. Civetweb does not allow changing
    The value returned is read-only. Civetweb does not allow changing
@@ -275,11 +320,19 @@ CIVETWEB_API const char *mg_get_option(const struct mg_context *ctx, const char
 
 
 
 
 /* Get context from connection. */
 /* Get context from connection. */
-CIVETWEB_API struct mg_context *mg_get_context(struct mg_connection *conn);
+CIVETWEB_API struct mg_context *mg_get_context(const struct mg_connection *conn);
 
 
 
 
 /* Get user data passed to mg_start from context. */
 /* Get user data passed to mg_start from context. */
-CIVETWEB_API void *mg_get_user_data(struct mg_context *ctx);
+CIVETWEB_API void *mg_get_user_data(const struct mg_context *ctx);
+
+
+/* Set user data for the current connection. */
+CIVETWEB_API void mg_set_user_connection_data(const struct mg_connection *conn, void *data);
+
+
+/* Get user data set for the current connection. */
+CIVETWEB_API void *mg_get_user_connection_data(const struct mg_connection *conn);
 
 
 
 
 #if defined(MG_LEGACY_INTERFACE)
 #if defined(MG_LEGACY_INTERFACE)
@@ -344,7 +397,7 @@ CIVETWEB_API int mg_modify_passwords_file(const char *passwords_file_name,
 
 
 
 
 /* Return information associated with the request. */
 /* Return information associated with the request. */
-CIVETWEB_API struct mg_request_info *mg_get_request_info(struct mg_connection *);
+CIVETWEB_API const struct mg_request_info *mg_get_request_info(const struct mg_connection *);
 
 
 
 
 /* Send data to the client.
 /* Send data to the client.
@@ -591,7 +644,7 @@ CIVETWEB_API char *mg_md5(char buf[33], ...);
      ...: variable argument list
      ...: variable argument list
    Example:
    Example:
      mg_cry(conn,"i like %s", "logging"); */
      mg_cry(conn,"i like %s", "logging"); */
-CIVETWEB_API void mg_cry(struct mg_connection *conn,
+CIVETWEB_API void mg_cry(const struct mg_connection *conn,
                          PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
                          PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
 
 
 
 
@@ -615,15 +668,10 @@ CIVETWEB_API int mg_strncasecmp(const char *s1, const char *s2, size_t len);
      On error, NULL. Se error_buffer for details.
      On error, NULL. Se error_buffer for details.
 */
 */
 
 
-typedef int  (*websocket_data_func)(struct mg_connection *, int bits,
-                           char *data, size_t data_len);
-
-typedef void (*websocket_close_func)(struct mg_connection *);
-
 CIVETWEB_API struct mg_connection *mg_connect_websocket_client(const char *host, int port, int use_ssl,
 CIVETWEB_API struct mg_connection *mg_connect_websocket_client(const char *host, int port, int use_ssl,
                                                char *error_buffer, size_t error_buffer_size,
                                                char *error_buffer, size_t error_buffer_size,
                                                const char *path, const char *origin,
                                                const char *path, const char *origin,
-                                               websocket_data_func data_func, websocket_close_func close_func,
+                                               mg_websocket_data_handler data_func, mg_websocket_close_handler close_func,
                                                void * user_data);
                                                void * user_data);
 
 
 
 

+ 5 - 5
src/CivetServer.cpp

@@ -52,7 +52,7 @@ bool CivetHandler::handleOptions(CivetServer *server, struct mg_connection *conn
 
 
 int CivetServer::requestHandler(struct mg_connection *conn, void *cbdata)
 int CivetServer::requestHandler(struct mg_connection *conn, void *cbdata)
 {
 {
-    struct mg_request_info *request_info = mg_get_request_info(conn);
+    const struct mg_request_info *request_info = mg_get_request_info(conn);
     assert(request_info != NULL);
     assert(request_info != NULL);
     CivetServer *me = (CivetServer*) (request_info->user_data);
     CivetServer *me = (CivetServer*) (request_info->user_data);
     assert(me != NULL);
     assert(me != NULL);
@@ -106,9 +106,9 @@ CivetServer::~CivetServer()
     close();
     close();
 }
 }
 
 
-void CivetServer::closeHandler(struct mg_connection *conn)
+void CivetServer::closeHandler(const struct mg_connection *conn)
 {
 {
-    struct mg_request_info *request_info = mg_get_request_info(conn);
+    const struct mg_request_info *request_info = mg_get_request_info(conn);
     assert(request_info != NULL);
     assert(request_info != NULL);
     CivetServer *me = (CivetServer*) (request_info->user_data);
     CivetServer *me = (CivetServer*) (request_info->user_data);
     assert(me != NULL);
     assert(me != NULL);
@@ -118,7 +118,7 @@ void CivetServer::closeHandler(struct mg_connection *conn)
 
 
     if (me->userCloseHandler) me->userCloseHandler(conn);
     if (me->userCloseHandler) me->userCloseHandler(conn);
     mg_lock_context(me->context);
     mg_lock_context(me->context);
-    me->connections.erase(conn);
+    me->connections.erase(const_cast<struct mg_connection *>(conn));
     mg_unlock_context(me->context);
     mg_unlock_context(me->context);
 }
 }
 
 
@@ -190,7 +190,7 @@ CivetServer::getParam(struct mg_connection *conn, const char *name,
                       std::string &dst, size_t occurrence)
                       std::string &dst, size_t occurrence)
 {
 {
     const char *formParams = NULL;
     const char *formParams = NULL;
-    struct mg_request_info *ri = mg_get_request_info(conn);
+    const struct mg_request_info *ri = mg_get_request_info(conn);
     assert(ri != NULL);
     assert(ri != NULL);
     CivetServer *me = (CivetServer*) (ri->user_data);
     CivetServer *me = (CivetServer*) (ri->user_data);
     assert(me != NULL);
     assert(me != NULL);

File diff suppressed because it is too large
+ 446 - 152
src/civetweb.c


+ 113 - 74
src/main.c

@@ -21,7 +21,12 @@
 */
 */
 
 
 #if defined(_WIN32)
 #if defined(_WIN32)
+#ifndef _CRT_SECURE_NO_WARNINGS
 #define _CRT_SECURE_NO_WARNINGS  /* Disable deprecation warning in VS2005 */
 #define _CRT_SECURE_NO_WARNINGS  /* Disable deprecation warning in VS2005 */
+#endif
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
 #else
 #else
 #define _XOPEN_SOURCE 600  /* For PATH_MAX on linux */
 #define _XOPEN_SOURCE 600  /* For PATH_MAX on linux */
 #endif
 #endif
@@ -48,6 +53,7 @@
 #ifndef _WIN32_WINNT
 #ifndef _WIN32_WINNT
 #define _WIN32_WINNT 0x0501 /* Target Windows XP or higher */
 #define _WIN32_WINNT 0x0501 /* Target Windows XP or higher */
 #endif
 #endif
+#undef UNICODE
 #include <windows.h>
 #include <windows.h>
 #include <winsvc.h>
 #include <winsvc.h>
 #include <shlobj.h>
 #include <shlobj.h>
@@ -59,6 +65,11 @@ extern char *_getcwd(char *buf, size_t size);
 #endif
 #endif
 static int guard = 0;                   /* test if any dialog is already open */
 static int guard = 0;                   /* test if any dialog is already open */
 
 
+#if defined (_MSC_VER)
+#define strdup _strdup
+/* or #pragma warning (disable : 4996 ) */
+#endif
+
 #ifndef PATH_MAX
 #ifndef PATH_MAX
 #define PATH_MAX MAX_PATH
 #define PATH_MAX MAX_PATH
 #endif
 #endif
@@ -84,12 +95,17 @@ static int guard = 0;                   /* test if any dialog is already open */
 #define MAX_OPTIONS 50
 #define MAX_OPTIONS 50
 #define MAX_CONF_FILE_LINE_SIZE (8 * 1024)
 #define MAX_CONF_FILE_LINE_SIZE (8 * 1024)
 
 
-static int exit_flag = 0;               /* Main loop should exit */
-static char server_base_name[40];       /* Set by init_server_name() */
-static char *server_name;               /* Set by init_server_name() */
-static char *icon_name;                 /* Set by init_server_name() */
-static char config_file[PATH_MAX] = ""; /* Set by process_command_line_arguments() */
-static struct mg_context *ctx;          /* Set by start_civetweb() */
+struct tuser_data {
+    char * first_message;
+};
+
+static int g_exit_flag = 0;               /* Main loop should exit */
+static char g_server_base_name[40];       /* Set by init_server_name() */
+static char *g_server_name;               /* Set by init_server_name() */
+static char *g_icon_name;                 /* Set by init_server_name() */
+static char g_config_file[PATH_MAX] = ""; /* Set by process_command_line_arguments() */
+static struct mg_context *g_ctx;          /* Set by start_civetweb() */
+static struct tuser_data g_user_data;     /* Passed to mg_start() by start_civetweb() */
 
 
 #if !defined(CONFIG_FILE)
 #if !defined(CONFIG_FILE)
 #define CONFIG_FILE "civetweb.conf"
 #define CONFIG_FILE "civetweb.conf"
@@ -118,7 +134,7 @@ static struct mg_option main_config_options[] = {
 
 
 static void WINCDECL signal_handler(int sig_num)
 static void WINCDECL signal_handler(int sig_num)
 {
 {
-    exit_flag = sig_num;
+    g_exit_flag = sig_num;
 }
 }
 
 
 static void die(const char *fmt, ...)
 static void die(const char *fmt, ...)
@@ -210,7 +226,7 @@ static const char *get_url_to_first_open_port(const struct mg_context *ctx)
     return url;
     return url;
 }
 }
 
 
-static void create_config_file(const char *path)
+static void create_config_file(const struct mg_context *ctx, const char *path)
 {
 {
     const struct mg_option *options;
     const struct mg_option *options;
     const char *value;
     const char *value;
@@ -408,26 +424,25 @@ static void process_command_line_arguments(char *argv[], char **options)
 
 
     /* Should we use a config file ? */
     /* Should we use a config file ? */
     if (argv[1] != NULL && argv[1][0] != '-') {
     if (argv[1] != NULL && argv[1][0] != '-') {
-        snprintf(config_file, sizeof(config_file), "%s", argv[1]);
+        snprintf(g_config_file, sizeof(g_config_file)-1, "%s", argv[1]);
         cmd_line_opts_start = 2;
         cmd_line_opts_start = 2;
     } else if ((p = strrchr(argv[0], DIRSEP)) == NULL) {
     } else if ((p = strrchr(argv[0], DIRSEP)) == NULL) {
         /* No command line flags specified. Look where binary lives */
         /* No command line flags specified. Look where binary lives */
-        snprintf(config_file, sizeof(config_file)-1, "%s", CONFIG_FILE);
-        config_file[sizeof(config_file)-1] = 0;
+        snprintf(g_config_file, sizeof(g_config_file)-1, "%s", CONFIG_FILE);
     } else {
     } else {
-        snprintf(config_file, sizeof(config_file)-1, "%.*s%c%s",
+        snprintf(g_config_file, sizeof(g_config_file)-1, "%.*s%c%s",
                  (int) (p - argv[0]), argv[0], DIRSEP, CONFIG_FILE);
                  (int) (p - argv[0]), argv[0], DIRSEP, CONFIG_FILE);
-        config_file[sizeof(config_file)-1] = 0;
     }
     }
+    g_config_file[sizeof(g_config_file)-1] = 0;
 
 
 #ifdef CONFIG_FILE2
 #ifdef CONFIG_FILE2
-    fp = fopen(config_file, "r");
+    fp = fopen(g_config_file, "r");
 
 
     /* try alternate config file */
     /* try alternate config file */
     if (fp == NULL) {
     if (fp == NULL) {
         fp = fopen(CONFIG_FILE2, "r");
         fp = fopen(CONFIG_FILE2, "r");
         if (fp != NULL) {
         if (fp != NULL) {
-            strcpy(config_file, CONFIG_FILE2);
+            strcpy(g_config_file, CONFIG_FILE2);
         }
         }
     }
     }
     if (fp != NULL) {
     if (fp != NULL) {
@@ -436,7 +451,7 @@ static void process_command_line_arguments(char *argv[], char **options)
 #endif
 #endif
 
 
     /* read all configurations from a config file */
     /* read all configurations from a config file */
-    (void)read_config_file(config_file, options);
+    (void)read_config_file(g_config_file, options);
 
 
     /* If we're under MacOS and started by launchd, then the second
     /* If we're under MacOS and started by launchd, then the second
        argument is process serial number, -psn_.....
        argument is process serial number, -psn_.....
@@ -460,28 +475,35 @@ static void init_server_name(int argc, const char *argv[])
 {
 {
     int i;
     int i;
     assert(sizeof(main_config_options)/sizeof(main_config_options[0]) == NUM_MAIN_OPTIONS+1);
     assert(sizeof(main_config_options)/sizeof(main_config_options[0]) == NUM_MAIN_OPTIONS+1);
-    assert((strlen(mg_version())+12)<sizeof(server_base_name));
-    snprintf(server_base_name, sizeof(server_base_name), "Civetweb V%s",
+    assert((strlen(mg_version())+12)<sizeof(g_server_base_name));
+    snprintf(g_server_base_name, sizeof(g_server_base_name), "Civetweb V%s",
              mg_version());
              mg_version());
 
 
-    server_name = server_base_name;
+    g_server_name = g_server_base_name;
     for (i=0; i<argc-1; i++) {
     for (i=0; i<argc-1; i++) {
         if ((argv[i][0]=='-') && (0==strcmp(argv[i]+1, main_config_options[OPTION_TITLE].name))) {
         if ((argv[i][0]=='-') && (0==strcmp(argv[i]+1, main_config_options[OPTION_TITLE].name))) {
-            server_name = (char*)(argv[i+1]);
+            g_server_name = (char*)(argv[i+1]);
         }
         }
     }
     }
-    icon_name = NULL;
+    g_icon_name = NULL;
     for (i=0; i<argc-1; i++) {
     for (i=0; i<argc-1; i++) {
         if ((argv[i][0]=='-') && (0==strcmp(argv[i]+1, main_config_options[OPTION_ICON].name))) {
         if ((argv[i][0]=='-') && (0==strcmp(argv[i]+1, main_config_options[OPTION_ICON].name))) {
-            icon_name = (char*)(argv[i+1]);
+            g_icon_name = (char*)(argv[i+1]);
         }
         }
     }
     }
 }
 }
 
 
 static int log_message(const struct mg_connection *conn, const char *message)
 static int log_message(const struct mg_connection *conn, const char *message)
 {
 {
-    (void) conn;
+    const struct mg_context * ctx = mg_get_context(conn);
+    struct tuser_data * ud = (struct tuser_data *) mg_get_user_data(ctx);
+
     printf("%s\n", message);
     printf("%s\n", message);
+
+    if (ud->first_message == NULL) {
+        ud->first_message = strdup(message);
+    }
+
     return 0;
     return 0;
 }
 }
 
 
@@ -514,6 +536,7 @@ static void verify_existence(char **options, const char *option_name,
         len = MultiByteToWideChar(CP_UTF8, 0, path, -1, wbuf, (int) sizeof(wbuf)/sizeof(wbuf[0])-1);
         len = MultiByteToWideChar(CP_UTF8, 0, path, -1, wbuf, (int) sizeof(wbuf)/sizeof(wbuf[0])-1);
         wcstombs(mbbuf, wbuf, sizeof(mbbuf)-1);
         wcstombs(mbbuf, wbuf, sizeof(mbbuf)-1);
         path = mbbuf;
         path = mbbuf;
+        (void)len;
     }
     }
 #endif
 #endif
 
 
@@ -639,19 +662,29 @@ static void start_civetweb(int argc, char *argv[])
     signal(SIGTERM, signal_handler);
     signal(SIGTERM, signal_handler);
     signal(SIGINT, signal_handler);
     signal(SIGINT, signal_handler);
 
 
+    /* Initialize user data */
+    memset(&g_user_data, 0, sizeof(g_user_data));
+
     /* Start Civetweb */
     /* Start Civetweb */
     memset(&callbacks, 0, sizeof(callbacks));
     memset(&callbacks, 0, sizeof(callbacks));
     callbacks.log_message = &log_message;
     callbacks.log_message = &log_message;
-    ctx = mg_start(&callbacks, NULL, (const char **) options);
+    g_ctx = mg_start(&callbacks, &g_user_data, (const char **) options);
     for (i = 0; options[i] != NULL; i++) {
     for (i = 0; options[i] != NULL; i++) {
         free(options[i]);
         free(options[i]);
     }
     }
 
 
-    if (ctx == NULL) {
-        die("%s", "Failed to start Civetweb.");
+    if (g_ctx == NULL) {
+        die("Failed to start Civetweb:\n%s", (g_user_data.first_message == NULL) ? "unknown reason" : g_user_data.first_message);
     }
     }
 }
 }
 
 
+void stop_civetweb(void)
+{
+    mg_stop(g_ctx);
+    free(g_user_data.first_message);
+    g_user_data.first_message = NULL;
+}
+
 #ifdef _WIN32
 #ifdef _WIN32
 enum {
 enum {
     ID_ICON = 100, ID_QUIT, ID_SETTINGS, ID_SEPARATOR, ID_INSTALL_SERVICE,
     ID_ICON = 100, ID_QUIT, ID_SETTINGS, ID_SEPARATOR, ID_INSTALL_SERVICE,
@@ -690,13 +723,13 @@ static void WINAPI ServiceMain(void)
     ss.dwCurrentState = SERVICE_RUNNING;
     ss.dwCurrentState = SERVICE_RUNNING;
     ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
     ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
 
 
-    hStatus = RegisterServiceCtrlHandler(server_name, ControlHandler);
+    hStatus = RegisterServiceCtrlHandler(g_server_name, ControlHandler);
     SetServiceStatus(hStatus, &ss);
     SetServiceStatus(hStatus, &ss);
 
 
     while (ss.dwCurrentState == SERVICE_RUNNING) {
     while (ss.dwCurrentState == SERVICE_RUNNING) {
         Sleep(1000);
         Sleep(1000);
     }
     }
-    mg_stop(ctx);
+    stop_civetweb();
 
 
     ss.dwCurrentState = SERVICE_STOPPED;
     ss.dwCurrentState = SERVICE_STOPPED;
     ss.dwWin32ExitCode = (DWORD) -1;
     ss.dwWin32ExitCode = (DWORD) -1;
@@ -747,7 +780,7 @@ static void save_config(HWND hDlg, FILE *fp)
     }
     }
 }
 }
 
 
-static BOOL CALLBACK SettingsDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
+static BOOL CALLBACK SettingsDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 {
 {
     FILE *fp;
     FILE *fp;
     int i, j;
     int i, j;
@@ -755,6 +788,7 @@ static BOOL CALLBACK SettingsDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM
     const struct mg_option *default_options = mg_get_valid_options();
     const struct mg_option *default_options = mg_get_valid_options();
     char *file_options[MAX_OPTIONS*2+1] = {0};
     char *file_options[MAX_OPTIONS*2+1] = {0};
     char *title;
     char *title;
+    (void)lParam;
 
 
     switch (msg) {
     switch (msg) {
     case WM_CLOSE:
     case WM_CLOSE:
@@ -766,10 +800,10 @@ static BOOL CALLBACK SettingsDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM
 
 
         case ID_SAVE:
         case ID_SAVE:
             EnableWindow(GetDlgItem(hDlg, ID_SAVE), FALSE);
             EnableWindow(GetDlgItem(hDlg, ID_SAVE), FALSE);
-            if ((fp = fopen(config_file, "w+")) != NULL) {
+            if ((fp = fopen(g_config_file, "w+")) != NULL) {
                 save_config(hDlg, fp);
                 save_config(hDlg, fp);
                 fclose(fp);
                 fclose(fp);
-                mg_stop(ctx);
+                stop_civetweb();
                 start_civetweb(__argc, __argv);
                 start_civetweb(__argc, __argv);
             }
             }
             EnableWindow(GetDlgItem(hDlg, ID_SAVE), TRUE);
             EnableWindow(GetDlgItem(hDlg, ID_SAVE), TRUE);
@@ -789,7 +823,7 @@ static BOOL CALLBACK SettingsDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM
             break;
             break;
 
 
         case ID_RESET_FILE:
         case ID_RESET_FILE:
-            read_config_file(config_file, file_options);
+            read_config_file(g_config_file, file_options);
             for (i = 0; default_options[i].name != NULL; i++) {
             for (i = 0; default_options[i].name != NULL; i++) {
                 name = default_options[i].name;
                 name = default_options[i].name;
                 value = default_options[i].default_value;
                 value = default_options[i].default_value;
@@ -816,7 +850,7 @@ static BOOL CALLBACK SettingsDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM
         case ID_RESET_ACTIVE:
         case ID_RESET_ACTIVE:
             for (i = 0; default_options[i].name != NULL; i++) {
             for (i = 0; default_options[i].name != NULL; i++) {
                 name = default_options[i].name;
                 name = default_options[i].name;
-                value = mg_get_option(ctx, name);
+                value = mg_get_option(g_ctx, name);
                 if (default_options[i].type == CONFIG_TYPE_BOOLEAN) {
                 if (default_options[i].type == CONFIG_TYPE_BOOLEAN) {
                     CheckDlgButton(hDlg, ID_CONTROLS + i, !strcmp(value, "yes") ?
                     CheckDlgButton(hDlg, ID_CONTROLS + i, !strcmp(value, "yes") ?
                                    BST_CHECKED : BST_UNCHECKED);
                                    BST_CHECKED : BST_UNCHECKED);
@@ -840,7 +874,7 @@ static BOOL CALLBACK SettingsDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM
                 of.hwndOwner = (HWND) hDlg;
                 of.hwndOwner = (HWND) hDlg;
                 of.lpstrFile = path;
                 of.lpstrFile = path;
                 of.nMaxFile = sizeof(path);
                 of.nMaxFile = sizeof(path);
-                of.lpstrInitialDir = mg_get_option(ctx, "document_root");
+                of.lpstrInitialDir = mg_get_option(g_ctx, "document_root");
                 of.Flags = OFN_CREATEPROMPT | OFN_NOCHANGEDIR | OFN_HIDEREADONLY;
                 of.Flags = OFN_CREATEPROMPT | OFN_NOCHANGEDIR | OFN_HIDEREADONLY;
 
 
                 memset(&bi, 0, sizeof(bi));
                 memset(&bi, 0, sizeof(bi));
@@ -864,9 +898,9 @@ static BOOL CALLBACK SettingsDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM
     case WM_INITDIALOG:
     case WM_INITDIALOG:
         SendMessage(hDlg, WM_SETICON, (WPARAM) ICON_SMALL, (LPARAM) hIcon);
         SendMessage(hDlg, WM_SETICON, (WPARAM) ICON_SMALL, (LPARAM) hIcon);
         SendMessage(hDlg, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM) hIcon);
         SendMessage(hDlg, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM) hIcon);
-        title = malloc(strlen(server_name)+16);
+        title = malloc(strlen(g_server_name)+16);
         if (title) {
         if (title) {
-            strcpy(title, server_name);
+            strcpy(title, g_server_name);
             strcat(title, " settings");
             strcat(title, " settings");
             SetWindowText(hDlg, title);
             SetWindowText(hDlg, title);
             free(title);
             free(title);
@@ -966,7 +1000,6 @@ static int get_password(const char * user, const char * realm, char * passwd, un
 #define WIDTH 280
 #define WIDTH 280
 #define LABEL_WIDTH 90
 #define LABEL_WIDTH 90
 
 
-    HWND hDlg = NULL;
     unsigned char mem[4096], *p;
     unsigned char mem[4096], *p;
     DLGTEMPLATE *dia = (DLGTEMPLATE *) mem;
     DLGTEMPLATE *dia = (DLGTEMPLATE *) mem;
     int ok, y;
     int ok, y;
@@ -1031,7 +1064,7 @@ static int get_password(const char * user, const char * realm, char * passwd, un
         WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP,
         WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP,
         140, y, 55, 12, "Cancel");
         140, y, 55, 12, "Cancel");
 
 
-    assert((int)p - (int)mem < sizeof(mem));
+    assert((int)p - (int)mem < (int)sizeof(mem));
 
 
     dia->cy = y + (WORD)(HEIGHT * 1.5);
     dia->cy = y + (WORD)(HEIGHT * 1.5);
 
 
@@ -1204,7 +1237,7 @@ static void show_settings_dialog()
                     (WORD) (x + LABEL_WIDTH), y, width, 12, "");
                     (WORD) (x + LABEL_WIDTH), y, width, 12, "");
         nelems++;
         nelems++;
 
 
-        assert((int)p - (int)mem < sizeof(mem));
+        assert(((int)p - (int)mem) < (int)sizeof(mem));
     }
     }
 
 
     y = (WORD) (((nelems + 1) / 2 + 1) * HEIGHT + 5);
     y = (WORD) (((nelems + 1) / 2 + 1) * HEIGHT + 5);
@@ -1225,9 +1258,9 @@ static void show_settings_dialog()
                 WIDTH - 280, y, 65, 12, "Reload active");
                 WIDTH - 280, y, 65, 12, "Reload active");
     add_control(&p, dia, 0x82, ID_STATIC,
     add_control(&p, dia, 0x82, ID_STATIC,
                 WS_CHILD | WS_VISIBLE | WS_DISABLED,
                 WS_CHILD | WS_VISIBLE | WS_DISABLED,
-                5, y, 100, 12, server_base_name);
+                5, y, 100, 12, g_server_base_name);
 
 
-    assert((int)p - (int)mem < sizeof(mem));
+    assert(((int)p - (int)mem) < (int)sizeof(mem));
 
 
     dia->cy = ((nelems + 1) / 2 + 1) * HEIGHT + 30;
     dia->cy = ((nelems + 1) / 2 + 1) * HEIGHT + 30;
     DialogBoxIndirectParam(NULL, dia, NULL, SettingsDlgProc, (LPARAM) NULL);
     DialogBoxIndirectParam(NULL, dia, NULL, SettingsDlgProc, (LPARAM) NULL);
@@ -1252,7 +1285,7 @@ static void change_password_file()
     int y, nelems;
     int y, nelems;
     unsigned char mem[4096], *p;
     unsigned char mem[4096], *p;
     DLGTEMPLATE *dia = (DLGTEMPLATE *) mem;
     DLGTEMPLATE *dia = (DLGTEMPLATE *) mem;
-    const char * domain = mg_get_option(ctx, "authentication_domain");
+    const char * domain = mg_get_option(g_ctx, "authentication_domain");
 
 
     static struct {
     static struct {
         DLGTEMPLATE template; /* 18 bytes */
         DLGTEMPLATE template; /* 18 bytes */
@@ -1278,7 +1311,7 @@ static void change_password_file()
     of.hwndOwner = (HWND) hDlg;
     of.hwndOwner = (HWND) hDlg;
     of.lpstrFile = path;
     of.lpstrFile = path;
     of.nMaxFile = sizeof(path);
     of.nMaxFile = sizeof(path);
-    of.lpstrInitialDir = mg_get_option(ctx, "document_root");
+    of.lpstrInitialDir = mg_get_option(g_ctx, "document_root");
     of.Flags = OFN_CREATEPROMPT | OFN_NOCHANGEDIR | OFN_HIDEREADONLY;
     of.Flags = OFN_CREATEPROMPT | OFN_NOCHANGEDIR | OFN_HIDEREADONLY;
 
 
     if (IDOK != GetSaveFileName(&of)) {
     if (IDOK != GetSaveFileName(&of)) {
@@ -1329,7 +1362,7 @@ static void change_password_file()
                 140, y, 100, 12, u);
                 140, y, 100, 12, u);
 
 
             nelems++;
             nelems++;
-            assert((int)p - (int)mem < sizeof(mem));
+            assert(((int)p - (int)mem) < (int)sizeof(mem));
         }
         }
         fclose(f);
         fclose(f);
 
 
@@ -1351,12 +1384,12 @@ static void change_password_file()
         y += HEIGHT;
         y += HEIGHT;
         add_control(&p, dia, 0x82, ID_STATIC,
         add_control(&p, dia, 0x82, ID_STATIC,
             WS_CHILD | WS_VISIBLE | WS_DISABLED,
             WS_CHILD | WS_VISIBLE | WS_DISABLED,
-            5, y, 100, 12, server_base_name);
+            5, y, 100, 12, g_server_base_name);
 
 
-        assert((int)p - (int)mem < sizeof(mem));
+        assert(((int)p - (int)mem) < (int)sizeof(mem));
 
 
         dia->cy = y + 20;
         dia->cy = y + 20;
-    } while ((IDOK == DialogBoxIndirectParam(NULL, dia, NULL, PasswordDlgProc, (LPARAM) path)) && (!exit_flag));
+    } while ((IDOK == DialogBoxIndirectParam(NULL, dia, NULL, PasswordDlgProc, (LPARAM) path)) && (!g_exit_flag));
 
 
     guard--;
     guard--;
 
 
@@ -1369,7 +1402,7 @@ static int manage_service(int action)
 {
 {
     static const char *service_name = "Civetweb"; /* TODO: check using server_name instead of service_name */
     static const char *service_name = "Civetweb"; /* TODO: check using server_name instead of service_name */
     SC_HANDLE hSCM = NULL, hService = NULL;
     SC_HANDLE hSCM = NULL, hService = NULL;
-    SERVICE_DESCRIPTION descr = {server_name};
+    SERVICE_DESCRIPTION descr = {g_server_name};
     char path[PATH_MAX + 20] = "";/* Path to executable plus magic argument */
     char path[PATH_MAX + 20] = "";/* Path to executable plus magic argument */
     int success = 1;
     int success = 1;
 
 
@@ -1412,14 +1445,15 @@ static int manage_service(int action)
 static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
 static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
                                    LPARAM lParam)
                                    LPARAM lParam)
 {
 {
-    static SERVICE_TABLE_ENTRY service_table[2] = {0};
+    static SERVICE_TABLE_ENTRY service_table[2];
     int service_installed;
     int service_installed;
     char buf[200], *service_argv[] = {__argv[0], NULL};
     char buf[200], *service_argv[] = {__argv[0], NULL};
     POINT pt;
     POINT pt;
     HMENU hMenu;
     HMENU hMenu;
     static UINT s_uTaskbarRestart; /* for taskbar creation */
     static UINT s_uTaskbarRestart; /* for taskbar creation */
 
 
-    service_table[0].lpServiceName = server_name;
+    memset(service_table, 0, sizeof(service_table));
+    service_table[0].lpServiceName = g_server_name;
     service_table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
     service_table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
 
 
     switch (msg) {
     switch (msg) {
@@ -1437,9 +1471,9 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
     case WM_COMMAND:
     case WM_COMMAND:
         switch (LOWORD(wParam)) {
         switch (LOWORD(wParam)) {
         case ID_QUIT:
         case ID_QUIT:
-            mg_stop(ctx);
+            stop_civetweb();
             Shell_NotifyIcon(NIM_DELETE, &TrayIcon);
             Shell_NotifyIcon(NIM_DELETE, &TrayIcon);
-            exit_flag = 1;
+            g_exit_flag = 1;
             PostQuitMessage(0);
             PostQuitMessage(0);
             return 0;
             return 0;
         case ID_SETTINGS:
         case ID_SETTINGS:
@@ -1453,8 +1487,8 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
             manage_service(LOWORD(wParam));
             manage_service(LOWORD(wParam));
             break;
             break;
         case ID_CONNECT:
         case ID_CONNECT:
-            printf("[%s]\n", get_url_to_first_open_port(ctx));
-            ShellExecute(NULL, "open", get_url_to_first_open_port(ctx),
+            printf("[%s]\n", get_url_to_first_open_port(g_ctx));
+            ShellExecute(NULL, "open", get_url_to_first_open_port(g_ctx),
                          NULL, NULL, SW_SHOW);
                          NULL, NULL, SW_SHOW);
             break;
             break;
         }
         }
@@ -1465,7 +1499,7 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
         case WM_LBUTTONUP:
         case WM_LBUTTONUP:
         case WM_LBUTTONDBLCLK:
         case WM_LBUTTONDBLCLK:
             hMenu = CreatePopupMenu();
             hMenu = CreatePopupMenu();
-            AppendMenu(hMenu, MF_STRING | MF_GRAYED, ID_SEPARATOR, server_name);
+            AppendMenu(hMenu, MF_STRING | MF_GRAYED, ID_SEPARATOR, g_server_name);
             AppendMenu(hMenu, MF_SEPARATOR, ID_SEPARATOR, "");
             AppendMenu(hMenu, MF_SEPARATOR, ID_SEPARATOR, "");
             service_installed = manage_service(0);
             service_installed = manage_service(0);
             snprintf(buf, sizeof(buf)-1, "NT service: %s installed",
             snprintf(buf, sizeof(buf)-1, "NT service: %s installed",
@@ -1491,9 +1525,9 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
         }
         }
         break;
         break;
     case WM_CLOSE:
     case WM_CLOSE:
-        mg_stop(ctx);
+        stop_civetweb();
         Shell_NotifyIcon(NIM_DELETE, &TrayIcon);
         Shell_NotifyIcon(NIM_DELETE, &TrayIcon);
-        exit_flag = 1;
+        g_exit_flag = 1;
         PostQuitMessage(0);
         PostQuitMessage(0);
         return 0;/* We've just sent our own quit message, with proper hwnd. */
         return 0;/* We've just sent our own quit message, with proper hwnd. */
     default:
     default:
@@ -1528,7 +1562,7 @@ static int MakeConsole() {
     }
     }
 
 
     if (ok) {
     if (ok) {
-        SetConsoleTitle(server_name);
+        SetConsoleTitle(g_server_name);
     }
     }
 
 
     return ok;
     return ok;
@@ -1540,19 +1574,24 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdline, int show)
     HWND hWnd;
     HWND hWnd;
     MSG msg;
     MSG msg;
 
 
-    init_server_name(__argc, __argv);
+    (void)hInst;
+    (void)hPrev;
+    (void)cmdline;
+    (void)show;
+
+    init_server_name((int)__argc, (const char **)__argv);
     memset(&cls, 0, sizeof(cls));
     memset(&cls, 0, sizeof(cls));
     cls.lpfnWndProc = (WNDPROC) WindowProc;
     cls.lpfnWndProc = (WNDPROC) WindowProc;
     cls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
     cls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
-    cls.lpszClassName = server_base_name;
+    cls.lpszClassName = g_server_base_name;
 
 
     RegisterClass(&cls);
     RegisterClass(&cls);
-    hWnd = CreateWindow(cls.lpszClassName, server_name, WS_OVERLAPPEDWINDOW,
+    hWnd = CreateWindow(cls.lpszClassName, g_server_name, WS_OVERLAPPEDWINDOW,
                         0, 0, 0, 0, NULL, NULL, NULL, NULL);
                         0, 0, 0, 0, NULL, NULL, NULL, NULL);
     ShowWindow(hWnd, SW_HIDE);
     ShowWindow(hWnd, SW_HIDE);
 
 
-    if (icon_name) {
-        hIcon = LoadImage(NULL, icon_name, IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
+    if (g_icon_name) {
+        hIcon = LoadImage(NULL, g_icon_name, IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
     } else {
     } else {
         hIcon = LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(ID_ICON), IMAGE_ICON, 16, 16, 0);
         hIcon = LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(ID_ICON), IMAGE_ICON, 16, 16, 0);
     }
     }
@@ -1562,7 +1601,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdline, int show)
     TrayIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
     TrayIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
     TrayIcon.hIcon = hIcon;
     TrayIcon.hIcon = hIcon;
     TrayIcon.hWnd = hWnd;
     TrayIcon.hWnd = hWnd;
-    snprintf(TrayIcon.szTip, sizeof(TrayIcon.szTip), "%s", server_name);
+    snprintf(TrayIcon.szTip, sizeof(TrayIcon.szTip), "%s", g_server_name);
     TrayIcon.uCallbackMessage = WM_USER;
     TrayIcon.uCallbackMessage = WM_USER;
     Shell_NotifyIcon(NIM_ADD, &TrayIcon);
     Shell_NotifyIcon(NIM_ADD, &TrayIcon);
 
 
@@ -1595,12 +1634,12 @@ NSObject<NSApplicationDelegate>
 - (void) openBrowser {
 - (void) openBrowser {
     [[NSWorkspace sharedWorkspace]
     [[NSWorkspace sharedWorkspace]
 openURL:[NSURL URLWithString:
 openURL:[NSURL URLWithString:
-[NSString stringWithUTF8String:get_url_to_first_open_port(ctx)]]];
+[NSString stringWithUTF8String:get_url_to_first_open_port(g_ctx)]]];
 }
 }
 - (void) editConfig {
 - (void) editConfig {
-    create_config_file(config_file);
+    create_config_file(g_ctx, g_config_file);
     [[NSWorkspace sharedWorkspace]
     [[NSWorkspace sharedWorkspace]
-openFile:[NSString stringWithUTF8String:config_file]
+openFile:[NSString stringWithUTF8String:g_config_file]
 withApplication:@"TextEdit"];
 withApplication:@"TextEdit"];
 }
 }
 - (void)shutDown {
 - (void)shutDown {
@@ -1631,7 +1670,7 @@ int main(int argc, char *argv[])
     /* Add version menu item */
     /* Add version menu item */
 [menu addItem:[[[NSMenuItem alloc]
 [menu addItem:[[[NSMenuItem alloc]
                     /*initWithTitle:[NSString stringWithFormat:@"%s", server_name]*/
                     /*initWithTitle:[NSString stringWithFormat:@"%s", server_name]*/
-                initWithTitle:[NSString stringWithUTF8String:server_name]
+                initWithTitle:[NSString stringWithUTF8String:g_server_name]
                 action:@selector(noexist) keyEquivalent:@""] autorelease]];
                 action:@selector(noexist) keyEquivalent:@""] autorelease]];
 
 
     /* Add configuration menu item */
     /* Add configuration menu item */
@@ -1663,7 +1702,7 @@ int main(int argc, char *argv[])
 [NSApp activateIgnoringOtherApps:YES];
 [NSApp activateIgnoringOtherApps:YES];
     [NSApp run];
     [NSApp run];
 
 
-    mg_stop(ctx);
+    stop_civetweb(g_ctx);
 
 
     return EXIT_SUCCESS;
     return EXIT_SUCCESS;
 }
 }
@@ -1673,15 +1712,15 @@ int main(int argc, char *argv[])
     init_server_name(argc, (const char **)argv);
     init_server_name(argc, (const char **)argv);
     start_civetweb(argc, argv);
     start_civetweb(argc, argv);
     printf("%s started on port(s) %s with web root [%s]\n",
     printf("%s started on port(s) %s with web root [%s]\n",
-           server_name, mg_get_option(ctx, "listening_ports"),
-           mg_get_option(ctx, "document_root"));
-    while (exit_flag == 0) {
+           g_server_name, mg_get_option(g_ctx, "listening_ports"),
+           mg_get_option(g_ctx, "document_root"));
+    while (g_exit_flag == 0) {
         sleep(1);
         sleep(1);
     }
     }
     printf("Exiting on signal %d, waiting for all threads to finish...",
     printf("Exiting on signal %d, waiting for all threads to finish...",
-           exit_flag);
+           g_exit_flag);
     fflush(stdout);
     fflush(stdout);
-    mg_stop(ctx);
+    stop_civetweb();
     printf("%s", " done.\n");
     printf("%s", " done.\n");
 
 
     return EXIT_SUCCESS;
     return EXIT_SUCCESS;

+ 24 - 22
src/md5.inl

@@ -14,7 +14,7 @@
 
 
   This code implements the MD5 Algorithm defined in RFC 1321, whose
   This code implements the MD5 Algorithm defined in RFC 1321, whose
   text is available at
   text is available at
-	http://www.ietf.org/rfc/rfc1321.txt
+    http://www.ietf.org/rfc/rfc1321.txt
   The code is derived from the text of the RFC, including the test suite
   The code is derived from the text of the RFC, including the test suite
   (section A.5) but excluding the rest of Appendix A.  It does not include
   (section A.5) but excluding the rest of Appendix A.  It does not include
   any code or documentation that is identified in the RFC as being
   any code or documentation that is identified in the RFC as being
@@ -25,12 +25,12 @@
   that follows (in reverse chronological order):
   that follows (in reverse chronological order):
 
 
   2002-04-13 lpd Removed support for non-ANSI compilers; removed
   2002-04-13 lpd Removed support for non-ANSI compilers; removed
-	references to Ghostscript; clarified derivation from RFC 1321;
-	now handles byte order either statically or dynamically.
+    references to Ghostscript; clarified derivation from RFC 1321;
+    now handles byte order either statically or dynamically.
   1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
   1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
   1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
   1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
-	added conditionalization for C++ compilation from Martin
-	Purschke <purschke@bnl.gov>.
+    added conditionalization for C++ compilation from Martin
+    Purschke <purschke@bnl.gov>.
   1999-05-03 lpd Original version.
   1999-05-03 lpd Original version.
  */
  */
 
 
@@ -52,9 +52,9 @@ typedef unsigned int md5_word_t; /* 32-bit word */
 
 
 /* Define the state of the MD5 Algorithm. */
 /* Define the state of the MD5 Algorithm. */
 typedef struct md5_state_s {
 typedef struct md5_state_s {
-    md5_word_t count[2];	/* message length in bits, lsw first */
-    md5_word_t abcd[4];		/* digest buffer */
-    md5_byte_t buf[64];		/* accumulate block */
+    md5_word_t count[2];    /* message length in bits, lsw first */
+    md5_word_t abcd[4];        /* digest buffer */
+    md5_byte_t buf[64];        /* accumulate block */
 } md5_state_t;
 } md5_state_t;
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
@@ -106,7 +106,7 @@ MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
 
 
   This code implements the MD5 Algorithm defined in RFC 1321, whose
   This code implements the MD5 Algorithm defined in RFC 1321, whose
   text is available at
   text is available at
-	http://www.ietf.org/rfc/rfc1321.txt
+    http://www.ietf.org/rfc/rfc1321.txt
   The code is derived from the text of the RFC, including the test suite
   The code is derived from the text of the RFC, including the test suite
   (section A.5) but excluding the rest of Appendix A.  It does not include
   (section A.5) but excluding the rest of Appendix A.  It does not include
   any code or documentation that is identified in the RFC as being
   any code or documentation that is identified in the RFC as being
@@ -117,14 +117,14 @@ MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
   that follows (in reverse chronological order):
   that follows (in reverse chronological order):
 
 
   2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
   2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
-	either statically or dynamically; added missing #include <string.h>
-	in library.
+    either statically or dynamically; added missing #include <string.h>
+    in library.
   2002-03-11 lpd Corrected argument list for main(), and added int return
   2002-03-11 lpd Corrected argument list for main(), and added int return
-	type, in test program and T value program.
+    type, in test program and T value program.
   2002-02-21 lpd Added missing #include <stdio.h> in test program.
   2002-02-21 lpd Added missing #include <stdio.h> in test program.
   2000-07-03 lpd Patched to eliminate warnings about "constant is
   2000-07-03 lpd Patched to eliminate warnings about "constant is
-	unsigned in ANSI C, signed in traditional"; made test program
-	self-checking.
+    unsigned in ANSI C, signed in traditional"; made test program
+    self-checking.
   1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
   1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
   1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
   1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
   1999-05-03 lpd Original version.
   1999-05-03 lpd Original version.
@@ -134,7 +134,7 @@ MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
 #include <string.h>
 #include <string.h>
 #endif
 #endif
 
 
-#undef BYTE_ORDER	/* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#undef BYTE_ORDER    /* 1 = big-endian, -1 = little-endian, 0 = unknown */
 #ifdef ARCH_IS_BIG_ENDIAN
 #ifdef ARCH_IS_BIG_ENDIAN
 #  define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
 #  define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
 #else
 #else
@@ -235,15 +235,17 @@ md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
 
 
         if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
         if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
 #endif
 #endif
-#if BYTE_ORDER <= 0		/* little-endian */
+#if BYTE_ORDER <= 0        /* little-endian */
         {
         {
             /*
             /*
              * On little-endian machines, we can process properly aligned
              * On little-endian machines, we can process properly aligned
              * data without copying it.
              * data without copying it.
              */
              */
             if (!((data - (const md5_byte_t *)0) & 3)) {
             if (!((data - (const md5_byte_t *)0) & 3)) {
-                /* data are properly aligned */
-                X = (const md5_word_t *)data;
+                /* data are properly aligned, a direct assignment is possible */
+                /* cast through a (void *) should avoid a compiler warning,
+                   see https://github.com/bel2125/civetweb/issues/94#issuecomment-98112861 */
+                X = (const md5_word_t *)(void *)data;
             } else {
             } else {
                 /* not aligned */
                 /* not aligned */
                 memcpy(xbuf, data, 64);
                 memcpy(xbuf, data, 64);
@@ -252,9 +254,9 @@ md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
         }
         }
 #endif
 #endif
 #if BYTE_ORDER == 0
 #if BYTE_ORDER == 0
-        else			/* dynamic big-endian */
+        else            /* dynamic big-endian */
 #endif
 #endif
-#if BYTE_ORDER >= 0		/* big-endian */
+#if BYTE_ORDER >= 0        /* big-endian */
         {
         {
             /*
             /*
              * On big-endian machines, we must arrange the bytes in the
              * On big-endian machines, we must arrange the bytes in the
@@ -264,9 +266,9 @@ md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
             int i;
             int i;
 
 
 #  if BYTE_ORDER == 0
 #  if BYTE_ORDER == 0
-            X = xbuf;		/* (dynamic only) */
+            X = xbuf;        /* (dynamic only) */
 #  else
 #  else
-#    define xbuf X		/* (static only) */
+#    define xbuf X        /* (static only) */
 #  endif
 #  endif
             for (i = 0; i < 16; ++i, xp += 4)
             for (i = 0; i < 16; ++i, xp += 4)
                 xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
                 xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);

+ 4 - 2
src/mod_lua.inl

@@ -1161,8 +1161,10 @@ void mg_exec_lua_script(struct mg_connection *conn, const char *path,
         if (exports != NULL) {
         if (exports != NULL) {
             lua_pushglobaltable(L);
             lua_pushglobaltable(L);
             for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) {
             for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) {
+                lua_CFunction func;
                 lua_pushstring(L, (const char *)(exports[i]));
                 lua_pushstring(L, (const char *)(exports[i]));
-                lua_pushcclosure(L, (lua_CFunction) exports[i + 1], 0);
+                *(const void**)(&func) = exports[i + 1];
+                lua_pushcclosure(L, func, 0);
                 lua_rawset(L, -3);
                 lua_rawset(L, -3);
             }
             }
         }
         }
@@ -1306,7 +1308,7 @@ static void * lua_websocket_new(const char * script, struct mg_connection *conn)
     return ok ? (void*)ws : NULL;
     return ok ? (void*)ws : NULL;
 }
 }
 
 
-static int lua_websocket_data(struct mg_connection * conn, void *ws_arg, int bits, char *data, size_t data_len)
+static int lua_websocket_data(struct mg_connection * conn, int bits, char *data, size_t data_len, void *ws_arg)
 {
 {
     struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
     struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
     int err, ok = 0;
     int err, ok = 0;

+ 8 - 1
test/resource_script_demo.lua

@@ -72,7 +72,14 @@ if method=="PUT" then
         mg.write("<body>Resource of type \"" .. mime .. "\" already exists.</body></html>\r\n")
         mg.write("<body>Resource of type \"" .. mime .. "\" already exists.</body></html>\r\n")
     else
     else
         local f = io.open(file, "w")
         local f = io.open(file, "w")
-        f:write(mg.read())
+
+        local data = {}
+        repeat
+            local l = mg.read();
+            data[#data+1] = l;
+        until ((l == "") or (l == nil));
+
+        f:write(table.concat(data, ""))
         f:close()
         f:close()
         mg.write("HTTP/1.0 200 OK\r\n")
         mg.write("HTTP/1.0 200 OK\r\n")
         mg.write("Connection: close\r\n")
         mg.write("Connection: close\r\n")

+ 16 - 6
test/unit_test.c

@@ -407,7 +407,7 @@ static void test_mg_download(int use_ssl) {
     int i, len1, len2, port;
     int i, len1, len2, port;
     struct mg_connection *conn;
     struct mg_connection *conn;
     struct mg_context *ctx;
     struct mg_context *ctx;
-    struct mg_request_info *ri;
+    const struct mg_request_info *ri;
 
 
     if (use_ssl) port = atoi(HTTPS_PORT); else port = atoi(HTTP_PORT);
     if (use_ssl) port = atoi(HTTPS_PORT); else port = atoi(HTTP_PORT);
 
 
@@ -568,12 +568,13 @@ static void test_mg_download(int use_ssl) {
     mg_stop(ctx);
     mg_stop(ctx);
 }
 }
 
 
-static int websocket_data_handler(struct mg_connection *conn, int flags, char *data, size_t data_len)
+static int websocket_data_handler(const struct mg_connection *conn, int flags, char *data, size_t data_len, void *cbdata)
 {
 {
     (void)conn;
     (void)conn;
     (void)flags;
     (void)flags;
     (void)data;
     (void)data;
     (void)data_len;
     (void)data_len;
+    (void)cbdata;
     return 1;
     return 1;
 }
 }
 
 
@@ -910,7 +911,7 @@ static void test_request_handlers(void) {
     char uri[64];
     char uri[64];
     int i;
     int i;
     const char *request = "GET /U7 HTTP/1.0\r\n\r\n";
     const char *request = "GET /U7 HTTP/1.0\r\n\r\n";
-    
+
     ctx = mg_start(NULL, NULL, OPTIONS);
     ctx = mg_start(NULL, NULL, OPTIONS);
     ASSERT(ctx != NULL);
     ASSERT(ctx != NULL);
 
 
@@ -934,18 +935,18 @@ static void test_request_handlers(void) {
         sprintf(uri, "/U%u", i);
         sprintf(uri, "/U%u", i);
         mg_set_request_handler(ctx, uri, request_test_handler, (void*)i);
         mg_set_request_handler(ctx, uri, request_test_handler, (void*)i);
     }
     }
-    
+
     conn = mg_download("localhost", atoi(HTTP_PORT), 0, ebuf, sizeof(ebuf), "%s", request);
     conn = mg_download("localhost", atoi(HTTP_PORT), 0, ebuf, sizeof(ebuf), "%s", request);
     ASSERT((conn) != NULL);
     ASSERT((conn) != NULL);
     mg_sleep(1000);
     mg_sleep(1000);
     mg_close_connection(conn);
     mg_close_connection(conn);
-    
+
     mg_stop(ctx);
     mg_stop(ctx);
 
 
 }
 }
 
 
 static int api_callback(struct mg_connection *conn) {
 static int api_callback(struct mg_connection *conn) {
-    struct mg_request_info *ri = mg_get_request_info(conn);
+    const struct mg_request_info *ri = mg_get_request_info(conn);
     char post_data[100] = "";
     char post_data[100] = "";
 
 
     ASSERT(ri->user_data == (void *) 123);
     ASSERT(ri->user_data == (void *) 123);
@@ -1189,6 +1190,15 @@ int __cdecl main(void) {
     /* test completed */
     /* test completed */
     mg_free(fetch_data);
     mg_free(fetch_data);
 
 
+#ifdef MEMORY_DEBUGGING
+    {
+    extern unsigned long mg_memory_debug_blockCount;
+    extern unsigned long mg_memory_debug_totalMemUsed;
+
+    printf("MEMORY DEBUGGING: %u %u\n", mg_memory_debug_blockCount, mg_memory_debug_totalMemUsed);
+    }
+#endif
+
     printf("TOTAL TESTS: %d, FAILED: %d\n", s_total_tests, s_failed_tests);
     printf("TOTAL TESTS: %d, FAILED: %d\n", s_total_tests, s_failed_tests);
     return s_failed_tests == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
     return s_failed_tests == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 }

+ 2 - 0
test/windows.cgi

@@ -0,0 +1,2 @@
+#!windows.cgi.cmd
+

+ 7 - 0
test/windows.cgi.cmd

@@ -0,0 +1,7 @@
+@echo off
+echo HTTP/1.1 200 OK
+echo Connection: close
+echo.
+echo CGI test:
+echo.
+set

+ 21 - 7
testutils/testclient/testclient.c

@@ -8,18 +8,20 @@ unsigned short PORT = 8080;
 static const char * RESOURCELIST[] = {
 static const char * RESOURCELIST[] = {
     "/hello.txt",
     "/hello.txt",
     "/imagetest/00.png",
     "/imagetest/00.png",
+    "/resource_script_demo.lua/r1.txt",
     "/"
     "/"
 };
 };
 static const char * METHODLIST[] = {
 static const char * METHODLIST[] = {
     "GET",
     "GET",
-    "POST"
+    "POST",
+    "PUT"
 };
 };
 
 
 
 
 static int CLIENTCOUNT = 0; // 20;
 static int CLIENTCOUNT = 0; // 20;
-static int TESTCYCLES = 50;
-static int RESOURCEINDEX = 0;
-static int METHODINDEX = 0;
+static int TESTCYCLES = 1;
+static int RESOURCEINDEX = 2;
+static int METHODINDEX = 2;
 
 
 
 
 int sockvprintf(SOCKET soc, const char * fmt, va_list vl) {
 int sockvprintf(SOCKET soc, const char * fmt, va_list vl) {
@@ -53,7 +55,8 @@ static unsigned bad = 0;
 unsigned long postSize = 0;
 unsigned long postSize = 0;
 unsigned long extraHeadSize = 0;
 unsigned long extraHeadSize = 0;
 unsigned long queryStringSize = 0;
 unsigned long queryStringSize = 0;
-unsigned long keep_alive = 10;
+unsigned long keep_alive = 0;
+int chunked = 1;
 
 
 
 
 int WINAPI ClientMain(void * clientNo) {
 int WINAPI ClientMain(void * clientNo) {
@@ -139,6 +142,17 @@ int WINAPI ClientMain(void * clientNo) {
 
 
         if (!strcmp(method,"GET")) {
         if (!strcmp(method,"GET")) {
             sockprintf(soc, "\r\n");
             sockprintf(soc, "\r\n");
+        } else if (chunked) {
+
+            sockprintf(soc, "Transfer-Encoding: chunked\r\n\r\n", postSize);
+
+            for (i=0;i<(postSize/10);i++) {sockprintf(soc, "A\r\n1234567890\r\n");}
+            if ((postSize%10)>0) {
+                sockprintf(soc, "%x\r\n", postSize%10);
+                for (i=0;i<(postSize%10);i++) {sockprintf(soc, "_");}
+                sockprintf(soc, "\r\n");
+            }
+
         } else {
         } else {
             // not GET
             // not GET
             sockprintf(soc, "Content-Length: %u\r\n\r\n", postSize);
             sockprintf(soc, "Content-Length: %u\r\n\r\n", postSize);
@@ -301,9 +315,9 @@ int SingleClientTestAutomatic(unsigned long initialPostSize) {
     int           i;
     int           i;
 
 
     postSize = initialPostSize;
     postSize = initialPostSize;
-    for (cycle=0;;cycle++) {
+    for (cycle=1;cycle<=TESTCYCLES;cycle++) {
         good=bad=0;
         good=bad=0;
-        for (i=0;i<1000;i++) {
+        for (i=0;i<1 /* 000 */;i++) {
             expectedData=17;
             expectedData=17;
             ClientMain((void*)1);
             ClientMain((void*)1);
         }
         }

+ 3 - 2
testutils/testclient/testclient.vcxproj

@@ -19,13 +19,14 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
+    <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <UseDebugLibraries>false</UseDebugLibraries>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
+    <CharacterSet>MultiByte</CharacterSet>
+    <PlatformToolset>v100</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
   <ImportGroup Label="ExtensionSettings">

+ 239 - 0
testutils/testclient_chunked_linux/testclient.c

@@ -0,0 +1,239 @@
+/* quick and dirty test for chunked encoding */
+
+#ifdef WIN32
+#include <WinSock2.h>
+#else
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <termios.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netinet/ip.h>
+typedef int SOCKET;
+typedef struct sockaddr SOCKADDR;
+typedef struct hostent HOSTENT;
+const int INVALID_SOCKET = -1;
+const int SD_SEND = SHUT_WR;
+const int SD_BOTH = SHUT_RDWR;
+#define closesocket(x) close(x)
+#define Sleep(x) usleep((x)*1000)
+#define ioctlsocket(a,b,c) ioctl(a,b,c)
+#endif
+#include <stdio.h>
+#include <stdarg.h>
+#include <time.h>
+
+char * HOST = "127.0.0.1";
+unsigned short PORT = 8080;
+const char * RESOURCE = "/resource_script_demo.lua/r1.txt";
+const char * METHOD = "PUT";
+
+unsigned postSize = 9876;
+unsigned extraHeadSize = 0;
+unsigned queryStringSize = 0;
+int keep_alive = 0;
+int chunked = 1;
+
+
+int sockvprintf(SOCKET soc, const char * fmt, va_list vl) {
+
+    char buf[1024*8];
+#ifdef WIN32
+    int len = vsprintf_s(buf, sizeof(buf), fmt, vl);
+#else
+    int len = vsprintf(buf, fmt, vl);
+#endif
+    int ret = send(soc, buf, len, 0);
+    return ret;
+}
+
+
+int sockprintf(SOCKET soc, const char * fmt, ...) {
+
+    int ret = -1;
+    va_list vl;
+    va_start(vl, fmt);
+    ret = sockvprintf(soc, fmt, vl);
+    va_end(vl);
+    return ret;
+}
+
+
+static struct sockaddr_in target = {0};
+
+
+int TestClient(unsigned clientNo) {
+
+    SOCKET soc;
+    time_t lastData;
+    size_t totalData = 0;
+    size_t bodyData = 0;
+    int isBody = 0;
+    int timeOut = 10;
+    unsigned long i;
+
+    // TCP
+    soc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (soc==INVALID_SOCKET) {
+        printf("\r\nClient %u: cannot create socket\a\r\n", (int)clientNo);
+        return 3;
+    }
+
+    // comment in to disable Nagle:
+    {int disable_Nagle = 1; setsockopt(soc, IPPROTO_TCP, TCP_NODELAY, (char *) &disable_Nagle, sizeof(disable_Nagle));}
+
+    if (connect(soc, (SOCKADDR*)&target, sizeof(target))) {
+        printf("\r\nClient %u: cannot connect to server %s:%u\a\r\n", (int)clientNo, HOST, PORT);
+        return 4;
+    }
+
+    sockprintf(soc, "%s %s", METHOD, RESOURCE);
+
+    if (queryStringSize>0) {
+        sockprintf(soc, "?", METHOD, RESOURCE);
+        for (i=0;i<(queryStringSize/10);i++) {sockprintf(soc, "1234567890");}
+        for (i=0;i<(queryStringSize%10);i++) {sockprintf(soc, "_");}
+    }
+
+    sockprintf(soc, " HTTP/1.1\r\nHost: %s\r\n", HOST);
+
+    if (keep_alive) {
+        sockprintf(soc, "Connection: Keep-Alive\r\n");
+    } else {
+        sockprintf(soc, "Connection: Close\r\n");
+    }
+
+    for (i=0;i<(extraHeadSize/25);i++) {
+        sockprintf(soc, "Comment%04u: 1234567890\r\n", i % 10000);
+    }
+
+    if (!strcmp(METHOD, "GET")) {
+        sockprintf(soc, "\r\n");
+
+    } else if (chunked) {
+
+        unsigned remaining_postSize = postSize;
+        sockprintf(soc, "Transfer-Encoding: chunked\r\n\r\n", postSize);
+
+        while (remaining_postSize > 0) {
+            unsigned chunk = rand()%200 + 1;
+            if (chunk>remaining_postSize) chunk = remaining_postSize;
+
+            sockprintf(soc, "%x\r\n", chunk);
+            for (i=0;i<chunk;i++) {sockprintf(soc, "_");}
+            sockprintf(soc, "\r\n");
+
+            remaining_postSize -= chunk;
+        }
+        sockprintf(soc, "0\r\n\r\n", postSize%10);
+
+
+    } else {
+
+        sockprintf(soc, "Content-Length: %u\r\n\r\n", postSize);
+
+        for (i=0;i<postSize/10;i++) {sockprintf(soc, "1234567890");}
+        for (i=0;i<postSize%10;i++) {sockprintf(soc, ".");}
+
+        timeOut += postSize/10000;
+    }
+
+    if (!keep_alive) {
+        shutdown(soc, SD_SEND);
+    } else {
+        timeOut = 2;
+    }
+
+    // wait for response from the server
+    bodyData = totalData = 0;
+    isBody = 0;
+    lastData = time(0);
+    for (;;) {
+        char buf[20480];
+        int chunkSize = 0;
+        unsigned long dataReady = 0;
+
+        Sleep(1);
+
+        if (ioctlsocket(soc, FIONREAD, &dataReady) < 0) break;
+        if (dataReady) {
+            chunkSize = recv(soc, buf+totalData, sizeof(buf)-totalData, 0);
+            if (chunkSize<0) {
+                printf("Error: recv failed for client %i\r\n", (int)clientNo);
+                break;
+            } else if (!isBody) {
+                char * headEnd = strstr(buf,"\xD\xA\xD\xA");
+                if (headEnd) {
+                    headEnd+=4;
+                    chunkSize -= ((int)headEnd - (int)buf);
+                    if (chunkSize>0) {
+                        //fwrite(headEnd,1,got,STORE);
+                        bodyData += chunkSize;
+                    }
+                    isBody=1;
+                }
+            } else {
+                //fwrite(buf,1,got,STORE);
+                bodyData += chunkSize;
+            }
+            lastData = time(0);
+            totalData += chunkSize;
+        } else {
+            time_t current = time(0);
+            if (difftime(current, lastData) > timeOut) {
+                break;
+            }
+            Sleep(10);
+        }
+    }
+
+    shutdown(soc, SD_BOTH);
+    closesocket(soc);
+
+    return 0;
+}
+
+
+
+int main(int argc, char * argv[]) {
+
+    HOSTENT     * lpHost = 0;
+
+#ifdef WIN32
+    WSADATA       wsaData = {0};
+
+    if (WSAStartup(MAKEWORD(2,2), &wsaData) != NO_ERROR) {
+        printf("\r\nCannot init WinSock\a\r\n");
+        return 1;
+    }
+#endif
+
+    srand((unsigned int)time(NULL));
+
+    lpHost = gethostbyname(HOST);
+    if (lpHost == NULL) {
+        printf("\r\nCannot find host %s\a\r\n",HOST);
+        return 2;
+    }
+
+    target.sin_family = AF_INET;
+#ifdef WIN32
+    target.sin_addr.s_addr = *((u_long FAR *) (lpHost->h_addr));
+#else
+    target.sin_addr.s_addr = htonl(0x7F000001);
+#endif
+    target.sin_port = htons(PORT);
+    printf("\r\nConnect to %s\r\n", inet_ntoa(target.sin_addr));
+
+    TestClient(1);
+
+#ifdef WIN32
+    WSACleanup();
+#endif
+
+    return 0;
+}

+ 91 - 0
testutils/testclient_chunked_linux/testclient2.vcxproj

@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.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>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{150140C5-2989-4D0D-8714-5A47B78EAD4D}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>testclient2</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </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>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+    <GenerateManifest>false</GenerateManifest>
+    <OutDir>$(ProjectDir)$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <GenerateManifest>false</GenerateManifest>
+    <OutDir>$(ProjectDir)$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>binmode.obj;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <AdditionalDependencies>binmode.obj;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="testclient.c" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

Some files were not shown because too many files changed in this diff