Преглед на файлове

Merge branch 'master' of https://github.com/bel2125/civetweb

Maarten Fremouw преди 11 години
родител
ревизия
dd9f9cc5f5
променени са 100 файла, в които са добавени 3270 реда и са изтрити 1109 реда
  1. 5 0
      .gitignore
  2. 3 1
      CREDITS.md
  3. 28 0
      LICENSE.md
  4. 3 3
      Makefile.deprecated
  5. 27 21
      README.md
  6. 28 4
      RELEASE_NOTES.md
  7. 12 0
      VS2012/civetweb.sln
  8. 1 1
      VS2012/civetweb/civetweb.vcxproj
  9. 14 9
      VS2012/civetweb_lua/civetweb_lua.vcxproj
  10. 16 2
      VS2012/civetweb_lua/civetweb_lua.vcxproj.filters
  11. 1 1
      VS2012/ex_embed_cpp/ex_embed_cpp.vcxproj
  12. 1 1
      VS2012/ex_embedded_c/ex_embedded_c.vcxproj
  13. 2 1
      VS2012/ex_websocket/ex_websocket.vcxproj
  14. 6 0
      VS2012/ex_websocket/ex_websocket.vcxproj.filters
  15. 157 0
      VS2012/ex_websocket_client/ex_websocket_client.vcxproj
  16. 30 0
      VS2012/ex_websocket_client/ex_websocket_client.vcxproj.filters
  17. 39 36
      VS2012/lua_lib/lua_lib.vcxproj.filters
  18. 2 2
      VS2012/unit_test/unit_test.vcxproj
  19. 2 2
      contrib/buildroot/civetweb.mk
  20. 1 1
      distribution/arch/PKGBUILD.git.example
  21. 8 5
      docs/Building.md
  22. 3 3
      docs/Embedding.md
  23. 4 3
      docs/Installing.md
  24. 192 129
      docs/UserManual.md
  25. 1 1
      docs/yaSSL.md
  26. 1 1
      examples/chat/chat.c
  27. 10 8
      examples/embedded_cpp/embedded_cpp.cpp
  28. 1 1
      examples/upload/upload.c
  29. 54 82
      examples/websocket/WebSockCallbacks.c
  30. 17 3
      examples/websocket/WebSockCallbacks.h
  31. 7 5
      examples/websocket/websocket.c
  32. 37 0
      examples/websocket_client/Makefile
  33. 13 0
      examples/websocket_client/ssl/server.crt
  34. 11 0
      examples/websocket_client/ssl/server.csr
  35. 15 0
      examples/websocket_client/ssl/server.key
  36. 18 0
      examples/websocket_client/ssl/server.key.orig
  37. 28 0
      examples/websocket_client/ssl/server.pem
  38. 303 0
      examples/websocket_client/websocket_client.c
  39. 1 1
      examples/ws_server/ws_server.c
  40. 61 45
      include/CivetServer.h
  41. 60 5
      include/civetweb.h
  42. 1 1
      resources/Makefile.in-lua
  43. 2 2
      resources/civetweb.conf
  44. 3 3
      resources/itworks.html
  45. BIN
      resources/luafilesystem-logo.jpg
  46. BIN
      resources/luasqlite-logo.jpg
  47. BIN
      resources/luaxml-logo.jpg
  48. 34 14
      src/CivetServer.cpp
  49. 443 258
      src/civetweb.c
  50. 462 59
      src/main.c
  51. 516 315
      src/mod_lua.inl
  52. 458 0
      src/third_party/LuaXML_lib.c
  53. 1 1
      src/third_party/lua-5.2.3/Makefile
  54. 1 1
      src/third_party/lua-5.2.3/README
  55. 0 0
      src/third_party/lua-5.2.3/doc/contents.html
  56. 0 0
      src/third_party/lua-5.2.3/doc/logo.gif
  57. 0 0
      src/third_party/lua-5.2.3/doc/lua.1
  58. 22 9
      src/third_party/lua-5.2.3/doc/lua.css
  59. 0 0
      src/third_party/lua-5.2.3/doc/luac.1
  60. 5 4
      src/third_party/lua-5.2.3/doc/manual.css
  61. 0 0
      src/third_party/lua-5.2.3/doc/manual.html
  62. 0 0
      src/third_party/lua-5.2.3/doc/osi-certified-72x60.png
  63. 4 3
      src/third_party/lua-5.2.3/doc/readme.html
  64. 1 1
      src/third_party/lua-5.2.3/src/Makefile
  65. 1 1
      src/third_party/lua-5.2.3/src/lapi.c
  66. 1 1
      src/third_party/lua-5.2.3/src/lapi.h
  67. 1 1
      src/third_party/lua-5.2.3/src/lauxlib.c
  68. 1 1
      src/third_party/lua-5.2.3/src/lauxlib.h
  69. 1 1
      src/third_party/lua-5.2.3/src/lbaselib.c
  70. 3 2
      src/third_party/lua-5.2.3/src/lbitlib.c
  71. 1 1
      src/third_party/lua-5.2.3/src/lcode.c
  72. 1 1
      src/third_party/lua-5.2.3/src/lcode.h
  73. 1 1
      src/third_party/lua-5.2.3/src/lcorolib.c
  74. 1 1
      src/third_party/lua-5.2.3/src/lctype.c
  75. 1 1
      src/third_party/lua-5.2.3/src/lctype.h
  76. 1 1
      src/third_party/lua-5.2.3/src/ldblib.c
  77. 22 9
      src/third_party/lua-5.2.3/src/ldebug.c
  78. 1 1
      src/third_party/lua-5.2.3/src/ldebug.h
  79. 13 5
      src/third_party/lua-5.2.3/src/ldo.c
  80. 1 1
      src/third_party/lua-5.2.3/src/ldo.h
  81. 1 1
      src/third_party/lua-5.2.3/src/ldump.c
  82. 1 1
      src/third_party/lua-5.2.3/src/lfunc.c
  83. 1 1
      src/third_party/lua-5.2.3/src/lfunc.h
  84. 10 3
      src/third_party/lua-5.2.3/src/lgc.c
  85. 1 1
      src/third_party/lua-5.2.3/src/lgc.h
  86. 1 1
      src/third_party/lua-5.2.3/src/linit.c
  87. 12 11
      src/third_party/lua-5.2.3/src/liolib.c
  88. 4 1
      src/third_party/lua-5.2.3/src/llex.c
  89. 1 1
      src/third_party/lua-5.2.3/src/llex.h
  90. 1 1
      src/third_party/lua-5.2.3/src/llimits.h
  91. 1 1
      src/third_party/lua-5.2.3/src/lmathlib.c
  92. 1 1
      src/third_party/lua-5.2.3/src/lmem.c
  93. 1 1
      src/third_party/lua-5.2.3/src/lmem.h
  94. 1 1
      src/third_party/lua-5.2.3/src/loadlib.c
  95. 1 1
      src/third_party/lua-5.2.3/src/lobject.c
  96. 1 1
      src/third_party/lua-5.2.3/src/lobject.h
  97. 1 1
      src/third_party/lua-5.2.3/src/lopcodes.c
  98. 1 1
      src/third_party/lua-5.2.3/src/lopcodes.h
  99. 1 1
      src/third_party/lua-5.2.3/src/loslib.c
  100. 1 1
      src/third_party/lua-5.2.3/src/lparser.c

+ 5 - 0
.gitignore

@@ -230,3 +230,8 @@ pip-log.txt
 ##########################
 requests.db
 
+##########################
+## Files created by ctags
+##########################
+tags
+

+ 3 - 1
CREDITS.md

@@ -4,6 +4,7 @@
 * bel2125
 * celeron55
 * Daniel Oaks
+* Danny Al-Gaaf
 * F-Secure Corporation
 * Brian Spratke
 * HariKamath Kamath
@@ -14,9 +15,10 @@
 * Thomas Davis
 * Toni Wilk
 * William Greathouse
+* Jordan Shelley
 
 # Mongoose Contributors
-The following users contributed to the original Mongoose release between 2010 and 2013.  Civitweb is based on the Mongoose code.  This list was generated from the Mongoose GIT logs.  There is no record for contributors prior to 2010.
+Civetweb is based on the Mongoose code.  The following users contributed to the original Mongoose release between 2010 and 2013.  This list was generated from the Mongoose GIT logs.  There is no record for contributors prior to 2010.
 
 * Sergey Lyubka
 * Arnout Vandecappelle (Essensium/Mind)

+ 28 - 0
LICENSE.md

@@ -111,3 +111,31 @@ http://keplerproject.github.io/luafilesystem/license.html
 > 
 > 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
+------
+
+### Included only if built with Lua 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.

+ 3 - 3
Makefile.deprecated

@@ -19,9 +19,9 @@
 PROG        = civetweb
 CFLAGS      = -std=c99 -O2 -W -Wall -pedantic -pthread -pipe -Iinclude $(COPT)
 
-# To build with Lua, download and unzip Lua 5.2.2 source code into the
+# To build with Lua, download and unzip Lua 5.2.3 source code into the
 # civetweb directory, and then add $(LUA_SOURCES) to CFLAGS
-LUA         = src/third_party/lua-5.2.2/src
+LUA         = src/third_party/lua-5.2.3/src
 LUA_FLAGS   = -I$(LUA) -DLUA_COMPAT_ALL
 LUA_SOURCES = $(LUA)/lapi.c $(LUA)/lcode.c $(LUA)/lctype.c \
               $(LUA)/ldebug.c $(LUA)/ldo.c $(LUA)/ldump.c \
@@ -114,7 +114,7 @@ all:
 lua.lib: $(LUA_WINOBJS)
 	$(MSVC)/bin/lib /out:$@ $(LUA_WINOBJS)
 
-# To build with Lua, make sure you have Lua unpacked into src/third_party/lua-5.2.2 directory
+# To build with Lua, make sure you have Lua unpacked into src/third_party/lua-5.2.3 directory
 linux_lua: $(ALL_OBJECTS)
 	$(CC) $(ALL_OBJECTS) -o $(PROG) -ldl
 

+ 27 - 21
README.md

@@ -4,8 +4,8 @@
 There is a new home!!!
 -----------------
 https://github.com/bel2125/civetweb
-Bel has been taking the lead on Civetweb, so teh official repositiory 
-is being moved under his control for ease of maintanence.
+Bel has been taking the lead on Civetweb, so the official repository
+is being moved under his control for ease of maintenance.
 
 Project Mission
 -----------------
@@ -42,26 +42,25 @@ Overview
 --------
 
 Civetweb keeps the balance between functionality and
-simplicity by carefully selected list of features:
+simplicity by a carefully selected list of features:
 
 - Liberal, commercial-friendly, permissive,
   [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 Server Pages + Sqlite
-  which provides ready to go, powerful web development platform in
-  one single-click executable with **no dependencies**: forget LAMP!
-- Support for CGI, SSL, SSI, Digest (MD5) authorization, Websocket, WEbDAV
+- 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,
-  The source is in single file
-  to make things easy. Embedding examples included.
+- 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
 
 
-### Other optionally included software
+### Optionally included software
 
 <a href="http://lua.org">
 ![Lua](https://raw.github.com/bel2125/civetweb/master/resources/lua-logo.jpg "Lua Logo")
@@ -69,12 +68,23 @@ simplicity by carefully selected list of features:
 <a href="http://sqlite.org">
 ![Sqlite3](https://raw.github.com/bel2125/civetweb/master/resources/sqlite3-logo.jpg "Sqlite3 Logo")
 </a>
+<a href=http://keplerproject.github.io/luafilesystem/">
+![LuaFileSystem](https://raw.github.com/bel2125/civetweb/master/resources/luafilesystem-logo.jpg "LuaFileSystem Logo")
+</a>
+<a href=http://lua.sqlite.org/index.cgi/index">
+![LuaSQLite3](https://raw.github.com/bel2125/civetweb/master/resources/luasqlite-logo.jpg "LuaSQLite3 Logo")
+</a>
+<a href=http://viremo.eludi.net/LuaXML/index.html">
+![LuaXML](https://raw.github.com/bel2125/civetweb/master/resources/luaxml-logo.jpg "LuaXML Logo")
+</a>
 
 Support
 -------
 
-The original Mongoose project is recommended if support is needed.  However,
-this is very easy to install and use. 
+This project is very easy to install and use. Please read the [documentation](https://github.com/bel2125/civetweb/blob/master/docs/)
+and have a look at the [examples] (https://github.com/bel2125/civetweb/blob/master/examples/).
+More information may be found on the [mailing list](https://groups.google.com/d/forum/civetweb).
+
 
 Contributions
 ---------------
@@ -85,18 +95,14 @@ DO NOT APPLY fixes copied from Mongoose to this project to prevent GPL tainting.
 
 ### Author
 
-The original Author was Sergey Lyubka.  He still controls the original
-Mongoose project.  However, he has changed or said he would 
+Civetweb is based on the Mongoose project - the original Author was Sergey Lyubka.  He still
+controls the original Mongoose project.  However, he has changed or said he would
 change licenses after writing and distributing the original code this
 project is based on.
 
 Using this project ensures the MIT licenses terms are applied and
 GPL cannot be imposed on any of this code as long as it is sourced from
-here.
+here. This code will remain free with the MIT license protection.
 
-For the latest and greatest code and features, please use the Mongoose
-code from Sergey Lyubka.  However, doing so will require adherence to
-the new licenses.
+A list of authors can be found in [CREDITS.md](https://github.com/bel2125/civetweb/blob/master/CREDITS.md)
 
-This project ensures that GPL license cannot be applied to this code.
-This code will remain free with the MIT license protection.

+ 28 - 4
RELEASE_NOTES.md

@@ -1,10 +1,33 @@
-Release Notes v1.6 (Under Development)
+Release Notes v1.7 (Under Development)
 ===
-### Objectives: *Enhance Lua support, bug fixes and updates"
+### Objectives: *???*
 
 Changes
 -------
 
+- Add a websocket client example
+- Add a websocket client API
+- Update websocket example
+- New API functions: access context, callback for create/delete, access user data
+- Upgraded Lua from 5.2.2 to 5.2.3
+- Integrate LuaXML
+- Fix compiler warnings
+- Updated version number
+
+Release Notes v1.6
+===
+### Objectives: *Enhance Lua support, configuration dialog for windows, new examples, bug fixes and updates*
+
+Changes
+-------
+
+- Add examples of Lua pages, scripts and websockets to the test directory (bel)
+- Add dialog to change htpasswd files for the Windows standalone server (bel)
+- Fix compiler warnings and warnings from static code analysis (Danny Al-Gaaf, jmc-, Thomas, bel, ...)
+- Add new unit tests (bel)
+- Support includes in htpasswd files (bel)
+- Add a basic option check for the standalone executable (bel)
+- Support user defined error pages (bel)
 - Method to get POST request parameters via C++ interface (bel)
 - Re-Add unit tests for Linux and Windows (jmc-, bel)
 - Allow to specify title and tray icon for the Windows standalone server (bel)
@@ -25,7 +48,8 @@ Changes
 - Fixes for Lua Server Pages, as described within the google groups thread. (bel)
 - Added support for plain Lua Scripts, and an example script. (bel)
 - A completely new, and more illustrative websocket example for C. (bel)
-- An implementation of "Websocket for Lua", which allows to configure an optional websocket_root directory, incl. URL rewriting. Added an example. The Lua interface may change if the threading model changes.  (bel)
+- Websocket for Lua (bel)
+- An optional websocket_root directory, including URL rewriting (bel)
 - Update of SQLite3 to 3.8.1. (bel)
 - Add "date" header field to replies, according to the requirements of RFC 2616 (the HTTP standard), Section 14.18 (bel)
 - Fix websocket long pull (celeron55)
@@ -182,6 +206,6 @@ Changes
 
 - Renamed Mongoose to Civetweb in the code and documentation.
 - Replaced copyrighted images with new images
-- Created a new code respository at https://github.com/sunsetbrew/civetweb
+- Created a new code respository at https://github.com/bel2125/civetweb
 - Created a distribution site at https://sourceforge.net/projects/civetweb/
 - Basic build testing

+ 12 - 0
VS2012/civetweb.sln

@@ -15,6 +15,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ex_embedded_c", "ex_embedde
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unit_test", "unit_test\unit_test.vcxproj", "{1AC4A7A6-0100-4287-97F4-B95807BE5607}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ex_websocket_client", "ex_websocket_client\ex_websocket_client.vcxproj", "{58B93E94-7766-435E-93AE-42A2FB5D99B2}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Mixed Platforms = Debug|Mixed Platforms
@@ -107,6 +109,16 @@ Global
 		{1AC4A7A6-0100-4287-97F4-B95807BE5607}.Release|Win32.ActiveCfg = Release|Win32
 		{1AC4A7A6-0100-4287-97F4-B95807BE5607}.Release|Win32.Build.0 = Release|Win32
 		{1AC4A7A6-0100-4287-97F4-B95807BE5607}.Release|x64.ActiveCfg = Release|Win32
+		{58B93E94-7766-435E-93AE-42A2FB5D99B2}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+		{58B93E94-7766-435E-93AE-42A2FB5D99B2}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+		{58B93E94-7766-435E-93AE-42A2FB5D99B2}.Debug|Win32.ActiveCfg = Debug|Win32
+		{58B93E94-7766-435E-93AE-42A2FB5D99B2}.Debug|Win32.Build.0 = Debug|Win32
+		{58B93E94-7766-435E-93AE-42A2FB5D99B2}.Debug|x64.ActiveCfg = Debug|Win32
+		{58B93E94-7766-435E-93AE-42A2FB5D99B2}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+		{58B93E94-7766-435E-93AE-42A2FB5D99B2}.Release|Mixed Platforms.Build.0 = Release|Win32
+		{58B93E94-7766-435E-93AE-42A2FB5D99B2}.Release|Win32.ActiveCfg = Release|Win32
+		{58B93E94-7766-435E-93AE-42A2FB5D99B2}.Release|Win32.Build.0 = Release|Win32
+		{58B93E94-7766-435E-93AE-42A2FB5D99B2}.Release|x64.ActiveCfg = Release|Win32
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 1 - 1
VS2012/civetweb/civetweb.vcxproj

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

+ 14 - 9
VS2012/civetweb_lua/civetweb_lua.vcxproj

@@ -28,7 +28,7 @@
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <CharacterSet>MultiByte</CharacterSet>
-    <PlatformToolset>v110_xp</PlatformToolset>
+    <PlatformToolset>v100</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
@@ -41,7 +41,7 @@
     <UseDebugLibraries>false</UseDebugLibraries>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
-    <PlatformToolset>v110_xp</PlatformToolset>
+    <PlatformToolset>v100</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
@@ -88,8 +88,8 @@
       </PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.3\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
       <SubSystem>Windows</SubSystem>
@@ -103,7 +103,7 @@
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.3\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
       <SubSystem>Windows</SubSystem>
@@ -119,7 +119,7 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <PreprocessorDefinitions>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.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.3\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
       <SubSystem>Windows</SubSystem>
@@ -137,7 +137,7 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <PreprocessorDefinitions>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.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.3\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
       <SubSystem>Windows</SubSystem>
@@ -151,8 +151,8 @@
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\include\civetweb.h" />
-    <ClInclude Include="..\..\src\third_party\lua-5.2.2\src\lauxlib.h" />
-    <ClInclude Include="..\..\src\third_party\lua-5.2.2\src\lua.h" />
+    <ClInclude Include="..\..\src\third_party\lua-5.2.3\src\lauxlib.h" />
+    <ClInclude Include="..\..\src\third_party\lua-5.2.3\src\lua.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\src\civetweb.c" />
@@ -169,6 +169,11 @@
       <Project>{8f5e5d77-d269-4665-9e27-1045da6cf0d8}</Project>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\src\md5.inl" />
+    <None Include="..\..\src\mod_lua.inl" />
+    <None Include="..\..\src\timer.inl" />
+  </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>

+ 16 - 2
VS2012/civetweb_lua/civetweb_lua.vcxproj.filters

@@ -13,6 +13,9 @@
       <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
       <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
     </Filter>
+    <Filter Include="inl files">
+      <UniqueIdentifier>{1ef3413b-2315-48f2-ad22-57af6b4f7aca}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <Text Include="ReadMe.txt" />
@@ -21,10 +24,10 @@
     <ClInclude Include="..\..\include\civetweb.h">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\third_party\lua-5.2.2\src\lua.h">
+    <ClInclude Include="..\..\src\third_party\lua-5.2.3\src\lua.h">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\third_party\lua-5.2.2\src\lauxlib.h">
+    <ClInclude Include="..\..\src\third_party\lua-5.2.3\src\lauxlib.h">
       <Filter>Header Files</Filter>
     </ClInclude>
   </ItemGroup>
@@ -46,4 +49,15 @@
       <Filter>Resource Files</Filter>
     </Image>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\src\md5.inl">
+      <Filter>inl files</Filter>
+    </None>
+    <None Include="..\..\src\mod_lua.inl">
+      <Filter>inl files</Filter>
+    </None>
+    <None Include="..\..\src\timer.inl">
+      <Filter>inl files</Filter>
+    </None>
+  </ItemGroup>
 </Project>

+ 1 - 1
VS2012/ex_embed_cpp/ex_embed_cpp.vcxproj

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

+ 1 - 1
VS2012/ex_embedded_c/ex_embedded_c.vcxproj

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

+ 2 - 1
VS2012/ex_websocket/ex_websocket.vcxproj

@@ -86,7 +86,7 @@
       </PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>USE_WEBSOCKET;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>USE_WEBSOCKET;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
@@ -145,6 +145,7 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\examples\websocket\WebSockCallbacks.h" />
     <ClInclude Include="..\..\include\civetweb.h" />
   </ItemGroup>
   <ItemGroup>

+ 6 - 0
VS2012/ex_websocket/ex_websocket.vcxproj.filters

@@ -18,6 +18,9 @@
     <ClInclude Include="..\..\include\civetweb.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\examples\websocket\WebSockCallbacks.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\examples\websocket\websocket.c">
@@ -26,5 +29,8 @@
     <ClCompile Include="..\..\src\civetweb.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\examples\websocket\WebSockCallbacks.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 157 - 0
VS2012/ex_websocket_client/ex_websocket_client.vcxproj

@@ -0,0 +1,157 @@
+<?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="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{58B93E94-7766-435E-93AE-42A2FB5D99B2}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>ex_websocket_client</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v110</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v110</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </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 Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <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>
+    <OutDir>$(SolutionDir)\$(Configuration)\$(Platform)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+    <OutDir>$(SolutionDir)\$(Configuration)\$(Platform)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <OutDir>$(SolutionDir)\$(Configuration)\$(Platform)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+    <OutDir>$(SolutionDir)\$(Configuration)\$(Platform)\</OutDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>USE_WEBSOCKET;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>USE_WEBSOCKET;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>USE_WEBSOCKET;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>USE_WEBSOCKET;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\include\civetweb.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\src\civetweb.c" />
+    <ClCompile Include="..\..\examples\websocket_client\websocket_client.c" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 30 - 0
VS2012/ex_websocket_client/ex_websocket_client.vcxproj.filters

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\include\civetweb.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\examples\websocket_client\websocket_client.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\civetweb.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+</Project>

+ 39 - 36
VS2012/lua_lib/lua_lib.vcxproj.filters

@@ -15,109 +15,112 @@
     </Filter>
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lapi.c">
+    <ClCompile Include="..\..\src\third_party\lsqlite3.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lcode.c">
+    <ClCompile Include="..\..\src\third_party\sqlite3.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lctype.c">
+    <ClCompile Include="..\..\src\third_party\lfs.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\ldebug.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lapi.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\ldo.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lauxlib.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\ldump.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lbaselib.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lfunc.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lbitlib.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lgc.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lcode.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\llex.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lcorolib.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lmem.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lctype.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lobject.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\ldblib.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lopcodes.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\ldebug.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lparser.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\ldo.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lstate.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\ldump.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lstring.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lfunc.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\ltable.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lgc.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\ltm.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\linit.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lundump.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\liolib.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lauxlib.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\llex.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lbaselib.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lmathlib.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lbitlib.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lmem.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lcorolib.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\loadlib.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lvm.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lobject.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lzio.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lopcodes.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\ldblib.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\loslib.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\linit.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lparser.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\liolib.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lstate.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lmathlib.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lstring.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\loadlib.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lstrlib.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\loslib.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\ltable.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lstrlib.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\ltablib.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\ltablib.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\ltm.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lsqlite3.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lundump.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\sqlite3.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lvm.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\third_party\lfs.c">
+    <ClCompile Include="..\..\src\third_party\lua-5.2.3\src\lzio.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\third_party\LuaXML_lib.c">
       <Filter>Source Files</Filter>
     </ClCompile>
   </ItemGroup>
@@ -129,4 +132,4 @@
       <Filter>Header Files</Filter>
     </ClInclude>
   </ItemGroup>
-</Project>
+</Project>

+ 2 - 2
VS2012/unit_test/unit_test.vcxproj

@@ -50,7 +50,7 @@
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalIncludeDirectories>$(ProjectDir)..\..\src;$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(ProjectDir)..\..\src;$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.3\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
       <SubSystem>Console</SubSystem>
@@ -66,7 +66,7 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalIncludeDirectories>$(ProjectDir)..\..\src;$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(ProjectDir)..\..\src;$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.3\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
       <SubSystem>Console</SubSystem>

+ 2 - 2
contrib/buildroot/civetweb.mk

@@ -4,8 +4,8 @@
 #
 ################################################################################
 
-CIVETWEB_VERSION = 1.6
-CIVETWEB_SITE = http://github.com/sunsetbrew/civetweb/tarball/v$(CIVETWEB_VERSION)
+CIVETWEB_VERSION = 1.7
+CIVETWEB_SITE = http://github.com/bel2125/civetweb/tarball/v$(CIVETWEB_VERSION)
 CIVETWEB_LICENSE = MIT
 CIVETWEB_LICENSE_FILES = LICENSE.md
 

+ 1 - 1
distribution/arch/PKGBUILD.git.example

@@ -15,7 +15,7 @@ optdepends=('php-cgi: for php support')
 provides=("$_pkgname")
 conflicts=("$_pkgname")
 backup=("etc/$_pkgname/$_pkgname.conf")
-source=("$_pkgname::git+https://github.com/sunsetbrew/civetweb.git")
+source=("$_pkgname::git+https://github.com/bel2125/civetweb.git")
 md5sums=('SKIP')
 
 pkgver() {

+ 8 - 5
docs/Building.md

@@ -1,11 +1,11 @@
 Building Civetweb
 =========
 
-This guide covers the build instructions for stand-alone web server.  
-See [Embedding.md](https://github.com/sunsetbrew/civetweb/blob/master/docs/Embedding.md) for information on extending an application.
+This guide covers the build instructions for stand-alone web server.
+See [Embedding.md](https://github.com/bel2125/civetweb/blob/master/docs/Embedding.md) for information on extending an application.
 
 #### Where to get the source code?
-https://github.com/sunsetbrew/civetweb
+https://github.com/bel2125/civetweb
 
 
 Building for Windows
@@ -13,7 +13,7 @@ Building for Windows
 
 Open the *VS2012/civetweb.sln* in Visual Studio.
 To include SSL support, you may have to use yaSSL.  However, it is GPL licensed.
-See [yaSSL.md](https://github.com/sunsetbrew/civetweb/blob/master/docs/yaSSL.md) for more information.
+See [yaSSL.md](https://github.com/bel2125/civetweb/blob/master/docs/yaSSL.md) for more information.
 
 
 Building for Linux, BSD, and OSX
@@ -79,6 +79,9 @@ make build WITH_LUA=1
 | PREFIX=/usr/local         | sets the install directory               |
 | COPT='-DNO_SSL'           | method to insert compile flags           |
 
+Note that the WITH_* options used for *make* are not identical to the
+preprocessor defines in the source code - usually USE_* is used there.
+
 ## Setting compile flags
 
 Compile flags can be set using the *COPT* make option like so.
@@ -97,7 +100,7 @@ make build COPT="-DNDEBUG -DNO_CGI"
 
 ## Cross Compiling
 
-Take total control with *CC*, *COPTS* and *TARGET_OS* as make options.
+Take total control with *CC*, *COPT* and *TARGET_OS* as make options.
 TARGET_OS is used to determine some compile details as will as code function.
 TARGET_OS values should be be one found in *resources/Makefile.in-os*.
 

+ 3 - 3
docs/Embedding.md

@@ -7,7 +7,7 @@ Files
 ------
 
 There is just a small set of files to compile in to the application,
-but if a library is desired, see [Building.md](https://github.com/sunsetbrew/civetweb/blob/master/docs/Building.md)
+but if a library is desired, see [Building.md](https://github.com/bel2125/civetweb/blob/master/docs/Building.md)
 
 #### Regarding the INL file extension
 The *INL* file extension represents code that is statically included inline in a source file.  Slightly different from C++ where it means "inline" code which is technically not the same as static code. Civetweb overloads this extension for the sake of clearity as opossed to having .c extensions on files that should not be directly compiled.
@@ -64,7 +64,7 @@ Lua is a server side include functionality.  Files ending in .la will be process
 ##### Add the following sources
 
   - src/mod_lua.inl
-  - src/third_party/lua-5.2.2/src
+  - src/third_party/lua-5.2.3/src
      + lapi.c
      + lauxlib.c
      + lbaselib.c
@@ -128,7 +128,7 @@ limit on number of simultaneous requests that can be handled by civetweb.
 
 When master thread accepts new connection, a new accepted socket (described by
 `struct socket`) it placed into the accepted sockets queue,
-which has size of 20 (see [code](https://github.com/sunsetbrew/civetweb/blob/3892e0199e6ca9613b160535d9d107ede09daa43/civetweb.c#L486)). Any idle worker thread
+which has size of 20 (see [code](https://github.com/bel2125/civetweb/blob/3892e0199e6ca9613b160535d9d107ede09daa43/civetweb.c#L486)). Any idle worker thread
 can grab accepted sockets from that queue. If all worker threads are busy,
 master thread can accept and queue up to 20 more TCP connections,
 filling up the queue.

+ 4 - 3
docs/Installing.md

@@ -1,16 +1,17 @@
 Civetweb Install Guide
 ====
 
-This guide covers the distributions for CivetWeb.  The latest source code is available at [https://github.com/sunsetbrew/civetweb](https://github.com/sunsetbrew/civetweb).
+This guide covers the distributions for CivetWeb.  The latest source code is available at [https://github.com/bel2125/civetweb](https://github.com/bel2125/civetweb).
 
 Windows
 ---
 
 This pre-built version comes pre-built wit Lua support. Libraries for SSL support are not included due to licensing restrictions;
 however, users may add an SSL library themselves.
-Instructions for adding SSL support can be found in [https://github.com/sunsetbrew/civetweb/tree/master/docs](https://github.com/sunsetbrew/civetweb/tree/master/docs)
+Instructions for adding SSL support can be found in [https://github.com/bel2125/civetweb/tree/master/docs](https://github.com/bel2125/civetweb/tree/master/docs)
 
-1. Install the [Visual C++ Redistributable for Visual Studio 2012](http://www.microsoft.com/en-us/download/details.aspx?id=30679)
+1a. 32 Bit: Install the [Visual C++ Redistributable for Visual Studio 2010](http://www.microsoft.com/en-us/download/details.aspx?id=8328)
+1b. 64 Bit: Install the [Visual C++ Redistributable for Visual Studio 2013](http://www.microsoft.com/en-us/download/details.aspx?id=40784)
 2. Download latest *civetweb-win.zip* from [SourceForge](https://sourceforge.net/projects/civetweb/files/)
 3. When started, Civetweb puts itself into the tray.
 

+ 192 - 129
docs/UserManual.md

@@ -2,54 +2,62 @@
 Overview
 =====
 
-Civetweb is small and easy to use web server. It is self-contained, and does
-not require any external software to run.
+Civetweb is small and easy to use web server.
+It may be embedded into C/C++ host applications or used as a stand-alone
+server. See `Embedding.md` for information on embedding civetweb into
+host applications.
+
+The stand-alone server is self-contained, and does not require any external
+software to run. Some Windows users may need to install the
+[Visual C++ Redistributable](http://www.microsoft.com/en-us/download/details.aspx?id=30679).
 
 Installation
 ----
 
-### Some Windows users may be the install the
-[Visual C++ Redistributable for Visual Studio 2012](http://www.microsoft.com/en-us/download/details.aspx?id=30679)
+On Windows, UNIX and Mac, the civetweb stand-alone executable may be started
+from the command line.
+Running `civetweb` in a terminal, optionally followed by configuration parameters
+(`civetweb [OPTIONS]`) or a configuration file name (`civetweb [config_file_name]`),
+starts the web server.
+
+For UNIX and Mac, civetweb does not detach from the terminal.
+Pressing `Ctrl-C` keys will stop the server.
 
 On Windows, civetweb iconifies itself to the system tray icon when started.
 Right-click on the icon pops up a menu, where it is possible to stop
-civetweb, or configure it, or install it as Windows service. The easiest way
-to share a folder on Windows is to copy `civetweb.exe` to a folder,
-double-click the exe, and launch a browser at
+civetweb, or configure it, or install it as Windows service.
+
+When started without options, the server exposes the local directory at
+[http](http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol) port 8080.
+Thus, the easiest way to share a folder on Windows is to copy `civetweb.exe`
+to this folder, double-click the exe, and launch a browser at
 [http://localhost:8080](http://localhost:8080). Note that 'localhost' should
 be changed to a machine's name if a folder is accessed from other computer.
 
-On UNIX and Mac, civetweb is a command line utility. Running `civetweb` in
-terminal, optionally followed by configuration parameters
-(`civetweb [OPTIONS]`) or configuration file name
-(`civetweb [config_file_name]`) starts the
-web server. Civetweb does not detach from terminal. Pressing `Ctrl-C` keys
-would stop the server.
-
 When started, civetweb first searches for the configuration file.
 If configuration file is specified explicitly in the command line, i.e.
 `civetweb path_to_config_file`, then specified configuration file is used.
 Otherwise, civetweb would search for file `civetweb.conf` in the same directory
-where binary is located, and use it. Configuration file can be absent.
+the executable is located, and use it. This configuration file is optional.
 
-
-Configuration file is a sequence of lines, each line containing
-command line argument name and it's value. Empty lines, and lines beginning
-with `#`, are ignored. Here is the example of `civetweb.conf` file:
+The configuration file is a sequence of lines, each line containing one
+command line argument name and the corresponding value.
+Empty lines, and lines beginning with `#`, are ignored.
+Here is the example of `civetweb.conf` file:
 
     document_root c:\www
-    listening_ports 8080,8043s
+    listening_ports 80,443s
     ssl_certificate c:\civetweb\ssl_cert.pem
 
-When configuration file is processed, civetweb process command line arguments,
-if they are specified. Command line arguments therefore can override
-configuration file settings. Command line arguments must start with `-`.
-For example, if `civetweb.conf` has line
-`document_root /var/www`, and civetweb has been started as
-`civetweb -document_root /etc`, then `/etc` directory will be served as
-document root, because command line options take priority over
-configuration file. Configuration options section below provide a good
-overview of Civetweb features.
+When a configuration file is used, additional command line arguments may
+override the configuration file settings.
+All command line arguments must start with `-`.
+
+For example: The above `civetweb.conf` file is used, and civetweb started as
+`civetweb -document_root D:\web`. Then the `D:\web` directory will be served
+as document root, because command line options take priority over the
+configuration file. The configuration options section below provides a good
+overview of the Civetweb features.
 
 Note that configuration options on the command line must start with `-`,
 but their names are the same as in the config file. All option names are
@@ -64,12 +72,12 @@ listed in the next section. Thus, the following two setups are equivalent:
     document_root /var/www
     $ civetweb
 
-Civetweb can also be used to modify `.htpasswd` passwords file:
+Civetweb can also be used to modify `.htpasswd` passwords files:
 
     civetweb -A <htpasswd_file> <realm> <user> <passwd>
 
-Unlike other web servers, civetweb does not require CGI scripts be located in
-a special directory. CGI scripts can be anywhere. CGI (and SSI) files are
+Unlike other web servers, civetweb does not require CGI scripts to be located
+in a special directory. CGI scripts can be anywhere. CGI (and SSI) files are
 recognized by the file name pattern. Civetweb uses shell-like glob
 patterns. Pattern match starts at the beginning of the string, so essentially
 patterns are prefix patterns. Syntax is as follows:
@@ -88,66 +96,71 @@ All other characters in the pattern match themselves. Examples:
 
 # Configuration Options
 
-Below is a list of configuration options Civetweb understands. Every option
-is followed by it's default value. If default value is not present, then
-it is empty.
+Below is a list of configuration options understood by Civetweb.
+Every option is followed by it's default value. If a default value is not
+present, then the default is empty.
 
-### cgi_pattern `**.cgi$|**.pl$|**.php$`
+### cgi\_pattern `**.cgi$|**.pl$|**.php$`
 All files that match `cgi_pattern` are treated as CGI files. Default pattern
 allows CGI files be anywhere. To restrict CGIs to a certain directory,
-use `/path/to/cgi-bin/**.cgi` as pattern. Note that full file path is
+use `/path/to/cgi-bin/**.cgi` as pattern. Note that the full file path is
 matched against the pattern, not the URI.
 
-### cgi_environment
+### cgi\_environment
 Extra environment variables to be passed to the CGI script in
 addition to standard ones. The list must be comma-separated list
 of name=value pairs, like this: `VARIABLE1=VALUE1,VARIABLE2=VALUE2`.
 
 ### put\_delete\_auth\_file
-Passwords file for PUT and DELETE requests. Without it, PUT and DELETE requests
-will fail.
+Passwords file for PUT and DELETE requests. Without password file, it will not
+be possible to, PUT new files to the server or DELETE existing ones. PUT and
+DELETE requests might still be handled by Lua scripts and CGI paged.
 
-### cgi_interpreter
+### cgi\_interpreter
 Path to an executable to use as CGI interpreter for __all__ CGI scripts
-regardless script extension. If this option is not set (which is a default),
-Civetweb looks at first line of a CGI script,
-[shebang line](http://en.wikipedia.org/wiki/Shebang_(Unix\)), for an interpreter.
+regardless of the script file extension. If this option is not set (which is
+the default), Civetweb looks at first line of a CGI script,
+[shebang line](http://en.wikipedia.org/wiki/Shebang_(Unix\)), for an
+interpreter (not only on Linux and Mac but also for Windows).
 
-For example, if both PHP and perl CGIs are used, then
+For example, if both PHP and Perl CGIs are used, then
 `#!/path/to/php-cgi.exe` and `#!/path/to/perl.exe` must be first lines of the
 respective CGI scripts. Note that paths should be either full file paths,
-or file paths relative to the current working directory of civetweb server.
-If civetweb is started by mouse double-click on Windows, current working
-directory is a directory where civetweb executable is located.
+or file paths relative to the current working directory of the civetweb
+server. If civetweb is started by mouse double-click on Windows, the current
+working directory is the directory where the civetweb executable is located.
 
-If all CGIs use the same interpreter, for example they are all PHP, then
-`cgi_interpreter` can be set to the path to `php-cgi.exe` executable and
-shebang line in the CGI scripts can be omitted.
-Note that PHP scripts must use `php-cgi.exe` executable, not `php.exe`.
+If all CGIs use the same interpreter, for example they are all PHP, it is
+more efficient to set `cgi_interpreter` to the path to `php-cgi.exe`.
+The  shebang line in the CGI scripts can be omitted in this case.
+Note that PHP scripts must use `php-cgi.exe` as executable, not `php.exe`.
 
-### protect_uri
+### protect\_uri
 Comma separated list of URI=PATH pairs, specifying that given
-URIs must be protected with respected password files. Paths must be full
-file paths.
+URIs must be protected with password files specified by PATH.
+All Paths must be full file paths.
 
 ### authentication_domain `mydomain.com`
-Authorization realm used in `.htpasswd` authorization.
+Authorization realm used for HTTP digest authentication. This domain is
+used in the encoding of the `.htpasswd` authorization files as well.
+Changing the domain retroactively will render the existing passwords useless.
 
-### ssi_pattern `**.shtml$|**.shtm$`
-All files that match `ssi_pattern` are treated as SSI.
+### ssi\_pattern `**.shtml$|**.shtm$`
+All files that match `ssi_pattern` are treated as Server Side Includes (SSI).
 
-Server Side Includes (SSI) is a simple interpreted server-side scripting
-language which is most commonly used to include the contents of a file into
-a web page. It can be useful when it is desirable to include a common piece
+SSI is a simple interpreted server-side scripting language which is most
+commonly used to include the contents of another file into a web page.
+It can be useful when it is desirable to include a common piece
 of code throughout a website, for example, headers and footers.
 
 In order for a webpage to recognize an SSI-enabled HTML file, the filename
 should end with a special extension, by default the extension should be
-either `.shtml` or `.shtm`.
+either `.shtml` or `.shtm`. These extentions may be changed using the
+`ssi_pattern` option.
 
 Unknown SSI directives are silently ignored by civetweb. Currently, two SSI
 directives are supported, `<!--#include ...>` and
-`<!--#exec "command">`. Note that `<!--#include ...>` directive supports
+`<!--#exec "command">`. Note that the `<!--#include ...>` directive supports
 three path specifications:
 
     <!--#include virtual="path">  Path is relative to web server root
@@ -158,7 +171,8 @@ three path specifications:
 
 The `include` directive may be used to include the contents of a file or the
 result of running a CGI script. The `exec` directive is used to execute a
-command on a server, and show command's output. Example:
+command on a server, and show the output that would have been printed to
+stdout (the terminal window) otherwise. Example:
 
     <!--#exec "ls -l" -->
 
@@ -179,21 +193,21 @@ megabytes respectively. A limit of 0 means unlimited rate. The
 last matching rule wins. Examples:
 
     *=1k,10.0.0.0/8=0   limit all accesses to 1 kilobyte per second,
-                        but give connections from 10.0.0.0/8 subnet
+                        but give connections the from 10.0.0.0/8 subnet
                         unlimited speed
 
     /downloads/=5k      limit accesses to all URIs in `/downloads/` to
                         5 kilobytes per second. All other accesses are unlimited
 
 ### access\_log\_file
-Path to a file for access logs. Either full path, or relative to current
+Path to a file for access logs. Either full path, or relative to the current
 working directory. If absent (default), then accesses are not logged.
 
 ### enable\_directory\_listing `yes`
 Enable directory listing, either `yes` or `no`.
 
 ### error\_log\_file
-Path to a file for error logs. Either full path, or relative to current
+Path to a file for error logs. Either full path, or relative to the current
 working directory. If absent (default), then errors are not logged.
 
 ### global\_auth\_file
@@ -201,28 +215,31 @@ Path to a global passwords file, either full path or relative to the current
 working directory. If set, per-directory `.htpasswd` files are ignored,
 and all requests are authorized against that file.
 
-The file has to include the realm set through `authentication_domain` and the password in digest format:
+The file has to include the realm set through `authentication_domain` and the
+password in digest format:
 
     user:realm:digest
     test:test.com:ce0220efc2dd2fad6185e1f1af5a4327
 
-(e.g. use [this generator](http://www.askapache.com/online-tools/htpasswd-generator))
+Password files may be generated using `civetweb -A` as explained above, or
+online tools e.g. [this generator](http://www.askapache.com/online-tools/htpasswd-generator).
 
-### index_files `index.html,index.htm,index.cgi,index.shtml,index.php`
-Comma-separated list of files to be treated as directory index
-files.
+### index\_files `index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php`
+Comma-separated list of files to be treated as directory index files.
+If more than one matching file is present in a directory, the one listed to the left
+is used as a directory index.
 
 In case built-in Lua support has been enabled, `index.lp,index.lsp,index.lua`
-are additional default files.
+are additional default index files, ordered before `index.cgi`.
 
 ### enable\_keep\_alive `no`
 Enable connection keep alive, either `yes` or `no`.
 
-Experimental feature. Allows clients to reuse TCP connection for
-subsequent HTTP requests, which improves performance.
-For this to work when using request handlers it's important to add the correct
-Content-Length HTTP header for each request. If this is forgotten the client
-will time out.
+Experimental feature. Allows clients to reuse TCP connection for subsequent
+HTTP requests, which improves performance.
+For this to work when using request handlers it is important to add the
+correct Content-Length HTTP header for each request. If this is forgotten the
+client will time out.
 
 ### access\_control\_list
 An Access Control List (ACL) allows restrictions to be put on the list of IP
@@ -239,14 +256,15 @@ the last match wins. Examples:
     -0.0.0.0/0,+192.168/16    deny all accesses, only allow 192.168/16 subnet
 
 To learn more about subnet masks, see the
-[Wikipedia page on Subnetwork](http://en.wikipedia.org/wiki/Subnetwork)
+[Wikipedia page on Subnetwork](http://en.wikipedia.org/wiki/Subnetwork).
 
 ### extra\_mime\_types
-Extra mime types to recognize, in form `extension1=type1,exten-
-sion2=type2,...`. Extension must include dot.  Example:
+Extra mime types, in tha form `extension1=type1,exten-sion2=type2,...`.
+See the [Wikipedia page on Internet media types](http://en.wikipedia.org/wiki/Internet_media_type).
+Extension must include a leading dot. Example:
 `.cpp=plain/text,.java=plain/text`
 
-### listening_ports `8080`
+### listening\_ports `8080`
 Comma-separated list of ports to listen on. If the port is SSL, a
 letter `s` must be appended, for example, `80,443s` will open
 port 80 and port 443, and connections on port 443 will be SSL-ed.
@@ -260,33 +278,34 @@ an IP address and a colon must be pre-pended to the port number.
 For example, to bind to a loopback interface on port 80 and to
 all interfaces on HTTPS port 443, use `127.0.0.1:80,443s`.
 
-### document_root `.`
-A directory to serve. By default, current directory is served. Current
-directory is commonly referenced as dot (`.`).
+### document\_root `.`
+A directory to serve. By default, the current workubg directory is served.
+The current directory is commonly referenced as dot (`.`).
 
-### ssl_certificate
-Path to SSL certificate file. This option is only required when at least one
-of the `listening_ports` is SSL. The file must be in PEM format,
-and it must have both private key and certificate, see for example
-[ssl_cert.pem](https://github.com/sunsetbrew/civetweb/blob/master/resources/ssl_cert.pem)
+### ssl\_certificate
+Path to the SSL certificate file. This option is only required when at least
+one of the `listening\_ports` is SSL. The file must be in PEM format,
+and it must have both, private key and certificate, see for example
+[ssl_cert.pem](https://github.com/bel2125/civetweb/blob/master/resources/ssl_cert.pem)
 A description how to create a certificate can be found in doc/OpenSSL.md
 
-### num_threads `50`
+### num\_threads `50`
 Number of worker threads. Civetweb handles each incoming connection in a
-separate thread. Therefore, the value of this option is effectively a number
+separate thread. Therefore, the value of this option is effectively the number
 of concurrent HTTP connections Civetweb can handle.
 
 ### run\_as\_user
 Switch to given user credentials after startup. Usually, this option is
-required when civetweb needs to bind on privileged port on UNIX. To do
-that, civetweb needs to be started as root. But running as root is a bad idea,
-therefore this option can be used to drop privileges. Example:
+required when civetweb needs to bind on privileged ports on UNIX. To do
+that, civetweb needs to be started as root. From a security point of view,
+running as root is not advisable, therefore this option can be used to drop
+privileges. Example:
 
-    civetweb -listening_ports 80 -run_as_user nobody
+    civetweb -listening_ports 80 -run_as_user webserver
 
 ### url\_rewrite\_patterns
 Comma-separated list of URL rewrites in the form of
-`uri_pattern=file_or_directory_path`. When Civetweb receives the request,
+`uri_pattern=file_or_directory_path`. When Civetweb receives any request,
 it constructs the file name to show by combining `document_root` and the URI.
 However, if the rewrite option is used and `uri_pattern` matches the
 requested URI, then `document_root` is ignored. Instead,
@@ -300,48 +319,67 @@ to redirect all accesses to `.doc` files to a special script, do:
 
     civetweb -url_rewrite_patterns **.doc$=/path/to/cgi-bin/handle_doc.cgi
 
-Or, to imitate user home directories support, do:
+Or, to imitate support for user home directories, do:
 
     civetweb -url_rewrite_patterns /~joe/=/home/joe/,/~bill=/home/bill/
 
 ### hide\_files\_patterns
 A pattern for the files to hide. Files that match the pattern will not
 show up in directory listing and return `404 Not Found` if requested. Pattern
-must be for a file name only, not including directory name. Example:
+must be for a file name only, not including directory names. Example:
 
-    civetweb -hide_files_patterns secret.txt|even_more_secret.txt
+    civetweb -hide_files_patterns secret.txt|*.hide
 
 ### request\_timeout\_ms `30000`
 Timeout for network read and network write operations, in milliseconds.
-If client intends to keep long-running connection, either increase this value
-or use keep-alive messages.
+If a client intends to keep long-running connection, either increase this
+value or (better) use keep-alive messages.
 
-### lua_preload_file
+### lua\_preload\_file
 This configuration option can be used to specify a Lua script file, which
 is executed before the actual web page script (Lua script, Lua server page
 or Lua websocket). It can be used to modify the Lua environment of all web
-page scripts, e.g., by loading additional libraries required by all scripts
-or to achieve backward compatibility by defining obsolete functions.
+page scripts, e.g., by loading additional libraries or defining functions
+required by all scripts.
+It may be used to achieve backward compatibility by defining obsolete
+functions as well.
 
-### lua_script_pattern `"**.lua$`
+### lua\_script\_pattern `"**.lua$`
 A pattern for files that are interpreted as Lua scripts by the server.
 In contrast to Lua server pages, Lua scripts use plain Lua syntax.
 An example can be found in the test directory.
 
-### lua_server_page_pattern `**.lp$|**.lsp$`
+### lua\_server\_page\_pattern `**.lp$|**.lsp$`
 Files matching this pattern are treated as Lua server pages.
 In contrast to Lua scripts, the content of a Lua server pages is delivered
 directly to the client. Lua script parts are delimited from the standard
 content by including them between <? and ?> tags.
 An example can be found in the test directory.
 
-### websocket_root
+### websocket\_root
 In case civetweb is built with Lua and websocket support, Lua scripts may
 be used for websockets as well. Since websockets use a different URL scheme
 (ws, wss) than other http pages (http, https), the Lua scripts used for
 websockets may also be served from a different directory. By default,
 the document_root is used as websocket_root as well.
 
+### access\_control\_allow\_origin
+Access-Control-Allow-Origin header field, used for cross-origin resource
+sharing (CORS).
+See the [Wikipedia page on CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing).
+
+### error\_pages
+This option may be used to specify a directory for user defined error pages.
+The error pages may be specified for an individual http status code (e.g.,
+404 - page requested by the client not found), a group of http status codes
+(e.g., 4xx - all client errors) or all errors. The corresponding error pages
+must be called error404.ext, error4xx.ext or error.ext, whereas the file
+extention may be one of the extentions specified for the index_files option.
+See the [Wikipedia page on HTTP status codes](http://en.wikipedia.org/wiki/HTTP_status_code).
+
+### decode\_url `yes`
+URL encoded request strings are decoded in the server, unless it is disabled
+by setting this option to `no`.
 
 # Lua Scripts and Lua Server Pages
 Pre-built Windows and Mac civetweb binaries have built-in Lua scripting
@@ -358,8 +396,9 @@ PHP. Lua script elements must be enclosed in `<?  ?>` blocks, and can appear
 anywhere on the page. Furthermore, Lua Server Pages offer the opportunity to
 insert the content of a variable by enclosing the Lua variable name in
 `<?=  ?>` blocks, similar to PHP.
-For example, to print current weekday name and the URI of the current page,
-one can write:
+For example, to print the current weekday name and the URI of the current
+page, one can write:
+
     <p>
       <span>Today is:</span>
       <? mg.write(os.date("%A")) ?>
@@ -368,38 +407,40 @@ one can write:
       URI is <?=mg.request_info.uri?>
     </p>
 
-Lua is known for it's speed and small size. Civetweb uses Lua version 5.2.2,
-the documentation for it can be found at
+Lua is known for it's speed and small size. Civetweb currently uses Lua
+version 5.2.3. The documentation for it can be found in the
 [Lua 5.2 reference manual](http://www.lua.org/manual/5.2/).
 
 
-Note that this example uses function `mg.write()`, which prints data to the
-web page. Using function `mg.write()` is the way to generate web content from
-inside Lua code. In addition to `mg.write()`, all standard library functions
-are accessible from the Lua code (please check reference manual for details),
-and also information about the request is available in `mg.request_info`
-object, like request method, all headers, etcetera.
+Note that this example uses function `mg.write()`, which sends data to the
+web client. Using `mg.write()` is the way to generate web content from inside
+Lua code. In addition to `mg.write()`, all standard Lua library functions
+are accessible from the Lua code (please check the reference manual for
+details). Information on the request is available in the `mg.request_info`
+object, like the request method, all HTTP headers, etcetera.
 
-[page2.lua](https://github.com/sunsetbrew/civetweb/blob/master/test/page2.lua)
+[page2.lua](https://github.com/bel2125/civetweb/blob/master/test/page2.lua)
 is an example for a plain Lua script.
 
-[page2.lp](https://github.com/sunsetbrew/civetweb/blob/master/test/page2.lp)
+[page2.lp](https://github.com/bel2125/civetweb/blob/master/test/page2.lp)
 is an example for a Lua Server Page.
 
 Both examples show the content of the `mg.request_info` object as the page
 content. Please refer to `struct mg_request_info` definition in
-[civetweb.h](https://github.com/sunsetbrew/civetweb/blob/master/include/civetweb.h)
+[civetweb.h](https://github.com/bel2125/civetweb/blob/master/include/civetweb.h)
 to see additional information on the elements of the `mg.request_info` object.
 
 Civetweb also provides access to the [SQlite3 database](http://www.sqlite.org/)
 through the [LuaSQLite3 interface](http://lua.sqlite.org/index.cgi/doc/tip/doc/lsqlite3.wiki)
-in Lua. An example is given in
-[page.lp](https://github.com/sunsetbrew/civetweb/blob/master/test/page.lp).
+in Lua. Examples are given in
+[page.lua](https://github.com/bel2125/civetweb/blob/master/test/page.lua) and
+[page.lp](https://github.com/bel2125/civetweb/blob/master/test/page.lp).
 
 
 Civetweb exports the following functions to Lua:
 
 mg (table):
+
     mg.read()                  -- reads a chunk from POST data, returns it as a string
     mg.write(str)              -- writes string to the client
     mg.include(path)           -- sources another Lua file
@@ -431,6 +472,7 @@ mg (table):
          .remote_user          -- user name if authenticated, nil otherwise
 
 connect (function):
+
     -- Connect to the remote TCP server. This function is an implementation
     -- of simple socket interface. It returns a socket object with three
     -- methods: send, recv, close, which are synchronous (blocking).
@@ -450,25 +492,46 @@ connect (function):
 
 
 **IMPORTANT: Civetweb does not send HTTP headers for Lua pages. Therefore,
-every Lua Page must begin with HTTP reply line and headers**, like this:
+every Lua Page must begin with a HTTP reply line and headers**, like this:
 
     <? print('HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n') ?>
     <html><body>
       ... the rest of the web page ...
 
-To serve Lua Page, civetweb creates Lua context. That context is used for
+To serve a Lua Page, civetweb creates a Lua context. That context is used for
 all Lua blocks within the page. That means, all Lua blocks on the same page
 share the same context. If one block defines a variable, for example, that
-variable is visible in the block that follows.
+variable is visible in all block that follow.
+
+## Websockets for Lua
+Civetweb offers support for websockets in Lua as well. In contrast to plain
+Lua scripts and Lua server pages, Lua websocket scripts are shared by all clients.
+
+Lua websocket scripts must define a few functions:
+    open(arg)    -- callback to accept or reject a connection
+    ready(arg)   -- called after a connection has been established
+    data(arg)    -- called when the server receives data from the client
+    close(arg)   -- called when a websocket connection is closed
+All function are called with one argument of type table with at least one field
+"client" to identify the client. When "open" is called, the argument table additionally
+contains the "request_info" table as defined above. For the "data" handler, an
+additional field "data" is available. The functions "open", "ready" and "data"
+must return true in order to keep the connetion open.
+
+Lua websocket pages do support single shot (timeout) and interval timers.
+
+An example is shown in
+[websocket.lua](https://github.com/bel2125/civetweb/blob/master/test/websocket.lua).
+
 
 # Common Problems
 - PHP doesn't work - getting empty page, or 'File not found' error. The
   reason for that is wrong paths to the interpreter. Remember that with PHP,
-  correct interpreter is `php-cgi.exe` (`php-cgi` on UNIX). Solution: specify
-  full path to the PHP interpreter, e.g.:
+  the correct interpreter is `php-cgi.exe` (`php-cgi` on UNIX).
+  Solution: specify the full path to the PHP interpreter, e.g.:
     `civetweb -cgi_interpreter /full/path/to/php-cgi`
 
-- Civetweb fails to start. If Civetweb exits immediately when run, this
+- Civetweb fails to start. If Civetweb exits immediately when started, this
   usually indicates a syntax error in the configuration file
   (named `civetweb.conf` by default) or the command-line arguments.
   Syntax checking is omitted from Civetweb to keep its size low. However,

+ 1 - 1
docs/yaSSL.md

@@ -4,7 +4,7 @@ Adding CyaSSL Support
 ### Only required for Windows!
 
 In order to support SSL *HTTPS* connections in Civetweb on Windows,
-you will have to use the GPLv2 licensed CyaSSL library.  By using this
+you may wish to use the GPLv2 licensed CyaSSL library.  By using this
 library, the resulting binary may have to have the GPL license unless
 you buy a commercial license from [wolfSSL](http://www.yassl.com/).
 

+ 1 - 1
examples/chat/chat.c

@@ -105,7 +105,7 @@ static char *messages_to_json(long last_id)
         // messages (it may be too small if the ringbuffer is full and all
         // messages are large. in this case asserts will trigger).
         len += snprintf(buf + len, sizeof(buf) - len,
-                        "{user: '%s', text: '%s', timestamp: %lu, id: %lu},",
+                        "{user: '%s', text: '%s', timestamp: %lu, id: %ld},",
                         message->user, message->text, message->timestamp, message->id);
         assert(len > 0);
         assert((size_t) len < sizeof(buf));

+ 10 - 8
examples/embedded_cpp/embedded_cpp.cpp

@@ -9,6 +9,8 @@
 
 #ifdef _WIN32
 #include <Windows.h>
+#else
+#include <unistd.h>
 #endif
 
 #define DOCUMENT_ROOT "."
@@ -22,14 +24,14 @@ class ExampleHandler: public CivetHandler
 public:
     bool handleGet(CivetServer *server, struct mg_connection *conn) {
         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, "<h2>This is an example text from a C++ handler</h2>");
-        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 *.foo handler <a href=\"xy.foo\">click here</a></p>");
-        mg_printf(conn, "<p>To exit <a href=\"%s\">click here</a></p>",
-                  EXIT_URI);
-        mg_printf(conn, "</body></html>\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, "<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 exit <a href=\"%s\">click here</a></p>\r\n", EXIT_URI);
+        mg_printf(conn, "</body></html>\r\n");
         return true;
     }
 };

+ 1 - 1
examples/upload/upload.c

@@ -1,5 +1,5 @@
 // Copyright (c) 2004-2012 Sergey Lyubka
-// This file is a part of civetweb project, http://github.com/sunsetbrew/civetweb
+// This file is a part of civetweb project, http://github.com/bel2125/civetweb
 
 #include <stdio.h>
 #include <string.h>

+ 54 - 82
examples/websocket/WebSockCallbacks.c

@@ -1,32 +1,11 @@
 #include <assert.h>
 #include <stdlib.h>
 #include <time.h>
-#include "WebSockCallbacks.h"
-
-#ifdef __APPLE__
 #include <string.h>
-#endif
+#include "WebSockCallbacks.h"
 
 #ifdef _WIN32
 #include <Windows.h>
-typedef HANDLE pthread_mutex_t;
-static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused) {
-    unused = NULL;
-    *mutex = CreateMutex(NULL, FALSE, NULL);
-    return *mutex == NULL ? -1 : 0;
-}
-
-static int pthread_mutex_destroy(pthread_mutex_t *mutex) {
-    return CloseHandle(*mutex) == 0 ? -1 : 0;
-}
-
-static int pthread_mutex_lock(pthread_mutex_t *mutex) {
-    return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
-}
-
-static int pthread_mutex_unlock(pthread_mutex_t *mutex) {
-    return ReleaseMutex(*mutex) == 0 ? -1 : 0;
-}
 #define mg_sleep(x) Sleep(x)
 #else
 #include <unistd.h>
@@ -35,27 +14,18 @@ static int pthread_mutex_unlock(pthread_mutex_t *mutex) {
 #endif
 
 
-typedef struct tWebSockInfo {
-    int webSockState;
-    unsigned long initId;
-    struct mg_connection *conn;
-} tWebSockInfo;
-
-static pthread_mutex_t sMutex;
-
-#define MAX_NUM_OF_WEBSOCKS (256)
-static tWebSockInfo *socketList[MAX_NUM_OF_WEBSOCKS];
-
-
-static void send_to_all_websockets(const char * data, int data_len) {
+static void send_to_all_websockets(struct mg_context *ctx, const char * data, int data_len) {
 
     int i;
+    tWebSockContext *ws_ctx = (tWebSockContext*) mg_get_user_data(ctx);
 
+    mg_lock_context(ctx);
     for (i=0;i<MAX_NUM_OF_WEBSOCKS;i++) {
-        if (socketList[i] && (socketList[i]->webSockState==2)) {
-            mg_websocket_write(socketList[i]->conn, WEBSOCKET_OPCODE_TEXT, data, data_len);
+        if (ws_ctx->socketList[i] && (ws_ctx->socketList[i]->webSockState==2)) {
+            mg_websocket_write(ws_ctx->socketList[i]->conn, WEBSOCKET_OPCODE_TEXT, data, data_len);
         }
     }
+    mg_unlock_context(ctx);
 }
 
 
@@ -63,32 +33,36 @@ void websocket_ready_handler(struct mg_connection *conn) {
 
     int i;
     struct mg_request_info * rq = mg_get_request_info(conn);
+    struct mg_context * ctx = mg_get_context(conn);
+    tWebSockContext *ws_ctx = (tWebSockContext*) mg_get_user_data(ctx);
     tWebSockInfo * wsock = malloc(sizeof(tWebSockInfo));
     assert(wsock);
     wsock->webSockState = 0;
     rq->conn_data = wsock;
 
-    pthread_mutex_lock(&sMutex);
+    mg_lock_context(ctx);
     for (i=0;i<MAX_NUM_OF_WEBSOCKS;i++) {
-        if (0==socketList[i]) {
-            socketList[i] = wsock;
+        if (0==ws_ctx->socketList[i]) {
+            ws_ctx->socketList[i] = wsock;
             wsock->conn = conn;
             wsock->webSockState = 1;
             break;
         }
     }
     printf("\nNew websocket attached: %08lx:%u\n", rq->remote_ip, rq->remote_port);
-    pthread_mutex_unlock(&sMutex);
+    mg_unlock_context(ctx);
 }
 
 
-static void websocket_done(tWebSockInfo * wsock) {
+static void websocket_done(tWebSockContext *ws_ctx, tWebSockInfo * wsock) {
+
     int i;
+
     if (wsock) {
         wsock->webSockState = 99;
         for (i=0;i<MAX_NUM_OF_WEBSOCKS;i++) {
-            if (wsock==socketList[i]) {
-                socketList[i] = 0;
+            if (wsock==ws_ctx->socketList[i]) {
+                ws_ctx->socketList[i] = 0;
                 break;
             }
         }
@@ -99,16 +73,19 @@ static void websocket_done(tWebSockInfo * wsock) {
 
 
 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);
     tWebSockInfo * wsock = (tWebSockInfo*)rq->conn_data;
+    struct mg_context * ctx = mg_get_context(conn);
+    tWebSockContext *ws_ctx = (tWebSockContext*) mg_get_user_data(ctx);
     char msg[128];
 
-    pthread_mutex_lock(&sMutex);
+    mg_lock_context(ctx);
     if (flags==136) {
         // close websock
-        websocket_done(wsock);
+        websocket_done(ws_ctx, wsock);
         rq->conn_data = 0;
-        pthread_mutex_unlock(&sMutex);
+        mg_unlock_context(ctx);
         return 1;
     }
     if (((data_len>=5) && (data_len<100) && (flags==129)) || (flags==130)) {
@@ -124,67 +101,64 @@ int websocket_data_handler(struct mg_connection *conn, int flags, char *data, si
             if (gid>0 && chk!=NULL && *chk==0) {
                 wsock->webSockState = 2;
             }
-            pthread_mutex_unlock(&sMutex);
+            mg_unlock_context(ctx);
             return 1;
         }
 
         // chat message
         if ((wsock->webSockState==2) && (!memcmp(data,"msg ",4))) {
-            send_to_all_websockets(data, data_len);
-            pthread_mutex_unlock(&sMutex);
+            send_to_all_websockets(ctx, data, data_len);
+            mg_unlock_context(ctx);
             return 1;
         }
     }
 
     // keep alive
     if ((data_len==4) && !memcmp(data,"ping",4)) {
-        pthread_mutex_unlock(&sMutex);
+        mg_unlock_context(ctx);
         return 1;
     }
 
-    pthread_mutex_unlock(&sMutex);
+    mg_unlock_context(ctx);
     return 0;
 }
 
 
 void connection_close_handler(struct mg_connection *conn) {
+
     struct mg_request_info * rq = mg_get_request_info(conn);
     tWebSockInfo * wsock = (tWebSockInfo*)rq->conn_data;
+    struct mg_context * ctx = mg_get_context(conn);
+    tWebSockContext *ws_ctx = (tWebSockContext*) mg_get_user_data(ctx);
 
-    pthread_mutex_lock(&sMutex);
-    websocket_done(wsock);
+    mg_lock_context(ctx);
+    websocket_done(ws_ctx, wsock);
     rq->conn_data = 0;
-    pthread_mutex_unlock(&sMutex);
+    mg_unlock_context(ctx);
 }
 
 
-static int runLoop = 0;
+static void * eventMain(void * arg) {
 
-static void * eventMain(void * _ignored) {
-    int i;
     char msg[256];
+    struct mg_context *ctx = (struct mg_context *)arg;
+    tWebSockContext *ws_ctx = (tWebSockContext*) mg_get_user_data(ctx);
 
-    runLoop = 1;
-    while (runLoop) {
+    ws_ctx->runLoop = 1;
+    while (ws_ctx->runLoop) {
         time_t t = time(0);
         struct tm * timestr = localtime(&t);
         sprintf(msg,"title %s",asctime(timestr));
 
-        pthread_mutex_lock(&sMutex);
-        for (i=0;i<MAX_NUM_OF_WEBSOCKS;i++) {
-            if (socketList[i] && (socketList[i]->webSockState==2)) {
-                mg_websocket_write(socketList[i]->conn, WEBSOCKET_OPCODE_TEXT, msg, strlen(msg));
-            }
-        }
-        pthread_mutex_unlock(&sMutex);
+        send_to_all_websockets(ctx, msg, strlen(msg));
 
         mg_sleep(1000);
     }
 
-    return _ignored;
+    return NULL;
 }
 
-void websock_send_broadcast(const char * data, int data_len) {
+void websock_send_broadcast(struct mg_context *ctx, const char * data, int data_len) {
 
     char buffer[260];
 
@@ -192,24 +166,22 @@ void websock_send_broadcast(const char * data, int data_len) {
         strcpy(buffer, "msg ");
         memcpy(buffer+4, data, data_len);
 
-        pthread_mutex_lock(&sMutex);
-        send_to_all_websockets(buffer, data_len+4);
-        pthread_mutex_unlock(&sMutex);
+        send_to_all_websockets(ctx, buffer, data_len+4);
     }
 }
 
-void websock_init_lib(void) {
-
-    int ret;
-    ret = pthread_mutex_init(&sMutex, 0);
-    assert(ret==0);
-
-    memset(socketList,0,sizeof(socketList));
+void websock_init_lib(struct mg_context *ctx) {
 
-    mg_start_thread(eventMain, 0);
+    tWebSockContext *ws_ctx = (tWebSockContext*) mg_get_user_data(ctx);
+    memset(ws_ctx,0,sizeof(*ws_ctx));
+    /* todo: use mg_start_thread_id instead of mg_start_thread */
+    mg_start_thread(eventMain, ctx);
 }
 
-void websock_exit_lib(void) {
+void websock_exit_lib(struct mg_context *ctx) {
 
-    runLoop = 0;
+    tWebSockContext *ws_ctx = (tWebSockContext*) mg_get_user_data(ctx);
+    ws_ctx->runLoop = 0;
+    /* todo: wait for the thread instead of a timeout */
+    mg_sleep(2000);
 }

+ 17 - 3
examples/websocket/WebSockCallbacks.h

@@ -8,10 +8,24 @@
 extern "C" {
 #endif
 
-void websock_init_lib(void);
-void websock_exit_lib(void);
+typedef struct tWebSockInfo {
+    int webSockState;
+    unsigned long initId;
+    struct mg_connection *conn;
+} tWebSockInfo;
 
-void websock_send_broadcast(const char * data, int data_len);
+#define MAX_NUM_OF_WEBSOCKS (256)
+typedef struct tWebSockContext {
+    int runLoop;
+    void * thread_id;
+    tWebSockInfo *socketList[MAX_NUM_OF_WEBSOCKS];
+} tWebSockContext;
+
+
+void websock_init_lib(struct mg_context *ctx);
+void websock_exit_lib(struct mg_context *ctx);
+
+void websock_send_broadcast(struct mg_context *ctx, const char * data, int data_len);
 
 void websocket_ready_handler(struct mg_connection *conn);
 int websocket_data_handler(struct mg_connection *conn, int flags, char *data, size_t data_len);

+ 7 - 5
examples/websocket/websocket.c

@@ -9,6 +9,7 @@ int main(void)
 {
     struct mg_context *ctx = 0;
     struct mg_callbacks callback_funcs = {0};
+    tWebSockContext ws_ctx;
     char inbuf[4];
 
     const char *server_options[] = {
@@ -22,12 +23,14 @@ int main(void)
         NULL
     };
 
-    websock_init_lib();
-
+    callback_funcs.init_context = websock_init_lib;
+    callback_funcs.exit_context = websock_exit_lib;
     callback_funcs.websocket_ready = websocket_ready_handler;
     callback_funcs.websocket_data = websocket_data_handler;
     callback_funcs.connection_close = connection_close_handler;
-    ctx = mg_start(&callback_funcs, NULL, server_options);
+
+    ctx = mg_start(&callback_funcs, &ws_ctx, server_options);
+    printf("Connect to localhost:%s/websock.htm\n", mg_get_option(ctx, "listening_ports"));
 
     puts("Enter an (ASCII) character or * to exit:");
     for (;;) {
@@ -37,11 +40,10 @@ int main(void)
            break;
         }
         inbuf[0] = toupper(inbuf[0]);
-        websock_send_broadcast(inbuf, 1);
+        websock_send_broadcast(ctx, inbuf, 1);
     }
 
     mg_stop(ctx);
-    websock_exit_lib();
 
     return 0;
 }

+ 37 - 0
examples/websocket_client/Makefile

@@ -0,0 +1,37 @@
+# 
+# Copyright (c) 2014 Jordan Shelley
+# https://github.com/jshelley
+# License http://opensource.org/licenses/mit-license.php MIT License
+#
+
+#This makefile is used to test the other Makefiles
+
+
+PROG = websocket_client
+SRC = websocket_client.c
+
+TOP = ../..
+CIVETWEB_LIB = libcivetweb.a
+
+CFLAGS = -I$(TOP)/include $(COPT) 
+LIBS = -lpthread
+
+include $(TOP)/resources/Makefile.in-os
+
+ifeq ($(TARGET_OS),LINUX) 
+	LIBS += -ldl
+endif
+
+all: $(PROG)
+
+$(PROG): $(CIVETWEB_LIB) $(SRC)
+	$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(SRC) $(CIVETWEB_LIB) $(LIBS)
+
+$(CIVETWEB_LIB):
+	$(MAKE) -C $(TOP) clean lib
+	cp $(TOP)/$(CIVETWEB_LIB) .
+
+clean:
+	rm -f $(CIVETWEB_LIB) $(PROG)
+
+.PHONY: all clean

+ 13 - 0
examples/websocket_client/ssl/server.crt

@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICATCCAWoCCQC2BCIqIvgSUTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
+VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMB4XDTE0MDgyMTEyMzAwMVoXDTI0MDgxODEyMzAwMVowRTELMAkG
+A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0
+IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA9k9s
+gH22BCo9neTeB/YnilK7n0sMe0+pjS9KSWhU59Q4w8hqPrW0tuYikIDd0wVggkJF
+BZNg4WPoulTdwXsgNBeG88q2wnNtUosXTS+KQTQBSiQof9Ay9GHQtgxnogI1zIXb
+HOppyyG5zre8a/X6fzDOnFc4iJMBwxTAnjCqObkCAwEAATANBgkqhkiG9w0BAQUF
+AAOBgQBX9V46VUVsB9P9fb8sFuMx2ezFE42ynEeJPrKRrof+dFYbjvR1OUZFSLCy
+aZKwVH7iCnVBJiU12JxO7PR3L6ob3FYPyNHQWYq1/IFUvqBRagehldj5H8iFeEDz
+Wtz2+p1rUyVxcSUqTjobaji0aC8lzPZio0nd1KKM6A92/adHyQ==
+-----END CERTIFICATE-----

+ 11 - 0
examples/websocket_client/ssl/server.csr

@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIBhDCB7gIBADBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh
+MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQD2T2yAfbYEKj2d5N4H9ieKUrufSwx7T6mNL0pJaFTn1DjD
+yGo+tbS25iKQgN3TBWCCQkUFk2DhY+i6VN3BeyA0F4bzyrbCc21SixdNL4pBNAFK
+JCh/0DL0YdC2DGeiAjXMhdsc6mnLIbnOt7xr9fp/MM6cVziIkwHDFMCeMKo5uQID
+AQABoAAwDQYJKoZIhvcNAQEFBQADgYEA1EOFwyFJ2NAnRNktZCy5yVcLx9C78HoC
+oHPPCOElu0VDIqe6ZecYdaqWbYlhGE0+isbOQn2CwHOeBGN8mIDsNUYzVEpsEfgg
+9OK873LpE5pf4mdjSiRBXkk/h8BxuqkcKi+Qx+qEE7+dH2nK5aKeIHVvbLyfGOch
+9I85q+msBNE=
+-----END CERTIFICATE REQUEST-----

+ 15 - 0
examples/websocket_client/ssl/server.key

@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQD2T2yAfbYEKj2d5N4H9ieKUrufSwx7T6mNL0pJaFTn1DjDyGo+
+tbS25iKQgN3TBWCCQkUFk2DhY+i6VN3BeyA0F4bzyrbCc21SixdNL4pBNAFKJCh/
+0DL0YdC2DGeiAjXMhdsc6mnLIbnOt7xr9fp/MM6cVziIkwHDFMCeMKo5uQIDAQAB
+AoGAYwospr3lomcZv5N3c9wWqhf6OWMD8dFma87IIBxDh7Rd3tuHXQ/TSnffDhvD
+FkbjN31OI5/PJNH3knTtdg78MywPloE4jYsbt4+fEaW7Fzww2nU61N1p+mYk5d/b
+SCTAHhGzF9g9ZMw25CCUFGjDU2z+Ty6my22Euxhk2Qq8tMECQQD9ZYIxWkPhywDW
+pX3v70dqIv7411hEYpuL/ZJl26UCmQsj4HPtXQCraQksVPs74WY5aTtd6MAV9V3M
+UnErHO5/AkEA+NdG2MmfBOBPusDB/WwQaUPiCWGITS9llGTR2JXbvDqmKgL1+UTG
+o27sLNIFCrF1wejpyRGqwjcObFYR0yKrxwJBAOB2uPuK4DL1psp9Uq/mIDbOxVod
+OF1rlCpP9w0vol5Iv+uJ+mc7SUqOAsg4h0yl/+2/YA1yDiXlcq96IDF2sXUCQGAv
+Nh9Nr72+xpK1N0axopZNuu1NWdYb3/PAFKzXIBxdvyS2CEXVo8JAeeHJPFGpzo6p
+bNRfk9WGWnjdu/4UhLkCQQCekR9zpIpzdJiPYCd6XMya+TPCDYlOQL1jlnJIRa2V
+BEOz0rSpzXAGh0PyCB/kMneyVk87LWn8joE6179RoUfv
+-----END RSA PRIVATE KEY-----

+ 18 - 0
examples/websocket_client/ssl/server.key.orig

@@ -0,0 +1,18 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,89778A6427F05D4A
+
+4aXqO/8oCHVfMLB+a1DfjbXyEddjbd7nB+YVFLPKy68Tam9PRTvC1zRHBet59ll0
+1w7R8tXR6/xH7HRhBeqDHCcuvBhtw3xGxtXWv54WBFhzuq7TvKOAaCFl++cw/JHq
+PCS0rAaYnqF2MAgMi7QBjZKmHFHL43Gy60VfOrB0mmOdxqqXA0NBFC2uEd7Z/MAx
+S2A85bNJJKQaWEeDThP1u0OOlNCq99lkLJ31jiOH7ntdL0/vqcbZ+PUtdPLwAG4L
+1GUHuiC2v5FvDlPiejMk2dvrxCNpcu2e3tQKHpg2KcsTVrpB7EVzRSazln4HywUZ
+EJfBvxqqrS7plImZgj4LXSnln0JPuBb+aHnhKIFvisjYSwqDGJnnp/OaD7YdRhYh
+UCcL011Ge+yUbRipeAmHdtJlSUSdB14KWq+WdIX/KgCRGx06QZm9s1PBLH+fww+I
+EL3A/LFX0a5KUHkCp29akYYv9bUYaQ79Nt7BlaEON+/SW3pJMbGr+nx8aqogr0Yo
+SJ/Zz5TSDBhecRjbCDGkT6DizVZ8cbm2xl8QLBd0H+ZA6uYMgfpAOJGrJx3Nm4Lv
+prEApgFtjSrsQDGYHAcmDMW1UWOVHuNp7BSvwUze9Ftnzr/jlpdzES2rhgMyGhg1
+0Szbsfs3vgw4iM83LFJXza07GQJzF8gRF79dY5JiQX/sOKUprA6Lofk631jE0G8r
+3z59cxblaq9y7EgFsE944Gk7/HIEimBRiqIZzGVJVukD0itynQ+XmYTdbyH1lpvi
+c0ZheZPUoGwUW9RYy+nle5gEDFyZWXcCAuJasQvDBXt//r/bso3ZpA==
+-----END RSA PRIVATE KEY-----

+ 28 - 0
examples/websocket_client/ssl/server.pem

@@ -0,0 +1,28 @@
+-----BEGIN CERTIFICATE-----
+MIICATCCAWoCCQC2BCIqIvgSUTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
+VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMB4XDTE0MDgyMTEyMzAwMVoXDTI0MDgxODEyMzAwMVowRTELMAkG
+A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0
+IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA9k9s
+gH22BCo9neTeB/YnilK7n0sMe0+pjS9KSWhU59Q4w8hqPrW0tuYikIDd0wVggkJF
+BZNg4WPoulTdwXsgNBeG88q2wnNtUosXTS+KQTQBSiQof9Ay9GHQtgxnogI1zIXb
+HOppyyG5zre8a/X6fzDOnFc4iJMBwxTAnjCqObkCAwEAATANBgkqhkiG9w0BAQUF
+AAOBgQBX9V46VUVsB9P9fb8sFuMx2ezFE42ynEeJPrKRrof+dFYbjvR1OUZFSLCy
+aZKwVH7iCnVBJiU12JxO7PR3L6ob3FYPyNHQWYq1/IFUvqBRagehldj5H8iFeEDz
+Wtz2+p1rUyVxcSUqTjobaji0aC8lzPZio0nd1KKM6A92/adHyQ==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQD2T2yAfbYEKj2d5N4H9ieKUrufSwx7T6mNL0pJaFTn1DjDyGo+
+tbS25iKQgN3TBWCCQkUFk2DhY+i6VN3BeyA0F4bzyrbCc21SixdNL4pBNAFKJCh/
+0DL0YdC2DGeiAjXMhdsc6mnLIbnOt7xr9fp/MM6cVziIkwHDFMCeMKo5uQIDAQAB
+AoGAYwospr3lomcZv5N3c9wWqhf6OWMD8dFma87IIBxDh7Rd3tuHXQ/TSnffDhvD
+FkbjN31OI5/PJNH3knTtdg78MywPloE4jYsbt4+fEaW7Fzww2nU61N1p+mYk5d/b
+SCTAHhGzF9g9ZMw25CCUFGjDU2z+Ty6my22Euxhk2Qq8tMECQQD9ZYIxWkPhywDW
+pX3v70dqIv7411hEYpuL/ZJl26UCmQsj4HPtXQCraQksVPs74WY5aTtd6MAV9V3M
+UnErHO5/AkEA+NdG2MmfBOBPusDB/WwQaUPiCWGITS9llGTR2JXbvDqmKgL1+UTG
+o27sLNIFCrF1wejpyRGqwjcObFYR0yKrxwJBAOB2uPuK4DL1psp9Uq/mIDbOxVod
+OF1rlCpP9w0vol5Iv+uJ+mc7SUqOAsg4h0yl/+2/YA1yDiXlcq96IDF2sXUCQGAv
+Nh9Nr72+xpK1N0axopZNuu1NWdYb3/PAFKzXIBxdvyS2CEXVo8JAeeHJPFGpzo6p
+bNRfk9WGWnjdu/4UhLkCQQCekR9zpIpzdJiPYCd6XMya+TPCDYlOQL1jlnJIRa2V
+BEOz0rSpzXAGh0PyCB/kMneyVk87LWn8joE6179RoUfv
+-----END RSA PRIVATE KEY-----

+ 303 - 0
examples/websocket_client/websocket_client.c

@@ -0,0 +1,303 @@
+/*
+* Copyright (c) 2014 the Civetweb developers
+* Copyright (c) 2014 Jordan Shelley
+* https://github.com/jshelley
+* License http://opensource.org/licenses/mit-license.php MIT License
+*/
+
+// Simple example program on how to use websocket client embedded C interface.
+#ifdef _WIN32
+#include <Windows.h>
+#define sleep(x) Sleep(1000*(x))
+#else
+#include <unistd.h>
+#endif
+
+#include <assert.h>
+#include <string.h>
+#include "civetweb.h"
+
+#define DOCUMENT_ROOT "."
+#define PORT "8888"
+#define SSL_CERT "./ssl/server.pem"
+
+const char * websocket_welcome_msg = "websocket welcome\n";
+const size_t websocket_welcome_msg_len = 18 /* strlen(websocket_welcome_msg) */ ;
+const char * websocket_acknowledge_msg = "websocket msg ok\n";
+const size_t websocket_acknowledge_msg_len = 17 /* strlen(websocket_acknowledge_msg) */ ;
+const char * websocket_goodbye_msg = "websocket bye\n";
+const size_t websocket_goodbye_msg_len = 14 /* strlen(websocket_goodbye_msg) */ ;
+
+
+/*************************************************************************************/
+/* WEBSOCKET SERVER                                                                  */
+/*************************************************************************************/
+int websock_server_connect(const struct mg_connection * conn)
+{
+    printf("Server: Websocket connected\n");
+    return 0; /* return 0 to accept every connection */
+}
+
+void websocket_server_ready(struct mg_connection * conn)
+{
+    printf("Server: Websocket ready\n");
+
+    /* Send websocket welcome message */
+    mg_lock_connection(conn);
+    mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, websocket_welcome_msg, websocket_welcome_msg_len);
+    mg_unlock_connection(conn);
+}
+
+int websocket_server_data(struct mg_connection * conn, int bits, char *data, size_t data_len)
+{
+    printf("Server: Got %u bytes from the client\n", data_len);
+
+    if (data_len<3 || 0!=memcmp(data, "bye", 3)) {
+        /* Send websocket acknowledge message */
+        mg_lock_connection(conn);
+        mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, websocket_acknowledge_msg, websocket_acknowledge_msg_len);
+        mg_unlock_connection(conn);
+    } else {
+        /* Send websocket acknowledge message */
+        mg_lock_connection(conn);
+        mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, websocket_goodbye_msg, websocket_goodbye_msg_len);
+        mg_unlock_connection(conn);
+    }
+
+    return 1; /* return 1 to keep the connetion open */
+}
+
+void websocket_server_connection_close(struct mg_connection * conn)
+{
+    printf("Server: Close connection\n");
+
+    /* Can not send a websocket goodbye message here - the connection is already closed */
+}
+
+struct mg_context * start_websocket_server()
+{
+    const char * options[] = { "document_root", DOCUMENT_ROOT,
+        "ssl_certificate", SSL_CERT,
+        "listening_ports", PORT,
+        "request_timeout_ms", "5000",
+        0
+    };
+    struct mg_callbacks callbacks;
+    struct mg_context *ctx;
+
+    memset(&callbacks, 0, sizeof(callbacks));
+    callbacks.websocket_connect = websock_server_connect;
+    callbacks.websocket_ready = websocket_server_ready;
+    callbacks.websocket_data = websocket_server_data;
+    callbacks.connection_close = websocket_server_connection_close;
+    ctx = mg_start(&callbacks, 0, options);
+
+    return ctx;
+}
+
+
+/*************************************************************************************/
+/* WEBSOCKET CLIENT                                                                  */
+/*************************************************************************************/
+struct tclient_data {
+    void * data;
+    size_t len;
+    int closed;
+};
+
+static int websocket_client_data_handler(struct mg_connection *conn, int flags, char *data, size_t data_len)
+{
+    struct mg_context *ctx = mg_get_context(conn);
+    struct tclient_data *pclient_data = (struct tclient_data *) mg_get_user_data(ctx);
+
+    printf("Client received data from server: ");
+    fwrite(data, 1, data_len, stdout);
+    printf("\n");
+
+    pclient_data->data = malloc(data_len);
+    assert(pclient_data->data != NULL);
+    memcpy(pclient_data->data, data, data_len);
+    pclient_data->len = data_len;
+
+    return 1;
+}
+
+static void websocket_client_close_handler(struct mg_connection *conn)
+{
+    struct mg_context *ctx = mg_get_context(conn);
+    struct tclient_data *pclient_data = (struct tclient_data *) mg_get_user_data(ctx);
+
+    printf("Client: Close handler\n");
+    pclient_data->closed++;
+}
+
+
+int main(int argc, char *argv[])
+{
+    struct mg_context *ctx = NULL;
+    struct tclient_data client1_data = {NULL, 0, 0};
+    struct tclient_data client2_data = {NULL, 0, 0};
+    struct tclient_data client3_data = {NULL, 0, 0};
+    struct mg_connection* newconn1 = NULL;
+    struct mg_connection* newconn2 = NULL;
+    struct mg_connection* newconn3 = NULL;
+    char ebuf[100] = {0};
+
+    assert(websocket_welcome_msg_len == strlen(websocket_welcome_msg));
+
+    /* First set up a websocket server */
+    ctx = start_websocket_server();
+    assert(ctx != NULL);
+    printf("Server init\n\n");
+
+    /* Then connect a first client */
+    newconn1 = mg_connect_websocket_client("localhost", atoi(PORT), 0, ebuf, sizeof(ebuf),
+        "/websocket", NULL, websocket_client_data_handler, websocket_client_close_handler,
+        &client1_data);
+
+    if (newconn1 == NULL)
+    {
+        printf("Error: %s", ebuf);
+        return 1;
+    }
+
+    sleep(1); /* Should get the websocket welcome message */
+    assert(client1_data.closed == 0);
+    assert(client2_data.closed == 0);
+    assert(client2_data.data == NULL);
+    assert(client2_data.len == 0);
+    assert(client1_data.data != NULL);
+    assert(client1_data.len == websocket_welcome_msg_len);
+    assert(!memcmp(client1_data.data, websocket_welcome_msg, websocket_welcome_msg_len));
+    free(client1_data.data);
+    client1_data.data = NULL;
+    client1_data.len = 0;
+
+    mg_websocket_write(newconn1, WEBSOCKET_OPCODE_TEXT, "data1", 5);
+
+    sleep(1); /* Should get the acknowledge message */
+    assert(client1_data.closed == 0);
+    assert(client2_data.closed == 0);
+    assert(client2_data.data == NULL);
+    assert(client2_data.len == 0);
+    assert(client1_data.data != NULL);
+    assert(client1_data.len == websocket_acknowledge_msg_len);
+    assert(!memcmp(client1_data.data, websocket_acknowledge_msg, websocket_acknowledge_msg_len));
+    free(client1_data.data);
+    client1_data.data = NULL;
+    client1_data.len = 0;
+
+    /* Now connect a second client */
+    newconn2 = mg_connect_websocket_client("localhost", atoi(PORT), 0, ebuf, sizeof(ebuf),
+        "/websocket", NULL, websocket_client_data_handler, websocket_client_close_handler,
+        &client2_data);
+
+    if (newconn2 == NULL)
+    {
+        printf("Error: %s", ebuf);
+        return 1;
+    }
+
+    sleep(1); /* Client 2 should get the websocket welcome message */
+    assert(client1_data.closed == 0);
+    assert(client2_data.closed == 0);
+    assert(client1_data.data == NULL);
+    assert(client1_data.len == 0);
+    assert(client2_data.data != NULL);
+    assert(client2_data.len == websocket_welcome_msg_len);
+    assert(!memcmp(client2_data.data, websocket_welcome_msg, websocket_welcome_msg_len));
+    free(client2_data.data);
+    client2_data.data = NULL;
+    client2_data.len = 0;
+
+    mg_websocket_write(newconn1, WEBSOCKET_OPCODE_TEXT, "data2", 5);
+
+    sleep(1); /* Should get the acknowledge message */
+    assert(client1_data.closed == 0);
+    assert(client2_data.closed == 0);
+    assert(client2_data.data == NULL);
+    assert(client2_data.len == 0);
+    assert(client1_data.data != NULL);
+    assert(client1_data.len == websocket_acknowledge_msg_len);
+    assert(!memcmp(client1_data.data, websocket_acknowledge_msg, websocket_acknowledge_msg_len));
+    free(client1_data.data);
+    client1_data.data = NULL;
+    client1_data.len = 0;
+
+    mg_websocket_write(newconn1, WEBSOCKET_OPCODE_TEXT, "bye", 3);
+
+    sleep(1); /* Should get the goodbye message */
+    assert(client1_data.closed == 0);
+    assert(client2_data.closed == 0);
+    assert(client2_data.data == NULL);
+    assert(client2_data.len == 0);
+    assert(client1_data.data != NULL);
+    assert(client1_data.len == websocket_goodbye_msg_len);
+    assert(!memcmp(client1_data.data, websocket_goodbye_msg, websocket_goodbye_msg_len));
+    free(client1_data.data);
+    client1_data.data = NULL;
+    client1_data.len = 0;
+
+    mg_close_connection(newconn1);
+
+    sleep(1); /* Won't get any message */
+    assert(client1_data.closed == 1);
+    assert(client2_data.closed == 0);
+    assert(client1_data.data == NULL);
+    assert(client1_data.len == 0);
+    assert(client2_data.data == NULL);
+    assert(client2_data.len == 0);
+
+    mg_websocket_write(newconn2, WEBSOCKET_OPCODE_TEXT, "bye", 3);
+
+    sleep(1); /* Should get the goodbye message */
+    assert(client1_data.closed == 1);
+    assert(client2_data.closed == 0);
+    assert(client1_data.data == NULL);
+    assert(client1_data.len == 0);
+    assert(client2_data.data != NULL);
+    assert(client2_data.len == websocket_goodbye_msg_len);
+    assert(!memcmp(client2_data.data, websocket_goodbye_msg, websocket_goodbye_msg_len));
+    free(client2_data.data);
+    client2_data.data = NULL;
+    client2_data.len = 0;
+
+    mg_close_connection(newconn2);
+
+    sleep(1); /* Won't get any message */
+    assert(client1_data.closed == 1);
+    assert(client2_data.closed == 1);
+    assert(client1_data.data == NULL);
+    assert(client1_data.len == 0);
+    assert(client2_data.data == NULL);
+    assert(client2_data.len == 0);
+
+    /* Connect client 3 */
+    newconn3 = mg_connect_websocket_client("localhost", atoi(PORT), 0, ebuf, sizeof(ebuf),
+        "/websocket", NULL, websocket_client_data_handler, websocket_client_close_handler,
+        &client3_data);
+
+    sleep(1); /* Client 3 should get the websocket welcome message */
+    assert(client1_data.closed == 1);
+    assert(client2_data.closed == 1);
+    assert(client3_data.closed == 0);
+    assert(client1_data.data == NULL);
+    assert(client1_data.len == 0);
+    assert(client2_data.data == NULL);
+    assert(client2_data.len == 0);
+    assert(client3_data.data != NULL);
+    assert(client3_data.len == websocket_welcome_msg_len);
+    assert(!memcmp(client3_data.data, websocket_welcome_msg, websocket_welcome_msg_len));
+    free(client3_data.data);
+    client3_data.data = NULL;
+    client3_data.len = 0;
+
+    mg_stop(ctx);
+    printf("Server shutdown\n");
+
+    sleep(10);
+
+    assert(client3_data.closed == 1);
+
+    return 0;
+}

+ 1 - 1
examples/ws_server/ws_server.c

@@ -1,5 +1,5 @@
 // Copyright (c) 2004-2012 Sergey Lyubka
-// This file is a part of civetweb project, http://github.com/sunsetbrew/civetweb
+// This file is a part of civetweb project, http://github.com/bel2125/civetweb
 //
 // v 0.1 Contributed by William Greathouse    9-Sep-2013
 

+ 61 - 45
include/CivetServer.h

@@ -9,10 +9,11 @@
 #ifdef __cplusplus
 
 #include "civetweb.h"
-#include <vector>
+#include <map>
 #include <string>
 
-class CivetServer; // forward declaration
+// forward declaration
+class CivetServer;
 
 /**
  * Basic interface for a URI request handler.  Handlers implementations
@@ -69,7 +70,7 @@ public:
 /**
  * CivetServer
  *
- * Basic class for embedded web server.  This has a URL mapping built-in.
+ * Basic class for embedded web server.  This has an URL mapping built-in.
  */
 class CivetServer
 {
@@ -127,16 +128,18 @@ public:
      *
      * Removes a handler.
      *
-     * @param - the exact URL used in addHandler().
+     * @param uri - the exact URL used in addHandler().
      */
     void removeHandler(const std::string &uri);
 
     /**
      * getCookie(struct mg_connection *conn, const std::string &cookieName, std::string &cookieValue)
+     *
+     * Puts the cookie value string that matches the cookie name in the cookieValue destinaton string.
+     *
      * @param conn - the connection information
      * @param cookieName - cookie name to get the value from
      * @param cookieValue - cookie value is returned using thiis reference
-     * @puts the cookie value string that matches the cookie name in the _cookieValue string.
      * @returns the size of the cookie value string read.
     */
     static int getCookie(struct mg_connection *conn, const std::string &cookieName, std::string &cookieValue);
@@ -154,13 +157,18 @@ public:
      *
      * Returns a query paramter contained in the supplied buffer.  The
      * occurance value is a zero-based index of a particular key name.  This
-     * should nto be confused with the index over all of the keys.
+     * should not be confused with the index over all of the keys.  Note that this
+     * function assumes that parameters are sent as text in http query string
+     * format, which is the default for web forms. This function will work for
+     * html forms with method="GET" and method="POST" attributes. In other cases,
+     * you may use a getParam version that directly takes the data instead of the
+     * connection as a first argument.
      *
-     * @param data the query string
-     * @param name the key to search for
-     * @param the destination string
-     * @param occurrence the occurrence of the selected name in the query (0 based).
-     * @return true of key was found
+     * @param conn - parameters are read from the data sent through this connection
+     * @param name - the key to search for
+     * @param dst - the destination string
+     * @param occurrence - the occurrence of the selected name in the query (0 based).
+     * @return true if key was found
      */
     static bool getParam(struct mg_connection *conn, const char *name,
                          std::string &dst, size_t occurrence=0);
@@ -170,13 +178,13 @@ public:
      *
      * Returns a query paramter contained in the supplied buffer.  The
      * occurance value is a zero-based index of a particular key name.  This
-     * should nto be confused with the index over all of the keys.
+     * should not be confused with the index over all of the keys.
      *
-     * @param data the query string
-     * @param name the key to search for
-     * @param the destination string
-     * @param occurrence the occurrence of the selected name in the query (0 based).
-     * @return true of key was found
+     * @param data - the query string (text)
+     * @param name - the key to search for
+     * @param dst - the destination string
+     * @param occurrence - the occurrence of the selected name in the query (0 based).
+     * @return true if key was found
      */
     static bool getParam(const std::string &data, const char *name,
                          std::string &dst, size_t occurrence=0) {
@@ -188,14 +196,14 @@ public:
      *
      * Returns a query paramter contained in the supplied buffer.  The
      * occurance value is a zero-based index of a particular key name.  This
-     * should nto be confused with the index over all of the keys.
+     * should not be confused with the index over all of the keys.
      *
-     * @param data the query string
-     * @param length length of the query string
-     * @param name the key to search for
-     * @param the destination string
-     * @param occurrence the occurrence of the selected name in the query (0 based).
-     * @return true of key was found
+     * @param data the - query string (text)
+     * @param data_len - length of the query string
+     * @param name - the key to search for
+     * @param dst - the destination string
+     * @param occurrence - the occurrence of the selected name in the query (0 based).
+     * @return true if key was found
      */
     static bool getParam(const char *data, size_t data_len, const char *name,
                          std::string &dst, size_t occurrence=0);
@@ -204,9 +212,9 @@ public:
     /**
      * urlDecode(const std::string &, std::string &, bool)
      *
-     * @param src string to be decoded
-     * @param dst destination string
-     * @is_form_url_encoded true if form url encoded
+     * @param src - string to be decoded
+     * @param dst - destination string
+     * @param is_form_url_encoded - true if form url encoded
      *       form-url-encoded data differs from URI encoding in a way that it
      *       uses '+' as character for space, see RFC 1866 section 8.2.1
      *       http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
@@ -218,10 +226,10 @@ public:
     /**
      * urlDecode(const char *, size_t, std::string &, bool)
      *
-     * @param src buffer to be decoded
-     * @param src_len length of buffer to be decoded
-     * @param dst destination string
-     * @is_form_url_encoded true if form url encoded
+     * @param src - buffer to be decoded
+     * @param src_len - length of buffer to be decoded
+     * @param dst - destination string
+     * @param is_form_url_encoded - true if form url encoded
      *       form-url-encoded data differs from URI encoding in a way that it
      *       uses '+' as character for space, see RFC 1866 section 8.2.1
      *       http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
@@ -231,9 +239,9 @@ public:
     /**
      * urlDecode(const char *, std::string &, bool)
      *
-     * @param src buffer to be decoded (0 terminated)
-     * @param dst destination string
-     * @is_form_url_encoded true if form url encoded
+     * @param src - buffer to be decoded (0 terminated)
+     * @param dst - destination string
+     * @param is_form_url_encoded true - if form url encoded
      *       form-url-encoded data differs from URI encoding in a way that it
      *       uses '+' as character for space, see RFC 1866 section 8.2.1
      *       http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
@@ -243,9 +251,9 @@ public:
     /**
      * urlEncode(const std::string &, std::string &, bool)
      *
-     * @param src buffer to be encoded
-     * @param dst destination string
-     * @append true if string should not be cleared before encoding.
+     * @param src - buffer to be encoded
+     * @param dst - destination string
+     * @param append - true if string should not be cleared before encoding.
      */
     static void urlEncode(const std::string &src, std::string &dst, bool append=false) {
         urlEncode(src.c_str(), src.length(), dst, append);
@@ -254,26 +262,34 @@ public:
     /**
      * urlEncode(const char *, size_t, std::string &, bool)
      *
-     * @param src buffer to be encoded (0 terminated)
-     * @param dst destination string
-     * @append true if string should not be cleared before encoding.
+     * @param src - buffer to be encoded (0 terminated)
+     * @param dst - destination string
+     * @param append - true if string should not be cleared before encoding.
      */
     static void urlEncode(const char *src, std::string &dst, bool append=false);
 
     /**
      * urlEncode(const char *, size_t, std::string &, bool)
      *
-     * @param src buffer to be encoded
-     * @param src_len length of buffer to be decoded
-     * @param dst destination string
-     * @append true if string should not be cleared before encoding.
+     * @param src - buffer to be encoded
+     * @param src_len - length of buffer to be decoded
+     * @param dst - destination string
+     * @param append - true if string should not be cleared before encoding.
      */
     static void urlEncode(const char *src, size_t src_len, std::string &dst, bool append=false);
 
 protected:
+    class CivetConnection {
+    public:
+        char * postData;
+        unsigned long postDataLen;
+
+        CivetConnection();
+        ~CivetConnection();
+    };
 
     struct mg_context *context;
-    char * postData;
+    std::map<struct mg_connection *, class CivetConnection> connections;
 
 private:
     /**

+ 60 - 5
include/civetweb.h

@@ -24,7 +24,7 @@
 #define CIVETWEB_HEADER_INCLUDED
 
 #ifndef CIVETWEB_VERSION
-#define CIVETWEB_VERSION "1.6"
+#define CIVETWEB_VERSION "1.7"
 #endif
 
 #ifndef CIVETWEB_API
@@ -62,6 +62,8 @@ struct mg_request_info {
     const char *remote_user;    /* Authenticated user, or NULL if no auth
                                    used */
     long remote_ip;             /* Client's IP address */
+    long long content_length;   /* Length (in bytes) of the request body,
+                                   can be -1 if no length was given. */
     int remote_port;            /* Client's port */
     int is_ssl;                 /* 1 if SSL-ed, 0 if not */
     void *user_data;            /* User data pointer passed to mg_start() */
@@ -77,7 +79,7 @@ struct mg_request_info {
 
 /* This structure needs to be passed to mg_start(), to let civetweb know
    which callbacks to invoke. For detailed description, see
-   https://github.com/sunsetbrew/civetweb/blob/master/docs/UserManual.md */
+   https://github.com/bel2125/civetweb/blob/master/docs/UserManual.md */
 struct mg_callbacks {
     /* Called when civetweb has received new HTTP request.
        If callback returns non-zero,
@@ -153,6 +155,17 @@ struct mg_callbacks {
        Parameters:
          status: HTTP error status code. */
     int  (*http_error)(struct mg_connection *, int status);
+
+    /* Called after civetweb context has been created, before requests
+       are processed.
+       Parameters:
+         ctx: context handle */
+    void (*init_context)(struct mg_context * ctx);
+
+    /* Called when civetweb context is deleted.
+       Parameters:
+         ctx: context handle */
+    void (*exit_context)(struct mg_context * ctx);
 };
 
 
@@ -176,7 +189,7 @@ struct mg_callbacks {
      };
      struct mg_context *ctx = mg_start(&my_func, NULL, options);
 
-   Refer to https://github.com/sunsetbrew/civetweb/blob/master/docs/UserManual.md
+   Refer to https://github.com/bel2125/civetweb/blob/master/docs/UserManual.md
    for the list of valid option and their possible values.
 
    Return:
@@ -236,6 +249,14 @@ CIVETWEB_API void mg_set_request_handler(struct mg_context *ctx, const char *uri
 CIVETWEB_API const char *mg_get_option(const struct mg_context *ctx, const char *name);
 
 
+/* Get context from connection. */
+CIVETWEB_API struct mg_context *mg_get_context(struct mg_connection *conn);
+
+
+/* Get user data passed to mg_start from context. */
+CIVETWEB_API void *mg_get_user_data(struct mg_context *ctx);
+
+
 #if defined(MG_LEGACY_INTERFACE)
 /* Return array of strings that represent valid configuration options.
    For each option, option name and default value is returned, i.e. the
@@ -330,8 +351,18 @@ CIVETWEB_API int mg_websocket_write(struct mg_connection* conn, int opcode,
    Invoke this before mg_write or mg_printf when communicating with a
    websocket if your code has server-initiated communication as well as
    communication in direct response to a message. */
-CIVETWEB_API void mg_lock(struct mg_connection* conn);
-CIVETWEB_API void mg_unlock(struct mg_connection* conn);
+CIVETWEB_API void mg_lock_connection(struct mg_connection* conn);
+CIVETWEB_API void mg_unlock_connection(struct mg_connection* conn);
+
+#if defined(MG_LEGACY_INTERFACE)
+#define mg_lock mg_lock_connection
+#define mg_unlock mg_unlock_connection
+#endif
+
+/* Lock server context.  This lock may be used to protect ressources
+   that are shared between different connection/worker threads. */
+CIVETWEB_API void mg_lock_context(struct mg_context* ctx);
+CIVETWEB_API void mg_unlock_context(struct mg_context* ctx);
 
 
 /* Opcodes, from http://tools.ietf.org/html/rfc6455 */
@@ -542,7 +573,31 @@ CIVETWEB_API void mg_cry(struct mg_connection *conn,
 /* utility method to compare two buffers, case incensitive. */
 CIVETWEB_API int mg_strncasecmp(const char *s1, const char *s2, size_t len);
 
+/* Connect to a websocket as a client
+   Parameters:
+     host: host to connect to, i.e. "echo.websocket.org" or "192.168.1.1" or "localhost"
+     port: server port
+     use_ssl: make a secure connection to server
+     error_buffer, error_buffer_size: error message placeholder.
+     path: server path you are trying to connect to, i.e. if connection to localhost/app, path should be "/app"
+     origin: value of the Origin HTTP header
+     data_func: callback that should be used when data is received from the server
+     user_data: user supplied argument
+
+   Return:
+     On success, valid mg_connection object.
+     On error, NULL. */
+
+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,
+                                               char *error_buffer, size_t error_buffer_size,
+                                               const char *path, const char *origin,
+                                               websocket_data_func data_func, websocket_close_func close_func,
+                                               void * user_data);
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

+ 1 - 1
resources/Makefile.in-lua

@@ -3,7 +3,7 @@
 # License http://opensource.org/licenses/mit-license.php MIT License
 #
 
-LUA_DIR = src/third_party/lua-5.2.2/src
+LUA_DIR = src/third_party/lua-5.2.3/src
 
 LUA_SOURCE_FILES = lapi.c  \
     lauxlib.c \

+ 2 - 2
resources/civetweb.conf

@@ -1,6 +1,6 @@
 # Civetweb web server configuration file.
 # For detailed description of every option, visit
-# https://github.com/sunsetbrew/civetweb/blob/master/docs/UserManual.md
+# https://github.com/bel2125/civetweb/blob/master/docs/UserManual.md
 # Lines starting with '#' and empty lines are ignored.
 # To make a change, remove leading '#', modify option's value,
 # save this file and then restart Civetweb.
@@ -29,4 +29,4 @@ listening_ports 8080
 # run_as_user 
 # url_rewrite_patterns 
 # hide_files_patterns 
-# request_timeout_ms 30000
+# request_timeout_ms 30000

+ 3 - 3
resources/itworks.html

@@ -12,10 +12,10 @@
 <b style="font-size:larger"><a style="text-decoration:none" href="https://sourceforge.net/projects/civetweb/">Civetweb</a></b><br>
 <i>Your web server</i>
 <ul>
-<li><a href="https://github.com/sunsetbrew/civetweb/blob/master/docs/UserManual.md">User Manual</a></li>
-<li><a href="https://github.com/sunsetbrew/civetweb/blob/master/RELEASE_NOTES.md">Release Notes</a></li>
+<li><a href="https://github.com/bel2125/civetweb/blob/master/docs/UserManual.md">User Manual</a></li>
+<li><a href="https://github.com/bel2125/civetweb/blob/master/RELEASE_NOTES.md">Release Notes</a></li>
 <li><a href="https://sourceforge.net/projects/civetweb/">Downloads</a></li>
-<li><a href="https://github.com/sunsetbrew/civetweb">GitHub</a></li>
+<li><a href="https://github.com/bel2125/civetweb">GitHub</a></li>
 </ul>
 </p>
 </div>

BIN
resources/luafilesystem-logo.jpg


BIN
resources/luasqlite-logo.jpg


BIN
resources/luaxml-logo.jpg


+ 34 - 14
src/CivetServer.cpp

@@ -48,6 +48,9 @@ int CivetServer::requestHandler(struct mg_connection *conn, void *cbdata)
     assert(request_info != NULL);
     CivetServer *me = (CivetServer*) (request_info->user_data);
     assert(me != NULL);
+    mg_lock_context(me->context);
+    me->connections[conn] = CivetConnection();
+    mg_unlock_context(me->context);
 
     CivetHandler *handler = (CivetHandler *)cbdata;
 
@@ -68,10 +71,11 @@ int CivetServer::requestHandler(struct mg_connection *conn, void *cbdata)
 
 CivetServer::CivetServer(const char **options,
                          const struct mg_callbacks *_callbacks) :
-    context(0), postData(0)
+    context(0)
 {
     struct mg_callbacks callbacks;
     memset(&callbacks, 0, sizeof(callbacks));
+
     if (_callbacks) {
         callbacks = *_callbacks;
         userCloseHandler = _callbacks->connection_close;
@@ -79,7 +83,6 @@ CivetServer::CivetServer(const char **options,
         userCloseHandler = NULL;
     }
     callbacks.connection_close = closeHandler;
-
     context = mg_start(&callbacks, this, options);
 }
 
@@ -96,10 +99,9 @@ void CivetServer::closeHandler(struct mg_connection *conn)
     assert(me != NULL);
 
     if (me->userCloseHandler) me->userCloseHandler(conn);
-    if (me->postData) {
-        free(me->postData);
-        me->postData = 0;
-    }
+    mg_lock_context(me->context);
+    me->connections.erase(conn);
+    mg_unlock_context(me->context);
 }
 
 void CivetServer::addHandler(const std::string &uri, CivetHandler *handler)
@@ -150,7 +152,7 @@ CivetServer::urlDecode(const char *src, size_t src_len, std::string &dst, bool i
 
     dst.clear();
     for (i = j = 0; i < (int)src_len; i++, j++) {
-        if (src[i] == '%' && i < (int)src_len - 2 &&
+        if (i < (int)src_len - 2 && src[i] == '%' &&
             isxdigit(* (const unsigned char *) (src + i + 1)) &&
             isxdigit(* (const unsigned char *) (src + i + 2))) {
             a = tolower(* (const unsigned char *) (src + i + 1));
@@ -174,19 +176,27 @@ CivetServer::getParam(struct mg_connection *conn, const char *name,
     assert(ri != NULL);
     CivetServer *me = (CivetServer*) (ri->user_data);
     assert(me != NULL);
+    mg_lock_context(me->context);
+    CivetConnection &conobj = me->connections[conn];
+    mg_lock_connection(conn);
+    mg_unlock_context(me->context);
 
-    if (me->postData != NULL) {
-        formParams = me->postData;
+    if (conobj.postData != NULL) {
+        formParams = conobj.postData;
     } else {
         const char * con_len_str = mg_get_header(conn, "Content-Length");
         if (con_len_str) {
             unsigned long con_len = atoi(con_len_str);
             if (con_len>0) {
-                me->postData = (char*)malloc(con_len);
-                if (me->postData != NULL) {
-                    /* malloc may fail for huge requests */
-                    mg_read(conn, me->postData, con_len);
-                    formParams = me->postData;
+                // Add one extra character: in case the post-data is a text, it is required as 0-termination.
+                // Do not increment con_len, since the 0 terminating is not part of the content (text or binary).
+                conobj.postData = (char*)malloc(con_len + 1);
+                if (conobj.postData != NULL) {
+                    // malloc may fail for huge requests
+                    mg_read(conn, conobj.postData, con_len);
+                    conobj.postData[con_len] = 0;
+                    formParams = conobj.postData;
+                    conobj.postDataLen = con_len;
                 }
             }
         }
@@ -195,6 +205,7 @@ CivetServer::getParam(struct mg_connection *conn, const char *name,
         // get requests do store html <form> field values in the http query_string
         formParams = ri->query_string;
     }
+    mg_unlock_connection(conn);
 
     if (formParams != NULL) {
         return getParam(formParams, strlen(formParams), name, dst, occurrence);
@@ -266,3 +277,12 @@ CivetServer::urlEncode(const char *src, size_t src_len, std::string &dst, bool a
         }
     }
 }
+
+CivetServer::CivetConnection::CivetConnection() {
+    postData = NULL;
+    postDataLen = 0;
+}
+
+CivetServer::CivetConnection::~CivetConnection() {
+    free(postData);
+}

Файловите разлики са ограничени, защото са твърде много
+ 443 - 258
src/civetweb.c


+ 462 - 59
src/main.c

@@ -51,6 +51,7 @@
 
 #define getcwd(a,b) _getcwd(a,b)
 extern char *_getcwd(char *buf, size_t size);
+static int guard = 0;                   /* test if any dialog is already open */
 
 #ifndef PATH_MAX
 #define PATH_MAX MAX_PATH
@@ -74,10 +75,10 @@ extern char *_getcwd(char *buf, size_t size);
 #define abs_path(rel, abs, abs_size) realpath((rel), (abs))
 #endif /* _WIN32 */
 
-#define MAX_OPTIONS 100
+#define MAX_OPTIONS 50
 #define MAX_CONF_FILE_LINE_SIZE (8 * 1024)
 
-static int exit_flag;
+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() */
@@ -88,6 +89,10 @@ static struct mg_context *ctx;          /* Set by start_civetweb() */
 #define CONFIG_FILE "civetweb.conf"
 #endif /* !CONFIG_FILE */
 
+#if !defined(PASSWORDS_FILE_NAME)
+#define PASSWORDS_FILE_NAME ".htpasswd"
+#endif
+
 /* backup config file */
 #if !defined(CONFIG_FILE2) && defined(LINUX)
 #define CONFIG_FILE2 "/usr/local/etc/civetweb.conf"
@@ -129,18 +134,17 @@ static void die(const char *fmt, ...)
     exit(EXIT_FAILURE);
 }
 
+#ifdef WIN32
+static int MakeConsole();
+#endif
+
 static void show_usage_and_exit(void)
 {
     const struct mg_option *options;
     int i;
 
 #ifdef WIN32
-    if (!AttachConsole(ATTACH_PARENT_PROCESS)) {
-        AllocConsole();
-        AttachConsole(GetCurrentProcessId());
-    }
-    freopen("CON", "a", stdout);
-    freopen("CON", "a", stderr);
+    MakeConsole();
 #endif
 
     fprintf(stderr, "Civetweb v%s, built on %s\n",
@@ -168,7 +172,7 @@ static void show_usage_and_exit(void)
 static const char *config_file_top_comment =
     "# Civetweb web server configuration file.\n"
     "# For detailed description of every option, visit\n"
-    "# https://github.com/sunsetbrew/civetweb/blob/master/docs/UserManual.md\n"
+    "# https://github.com/bel2125/civetweb/blob/master/docs/UserManual.md\n"
     "# Lines starting with '#' and empty lines are ignored.\n"
     "# To make a change, remove leading '#', modify option's value,\n"
     "# save this file and then restart Civetweb.\n\n";
@@ -226,12 +230,32 @@ static char *sdup(const char *str)
     return p;
 }
 
+static const char *get_option(char **options, const char *option_name)
+{
+    int i = 0;
+    const char *opt_value = NULL;
+
+    /* TODO: options should be an array of key-value-pairs, like
+       struct {const char * key, const char * value} options[]
+       but it currently is an array with
+       options[2*i] = key, options[2*i + 1] = value
+    */
+    while (options[2*i] != NULL) {
+        if (strcmp(options[2*i], option_name) == 0) {
+            opt_value = options[2*i + 1];
+            break;
+        }
+        i++;
+    }
+    return opt_value;
+}
+
 static int set_option(char **options, const char *name, const char *value)
 {
     int i, type;
     const struct mg_option *default_options = mg_get_valid_options();
 
-    for (i = 0; main_config_options[i].name != 0; i++) {
+    for (i = 0; main_config_options[i].name != NULL; i++) {
         if (0==strcmp(name, main_config_options[i].name)) {
             /* This option is evaluated by main.c, not civetweb.c - just skip it and return OK */
             return 1;
@@ -239,7 +263,7 @@ static int set_option(char **options, const char *name, const char *value)
     }
 
     type = CONFIG_TYPE_UNKNOWN;
-    for (i = 0; default_options[i].name != 0; i++) {
+    for (i = 0; default_options[i].name != NULL; i++) {
         if (!strcmp(default_options[i].name, name)) {
             type = default_options[i].type;
         }
@@ -249,37 +273,56 @@ static int set_option(char **options, const char *name, const char *value)
             /* unknown option */
             return 0;
         case CONFIG_TYPE_NUMBER:
+            /* integer number > 0, e.g. number of threads */
             if (atol(value)<1) {
                 /* invalid number */
                 return 0;
             }
             break;
+        case CONFIG_TYPE_STRING:
+            /* any text */
+            break;
         case CONFIG_TYPE_BOOLEAN:
+            /* boolean value, yes or no */
             if ((0!=strcmp(value,"yes")) && (0!=strcmp(value,"no"))) {
                 /* invalid boolean */
                 return 0;
             }
             break;
+        case CONFIG_TYPE_FILE:
+        case CONFIG_TYPE_DIRECTORY:
+            /* TODO: check this option when it is set, instead of calling verify_existence later */
+            break;
+        case CONFIG_TYPE_EXT_PATTERN:
+            /* list of file extentions */
+            break;
+        default:
+            die("Unknown option type - option %s", name);
+            break;
     }
 
-    for (i = 0; i < MAX_OPTIONS - 3; i++) {
-        if (options[i] == NULL) {
-            options[i] = sdup(name);
-            options[i + 1] = sdup(value);
-            options[i + 2] = NULL;
+    for (i = 0; i < MAX_OPTIONS; i++) {
+        if (options[2*i] == NULL) {
+            options[2*i] = sdup(name);
+            options[2*i + 1] = sdup(value);
+            options[2*i + 2] = NULL;
             break;
-        } else if (!strcmp(options[i], name)) {
-            free(options[i + 1]);
-            options[i + 1] = sdup(value);
+        } else if (!strcmp(options[2*i], name)) {
+            free(options[2*i + 1]);
+            options[2*i + 1] = sdup(value);
             break;
         }
     }
 
-    if (i == MAX_OPTIONS - 3) {
-        die("%s", "Too many options specified");
+    if (i == MAX_OPTIONS) {
+        die("Too many options specified");
+    }
+
+    if (options[2*i] == NULL || options[2*i + 1] == NULL) {
+        die("Out of memory");
     }
 
-    /* TODO: check if this option is defined and the correct data type, return 1 (OK) or 0 (false) */
+    /* option set correctly */
     return 1;
 }
 
@@ -344,8 +387,10 @@ static void read_config_file(const char *config_file, char **options)
 static void process_command_line_arguments(char *argv[], char **options)
 {
     char *p;
-    FILE *fp = NULL;
     size_t i, cmd_line_opts_start = 1;
+#ifdef CONFIG_FILE2
+    FILE *fp = NULL;
+#endif
 
     /* Should we use a config file ? */
     if (argv[1] != NULL && argv[1][0] != '-') {
@@ -411,7 +456,7 @@ static void init_server_name(int argc, const char *argv[])
             server_name = (char*)(argv[i+1]);
         }
     }
-    icon_name = 0;
+    icon_name = NULL;
     for (i=0; i<argc-1; i++) {
         if ((argv[i][0]=='-') && (0==strcmp(argv[i]+1, main_config_options[OPTION_ICON].name))) {
             icon_name = (char*)(argv[i+1]);
@@ -438,17 +483,6 @@ static int is_path_absolute(const char *path)
 #endif
 }
 
-static char *get_option(char **options, const char *option_name)
-{
-    int i;
-
-    for (i = 0; options[i] != NULL; i++)
-        if (!strcmp(options[i], option_name))
-            return options[i + 1];
-
-    return NULL;
-}
-
 static void verify_existence(char **options, const char *option_name,
                              int must_be_dir)
 {
@@ -500,8 +534,8 @@ static void set_absolute_path(char *options[], const char *option_name,
             path[sizeof(path)-1] = 0;
         }
 
-        strncat(path, "/", sizeof(path) - 1);
-        strncat(path, option_value, sizeof(path) - 1);
+        strncat(path, "/", sizeof(path) - strlen(path) - 1);
+        strncat(path, option_value, sizeof(path) - strlen(path) - 1);
 
         /* Absolutize the path, and set the option */
         IGNORE_UNUSED_RESULT(abs_path(path, abs, sizeof(abs)));
@@ -512,7 +546,7 @@ static void set_absolute_path(char *options[], const char *option_name,
 static void start_civetweb(int argc, char *argv[])
 {
     struct mg_callbacks callbacks;
-    char *options[MAX_OPTIONS];
+    char *options[2*MAX_OPTIONS+1];
     int i;
 
     /* Edit passwords file if -A option is specified */
@@ -575,9 +609,10 @@ static void start_civetweb(int argc, char *argv[])
 #ifdef _WIN32
 enum {
     ID_ICON = 100, ID_QUIT, ID_SETTINGS, ID_SEPARATOR, ID_INSTALL_SERVICE,
-    ID_REMOVE_SERVICE, ID_STATIC, ID_GROUP,
+    ID_REMOVE_SERVICE, ID_STATIC, ID_GROUP, ID_PASSWORD,
     ID_SAVE, ID_RESET_DEFAULTS, ID_RESET_FILE, ID_RESET_ACTIVE,
-    ID_STATUS, ID_CONNECT,
+    ID_STATUS, ID_CONNECT, ID_ADD_USER, ID_ADD_USER_NAME, ID_ADD_USER_REALM,
+    ID_INPUT_LINE,
 
     /* All dynamically created text boxes for options have IDs starting from
        ID_CONTROLS, incremented by one. */
@@ -622,7 +657,6 @@ static void WINAPI ServiceMain(void)
     SetServiceStatus(hStatus, &ss);
 }
 
-
 static void show_error(void)
 {
     char buf[256];
@@ -667,13 +701,13 @@ static void save_config(HWND hDlg, FILE *fp)
     }
 }
 
-static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
+static BOOL CALLBACK SettingsDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
 {
     FILE *fp;
     int i, j;
     const char *name, *value;
     const struct mg_option *default_options = mg_get_valid_options();
-    char *file_options[MAX_OPTIONS] = {0};
+    char *file_options[MAX_OPTIONS*2+1] = {0};
     char *title;
 
     switch (msg) {
@@ -728,7 +762,8 @@ static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
                 }
             }
             for (i = 0; i<MAX_OPTIONS; i++) {
-                free(file_options[i]);
+                free(file_options[2*i]);
+                free(file_options[2*i+1]);
             }
             break;
 
@@ -740,7 +775,7 @@ static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
                     CheckDlgButton(hDlg, ID_CONTROLS + i, !strcmp(value, "yes") ?
                                    BST_CHECKED : BST_UNCHECKED);
                 } else {
-                    SetWindowText(GetDlgItem(hDlg, ID_CONTROLS + i), value);
+                    SetDlgItemText(hDlg, ID_CONTROLS + i, value == NULL ? "" : value);
                 }
             }
             break;
@@ -781,8 +816,8 @@ static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
         break;
 
     case WM_INITDIALOG:
-        SendMessage(hDlg, WM_SETICON,(WPARAM) ICON_SMALL, (LPARAM) hIcon);
-        SendMessage(hDlg, WM_SETICON,(WPARAM) ICON_BIG, (LPARAM) hIcon);
+        SendMessage(hDlg, WM_SETICON, (WPARAM) ICON_SMALL, (LPARAM) hIcon);
+        SendMessage(hDlg, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM) hIcon);
         title = malloc(strlen(server_name)+16);
         if (title) {
             strcpy(title, server_name);
@@ -791,18 +826,229 @@ static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
             free(title);
         }
         SetFocus(GetDlgItem(hDlg, ID_SAVE));
-        for (i = 0; default_options[i].name != NULL; i++) {
-            name = default_options[i].name;
-            value = mg_get_option(ctx, name);
-            if (default_options[i].type == CONFIG_TYPE_BOOLEAN) {
-                CheckDlgButton(hDlg, ID_CONTROLS + i, !strcmp(value, "yes") ?
-                               BST_CHECKED : BST_UNCHECKED);
-            } else {
-                SetDlgItemText(hDlg, ID_CONTROLS + i, value == NULL ? "" : value);
+
+        /* Init dialog with active settings */
+        SendMessage(hDlg, WM_COMMAND, ID_RESET_ACTIVE, 0);
+        /* alternative: SendMessage(hDlg, WM_COMMAND, ID_RESET_FILE, 0); */
+        break;
+
+    default:
+        break;
+    }
+
+    return FALSE;
+}
+
+struct tstring_input_buf {
+    unsigned buflen;
+    char * buffer;
+};
+
+static BOOL CALLBACK InputDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
+{
+    static struct tstring_input_buf *inBuf = 0;
+    WORD ctrlId;
+
+    switch (msg) {
+    case WM_CLOSE:
+        inBuf = 0;
+        DestroyWindow(hDlg);
+        break;
+
+    case WM_COMMAND:
+        ctrlId = LOWORD(wParam);
+        if (ctrlId == IDOK) {
+            /* Add user */
+            GetWindowText(GetDlgItem(hDlg, ID_INPUT_LINE), inBuf->buffer, inBuf->buflen);
+            if (strlen(inBuf->buffer)>0) {
+                EndDialog(hDlg, IDOK);
             }
+        } else if (ctrlId == IDCANCEL) {
+            EndDialog(hDlg, IDCANCEL);
         }
         break;
 
+    case WM_INITDIALOG:
+        inBuf = (struct tstring_input_buf *) lP;
+        assert(inBuf != NULL);
+        assert((inBuf->buffer != NULL) && (inBuf->buflen != 0));
+        assert(strlen(inBuf->buffer) < inBuf->buflen);
+        SendMessage(hDlg, WM_SETICON, (WPARAM) ICON_SMALL, (LPARAM) hIcon);
+        SendMessage(hDlg, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM) hIcon);
+        SendDlgItemMessage(hDlg, ID_INPUT_LINE, EM_LIMITTEXT, inBuf->buflen-1, 0);
+        SetWindowText(GetDlgItem(hDlg, ID_INPUT_LINE), inBuf->buffer);
+        SetWindowText(hDlg, "Modify password");
+        SetFocus(GetDlgItem(hDlg, ID_INPUT_LINE));
+        break;
+
+    default:
+        break;
+    }
+
+    return FALSE;
+}
+
+void suggest_passwd(char *passwd)
+{
+    unsigned u;
+    char * p;
+    union {
+        FILETIME ft;
+        LARGE_INTEGER li;
+    } num;
+
+    /* valid characters are 32 to 126 */
+    GetSystemTimeAsFileTime(&num.ft);
+    num.li.HighPart |= GetCurrentProcessId();
+    p = passwd;
+    while (num.li.QuadPart) {
+        u = (unsigned)(num.li.QuadPart % 95);
+        num.li.QuadPart -= u;
+        num.li.QuadPart /= 95;
+        *p = (char)(u+32);
+        p++;
+    }
+}
+
+static void add_control(unsigned char **mem, DLGTEMPLATE *dia, WORD type,
+                        DWORD id, DWORD style, WORD x, WORD y,
+                        WORD cx, WORD cy, const char *caption);
+
+static int get_password(const char * user, const char * realm, char * passwd, unsigned passwd_len)
+{
+#define HEIGHT 15
+#define WIDTH 280
+#define LABEL_WIDTH 90
+
+    HWND hDlg = NULL;
+    unsigned char mem[4096], *p;
+    DLGTEMPLATE *dia = (DLGTEMPLATE *) mem;
+    int ok, y;
+    struct tstring_input_buf dlgprms = {passwd_len, passwd};
+
+    static struct {
+        DLGTEMPLATE template; /* 18 bytes */
+        WORD menu, class;
+        wchar_t caption[1];
+        WORD fontsiz;
+        wchar_t fontface[7];
+    } dialog_header = {{
+        WS_CAPTION | WS_POPUP | WS_SYSMENU | WS_VISIBLE |
+            DS_SETFONT | WS_DLGFRAME, WS_EX_TOOLWINDOW, 0, 200, 200, WIDTH, 0
+    },
+    0, 0, L"", 8, L"Tahoma"
+    };
+
+    assert((user!=NULL) && (realm!=NULL) && (passwd!=NULL));
+
+    if (guard < 100) {
+        guard += 100;
+    } else {
+        return 0;
+    }
+
+    /* Create a password suggestion */
+    memset(passwd, 0, passwd_len);
+    suggest_passwd(passwd);
+
+    /* Create the dialog */
+    (void) memset(mem, 0, sizeof(mem));
+    (void) memcpy(mem, &dialog_header, sizeof(dialog_header));
+    p = mem + sizeof(dialog_header);
+
+    y = HEIGHT;
+    add_control(&p, dia, 0x82, ID_STATIC, WS_VISIBLE | WS_CHILD,
+        10, y, LABEL_WIDTH, HEIGHT, "User:");
+    add_control(&p, dia, 0x81, ID_CONTROLS + 1,
+        WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | WS_DISABLED,
+        15+LABEL_WIDTH, y, WIDTH - LABEL_WIDTH - 25, HEIGHT, user);
+
+    y += HEIGHT;
+    add_control(&p, dia, 0x82, ID_STATIC, WS_VISIBLE | WS_CHILD,
+        10, y, LABEL_WIDTH, HEIGHT, "Realm:");
+    add_control(&p, dia, 0x81, ID_CONTROLS + 2,
+        WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | WS_DISABLED,
+        15+LABEL_WIDTH, y, WIDTH - LABEL_WIDTH - 25, HEIGHT, realm);
+
+    y += HEIGHT;
+    add_control(&p, dia, 0x82, ID_STATIC, WS_VISIBLE | WS_CHILD,
+        10, y, LABEL_WIDTH, HEIGHT, "Password:");
+    add_control(&p, dia, 0x81, ID_INPUT_LINE,
+        WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | WS_TABSTOP,
+        15+LABEL_WIDTH, y, WIDTH - LABEL_WIDTH - 25, HEIGHT, "");
+
+    y += (WORD)(HEIGHT * 2);
+    add_control(&p, dia, 0x80, IDOK,
+        WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP,
+        80, y, 55, 12, "Ok");
+    add_control(&p, dia, 0x80, IDCANCEL,
+        WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP,
+        140, y, 55, 12, "Cancel");
+
+    assert((int)p - (int)mem < sizeof(mem));
+
+    dia->cy = y + (WORD)(HEIGHT * 1.5);
+
+    ok = (IDOK == DialogBoxIndirectParam(NULL, dia, NULL, InputDlgProc, (LPARAM) &dlgprms));
+
+    guard -= 100;
+
+    return ok;
+
+#undef HEIGHT
+#undef WIDTH
+#undef LABEL_WIDTH
+}
+
+static BOOL CALLBACK PasswordDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
+{
+    static const char *passfile = 0;
+    char domain[256], user[256], password[256];
+    WORD ctrlId;
+
+    switch (msg) {
+    case WM_CLOSE:
+        passfile = 0;
+        DestroyWindow(hDlg);
+        break;
+
+    case WM_COMMAND:
+        ctrlId = LOWORD(wParam);
+        if (ctrlId == ID_ADD_USER) {
+            /* Add user */
+            GetWindowText(GetDlgItem(hDlg, ID_ADD_USER_NAME), user, sizeof(user));
+            GetWindowText(GetDlgItem(hDlg, ID_ADD_USER_REALM), domain, sizeof(domain));
+            if (get_password(user, domain, password, sizeof(password))) {
+                mg_modify_passwords_file(passfile, domain, user, password);
+                EndDialog(hDlg, IDOK);
+            }
+        } else if ((ctrlId>=(ID_CONTROLS + ID_FILE_BUTTONS_DELTA * 3)) &&
+                   (ctrlId<(ID_CONTROLS + ID_FILE_BUTTONS_DELTA * 4))) {
+            /* Modify password */
+            GetWindowText(GetDlgItem(hDlg, ctrlId - ID_FILE_BUTTONS_DELTA * 3), user, sizeof(user));
+            GetWindowText(GetDlgItem(hDlg, ctrlId - ID_FILE_BUTTONS_DELTA * 2), domain, sizeof(domain));
+            if (get_password(user, domain, password, sizeof(password))) {
+                mg_modify_passwords_file(passfile, domain, user, password);
+                EndDialog(hDlg, IDOK);
+            }
+        } else if ((ctrlId>=(ID_CONTROLS + ID_FILE_BUTTONS_DELTA * 2)) &&
+                   (ctrlId<(ID_CONTROLS + ID_FILE_BUTTONS_DELTA * 3))) {
+            /* Remove user */
+            GetWindowText(GetDlgItem(hDlg, ctrlId - ID_FILE_BUTTONS_DELTA * 2), user, sizeof(user));
+            GetWindowText(GetDlgItem(hDlg, ctrlId - ID_FILE_BUTTONS_DELTA), domain, sizeof(domain));
+            mg_modify_passwords_file(passfile, domain, user, NULL);
+            EndDialog(hDlg, IDOK);
+        }
+        break;
+
+    case WM_INITDIALOG:
+        passfile = (const char *)lP;
+        SendMessage(hDlg, WM_SETICON, (WPARAM) ICON_SMALL, (LPARAM) hIcon);
+        SendMessage(hDlg, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM) hIcon);
+        SetWindowText(hDlg, passfile);
+        SetFocus(GetDlgItem(hDlg, ID_ADD_USER_NAME));
+        break;
+
     default:
         break;
     }
@@ -855,7 +1101,6 @@ static void show_settings_dialog()
     DWORD style;
     DLGTEMPLATE *dia = (DLGTEMPLATE *) mem;
     WORD i, cl, x, y, width, nelems = 0;
-    static int guard = 0; /* test if dialog is already open */
 
     static struct {
         DLGTEMPLATE template; /* 18 bytes */
@@ -939,8 +1184,139 @@ static void show_settings_dialog()
     assert((int)p - (int)mem < sizeof(mem));
 
     dia->cy = ((nelems + 1) / 2 + 1) * HEIGHT + 30;
-    DialogBoxIndirectParam(NULL, dia, NULL, DlgProc, (LPARAM) NULL);
+    DialogBoxIndirectParam(NULL, dia, NULL, SettingsDlgProc, (LPARAM) NULL);
     guard--;
+
+#undef HEIGHT
+#undef WIDTH
+#undef LABEL_WIDTH
+}
+
+static void change_password_file()
+{
+#define HEIGHT 15
+#define WIDTH 320
+#define LABEL_WIDTH 90
+
+    OPENFILENAME of;
+    char path[PATH_MAX] = PASSWORDS_FILE_NAME;
+    char strbuf[256], u[256], d[256];
+    HWND hDlg = NULL;
+    FILE * f;
+    int y, nelems;
+    unsigned char mem[4096], *p;
+    DLGTEMPLATE *dia = (DLGTEMPLATE *) mem;
+    const char * domain = mg_get_option(ctx, "authentication_domain");
+
+    static struct {
+        DLGTEMPLATE template; /* 18 bytes */
+        WORD menu, class;
+        wchar_t caption[1];
+        WORD fontsiz;
+        wchar_t fontface[7];
+    } dialog_header = {{
+            WS_CAPTION | WS_POPUP | WS_SYSMENU | WS_VISIBLE |
+            DS_SETFONT | WS_DLGFRAME, WS_EX_TOOLWINDOW, 0, 200, 200, WIDTH, 0
+        },
+        0, 0, L"", 8, L"Tahoma"
+    };
+
+    if (guard == 0) {
+        guard++;
+    } else {
+        return;
+    }
+
+    memset(&of, 0, sizeof(of));
+    of.lStructSize = sizeof(of);
+    of.hwndOwner = (HWND) hDlg;
+    of.lpstrFile = path;
+    of.nMaxFile = sizeof(path);
+    of.lpstrInitialDir = mg_get_option(ctx, "document_root");
+    of.Flags = OFN_CREATEPROMPT | OFN_NOCHANGEDIR | OFN_HIDEREADONLY;
+
+    if (IDOK != GetSaveFileName(&of)) {
+        guard--;
+        return;
+    }
+
+    f = fopen(path, "a+");
+    if (f) {
+        fclose(f);
+    } else {
+        MessageBox(NULL, path, "Can not open file", MB_ICONERROR);
+        guard--;
+        return;
+    }
+
+    do {
+        (void) memset(mem, 0, sizeof(mem));
+        (void) memcpy(mem, &dialog_header, sizeof(dialog_header));
+        p = mem + sizeof(dialog_header);
+
+        f = fopen(path, "r+");
+        if (!f) {
+            MessageBox(NULL, path, "Can not open file", MB_ICONERROR);
+            guard--;
+            return;
+        }
+
+        nelems = 0;
+        while (fgets(strbuf, sizeof(strbuf), f)) {
+            if (sscanf(strbuf, "%255[^:]:%255[^:]:%*s", u, d) != 2) {
+                continue;
+            }
+            u[255]=0;
+            d[255]=0;
+            y = (nelems + 1) * HEIGHT + 5;
+            add_control(&p, dia, 0x80, ID_CONTROLS + nelems + ID_FILE_BUTTONS_DELTA * 3,
+                WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP,
+                10, y, 65, 12, "Modify password");
+            add_control(&p, dia, 0x80, ID_CONTROLS + nelems + ID_FILE_BUTTONS_DELTA * 2,
+                WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP,
+                80, y, 55, 12, "Remove user");
+            add_control(&p, dia, 0x81, ID_CONTROLS + nelems + ID_FILE_BUTTONS_DELTA,
+                WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | WS_DISABLED,
+                245, y, 60, 12, d);
+            add_control(&p, dia, 0x81, ID_CONTROLS + nelems,
+                WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | WS_DISABLED,
+                140, y, 100, 12, u);
+
+            nelems++;
+            assert((int)p - (int)mem < sizeof(mem));
+        }
+        fclose(f);
+
+        y = (WORD) ((nelems + 1) * HEIGHT + 10);
+        add_control(&p, dia, 0x80, ID_ADD_USER,
+            WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP,
+            80, y, 55, 12, "Add user");
+        add_control(&p, dia, 0x81, ID_ADD_USER_NAME,
+            WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | WS_TABSTOP,
+            140, y, 100, 12, "");
+        add_control(&p, dia, 0x81, ID_ADD_USER_REALM,
+            WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | WS_TABSTOP,
+            245, y, 60, 12, domain);
+
+        y = (WORD) ((nelems + 2) * HEIGHT + 10);
+        add_control(&p, dia, 0x80, ID_GROUP, WS_CHILD | WS_VISIBLE |
+            BS_GROUPBOX, 5, 5, WIDTH - 10, y, " Users ");
+
+        y += HEIGHT;
+        add_control(&p, dia, 0x82, ID_STATIC,
+            WS_CHILD | WS_VISIBLE | WS_DISABLED,
+            5, y, 100, 12, server_base_name);
+
+        assert((int)p - (int)mem < sizeof(mem));
+
+        dia->cy = y + 20;
+    } while ((IDOK == DialogBoxIndirectParam(NULL, dia, NULL, PasswordDlgProc, (LPARAM) path)) && (!exit_flag));
+
+    guard--;
+
+#undef HEIGHT
+#undef WIDTH
+#undef LABEL_WIDTH
 }
 
 static int manage_service(int action)
@@ -1017,11 +1393,15 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
         case ID_QUIT:
             mg_stop(ctx);
             Shell_NotifyIcon(NIM_DELETE, &TrayIcon);
+            exit_flag = 1;
             PostQuitMessage(0);
             return 0;
         case ID_SETTINGS:
             show_settings_dialog();
             break;
+        case ID_PASSWORD:
+            change_password_file();
+            break;
         case ID_INSTALL_SERVICE:
         case ID_REMOVE_SERVICE:
             manage_service(LOWORD(wParam));
@@ -1053,6 +1433,7 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
             AppendMenu(hMenu, MF_SEPARATOR, ID_SEPARATOR, "");
             AppendMenu(hMenu, MF_STRING, ID_CONNECT, "Start browser");
             AppendMenu(hMenu, MF_STRING, ID_SETTINGS, "Edit settings");
+            AppendMenu(hMenu, MF_STRING, ID_PASSWORD, "Modify password file");
             AppendMenu(hMenu, MF_SEPARATOR, ID_SEPARATOR, "");
             AppendMenu(hMenu, MF_STRING, ID_QUIT, "Exit");
             GetCursorPos(&pt);
@@ -1066,6 +1447,7 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
     case WM_CLOSE:
         mg_stop(ctx);
         Shell_NotifyIcon(NIM_DELETE, &TrayIcon);
+        exit_flag = 1;
         PostQuitMessage(0);
         return 0;/* We've just sent our own quit message, with proper hwnd. */
     default:
@@ -1076,6 +1458,27 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
     return DefWindowProc(hWnd, msg, wParam, lParam);
 }
 
+static int MakeConsole() {
+    DWORD err;
+    int ok = (GetConsoleWindow() != NULL);
+    if (!ok) {
+        if (!AttachConsole(ATTACH_PARENT_PROCESS)) {
+            FreeConsole();
+            if (!AllocConsole()) {
+                err = GetLastError();
+                if (err==ERROR_ACCESS_DENIED) {
+                    MessageBox(NULL, "Insufficient rights to create a console window", "Error", MB_ICONERROR);
+                }
+            }
+            AttachConsole(GetCurrentProcessId());
+        }
+        freopen("CON", "a", stdout);
+        freopen("CON", "a", stderr);
+        ok = (GetConsoleWindow() != NULL);
+    }
+    return ok;
+}
+
 int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdline, int show)
 {
     WNDCLASS cls;
@@ -1144,7 +1547,7 @@ withApplication:@"TextEdit"];
 
 int main(int argc, char *argv[])
 {
-    init_server_name(argc, argv);
+    init_server_name(argc, (const char **)argv);
     start_civetweb(argc, argv);
 
     [NSAutoreleasePool new];
@@ -1204,7 +1607,7 @@ int main(int argc, char *argv[])
 #else
 int main(int argc, char *argv[])
 {
-    init_server_name(argc, argv);
+    init_server_name(argc, (const char **)argv);
     start_civetweb(argc, argv);
     printf("%s started on port(s) %s with web root [%s]\n",
            server_name, mg_get_option(ctx, "listening_ports"),

+ 516 - 315
src/mod_lua.inl

@@ -26,6 +26,8 @@ static void munmap(void *addr, int64_t length)
 #endif
 
 static const char *LUASOCKET = "luasocket";
+static const char lua_regkey_ctx = 1;
+static const char lua_regkey_connlist = 2;
 
 /* Forward declarations */
 static void handle_request(struct mg_connection *);
@@ -59,10 +61,10 @@ static void reg_boolean(struct lua_State *L, const char *name, int val)
     }
 }
 
-static void reg_function(struct lua_State *L, const char *name,
+static void reg_conn_function(struct lua_State *L, const char *name,
     lua_CFunction func, struct mg_connection *conn)
 {
-    if (name!=NULL && func!=NULL) {
+    if (name!=NULL && func!=NULL && conn!=NULL) {
         lua_pushstring(L, name);
         lua_pushlightuserdata(L, conn);
         lua_pushcclosure(L, func, 1);
@@ -70,6 +72,42 @@ static void reg_function(struct lua_State *L, const char *name,
     }
 }
 
+static void reg_function(struct lua_State *L, const char *name, lua_CFunction func)
+{
+    if (name!=NULL && func!=NULL) {
+        lua_pushstring(L, name);
+        lua_pushcclosure(L, func, 0);
+        lua_rawset(L, -3);
+    }
+}
+
+static void lua_cry(struct mg_connection *conn, int err, lua_State * L, const char * lua_title, const char * lua_operation)
+{
+    switch (err) {
+    case LUA_OK:
+    case LUA_YIELD:
+        break;
+    case LUA_ERRRUN:
+        mg_cry(conn, "%s: %s failed: runtime error: %s", lua_title, lua_operation, lua_tostring(L, -1));
+        break;
+    case LUA_ERRSYNTAX:
+        mg_cry(conn, "%s: %s failed: syntax error: %s", lua_title, lua_operation, lua_tostring(L, -1));
+        break;
+    case LUA_ERRMEM:
+        mg_cry(conn, "%s: %s failed: out of memory", lua_title, lua_operation);
+        break;
+    case LUA_ERRGCMM:
+        mg_cry(conn, "%s: %s failed: error during garbage collection", lua_title, lua_operation);
+        break;
+    case LUA_ERRERR:
+        mg_cry(conn, "%s: %s failed: error in error handling: %s", lua_title, lua_operation, lua_tostring(L, -1));
+        break;
+    default:
+        mg_cry(conn, "%s: %s failed: error %i", lua_title, lua_operation, err);
+        break;
+    }
+}
+
 static int lsp_sock_close(lua_State *L)
 {
     int num_args = lua_gettop(L);
@@ -189,6 +227,7 @@ static const char * lsp_var_reader(lua_State *L, void *ud, size_t *sz)
 {
     struct lsp_var_reader_data * reader = (struct lsp_var_reader_data *)ud;
     const char * ret;
+	(void)(L); /* unused */
 
     switch (reader->state) {
     case 0:
@@ -315,7 +354,7 @@ static int lsp_keep_alive(lua_State *L)
     int num_args = lua_gettop(L);
 
     /* This function may be called with one parameter (boolean) to set the keep_alive state.
-       Or without a parameter to just query the current keep_alive state. */
+    Or without a parameter to just query the current keep_alive state. */
     if ((num_args==1) && lua_isboolean(L, 1)) {
         conn->must_close = !lua_toboolean(L, 1);
     } else if (num_args != 0) {
@@ -402,7 +441,6 @@ static int lsp_send_file(lua_State *L)
 /* mg.get_var */
 static int lsp_get_var(lua_State *L)
 {
-    struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
     int num_args = lua_gettop(L);
     const char *data, *var_name;
     size_t data_len, occurrence;
@@ -432,18 +470,28 @@ static int lsp_get_var(lua_State *L)
 /* mg.get_mime_type */
 static int lsp_get_mime_type(lua_State *L)
 {
-    struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
     int num_args = lua_gettop(L);
-    struct vec mime_type = {0};
+    struct vec mime_type = {0, 0};
+    struct mg_context *ctx;
     const char *text;
 
+    lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
+    lua_gettable(L, LUA_REGISTRYINDEX);
+    ctx = (struct mg_context *)lua_touserdata(L, -1);
+
     if (num_args==1) {
         text = lua_tostring(L, 1);
         if (text) {
-            get_mime_type(conn->ctx, text, &mime_type);
-            lua_pushlstring(L, mime_type.ptr, mime_type.len);
+            if (ctx) {
+                get_mime_type(ctx, text, &mime_type);
+                lua_pushlstring(L, mime_type.ptr, mime_type.len);
+            } else {
+                text = mg_get_builtin_mime_type(text);
+                lua_pushstring(L, text);
+            }
         } else {
-            lua_pushnil(L);
+            /* Syntax error */
+            return luaL_error(L, "invalid argument for get_mime_type() call");
         }
     } else {
         /* Syntax error */
@@ -456,7 +504,6 @@ static int lsp_get_mime_type(lua_State *L)
 static int lsp_get_cookie(lua_State *L)
 {
     int num_args = lua_gettop(L);
-    struct vec mime_type = {0};
     const char *cookie;
     const char *var_name;
     int ret;
@@ -572,7 +619,7 @@ static int lsp_base64_encode(lua_State *L)
         if (text) {
             dst = mg_malloc(text_len*8/6+4);
             if (dst) {
-                base64_encode(text, text_len, dst);
+                base64_encode((const unsigned char *)text, text_len, dst);
                 lua_pushstring(L, dst);
                 mg_free(dst);
             } else {
@@ -602,7 +649,7 @@ static int lsp_base64_decode(lua_State *L)
         if (text) {
             dst = mg_malloc(text_len);
             if (dst) {
-                ret = base64_decode(text, text_len, dst, &dst_len);
+                ret = base64_decode((const unsigned char *)text, text_len, dst, &dst_len);
                 if (ret != -1) {
                     mg_free(dst);
                     return luaL_error(L, "illegal character in lsp_base64_decode() call");
@@ -623,25 +670,43 @@ static int lsp_base64_decode(lua_State *L)
     return 1;
 }
 
+#ifdef USE_WEBSOCKET
+struct lua_websock_data {
+    lua_State *state;
+    char * script;
+    unsigned references;
+    struct mg_connection *conn[MAX_WORKER_THREADS];
+    pthread_mutex_t ws_mutex;
+};
+#endif
+
 /* mg.write for websockets */
 static int lwebsock_write(lua_State *L)
 {
 #ifdef USE_WEBSOCKET
     int num_args = lua_gettop(L);
-    struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
+    struct lua_websock_data *ws;
     const char *str;
     size_t size;
     int opcode = -1;
+    unsigned i;
+    struct mg_connection * client = NULL;
+
+    lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
+    lua_gettable(L, LUA_REGISTRYINDEX);
+    ws = (struct lua_websock_data *)lua_touserdata(L, -1);
 
     if (num_args == 1) {
+        /* just one text: send it to all client */
         if (lua_isstring(L, 1)) {
-            str = lua_tolstring(L, 1, &size);
-            mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, str, size);
+            opcode = WEBSOCKET_OPCODE_TEXT;
         }
     } else if (num_args == 2) {
         if (lua_isnumber(L, 1)) {
+            /* opcode number and message text */
             opcode = (int)lua_tointeger(L, 1);
         } else if (lua_isstring(L,1)) {
+            /* opcode string and message text */
             str = lua_tostring(L, 1);
             if (!mg_strncasecmp(str, "text", 4)) opcode = WEBSOCKET_OPCODE_TEXT;
             else if (!mg_strncasecmp(str, "bin", 3)) opcode = WEBSOCKET_OPCODE_BINARY;
@@ -649,40 +714,257 @@ static int lwebsock_write(lua_State *L)
             else if (!mg_strncasecmp(str, "ping", 4)) opcode = WEBSOCKET_OPCODE_PING;
             else if (!mg_strncasecmp(str, "pong", 4)) opcode = WEBSOCKET_OPCODE_PONG;
             else if (!mg_strncasecmp(str, "cont", 4)) opcode = WEBSOCKET_OPCODE_CONTINUATION;
+        } else if (lua_isuserdata(L, 1)) {
+            /* client id and message text */
+            client = (struct mg_connection *) lua_touserdata(L, 1);
+            opcode = WEBSOCKET_OPCODE_TEXT;
         }
-        if (opcode>=0 && opcode<16 && lua_isstring(L, 2)) {
-            str = lua_tolstring(L, 2, &size);
-            mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, str, size);
+    } else if (num_args == 3) {
+        if (lua_isuserdata(L, 1)) {
+            client = (struct mg_connection *) lua_touserdata(L, 1);
+            if (lua_isnumber(L, 2)) {
+                /* client id, opcode number and message text */
+                opcode = (int)lua_tointeger(L, 2);
+            } else if (lua_isstring(L,2)) {
+                /* client id, opcode string and message text */
+                str = lua_tostring(L, 2);
+                if (!mg_strncasecmp(str, "text", 4)) opcode = WEBSOCKET_OPCODE_TEXT;
+                else if (!mg_strncasecmp(str, "bin", 3)) opcode = WEBSOCKET_OPCODE_BINARY;
+                else if (!mg_strncasecmp(str, "close", 5)) opcode = WEBSOCKET_OPCODE_CONNECTION_CLOSE;
+                else if (!mg_strncasecmp(str, "ping", 4)) opcode = WEBSOCKET_OPCODE_PING;
+                else if (!mg_strncasecmp(str, "pong", 4)) opcode = WEBSOCKET_OPCODE_PONG;
+                else if (!mg_strncasecmp(str, "cont", 4)) opcode = WEBSOCKET_OPCODE_CONTINUATION;
+            }
         }
     }
+
+    if (opcode>=0 && opcode<16 && lua_isstring(L, num_args)) {
+        str = lua_tolstring(L, num_args, &size);
+        if (client) {
+            for (i=0; i<ws->references; i++) {
+                if (client == ws->conn[i]) {
+                    mg_websocket_write(ws->conn[i], opcode, str, size);
+                }
+            }
+        } else {
+            for (i=0; i<ws->references; i++) {
+                mg_websocket_write(ws->conn[i], opcode, str, size);
+            }
+        }
+    } else {
+        return luaL_error(L, "invalid websocket write() call");
+    }
+#else
+	(void)(L); /* unused */
 #endif
     return 0;
 }
 
+struct laction_arg {
+    lua_State *state;
+    const char *script;
+    pthread_mutex_t *pmutex;
+    char txt[1];
+};
+
+static int lua_action(struct laction_arg *arg)
+{
+    int err, ok;
+    struct mg_context *ctx;
+
+    (void)pthread_mutex_lock(arg->pmutex);
+
+    lua_pushlightuserdata(arg->state, (void *)&lua_regkey_ctx);
+    lua_gettable(arg->state, LUA_REGISTRYINDEX);
+    ctx = (struct mg_context *)lua_touserdata(arg->state, -1);
+
+    err = luaL_loadstring(arg->state, arg->txt);
+    if (err != 0) {
+        lua_cry(fc(ctx), err, arg->state, arg->script, "timer");
+        (void)pthread_mutex_unlock(arg->pmutex);
+        mg_free(arg);
+        return 0;
+    }
+    err = lua_pcall(arg->state, 0, 1, 0);
+    if (err != 0) {
+        lua_cry(fc(ctx), err, arg->state, arg->script, "timer");
+        (void)pthread_mutex_unlock(arg->pmutex);
+        mg_free(arg);
+        return 0;
+    }
+
+    ok = lua_type(arg->state, -1);
+    if (lua_isboolean(arg->state, -1)) {
+       ok = lua_toboolean(arg->state, -1);
+    } else {
+       ok = 0;
+    }
+    lua_pop(arg->state, 1);
+
+    (void)pthread_mutex_unlock(arg->pmutex);
+
+    if (!ok) {
+        mg_free(arg);
+    }
+    return ok;
+}
+
+static int lua_action_free(struct laction_arg *arg)
+{
+    if (lua_action(arg)) {
+        mg_free(arg);
+    }
+    return 0;
+}
+
+static int lwebsocket_set_timer(lua_State *L, int is_periodic)
+{
+#if defined(USE_TIMERS) && defined(USE_WEBSOCKET)
+    int num_args = lua_gettop(L);
+    struct lua_websock_data *ws;
+    int type1,type2, ok = 0;
+    double timediff;
+    struct mg_context *ctx;
+    struct laction_arg *arg;
+    const char *txt;
+    size_t txt_len;
+
+    lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
+    lua_gettable(L, LUA_REGISTRYINDEX);
+    ctx = (struct mg_context *)lua_touserdata(L, -1);
+
+    lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
+    lua_gettable(L, LUA_REGISTRYINDEX);
+    ws = (struct lua_websock_data *)lua_touserdata(L, -1);
+
+    if (num_args < 2) {
+        return luaL_error(L, "not enough arguments for set_timer/interval() call");
+    }
+
+    type1 = lua_type(L, 1);
+    type2 = lua_type(L, 2);
+
+    if (type1==LUA_TSTRING && type2==LUA_TNUMBER && num_args==2) {
+        timediff = (double)lua_tonumber(L, 2);
+        txt = lua_tostring(L, 1);
+        txt_len = strlen(txt);
+        arg = mg_malloc(sizeof(struct laction_arg) + txt_len + 10);
+        arg->state = L;
+        arg->script = ws->script;
+        arg->pmutex = &(ws->ws_mutex);
+        memcpy(arg->txt, "return(", 7);
+        memcpy(arg->txt+7, txt, txt_len);
+        arg->txt[txt_len+7] = ')';
+        arg->txt[txt_len+8] = 0;
+        ok = (0==timer_add(ctx, timediff, is_periodic, 1, (taction)(is_periodic ? lua_action : lua_action_free), (void*)arg));
+    } else if (type1==LUA_TFUNCTION && type2==LUA_TNUMBER)  {
+        /* TODO: not implemented yet */
+        return luaL_error(L, "invalid arguments for set_timer/interval() call");
+    } else {
+        return luaL_error(L, "invalid arguments for set_timer/interval() call");
+    }
+
+    lua_pushboolean(L, ok);
+    return 1;
+
+#else
+    (void)(L);           /* unused */
+    (void)(is_periodic); /* unused */
+    return 0;
+#endif
+}
+
+/* mg.set_timeout for websockets */
+static int lwebsocket_set_timeout(lua_State *L)
+{
+    return lwebsocket_set_timer(L, 0);
+}
+
+/* mg.set_interval for websockets */
+static int lwebsocket_set_interval(lua_State *L)
+{
+    return lwebsocket_set_timer(L, 1);
+}
+
 enum {
     LUA_ENV_TYPE_LUA_SERVER_PAGE = 0,
     LUA_ENV_TYPE_PLAIN_LUA_PAGE = 1,
     LUA_ENV_TYPE_LUA_WEBSOCKET = 2,
 };
 
-static void prepare_lua_environment(struct mg_connection *conn, lua_State *L, const char *script_name, int lua_env_type)
+static void prepare_lua_request_info(struct mg_connection *conn, lua_State *L)
 {
-    const struct mg_request_info *ri = mg_get_request_info(conn);
-    char src_addr[IP_ADDR_STR_LEN];
-    const char * preload_file = conn->ctx->config[LUA_PRELOAD_FILE];
+    char src_addr[IP_ADDR_STR_LEN] = "";
+    const char *s;
     int i;
 
-    extern void luaL_openlibs(lua_State *);
-
     sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
 
+    /* Export mg.request_info */
+    lua_pushstring(L, "request_info");
+    lua_newtable(L);
+    reg_string(L, "request_method", conn->request_info.request_method);
+    reg_string(L, "uri", conn->request_info.uri);
+    reg_string(L, "http_version", conn->request_info.http_version);
+    reg_string(L, "query_string", conn->request_info.query_string);
+    reg_int(L, "remote_ip", conn->request_info.remote_ip); /* remote_ip is deprecated, use remote_addr instead */
+    reg_string(L, "remote_addr", src_addr);
+    /* TODO: ip version */
+    reg_int(L, "remote_port", conn->request_info.remote_port);
+    reg_int(L, "num_headers", conn->request_info.num_headers);
+    reg_int(L, "server_port", ntohs(conn->client.lsa.sin.sin_port));
+
+    if (conn->request_info.content_length >= 0) {
+        /* reg_int64: content_length */
+        lua_pushstring(L, "content_length");
+        lua_pushnumber(L, (lua_Number)conn->request_info.content_length); /* lua_Number may be used as 52 bit integer */
+        lua_rawset(L, -3);
+    }
+    if ((s = mg_get_header(conn, "Content-Type")) != NULL) {
+        reg_string(L, "content_type", s);
+    }
+
+    if (conn->request_info.remote_user != NULL) {
+        reg_string(L, "remote_user", conn->request_info.remote_user);
+        reg_string(L, "auth_type", "Digest");
+    }
+
+    reg_boolean(L, "https", conn->ssl != NULL);
+
+    if (conn->status_code > 0) {
+        /* Lua error handler should show the status code */
+        reg_int(L, "status", conn->status_code);
+    }
+
+    lua_pushstring(L, "http_headers");
+    lua_newtable(L);
+    for (i = 0; i < conn->request_info.num_headers; i++) {
+        reg_string(L, conn->request_info.http_headers[i].name, conn->request_info.http_headers[i].value);
+    }
+    lua_rawset(L, -3);
+
+    lua_rawset(L, -3);
+}
+
+static void prepare_lua_environment(struct mg_context * ctx, struct mg_connection *conn, struct lua_websock_data *conn_list, lua_State *L, const char *script_name, int lua_env_type)
+{
+    const char * preload_file = ((conn != NULL) ? conn->ctx->config[LUA_PRELOAD_FILE] : NULL);
+
+    extern void luaL_openlibs(lua_State *);
     luaL_openlibs(L);
+
 #ifdef USE_LUA_SQLITE3
     {
         extern int luaopen_lsqlite3(lua_State *);
         luaopen_lsqlite3(L);
     }
 #endif
+#ifdef USE_LUA_LUAXML
+    {
+        extern int luaopen_LuaXML(lua_State *);
+        luaopen_LuaXML(L);
+    }
+#endif
 #ifdef USE_LUA_FILE_SYSTEM
     {
         extern int luaopen_lfs(lua_State *);
@@ -697,94 +979,81 @@ static void prepare_lua_environment(struct mg_connection *conn, lua_State *L, co
     lua_pop(L, 1);
     lua_register(L, "connect", lsp_connect);
 
-    if (conn == NULL) {
-        /* Do not register any connection specific functions or variables */
-        return;
+    /* Store context in the registry */
+    if (ctx) {
+        lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
+        lua_pushlightuserdata(L, (void *)ctx);
+        lua_settable(L, LUA_REGISTRYINDEX);
+    }
+    if (conn_list) {
+        lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
+        lua_pushlightuserdata(L, (void *)conn_list);
+        lua_settable(L, LUA_REGISTRYINDEX);
     }
 
     /* Register mg module */
     lua_newtable(L);
 
-    reg_function(L, "cry", lsp_cry, conn);
-
     switch (lua_env_type) {
-        case LUA_ENV_TYPE_LUA_SERVER_PAGE:
-            reg_string(L, "lua_type", "page");
-            break;
-        case LUA_ENV_TYPE_PLAIN_LUA_PAGE:
-            reg_string(L, "lua_type", "script");
-            break;
-        case LUA_ENV_TYPE_LUA_WEBSOCKET:
-            reg_string(L, "lua_type", "websocket");
-            break;
+    case LUA_ENV_TYPE_LUA_SERVER_PAGE:
+        reg_string(L, "lua_type", "page");
+        break;
+    case LUA_ENV_TYPE_PLAIN_LUA_PAGE:
+        reg_string(L, "lua_type", "script");
+        break;
+    case LUA_ENV_TYPE_LUA_WEBSOCKET:
+        reg_string(L, "lua_type", "websocket");
+        break;
     }
 
     if (lua_env_type==LUA_ENV_TYPE_LUA_SERVER_PAGE || lua_env_type==LUA_ENV_TYPE_PLAIN_LUA_PAGE) {
-        reg_function(L, "read", lsp_read, conn);
-        reg_function(L, "write", lsp_write, conn);
-        reg_function(L, "keep_alive", lsp_keep_alive, conn);
+        reg_conn_function(L, "cry", lsp_cry, conn);
+        reg_conn_function(L, "read", lsp_read, conn);
+        reg_conn_function(L, "write", lsp_write, conn);
+        reg_conn_function(L, "keep_alive", lsp_keep_alive, conn);
+        reg_conn_function(L, "send_file", lsp_send_file, conn);
     }
 
     if (lua_env_type==LUA_ENV_TYPE_LUA_SERVER_PAGE) {
-        reg_function(L, "include", lsp_include, conn);
-        reg_function(L, "redirect", lsp_redirect, conn);
+        reg_conn_function(L, "include", lsp_include, conn);
+        reg_conn_function(L, "redirect", lsp_redirect, conn);
     }
 
     if (lua_env_type==LUA_ENV_TYPE_LUA_WEBSOCKET) {
-        reg_function(L, "write", lwebsock_write, conn);
+        reg_function(L, "write", lwebsock_write);
+#ifdef USE_TIMERS
+        reg_function(L, "set_timeout", lwebsocket_set_timeout);
+        reg_function(L, "set_interval", lwebsocket_set_interval);
+#endif
+        /* reg_conn_function(L, "send_file", lsp_send_file, conn); */
     }
 
-    reg_function(L, "send_file", lsp_send_file, conn);
-    reg_function(L, "get_var", lsp_get_var, conn);
-    reg_function(L, "get_mime_type", lsp_get_mime_type, conn);
-    reg_function(L, "get_cookie", lsp_get_cookie, conn);
-    reg_function(L, "md5", lsp_md5, conn);
-    reg_function(L, "url_encode", lsp_url_encode, conn);
-    reg_function(L, "url_decode", lsp_url_decode, conn);
-    reg_function(L, "base64_encode", lsp_base64_encode, conn);
-    reg_function(L, "base64_decode", lsp_base64_decode, conn);
+    reg_function(L, "get_var", lsp_get_var);
+    reg_function(L, "get_mime_type", lsp_get_mime_type);
+    reg_function(L, "get_cookie", lsp_get_cookie);
+    reg_function(L, "md5", lsp_md5);
+    reg_function(L, "url_encode", lsp_url_encode);
+    reg_function(L, "url_decode", lsp_url_decode);
+    reg_function(L, "base64_encode", lsp_base64_encode);
+    reg_function(L, "base64_decode", lsp_base64_decode);
 
     reg_string(L, "version", CIVETWEB_VERSION);
-    reg_string(L, "document_root", conn->ctx->config[DOCUMENT_ROOT]);
-    reg_string(L, "auth_domain", conn->ctx->config[AUTHENTICATION_DOMAIN]);
+    reg_string(L, "document_root", ctx->config[DOCUMENT_ROOT]);
+    reg_string(L, "auth_domain", ctx->config[AUTHENTICATION_DOMAIN]);
 #if defined(USE_WEBSOCKET)
-    reg_string(L, "websocket_root", conn->ctx->config[WEBSOCKET_ROOT]);
+    reg_string(L, "websocket_root", ctx->config[WEBSOCKET_ROOT]);
 #endif
+    reg_string(L, "script_name", script_name);
 
-    if (conn->ctx->systemName) {
-        reg_string(L, "system", conn->ctx->systemName);
-    }
-
-    /* Export request_info */
-    lua_pushstring(L, "request_info");
-    lua_newtable(L);
-    reg_string(L, "request_method", ri->request_method);
-    reg_string(L, "uri", ri->uri);
-    reg_string(L, "http_version", ri->http_version);
-    reg_string(L, "query_string", ri->query_string);
-    reg_int(L, "remote_ip", ri->remote_ip); /* remote_ip is deprecated, use remote_addr instead */
-    reg_string(L, "remote_addr", src_addr);
-    /* TODO: ip version */
-    reg_int(L, "remote_port", ri->remote_port);
-    reg_int(L, "num_headers", ri->num_headers);
-    reg_int(L, "server_port", ntohs(conn->client.lsa.sin.sin_port));
-
-    if (conn->request_info.remote_user != NULL) {
-        reg_string(L, "remote_user", conn->request_info.remote_user);
-        reg_string(L, "auth_type", "Digest");
+    if (ctx->systemName != NULL) {
+        reg_string(L, "system", ctx->systemName);
     }
 
-    lua_pushstring(L, "http_headers");
-    lua_newtable(L);
-    for (i = 0; i < ri->num_headers; i++) {
-        reg_string(L, ri->http_headers[i].name, ri->http_headers[i].value);
+    /* Export connection specific info */
+    if (conn!=NULL) {
+        prepare_lua_request_info(conn, L);
     }
-    lua_rawset(L, -3);
-
-    reg_boolean(L, "https", conn->ssl != NULL);
-    reg_string(L, "script_name", script_name);
 
-    lua_rawset(L, -3);
     lua_setglobal(L, "mg");
 
     /* Register default mg.onerror function */
@@ -795,6 +1064,10 @@ static void prepare_lua_environment(struct mg_connection *conn, lua_State *L, co
     if ((preload_file != NULL) && (*preload_file != 0)) {
         IGNORE_UNUSED_RESULT(luaL_dofile(L, preload_file));
     }
+
+    if (ctx->callbacks.init_lua != NULL) {
+        ctx->callbacks.init_lua(conn, L);
+    }
 }
 
 static int lua_error_handler(lua_State *L)
@@ -839,7 +1112,7 @@ void mg_exec_lua_script(struct mg_connection *conn, const char *path,
 
     /* Execute a plain Lua script. */
     if (path != NULL && (L = lua_newstate(lua_allocator, NULL)) != NULL) {
-        prepare_lua_environment(conn, L, path, LUA_ENV_TYPE_PLAIN_LUA_PAGE);
+        prepare_lua_environment(conn->ctx, conn, NULL, L, path, LUA_ENV_TYPE_PLAIN_LUA_PAGE);
         lua_pushcclosure(L, &lua_error_handler, 0);
 
         if (exports != NULL) {
@@ -878,8 +1151,7 @@ static void lsp_send_err(struct mg_connection *conn, struct lua_State *L,
     }
 }
 
-static int handle_lsp_request(struct mg_connection *conn, const char *path,
-struct file *filep, struct lua_State *ls)
+static int handle_lsp_request(struct mg_connection *conn, const char *path, struct file *filep, struct lua_State *ls)
 {
     void *p = NULL;
     lua_State *L = NULL;
@@ -896,15 +1168,12 @@ struct file *filep, struct lua_State *ls)
         fileno(filep->fp), 0)) == MAP_FAILED) {
             lsp_send_err(conn, ls, "mmap(%s, %zu, %d): %s", path, (size_t) filep->size,
                 fileno(filep->fp), strerror(errno));
-    } else if ((L = ls != NULL ? ls : lua_newstate(lua_allocator, NULL)) == NULL) {
+    } else if ((L = (ls != NULL ? ls : lua_newstate(lua_allocator, NULL))) == NULL) {
         send_http_error(conn, 500, http_500_error, "%s", "luaL_newstate failed");
     } else {
         /* We're not sending HTTP headers here, Lua page must do it. */
         if (ls == NULL) {
-            prepare_lua_environment(conn, L, path, LUA_ENV_TYPE_LUA_SERVER_PAGE);
-            if (conn->ctx->callbacks.init_lua != NULL) {
-                conn->ctx->callbacks.init_lua(conn, L);
-            }
+            prepare_lua_environment(conn->ctx, conn, NULL, L, path, LUA_ENV_TYPE_LUA_SERVER_PAGE);
         }
         error = lsp(conn, path, filep->membuf == NULL ? p : filep->membuf,
             filep->size, L);
@@ -917,256 +1186,188 @@ struct file *filep, struct lua_State *ls)
 }
 
 #ifdef USE_WEBSOCKET
-struct lua_websock_data {
-    lua_State *main;
-    lua_State *thread;
-    char * script;
-    unsigned shared;
-    struct mg_connection *conn;
-    pthread_mutex_t mutex;
+struct mg_shared_lua_websocket_list {
+    struct lua_websock_data ws;
+    struct mg_shared_lua_websocket_list *next;
 };
 
-struct mg_shared_lua_websocket {
-    struct lua_websock_data *sock;
-    struct mg_shared_lua_websocket *next;
-};
-
-static void websock_cry(struct mg_connection *conn, int err, lua_State * L, const char * ws_operation, const char * lua_operation)
-{
-    switch (err) {
-        case LUA_OK:
-        case LUA_YIELD:
-            break;
-        case LUA_ERRRUN:
-            mg_cry(conn, "%s: %s failed: runtime error: %s", ws_operation, lua_operation, lua_tostring(L, -1));
-            break;
-        case LUA_ERRSYNTAX:
-            mg_cry(conn, "%s: %s failed: syntax error: %s", ws_operation, lua_operation, lua_tostring(L, -1));
-            break;
-        case LUA_ERRMEM:
-            mg_cry(conn, "%s: %s failed: out of memory", ws_operation, lua_operation);
-            break;
-        case LUA_ERRGCMM:
-            mg_cry(conn, "%s: %s failed: error during garbage collection", ws_operation, lua_operation);
-            break;
-        case LUA_ERRERR:
-            mg_cry(conn, "%s: %s failed: error in error handling: %s", ws_operation, lua_operation, lua_tostring(L, -1));
-            break;
-        default:
-            mg_cry(conn, "%s: %s failed: error %i", ws_operation, lua_operation, err);
-            break;
-    }
-}
-
-static void * lua_websocket_new(const char * script, struct mg_connection *conn, int is_shared)
+static void * lua_websocket_new(const char * script, struct mg_connection *conn)
 {
-    struct lua_websock_data *lws_data;
-    struct mg_shared_lua_websocket **shared_websock_list = &(conn->ctx->shared_lua_websockets);
-    int ok = 0;
-    int found = 0;
-    int err, nargs;
+    struct mg_shared_lua_websocket_list **shared_websock_list = &(conn->ctx->shared_lua_websockets);
+    struct lua_websock_data *ws;
+    int err, ok = 0;
 
     assert(conn->lua_websocket_state == NULL);
 
-    /*
-    lock list (mg_context global)
-    check if in list
-    yes: inc rec counter
-    no: create state, add to list
-    lock list element
-    unlock list (mg_context global)
-    call add
-    unlock list element
-    */
-
-    if (is_shared) {
-        (void)pthread_mutex_lock(&conn->ctx->mutex);
-        while (*shared_websock_list) {
-            if (!strcmp((*shared_websock_list)->sock->script, script)) {
-                lws_data = (*shared_websock_list)->sock;
-                lws_data->shared++;
-                found = 1;
-            }
-            shared_websock_list = &((*shared_websock_list)->next);
+    /* lock list (mg_context global) */
+    mg_lock_context(conn->ctx);
+    while (*shared_websock_list) {
+        /* check if ws already in list */
+        if (0==strcmp(script,(*shared_websock_list)->ws.script)) {
+            break;
         }
-        (void)pthread_mutex_unlock(&conn->ctx->mutex);
+        shared_websock_list = &((*shared_websock_list)->next);
     }
-
-    if (!found) {
-        lws_data = (struct lua_websock_data *) mg_malloc(sizeof(*lws_data));
+    if (*shared_websock_list == NULL) {
+        /* add ws to list */
+        *shared_websock_list = mg_calloc(sizeof(struct mg_shared_lua_websocket_list), 1);
+        if (*shared_websock_list == NULL) {
+            mg_unlock_context(conn->ctx);
+            mg_cry(conn, "Cannot create shared websocket struct, OOM");
+            return NULL;
+        }
+        /* init ws list element */
+        ws = &(*shared_websock_list)->ws;
+        ws->script = mg_strdup(script); /* TODO: handle OOM */
+        pthread_mutex_init(&(ws->ws_mutex), NULL);
+        ws->state = lua_newstate(lua_allocator, NULL);
+        ws->conn[0] = conn;
+        ws->references = 1;
+        (void)pthread_mutex_lock(&(ws->ws_mutex));
+        prepare_lua_environment(conn->ctx, NULL, ws, ws->state, script, LUA_ENV_TYPE_LUA_WEBSOCKET);
+        err = luaL_loadfile(ws->state, script);
+        if (err != 0) {
+            lua_cry(conn, err, ws->state, script, "load");
+        }
+        err = lua_pcall(ws->state, 0, 0, 0);
+        if (err != 0) {
+            lua_cry(conn, err, ws->state, script, "init");
+        }
+    } else {
+        /* inc ref count */
+        ws = &(*shared_websock_list)->ws;
+        (void)pthread_mutex_lock(&(ws->ws_mutex));
+        (*shared_websock_list)->ws.conn[(ws->references)++] = conn;
     }
-
-    if (lws_data) {
-        if (!found) {
-            lws_data->shared = is_shared;
-            lws_data->conn = conn;
-            lws_data->script = mg_strdup(script);
-            lws_data->main = lua_newstate(lua_allocator, NULL);
-            if (is_shared) {
-                (void)pthread_mutex_lock(&conn->ctx->mutex);
-                shared_websock_list = &(conn->ctx->shared_lua_websockets);
-                while (*shared_websock_list) {
-                    shared_websock_list = &((*shared_websock_list)->next);
-                }
-                *shared_websock_list = (struct mg_shared_lua_websocket *)mg_malloc(sizeof(struct mg_shared_lua_websocket));
-                if (*shared_websock_list) {
-                    (*shared_websock_list)->sock = lws_data;
-                    (*shared_websock_list)->next = 0;
-                }
-                (void)pthread_mutex_unlock(&conn->ctx->mutex);
-            }
+    mg_unlock_context(conn->ctx);
+
+    /* call add */
+    lua_getglobal(ws->state, "open");
+    lua_newtable(ws->state);
+    prepare_lua_request_info(conn, ws->state);
+    lua_pushstring(ws->state, "client");
+    lua_pushlightuserdata(ws->state, (void *)conn);
+    lua_rawset(ws->state, -3);
+
+    err = lua_pcall(ws->state, 1, 1, 0);
+    if (err != 0) {
+        lua_cry(conn, err, ws->state, script, "open handler");
+    } else {
+        if (lua_isboolean(ws->state, -1)) {
+            ok = lua_toboolean(ws->state, -1);
         }
+        lua_pop(ws->state, 1);
+    }
+    if (!ok) {
+        /* Remove from ws connection list. */
+        /* TODO: Check if list entry and Lua state needs to be deleted (see websocket_close). */
+        (*shared_websock_list)->ws.conn[--(ws->references)] = 0;
+        ws = NULL;
+    }
 
-        if (lws_data->main) {
-            prepare_lua_environment(conn, lws_data->main, script, LUA_ENV_TYPE_LUA_WEBSOCKET);
-            if (conn->ctx->callbacks.init_lua != NULL) {
-                conn->ctx->callbacks.init_lua(conn, lws_data->main);
-            }
-            lws_data->thread = lua_newthread(lws_data->main);
-            err = luaL_loadfile(lws_data->thread, script);
-            if (err==LUA_OK) {
-                /* Activate the Lua script. */
-                err = lua_resume(lws_data->thread, NULL, 0);
-                if (err!=LUA_YIELD) {
-                    websock_cry(conn, err, lws_data->thread, __func__, "lua_resume");
-                } else {
-                    nargs = lua_gettop(lws_data->thread);
-                    ok = (nargs==1) && lua_isboolean(lws_data->thread, 1) && lua_toboolean(lws_data->thread, 1);
-                }
-            } else {
-                websock_cry(conn, err, lws_data->thread, __func__, "lua_loadfile");
-            }
+    (void)pthread_mutex_unlock(&(ws->ws_mutex));
 
-        } else {
-            mg_cry(conn, "%s: luaL_newstate failed", __func__);
-        }
+    return (void*)ws;
+}
 
-        if (!ok) {
-            if (lws_data->main) lua_close(lws_data->main);
-            mg_free(lws_data->script);
-            mg_free(lws_data);
-            lws_data=0;
-        }
+static int lua_websocket_data(struct mg_connection * conn, void *ws_arg, int bits, char *data, size_t data_len)
+{
+    struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
+    int err, ok = 0;
+
+    assert(ws != NULL);
+    assert(ws->state != NULL);
+
+    (void)pthread_mutex_lock(&ws->ws_mutex);
+
+    lua_getglobal(ws->state, "data");
+    lua_newtable(ws->state);
+    lua_pushstring(ws->state, "client");
+    lua_pushlightuserdata(ws->state, (void *)conn);
+    lua_rawset(ws->state, -3);
+    lua_pushstring(ws->state, "bits"); /* TODO: dont use "bits" but fields with a meaning according to http://tools.ietf.org/html/rfc6455, section 5.2 */
+    lua_pushnumber(ws->state, bits);
+    lua_rawset(ws->state, -3);
+    lua_pushstring(ws->state, "data");
+    lua_pushlstring(ws->state, data, data_len);
+    lua_rawset(ws->state, -3);
+
+    err = lua_pcall(ws->state, 1, 1, 0);
+    if (err != 0) {
+        lua_cry(conn, err, ws->state, ws->script, "data handler");
     } else {
-        mg_cry(conn, "%s: out of memory", __func__);
+        if (lua_isboolean(ws->state, -1)) {
+            ok = lua_toboolean(ws->state, -1);
+        }
+        lua_pop(ws->state, 1);
     }
+    (void)pthread_mutex_unlock(&ws->ws_mutex);
 
-    return lws_data;
+    return ok;
 }
 
-static int lua_websocket_data(struct mg_connection *conn, int bits, char *data, size_t data_len)
+static int lua_websocket_ready(struct mg_connection * conn, void * ws_arg)
 {
-    struct lua_websock_data *lws_data = (struct lua_websock_data *)(conn->lua_websocket_state);
-    int err, nargs, ok=0, retry;
-    lua_Number delay;
-
-    assert(lws_data != NULL);
-    assert(lws_data->main != NULL);
-    assert(lws_data->thread != NULL);
-
-    /*
-    lock list element
-    call data
-    unlock list element
-    */
-
-    do {
-        retry=0;
-
-        /* Push the data to Lua, then resume the Lua state. */
-        /* The data will be available to Lua as the result of the coroutine.yield function. */
-        lua_pushboolean(lws_data->thread, 1);
-        if (bits >= 0) {
-            lua_pushinteger(lws_data->thread, bits);
-            if (data) {
-                lua_pushlstring(lws_data->thread, data, data_len);
-                err = lua_resume(lws_data->thread, NULL, 3);
-            } else {
-                err = lua_resume(lws_data->thread, NULL, 2);
-            }
-        } else {
-            err = lua_resume(lws_data->thread, NULL, 1);
-        }
+    struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
+    int err, ok = 0;
 
-        /* Check if Lua returned by a call to the coroutine.yield function. */
-        if (err!=LUA_YIELD) {
-            websock_cry(conn, err, lws_data->thread, __func__, "lua_resume");
-        } else {
-            nargs = lua_gettop(lws_data->thread);
-            ok = (nargs>=1) && lua_isboolean(lws_data->thread, 1) && lua_toboolean(lws_data->thread, 1);
-            delay = (nargs>=2) && lua_isnumber(lws_data->thread, 2) ? lua_tonumber(lws_data->thread, 2) : -1.0;
-            if (ok && delay>0) {
-                fd_set rfds;
-                struct timeval tv;
-
-                FD_ZERO(&rfds);
-                FD_SET(conn->client.sock, &rfds);
-
-                tv.tv_sec = (unsigned long)delay;
-                tv.tv_usec = (unsigned long)(((double)delay - (double)((unsigned long)delay))*1000000.0);
-                retry = (0==select(conn->client.sock+1, &rfds, NULL, NULL, &tv));
-            }
+    assert(ws != NULL);
+    assert(ws->state != NULL);
+
+    (void)pthread_mutex_lock(&ws->ws_mutex);
+
+    lua_getglobal(ws->state, "ready");
+    lua_newtable(ws->state);
+    lua_pushstring(ws->state, "client");
+    lua_pushlightuserdata(ws->state, (void *)conn);
+    lua_rawset(ws->state, -3);
+
+    err = lua_pcall(ws->state, 1, 1, 0);
+    if (err != 0) {
+        lua_cry(conn, err, ws->state, ws->script, "ready handler");
+    } else {
+        if (lua_isboolean(ws->state, -1)) {
+            ok = lua_toboolean(ws->state, -1);
         }
-    } while (retry);
+        lua_pop(ws->state, 1);
+    }
+
+    (void)pthread_mutex_unlock(&ws->ws_mutex);
 
     return ok;
 }
 
-static int lua_websocket_ready(struct mg_connection *conn)
+static void lua_websocket_close(struct mg_connection * conn, void * ws_arg)
 {
-    return lua_websocket_data(conn, -1, NULL, 0);
-}
+    struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
+    struct mg_shared_lua_websocket_list **shared_websock_list = &(conn->ctx->shared_lua_websockets);
+    int err = 0;
+    unsigned i;
 
-static void lua_websocket_close(struct mg_connection *conn)
-{
-    struct lua_websock_data *lws_data = (struct lua_websock_data *)(conn->lua_websocket_state);
-    struct mg_shared_lua_websocket **shared_websock_list;
-    int err;
-
-    assert(lws_data != NULL);
-    assert(lws_data->main != NULL);
-    assert(lws_data->thread != NULL);
-
-    /*
-    lock list element
-    lock list (mg_context global)
-    call remove    
-    dec ref counter
-    if ref counter == 0 close state and remove from list
-    unlock list element
-    unlock list (mg_context global)
-    */
-
-
-    lua_pushboolean(lws_data->thread, 0);
-    err = lua_resume(lws_data->thread, NULL, 1);
-
-    if (lws_data->shared) {
-        (void)pthread_mutex_lock(&conn->ctx->mutex);
-        lws_data->shared--;
-        if (lws_data->shared==0) {
-        /*
-            shared_websock_list = &(conn->ctx->shared_lua_websockets);
-            while (*shared_websock_list) {
-                if ((*shared_websock_list)->sock == lws_data) {
-                    *shared_websock_list = (*shared_websock_list)->next;
-                } else {
-                    shared_websock_list = &((*shared_websock_list)->next);
-                }
-            }
+    assert(ws != NULL);
+    assert(ws->state != NULL);
+
+    (void)pthread_mutex_lock(&ws->ws_mutex);
 
-            lua_close(lws_data->main);
-            mg_free(lws_data->script);
-            lws_data->script=0;
-            mg_free(lws_data);
-         */
+    lua_getglobal(ws->state, "close");
+    lua_newtable(ws->state);
+    lua_pushstring(ws->state, "client");
+    lua_pushlightuserdata(ws->state, (void *)conn);
+    lua_rawset(ws->state, -3);
+
+    err = lua_pcall(ws->state, 1, 0, 0);
+    if (err != 0) {
+        lua_cry(conn, err, ws->state, ws->script, "close handler");
+    }
+    for (i=0;i<ws->references;i++) {
+        if (ws->conn[i]==conn) {
+            ws->references--;
+            ws->conn[i] = ws->conn[ws->references];
         }
-        (void)pthread_mutex_unlock(&conn->ctx->mutex);
-    } else {
-        lua_close(lws_data->main);
-        mg_free(lws_data->script);
-        mg_free(lws_data);
     }
-    conn->lua_websocket_state = NULL;
+    /* TODO: Delete lua_websock_data and remove it from the websocket list.
+       This must only be done, when all connections are closed, and all
+       asynchronous operations and timers are completed/expired. */
+    (void)pthread_mutex_unlock(&ws->ws_mutex);
 }
 #endif

+ 458 - 0
src/third_party/LuaXML_lib.c

@@ -0,0 +1,458 @@
+/**
+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.
+*/
+
+#if defined __WIN32__ || defined WIN32
+# include <windows.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+#ifdef __cplusplus
+}
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+static const char ESC=27;
+static const char OPN=28;
+static const char CLS=29;
+
+/*--- auxliary functions -------------------------------------------*/
+
+static const char* char2code(unsigned char ch, char buf[8]) {
+    unsigned char i=0;
+    buf[i++]='&';
+    buf[i++]='#';
+    if(ch>99) buf[i++]=ch/100+48;
+    if(ch>9) buf[i++]=(ch%100)/10+48;
+    buf[i++]=ch%10+48;
+    buf[i++]=';';
+    buf[i]=0;
+    return buf;
+}
+
+static size_t find(const char* s, const char* pattern, size_t start) {
+    const char* found =strstr(s+start, pattern);
+    return found ? found-s : strlen(s);
+}
+
+/*--- internal tokenizer -------------------------------------------*/
+typedef struct Tokenizer_s  {    
+    const char* s; /* stores string to be tokenized */    
+    size_t s_size; /* stores size of string to be tokenized */    
+    size_t i; /* stores current read position */    
+    int tagMode; /* stores current read context */    
+    const char* m_next; /* stores next token, if already determined */    
+    size_t m_next_size; /* size of next token */    
+    char* m_token; /* pointer to current token */    
+    size_t m_token_size; /* size of current token */    
+    size_t m_token_capacity; /* capacity of current token */
+} Tokenizer;
+
+Tokenizer* Tokenizer_new(const char* str, size_t str_size) {
+    Tokenizer *tok = (Tokenizer*)malloc(sizeof(Tokenizer));
+    memset(tok, 0, sizeof(Tokenizer));
+    tok->s_size = str_size;
+    tok->s = str;
+    return tok;
+}
+
+void Tokenizer_delete(Tokenizer* tok) {
+    free(tok->m_token);
+    free(tok);
+}
+
+/*
+void Tokenizer_print(Tokenizer* tok) { printf("  @%u %s\n", tok->i, !tok->m_token ? "(null)" : (tok->m_token[0]==ESC)?"(esc)" : (tok->m_token[0]==OPN)?"(open)": (tok->m_token[0]==CLS)?"(close)" : tok->m_token); fflush(stdout); }
+*/
+
+static const char* Tokenizer_set(Tokenizer* tok, const char* s, size_t size) {
+    if(!size||!s) return 0;
+    free(tok->m_token);
+    tok->m_token = (char*)malloc(size+1);
+    strncpy(tok->m_token,s, size);
+    tok->m_token[size] = 0;
+    tok->m_token_size = tok->m_token_capacity = size;
+    /*Tokenizer_print(tok);*/
+    return tok->m_token;
+}
+
+static void Tokenizer_append(Tokenizer* tok, char ch) {
+    if(tok->m_token_size+1>=tok->m_token_capacity) {
+        tok->m_token_capacity = (tok->m_token_capacity==0) ? 16 : tok->m_token_capacity*2;
+        tok->m_token = (char*)realloc(tok->m_token, tok->m_token_capacity);
+    }
+    tok->m_token[tok->m_token_size]=ch;
+    tok->m_token[++tok->m_token_size]=0;
+}
+
+const char* Tokenizer_next(Tokenizer* tok) {
+    const char* ESC_str = "\033";
+    const char* OPEN_str = "\034";
+    const char* CLOSE_str = "\035";
+    int quotMode=0;
+    int tokenComplete = 0;
+
+    if(tok->m_token) {
+        free(tok->m_token);
+        tok->m_token = 0;
+        tok->m_token_size=tok->m_token_capacity = 0;
+    }
+
+    while(tok->m_next_size || (tok->i < tok->s_size)) {
+
+        if(tok->m_next_size) {
+            Tokenizer_set(tok, tok->m_next, tok->m_next_size);
+            tok->m_next=0;
+            tok->m_next_size=0;
+            return tok->m_token;
+        }
+
+        switch(tok->s[tok->i]) {
+        case '"':
+        case '\'':
+            if(tok->tagMode) {
+                if(!quotMode) quotMode=tok->s[tok->i];
+                else if(quotMode==tok->s[tok->i]) quotMode=0;
+            }
+            Tokenizer_append(tok, tok->s[tok->i]);
+            break;
+        case '<':
+            if(!quotMode&&(tok->i+4<tok->s_size)&&(strncmp(tok->s+tok->i,"<!--",4)==0)) /* strip comments */
+                tok->i=find(tok->s, "-->", tok->i+4)+2;
+            else if(!quotMode&&(tok->i+9<tok->s_size)&&(strncmp(tok->s+tok->i,"<![CDATA[",9)==0)) { /* interpet CDATA */
+                size_t b=tok->i+9;
+                tok->i=find(tok->s, "]]>",b)+3;
+                if(!tok->m_token_size) return Tokenizer_set(tok, tok->s+b, tok->i-b-3);
+                tokenComplete = 1;
+                tok->m_next = tok->s+b;
+                tok->m_next_size = tok->i-b-3;
+                --tok->i;
+            }
+            else if(!quotMode&&(tok->i+1<tok->s_size)&&((tok->s[tok->i+1]=='?')||(tok->s[tok->i+1]=='!'))) /* strip meta information */
+                tok->i=find(tok->s, ">", tok->i+2);
+            else if(!quotMode&&!tok->tagMode) {
+                if((tok->i+1<tok->s_size)&&(tok->s[tok->i+1]=='/')) {
+                    tok->m_next=ESC_str;
+                    tok->m_next_size = 1;
+                    tok->i=find(tok->s, ">", tok->i+2);
+                }
+                else {
+                    tok->m_next = OPEN_str;
+                    tok->m_next_size = 1;
+                    tok->tagMode=1;
+                }
+                tokenComplete = 1;
+            }
+            else Tokenizer_append(tok, tok->s[tok->i]);
+            break;
+        case '/':
+            if(tok->tagMode&&!quotMode) {
+                tokenComplete = 1;
+                if((tok->i+1 < tok->s_size) && (tok->s[tok->i+1]=='>')) {
+                    tok->tagMode=0;
+                    tok->m_next=ESC_str;
+                    tok->m_next_size = 1;
+                    ++tok->i;
+                }
+                else Tokenizer_append(tok, tok->s[tok->i]);
+            }
+            else Tokenizer_append(tok, tok->s[tok->i]);
+            break;
+        case '>':
+            if(!quotMode&&tok->tagMode) {
+                tok->tagMode=0;
+                tokenComplete = 1;
+                tok->m_next = CLOSE_str;
+                tok->m_next_size = 1;
+            }
+            else Tokenizer_append(tok, tok->s[tok->i]);
+            break;
+        case ' ':
+        case '\r':
+        case '\n':
+        case '\t':
+            if(tok->tagMode&&!quotMode) {
+                if(tok->m_token_size) tokenComplete=1;
+            }
+            else if(tok->m_token_size) Tokenizer_append(tok, tok->s[tok->i]);
+            break;
+        default: Tokenizer_append(tok, tok->s[tok->i]);
+        }
+        ++tok->i;
+        if((tok->i>=tok->s_size)||(tokenComplete&&tok->m_token_size)) {
+            tokenComplete=0;
+            while(tok->m_token_size&&isspace(tok->m_token[tok->m_token_size-1])) /* trim whitespace */
+                tok->m_token[--tok->m_token_size]=0;
+            if(tok->m_token_size) break;
+        }
+    }
+    /*Tokenizer_print(tok);*/
+    return tok->m_token;
+}
+
+/*--- local variables ----------------------------------------------*/
+static size_t sv_code_size=0; /* stores number of special character codes */
+static size_t sv_code_capacity=16; /* stores currently allocated capacity for special character codes */
+static char** sv_code=0; /* stores code table for special characters */
+
+/*--- public methods -----------------------------------------------*/
+static void Xml_pushDecode(lua_State* L, const char* s, size_t s_size) {
+
+    luaL_Buffer b;
+    const char* found;
+    size_t start=0, pos;
+    size_t i;
+
+    if(!s_size)
+        s_size=strlen(s);
+    luaL_buffinit(L, &b);
+    found = strstr(s, "&#");
+
+    pos = found ? found-s : s_size;
+    while(found) {
+        char ch = 0;
+        size_t i=0;
+        for(found += 2; i<3; ++i, ++found)
+            if(isdigit(*found))
+                ch = ch * 10 + (*found - 48);
+            else break;
+            if(*found == ';') {
+                if(pos>start)
+                    luaL_addlstring(&b, s+start, pos-start);
+                luaL_addchar(&b, ch);
+                start = pos + 3 + i;
+            }
+            found = strstr(found+1, "&#");
+            pos = found ? found-s : s_size;
+    }
+    if(pos>start)
+        luaL_addlstring(&b,s+start, pos-start);
+    luaL_pushresult(&b);
+
+    for(i=sv_code_size-1; i<sv_code_size; i-=2) {
+        luaL_gsub(L, lua_tostring(L,-1), sv_code[i], sv_code[i-1]);
+        lua_remove(L,-2);
+    }
+}
+
+int Xml_eval(lua_State *L) {
+    char* str = 0;
+    size_t str_size=0;
+    Tokenizer* tok;
+    const char* token=0;
+    int firstStatement = 1;
+
+    if(lua_isuserdata(L,1))
+        str = (char*)lua_touserdata(L,1);
+    else {
+        const char * sTmp = luaL_checklstring(L,1,&str_size);
+        str = (char*)malloc(str_size+1);
+        memcpy(str, sTmp, str_size);
+        str[str_size]=0;
+    }
+    tok = Tokenizer_new(str, str_size ? str_size : strlen(str));
+    lua_settop(L,0);
+
+    while((token=Tokenizer_next(tok))!=0) if(token[0]==OPN) { /* new tag found */
+        if(lua_gettop(L)) {
+            int newIndex=lua_rawlen(L,-1)+1;
+            lua_pushnumber(L,newIndex);
+            lua_newtable(L);
+            lua_settable(L, -3);
+            lua_pushnumber(L,newIndex);
+            lua_gettable(L,-2);
+        }
+        else {
+            if (firstStatement) {
+                lua_newtable(L);
+                firstStatement = 0;
+            }
+            else return lua_gettop(L);
+        }
+        /* set metatable: */
+        lua_newtable(L);
+        lua_pushliteral(L, "__index");
+        lua_getglobal(L, "xml");
+        lua_settable(L, -3);
+
+        lua_pushliteral(L, "__tostring"); /* set __tostring metamethod */
+        lua_getglobal(L, "xml");
+        lua_pushliteral(L,"str");
+        lua_gettable(L, -2);
+        lua_remove(L, -2);
+        lua_settable(L, -3);
+        lua_setmetatable(L, -2);
+
+        /* parse tag and content: */
+        lua_pushnumber(L,0); /* use index 0 for storing the tag */
+        lua_pushstring(L, Tokenizer_next(tok));
+        lua_settable(L, -3);
+
+        while(((token = Tokenizer_next(tok))!=0)&&(token[0]!=CLS)&&(token[0]!=ESC)) { /* parse tag header */
+            size_t sepPos=find(token, "=", 0);
+            if(token[sepPos]) { /* regular attribute */
+                const char* aVal =token+sepPos+2;
+                size_t lenVal;
+                lua_pushlstring(L, token, sepPos);
+                lenVal = strlen(aVal)-1;
+                if(!lenVal) Xml_pushDecode(L, "", 0);
+                else Xml_pushDecode(L, aVal, lenVal);
+                lua_settable(L, -3);
+            }
+        }
+        if(!token||(token[0]==ESC)) {
+            if(lua_gettop(L)>1) lua_settop(L,-2); /* this tag has no content, only attributes */
+            else break;
+        }
+    }
+    else if(token[0]==ESC) { /* previous tag is over */
+        if(lua_gettop(L)>1) lua_settop(L,-2); /* pop current table */
+        else break;
+    }
+    else { /* read elements */
+        lua_pushnumber(L,lua_rawlen(L,-1)+1);
+        Xml_pushDecode(L, token, 0);
+        lua_settable(L, -3);
+    }
+    Tokenizer_delete(tok);
+    free(str);
+    return lua_gettop(L);
+}
+
+int Xml_load (lua_State *L) {
+    const char * filename = luaL_checkstring(L,1);
+    size_t sz;
+    FILE * file=fopen(filename,"r");
+    char* buffer;
+
+    if(!file)
+        return luaL_error(L,"LuaXml ERROR: \"%s\" file error or file not found!",filename);
+
+    fseek (file , 0 , SEEK_END);
+    sz = ftell (file);
+    rewind (file);
+    buffer = (char*)malloc(sz+1);
+    sz = fread (buffer,1,sz,file);
+    fclose(file);
+    buffer[sz]=0;
+    lua_pushlightuserdata(L,buffer);
+    lua_replace(L,1);
+    return Xml_eval(L);
+};
+
+int Xml_registerCode(lua_State *L) {
+    const char * decoded = luaL_checkstring(L,1);
+    const char * encoded = luaL_checkstring(L,2);
+
+    size_t i;
+    for(i=0; i<sv_code_size; i+=2)
+        if(strcmp(sv_code[i],decoded)==0)
+            return luaL_error(L,"LuaXml ERROR: code already exists.");
+    if(sv_code_size+2>sv_code_capacity) {
+        sv_code_capacity*=2;
+        sv_code = (char**)realloc(sv_code, sv_code_capacity*sizeof(char*));
+    }
+    sv_code[sv_code_size]=(char*)malloc(strlen(decoded)+1);
+    strcpy(sv_code[sv_code_size++], decoded);
+    sv_code[sv_code_size]=(char*)malloc(strlen(encoded)+1);
+    strcpy(sv_code[sv_code_size++],encoded);
+    return 0;
+}
+
+int Xml_encode(lua_State *L) {
+    char buf[8];
+    size_t i, start, pos;
+    luaL_Buffer b;
+    const char* s;
+
+    if(lua_gettop(L)!=1)
+        return 0;
+    luaL_checkstring(L,-1);
+
+    for(i=0; i<sv_code_size; i+=2) {
+        luaL_gsub(L, lua_tostring(L,-1), sv_code[i], sv_code[i+1]);
+        lua_remove(L,-2);
+    }
+
+    s=lua_tostring(L,1);
+    luaL_buffinit(L, &b);
+    for(start=pos=0; s[pos]!=0; ++pos) if(s[pos]<0) {
+        if(pos>start) luaL_addlstring(&b,s+start, pos-start);
+        luaL_addstring(&b,char2code((unsigned char)(s[pos]),buf));
+        start=pos+1;
+    }
+    if(pos>start)
+        luaL_addlstring(&b,s+start, pos-start);
+    luaL_pushresult(&b);
+    lua_remove(L,-2);
+    return 1;
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+    int luaopen_LuaXML(lua_State* L) {
+        static const struct luaL_Reg funcs[] = {
+            {"load", Xml_load},
+            {"eval", Xml_eval},
+            {"encode", Xml_encode},
+            /* {"registerCode", Xml_registerCode}, */
+            {NULL, NULL}
+        };
+
+        luaL_newlibtable(L, funcs);
+        luaL_setfuncs(L, funcs, 0);
+        lua_setglobal(L, "xml");
+
+        /* register default codes: */
+        if(!sv_code) {
+            sv_code=(char**)malloc(sv_code_capacity*sizeof(char*));
+            sv_code[sv_code_size++]="&";
+            sv_code[sv_code_size++]="&amp;";
+            sv_code[sv_code_size++]="<";
+            sv_code[sv_code_size++]="&lt;";
+            sv_code[sv_code_size++]=">";
+            sv_code[sv_code_size++]="&gt;";
+            sv_code[sv_code_size++]="\"";
+            sv_code[sv_code_size++]="&quot;";
+            sv_code[sv_code_size++]="'";
+            sv_code[sv_code_size++]="&apos;";
+        }
+        return 1;
+    }
+#ifdef __cplusplus
+}
+#endif

+ 1 - 1
src/third_party/lua-5.2.2/Makefile → src/third_party/lua-5.2.3/Makefile

@@ -46,7 +46,7 @@ TO_MAN= lua.1 luac.1
 
 # Lua version and release.
 V= 5.2
-R= $V.1
+R= $V.3
 
 # Targets start here.
 all:	$(PLAT)

+ 1 - 1
src/third_party/lua-5.2.2/README → src/third_party/lua-5.2.3/README

@@ -1,5 +1,5 @@
 
-This is Lua 5.2.2, released on 21 Mar 2013.
+This is Lua 5.2.3, released on 11 Nov 2013.
 
 For installation instructions, license details, and
 further information about Lua, see doc/readme.html.

+ 0 - 0
src/third_party/lua-5.2.2/doc/contents.html → src/third_party/lua-5.2.3/doc/contents.html


+ 0 - 0
src/third_party/lua-5.2.2/doc/logo.gif → src/third_party/lua-5.2.3/doc/logo.gif


+ 0 - 0
src/third_party/lua-5.2.2/doc/lua.1 → src/third_party/lua-5.2.3/doc/lua.1


+ 22 - 9
src/third_party/lua-5.2.2/doc/lua.css → src/third_party/lua-5.2.3/doc/lua.css

@@ -1,30 +1,37 @@
+html {
+	background-color: #F8F8F8 ;
+}
+
 body {
+	border: solid #a0a0a0 1px ;
+	border-radius: 20px ;
+	padding: 26px ;
+	margin: 16px ;
 	color: #000000 ;
 	background-color: #FFFFFF ;
 	font-family: Helvetica, Arial, sans-serif ;
 	text-align: justify ;
-	margin-right: 30px ;
-	margin-left: 30px ;
 }
 
 h1, h2, h3, h4 {
 	font-family: Verdana, Geneva, sans-serif ;
 	font-weight: normal ;
-	font-style: italic ;
+	font-style: normal ;
 }
 
 h2 {
 	padding-top: 0.4em ;
 	padding-bottom: 0.4em ;
-	padding-left: 1em ;
-	padding-right: 1em ;
-	background-color: #E0E0FF ;
+	padding-left: 0.8em ;
+	padding-right: 0.8em ;
+	background-color: #D0D0FF ;
 	border-radius: 8px ;
+	border: solid #a0a0a0 1px ;
 }
 
 h3 {
 	padding-left: 0.5em ;
-	border-left: solid #E0E0FF 1em ;
+	border-left: solid #D0D0FF 1em ;
 }
 
 table h3 {
@@ -45,7 +52,7 @@ a:visited {
 
 a:link:hover, a:visited:hover {
 	color: #000080 ;
-	background-color: #E0E0FF ;
+	background-color: #D0D0FF ;
 }
 
 a:link:active, a:visited:active {
@@ -57,17 +64,23 @@ hr {
 	height: 1px ;
 	color: #a0a0a0 ;
 	background-color: #a0a0a0 ;
+	display: none ;
+}
+
+table hr {
+	display: block ;
 }
 
 :target {
 	background-color: #F8F8F8 ;
 	padding: 8px ;
 	border: solid #a0a0a0 2px ;
+	border-radius: 8px ;
 }
 
 .footer {
 	color: gray ;
-	font-size: small ;
+	font-size: x-small ;
 }
 
 input[type=text] {

+ 0 - 0
src/third_party/lua-5.2.2/doc/luac.1 → src/third_party/lua-5.2.3/doc/luac.1


+ 5 - 4
src/third_party/lua-5.2.2/doc/manual.css → src/third_party/lua-5.2.3/doc/manual.css

@@ -16,11 +16,12 @@ span.apii {
 }
 
 p+h1, ul+h1 {
+	font-style: normal ;
 	padding-top: 0.4em ;
 	padding-bottom: 0.4em ;
-	padding-left: 24px ;
-	margin-left: -24px ;
-	background-color: #E0E0FF ;
+	padding-left: 16px ;
+	margin-left: -16px ;
+	background-color: #D0D0FF ;
 	border-radius: 8px ;
+	border: solid #000080 1px ;
 }
-

+ 0 - 0
src/third_party/lua-5.2.2/doc/manual.html → src/third_party/lua-5.2.3/doc/manual.html


+ 0 - 0
src/third_party/lua-5.2.2/doc/osi-certified-72x60.png → src/third_party/lua-5.2.3/doc/osi-certified-72x60.png


+ 4 - 3
src/third_party/lua-5.2.2/doc/readme.html → src/third_party/lua-5.2.3/doc/readme.html

@@ -7,6 +7,7 @@
 <STYLE TYPE="text/css">
 blockquote, .display {
 	border: solid #a0a0a0 2px ;
+	border-radius: 8px ;
 	padding: 1em ;
 	margin: 0px ;
 }
@@ -109,7 +110,7 @@ Here are the details.
 <OL>
 <LI>
 Open a terminal window and move to
-the top-level directory, which is named <TT>lua-5.2.2</TT>.
+the top-level directory, which is named <TT>lua-5.2.3</TT>.
 The Makefile there controls both the build process and the installation process.
 <P>
 <LI>
@@ -402,10 +403,10 @@ THE SOFTWARE.
 <HR>
 <SMALL CLASS="footer">
 Last update:
-Fri Feb 22 09:24:20 BRT 2013
+Sat Nov  9 22:39:16 BRST 2013
 </SMALL>
 <!--
-Last change: revised for Lua 5.2.2
+Last change: revised for Lua 5.2.3
 -->
 
 </BODY>

+ 1 - 1
src/third_party/lua-5.2.2/src/Makefile → src/third_party/lua-5.2.3/src/Makefile

@@ -106,7 +106,7 @@ linux:
 	$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline"
 
 macosx:
-	$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline"
+	$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline" CC=cc
 
 mingw:
 	$(MAKE) "LUA_A=lua52.dll" "LUA_T=lua.exe" \

+ 1 - 1
src/third_party/lua-5.2.2/src/lapi.c → src/third_party/lua-5.2.3/src/lapi.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lapi.c,v 2.171 2013/03/16 21:10:18 roberto Exp $
+** $Id: lapi.c,v 2.171.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Lua API
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/lapi.h → src/third_party/lua-5.2.3/src/lapi.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lapi.h,v 2.7 2009/11/27 15:37:59 roberto Exp $
+** $Id: lapi.h,v 2.7.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Auxiliary functions from Lua API
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/lauxlib.c → src/third_party/lua-5.2.3/src/lauxlib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lauxlib.c,v 1.248 2013/03/21 13:54:57 roberto Exp $
+** $Id: lauxlib.c,v 1.248.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Auxiliary functions for building Lua libraries
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/lauxlib.h → src/third_party/lua-5.2.3/src/lauxlib.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lauxlib.h,v 1.120 2011/11/29 15:55:08 roberto Exp $
+** $Id: lauxlib.h,v 1.120.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Auxiliary functions for building Lua libraries
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/lbaselib.c → src/third_party/lua-5.2.3/src/lbaselib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lbaselib.c,v 1.276 2013/02/21 13:44:53 roberto Exp $
+** $Id: lbaselib.c,v 1.276.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Basic library
 ** See Copyright Notice in lua.h
 */

+ 3 - 2
src/third_party/lua-5.2.2/src/lbitlib.c → src/third_party/lua-5.2.3/src/lbitlib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lbitlib.c,v 1.18 2013/03/19 13:19:12 roberto Exp $
+** $Id: lbitlib.c,v 1.18.1.2 2013/07/09 18:01:41 roberto Exp $
 ** Standard library for bitwise operations
 ** See Copyright Notice in lua.h
 */
@@ -129,7 +129,8 @@ static int b_rot (lua_State *L, int i) {
   b_uint r = luaL_checkunsigned(L, 1);
   i &= (LUA_NBITS - 1);  /* i = i % NBITS */
   r = trim(r);
-  r = (r << i) | (r >> (LUA_NBITS - i));
+  if (i != 0)  /* avoid undefined shift of LUA_NBITS when i == 0 */
+    r = (r << i) | (r >> (LUA_NBITS - i));
   lua_pushunsigned(L, trim(r));
   return 1;
 }

+ 1 - 1
src/third_party/lua-5.2.2/src/lcode.c → src/third_party/lua-5.2.3/src/lcode.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.c,v 2.62 2012/08/16 17:34:28 roberto Exp $
+** $Id: lcode.c,v 2.62.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/lcode.h → src/third_party/lua-5.2.3/src/lcode.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.h,v 1.58 2011/08/30 16:26:41 roberto Exp $
+** $Id: lcode.h,v 1.58.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/lcorolib.c → src/third_party/lua-5.2.3/src/lcorolib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lcorolib.c,v 1.5 2013/02/21 13:44:53 roberto Exp $
+** $Id: lcorolib.c,v 1.5.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Coroutine Library
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/lctype.c → src/third_party/lua-5.2.3/src/lctype.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lctype.c,v 1.11 2011/10/03 16:19:23 roberto Exp $
+** $Id: lctype.c,v 1.11.1.1 2013/04/12 18:48:47 roberto Exp $
 ** 'ctype' functions for Lua
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/lctype.h → src/third_party/lua-5.2.3/src/lctype.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lctype.h,v 1.12 2011/07/15 12:50:29 roberto Exp $
+** $Id: lctype.h,v 1.12.1.1 2013/04/12 18:48:47 roberto Exp $
 ** 'ctype' functions for Lua
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/ldblib.c → src/third_party/lua-5.2.3/src/ldblib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldblib.c,v 1.132 2012/01/19 20:14:44 roberto Exp $
+** $Id: ldblib.c,v 1.132.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Interface from Lua to its debug API
 ** See Copyright Notice in lua.h
 */

+ 22 - 9
src/third_party/lua-5.2.2/src/ldebug.c → src/third_party/lua-5.2.3/src/ldebug.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldebug.c,v 2.90 2012/08/16 17:34:28 roberto Exp $
+** $Id: ldebug.c,v 2.90.1.3 2013/05/16 16:04:15 roberto Exp $
 ** Debug Interface
 ** See Copyright Notice in lua.h
 */
@@ -327,12 +327,20 @@ static void kname (Proto *p, int pc, int c, const char **name) {
 }
 
 
+static int filterpc (int pc, int jmptarget) {
+  if (pc < jmptarget)  /* is code conditional (inside a jump)? */
+    return -1;  /* cannot know who sets that register */
+  else return pc;  /* current position sets that register */
+}
+
+
 /*
 ** try to find last instruction before 'lastpc' that modified register 'reg'
 */
 static int findsetreg (Proto *p, int lastpc, int reg) {
   int pc;
   int setreg = -1;  /* keep last instruction that changed 'reg' */
+  int jmptarget = 0;  /* any code before this address is conditional */
   for (pc = 0; pc < lastpc; pc++) {
     Instruction i = p->code[pc];
     OpCode op = GET_OPCODE(i);
@@ -341,33 +349,38 @@ static int findsetreg (Proto *p, int lastpc, int reg) {
       case OP_LOADNIL: {
         int b = GETARG_B(i);
         if (a <= reg && reg <= a + b)  /* set registers from 'a' to 'a+b' */
-          setreg = pc;
+          setreg = filterpc(pc, jmptarget);
         break;
       }
       case OP_TFORCALL: {
-        if (reg >= a + 2) setreg = pc;  /* affect all regs above its base */
+        if (reg >= a + 2)  /* affect all regs above its base */
+          setreg = filterpc(pc, jmptarget);
         break;
       }
       case OP_CALL:
       case OP_TAILCALL: {
-        if (reg >= a) setreg = pc;  /* affect all registers above base */
+        if (reg >= a)  /* affect all registers above base */
+          setreg = filterpc(pc, jmptarget);
         break;
       }
       case OP_JMP: {
         int b = GETARG_sBx(i);
         int dest = pc + 1 + b;
         /* jump is forward and do not skip `lastpc'? */
-        if (pc < dest && dest <= lastpc)
-          pc += b;  /* do the jump */
+        if (pc < dest && dest <= lastpc) {
+          if (dest > jmptarget)
+            jmptarget = dest;  /* update 'jmptarget' */
+        }
         break;
       }
       case OP_TEST: {
-        if (reg == a) setreg = pc;  /* jumped code can change 'a' */
+        if (reg == a)  /* jumped code can change 'a' */
+          setreg = filterpc(pc, jmptarget);
         break;
       }
       default:
         if (testAMode(op) && reg == a)  /* any instruction that set A */
-          setreg = pc;
+          setreg = filterpc(pc, jmptarget);
         break;
     }
   }
@@ -518,7 +531,7 @@ l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
 
 l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2) {
   if (ttisstring(p1) || ttisnumber(p1)) p1 = p2;
-  lua_assert(!ttisstring(p1) && !ttisnumber(p2));
+  lua_assert(!ttisstring(p1) && !ttisnumber(p1));
   luaG_typeerror(L, p1, "concatenate");
 }
 

+ 1 - 1
src/third_party/lua-5.2.2/src/ldebug.h → src/third_party/lua-5.2.3/src/ldebug.h

@@ -1,5 +1,5 @@
 /*
-** $Id: ldebug.h,v 2.7 2011/10/07 20:45:19 roberto Exp $
+** $Id: ldebug.h,v 2.7.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Auxiliary functions from Debug Interface module
 ** See Copyright Notice in lua.h
 */

+ 13 - 5
src/third_party/lua-5.2.2/src/ldo.c → src/third_party/lua-5.2.3/src/ldo.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.c,v 2.108 2012/10/01 14:05:04 roberto Exp $
+** $Id: ldo.c,v 2.108.1.3 2013/11/08 18:22:50 roberto Exp $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -260,6 +260,7 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
   StkId base, fixed;
   lua_assert(actual >= nfixargs);
   /* move fixed parameters to final position */
+  luaD_checkstack(L, p->maxstacksize);  /* check again for new 'base' */
   fixed = L->top - actual;  /* first fixed argument */
   base = L->top;  /* final position of first argument */
   for (i=0; i<nfixargs; i++) {
@@ -324,12 +325,18 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
     case LUA_TLCL: {  /* Lua function: prepare its call */
       StkId base;
       Proto *p = clLvalue(func)->p;
-      luaD_checkstack(L, p->maxstacksize);
-      func = restorestack(L, funcr);
       n = cast_int(L->top - func) - 1;  /* number of real arguments */
+      luaD_checkstack(L, p->maxstacksize);
       for (; n < p->numparams; n++)
         setnilvalue(L->top++);  /* complete missing arguments */
-      base = (!p->is_vararg) ? func + 1 : adjust_varargs(L, p, n);
+      if (!p->is_vararg) {
+        func = restorestack(L, funcr);
+        base = func + 1;
+      }
+      else {
+        base = adjust_varargs(L, p, n);
+        func = restorestack(L, funcr);  /* previous call can change stack */
+      }
       ci = next_ci(L);  /* now 'enter' new function */
       ci->nresults = nresults;
       ci->func = func;
@@ -527,6 +534,7 @@ static void resume (lua_State *L, void *ud) {
 
 LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
   int status;
+  int oldnny = L->nny;  /* save 'nny' */
   lua_lock(L);
   luai_userstateresume(L, nargs);
   L->nCcalls = (from) ? from->nCcalls + 1 : 1;
@@ -548,7 +556,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
     }
     lua_assert(status == L->status);
   }
-  L->nny = 1;  /* do not allow yields */
+  L->nny = oldnny;  /* restore 'nny' */
   L->nCcalls--;
   lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0));
   lua_unlock(L);

+ 1 - 1
src/third_party/lua-5.2.2/src/ldo.h → src/third_party/lua-5.2.3/src/ldo.h

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.h,v 2.20 2011/11/29 15:55:08 roberto Exp $
+** $Id: ldo.h,v 2.20.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/ldump.c → src/third_party/lua-5.2.3/src/ldump.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldump.c,v 2.17 2012/01/23 23:02:10 roberto Exp $
+** $Id: ldump.c,v 2.17.1.1 2013/04/12 18:48:47 roberto Exp $
 ** save precompiled Lua chunks
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/lfunc.c → src/third_party/lua-5.2.3/src/lfunc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lfunc.c,v 2.30 2012/10/03 12:36:46 roberto Exp $
+** $Id: lfunc.c,v 2.30.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Auxiliary functions to manipulate prototypes and closures
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/lfunc.h → src/third_party/lua-5.2.3/src/lfunc.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lfunc.h,v 2.8 2012/05/08 13:53:33 roberto Exp $
+** $Id: lfunc.h,v 2.8.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Auxiliary functions to manipulate prototypes and closures
 ** See Copyright Notice in lua.h
 */

+ 10 - 3
src/third_party/lua-5.2.2/src/lgc.c → src/third_party/lua-5.2.3/src/lgc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 2.140 2013/03/16 21:10:18 roberto Exp $
+** $Id: lgc.c,v 2.140.1.2 2013/04/26 18:22:05 roberto Exp $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -493,17 +493,24 @@ static lu_mem traverseLclosure (global_State *g, LClosure *cl) {
 
 
 static lu_mem traversestack (global_State *g, lua_State *th) {
+  int n = 0;
   StkId o = th->stack;
   if (o == NULL)
     return 1;  /* stack not completely built yet */
-  for (; o < th->top; o++)
+  for (; o < th->top; o++)  /* mark live elements in the stack */
     markvalue(g, o);
   if (g->gcstate == GCSatomic) {  /* final traversal? */
     StkId lim = th->stack + th->stacksize;  /* real end of stack */
     for (; o < lim; o++)  /* clear not-marked stack slice */
       setnilvalue(o);
   }
-  return sizeof(lua_State) + sizeof(TValue) * th->stacksize;
+  else {  /* count call infos to compute size */
+    CallInfo *ci;
+    for (ci = &th->base_ci; ci != th->ci; ci = ci->next)
+      n++;
+  }
+  return sizeof(lua_State) + sizeof(TValue) * th->stacksize +
+         sizeof(CallInfo) * n;
 }
 
 

+ 1 - 1
src/third_party/lua-5.2.2/src/lgc.h → src/third_party/lua-5.2.3/src/lgc.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.h,v 2.58 2012/09/11 12:53:08 roberto Exp $
+** $Id: lgc.h,v 2.58.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/linit.c → src/third_party/lua-5.2.3/src/linit.c

@@ -1,5 +1,5 @@
 /*
-** $Id: linit.c,v 1.32 2011/04/08 19:17:36 roberto Exp $
+** $Id: linit.c,v 1.32.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Initialization of libraries for lua.c and other clients
 ** See Copyright Notice in lua.h
 */

+ 12 - 11
src/third_party/lua-5.2.2/src/liolib.c → src/third_party/lua-5.2.3/src/liolib.c

@@ -1,17 +1,17 @@
 /*
-** $Id: liolib.c,v 2.111 2013/03/21 13:57:27 roberto Exp $
+** $Id: liolib.c,v 2.112.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Standard I/O (and system) library
 ** See Copyright Notice in lua.h
 */
 
 
 /*
-** POSIX idiosyncrasy!
 ** This definition must come before the inclusion of 'stdio.h'; it
 ** should not affect non-POSIX systems
 */
 #if !defined(_FILE_OFFSET_BITS)
-#define _FILE_OFFSET_BITS 64
+#define	_LARGEFILE_SOURCE	1
+#define _FILE_OFFSET_BITS	64
 #endif
 
 
@@ -80,36 +80,37 @@
 
 /*
 ** {======================================================
-** lua_fseek/lua_ftell: configuration for longer offsets
+** lua_fseek: configuration for longer offsets
 ** =======================================================
 */
 
-#if !defined(lua_fseek)	/* { */
+#if !defined(lua_fseek)	&& !defined(LUA_ANSI)	/* { */
 
-#if defined(LUA_USE_POSIX)
+#if defined(LUA_USE_POSIX)	/* { */
 
 #define l_fseek(f,o,w)		fseeko(f,o,w)
 #define l_ftell(f)		ftello(f)
 #define l_seeknum		off_t
 
 #elif defined(LUA_WIN) && !defined(_CRTIMP_TYPEINFO) \
-   && defined(_MSC_VER) && (_MSC_VER >= 1400)
+   && defined(_MSC_VER) && (_MSC_VER >= 1400)	/* }{ */
 /* Windows (but not DDK) and Visual C++ 2005 or higher */
 
 #define l_fseek(f,o,w)		_fseeki64(f,o,w)
 #define l_ftell(f)		_ftelli64(f)
 #define l_seeknum		__int64
 
-#else
+#endif	/* } */
 
+#endif			/* } */
+
+
+#if !defined(l_fseek)		/* default definitions */
 #define l_fseek(f,o,w)		fseek(f,o,w)
 #define l_ftell(f)		ftell(f)
 #define l_seeknum		long
-
 #endif
 
-#endif			/* } */
-
 /* }====================================================== */
 
 

+ 4 - 1
src/third_party/lua-5.2.2/src/llex.c → src/third_party/lua-5.2.3/src/llex.c

@@ -1,5 +1,5 @@
 /*
-** $Id: llex.c,v 2.63 2013/03/16 21:10:18 roberto Exp $
+** $Id: llex.c,v 2.63.1.2 2013/08/30 15:49:41 roberto Exp $
 ** Lexical Analyzer
 ** See Copyright Notice in lua.h
 */
@@ -133,6 +133,9 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
     setbvalue(o, 1);  /* t[string] = true */
     luaC_checkGC(L);
   }
+  else {  /* string already present */
+    ts = rawtsvalue(keyfromval(o));  /* re-use value previously stored */
+  }
   L->top--;  /* remove string from stack */
   return ts;
 }

+ 1 - 1
src/third_party/lua-5.2.2/src/llex.h → src/third_party/lua-5.2.3/src/llex.h

@@ -1,5 +1,5 @@
 /*
-** $Id: llex.h,v 1.72 2011/11/30 12:43:51 roberto Exp $
+** $Id: llex.h,v 1.72.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Lexical Analyzer
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/llimits.h → src/third_party/lua-5.2.3/src/llimits.h

@@ -1,5 +1,5 @@
 /*
-** $Id: llimits.h,v 1.103 2013/02/20 14:08:56 roberto Exp $
+** $Id: llimits.h,v 1.103.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Limits, basic types, and some other `installation-dependent' definitions
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/lmathlib.c → src/third_party/lua-5.2.3/src/lmathlib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lmathlib.c,v 1.83 2013/03/07 18:21:32 roberto Exp $
+** $Id: lmathlib.c,v 1.83.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Standard mathematical library
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/lmem.c → src/third_party/lua-5.2.3/src/lmem.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lmem.c,v 1.84 2012/05/23 15:41:53 roberto Exp $
+** $Id: lmem.c,v 1.84.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Interface to Memory Manager
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/lmem.h → src/third_party/lua-5.2.3/src/lmem.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lmem.h,v 1.40 2013/02/20 14:08:21 roberto Exp $
+** $Id: lmem.h,v 1.40.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Interface to Memory Manager
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/loadlib.c → src/third_party/lua-5.2.3/src/loadlib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: loadlib.c,v 1.111 2012/05/30 12:33:44 roberto Exp $
+** $Id: loadlib.c,v 1.111.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Dynamic library loader for Lua
 ** See Copyright Notice in lua.h
 **

+ 1 - 1
src/third_party/lua-5.2.2/src/lobject.c → src/third_party/lua-5.2.3/src/lobject.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lobject.c,v 2.58 2013/02/20 14:08:56 roberto Exp $
+** $Id: lobject.c,v 2.58.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Some generic functions over Lua objects
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/lobject.h → src/third_party/lua-5.2.3/src/lobject.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lobject.h,v 2.71 2012/09/11 18:21:44 roberto Exp $
+** $Id: lobject.h,v 2.71.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Type definitions for Lua objects
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/lopcodes.c → src/third_party/lua-5.2.3/src/lopcodes.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.c,v 1.49 2012/05/14 13:34:18 roberto Exp $
+** $Id: lopcodes.c,v 1.49.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Opcodes for Lua virtual machine
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/lopcodes.h → src/third_party/lua-5.2.3/src/lopcodes.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.h,v 1.142 2011/07/15 12:50:29 roberto Exp $
+** $Id: lopcodes.h,v 1.142.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Opcodes for Lua virtual machine
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/loslib.c → src/third_party/lua-5.2.3/src/loslib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: loslib.c,v 1.40 2012/10/19 15:54:02 roberto Exp $
+** $Id: loslib.c,v 1.40.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Standard Operating System library
 ** See Copyright Notice in lua.h
 */

+ 1 - 1
src/third_party/lua-5.2.2/src/lparser.c → src/third_party/lua-5.2.3/src/lparser.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lparser.c,v 2.130 2013/02/06 13:37:39 roberto Exp $
+** $Id: lparser.c,v 2.130.1.1 2013/04/12 18:48:47 roberto Exp $
 ** Lua Parser
 ** See Copyright Notice in lua.h
 */

Някои файлове не бяха показани, защото твърде много файлове са промени