Jelajahi Sumber

Merge branch 'master' of https://github.com/civetweb/civetweb.git into add_conan_packaging_file

Tom Deblauwe 7 tahun lalu
induk
melakukan
f483eeac26
100 mengubah file dengan 3495 tambahan dan 1349 penghapusan
  1. 1 0
      .gitignore
  2. 97 74
      .travis.yml
  3. 23 7
      CMakeLists.txt
  4. 13 0
      CREDITS.md
  5. 39 6
      LICENSE.md
  6. 52 3
      Makefile
  7. 28 1
      Qt/CivetWeb.pro
  8. 2 2
      README.md
  9. 24 2
      RELEASE_NOTES.md
  10. 13 13
      VisualStudio/unit_test/unit_test.vcxproj
  11. 13 13
      VisualStudio/unit_test/unit_test.vcxproj.filters
  12. 33 3
      appveyor.yml
  13. 1 1
      ci/test/README.md
  14. 10 8
      docs/APIReference.md
  15. 36 14
      docs/Building.md
  16. 33 10
      docs/Embedding.md
  17. 82 24
      docs/Interface_Changes_1.10.md
  18. 1 1
      docs/OpenSSL.md
  19. 5 1
      docs/README.md
  20. 159 66
      docs/UserManual.md
  21. 3 3
      docs/api/mg_callbacks.md
  22. 1 1
      docs/api/mg_cry.md
  23. 1 1
      docs/api/mg_get_header.md
  24. 2 2
      docs/api/mg_get_option.md
  25. 1 1
      docs/api/mg_get_request_info.md
  26. 1 1
      docs/api/mg_get_response_info.md
  27. 1 1
      docs/api/mg_get_server_ports.md
  28. 1 1
      docs/api/mg_get_user_connection_data.md
  29. 1 1
      docs/api/mg_get_valid_option_names.md
  30. 1 1
      docs/api/mg_get_var2.md
  31. 1 1
      docs/api/mg_handle_form_request.md
  32. 1 1
      docs/api/mg_set_websocket_handler.md
  33. 1 1
      docs/api/mg_start_thread.md
  34. 1 1
      docs/api/mg_websocket_client_write.md
  35. 2 1
      docs/yaSSL.md
  36. 4 0
      examples/README.md
  37. 1 1
      examples/_obsolete/ws_server/ws_server.c
  38. 15 15
      examples/embedded_c/embedded_c.c
  39. 3 3
      examples/embedded_cpp/embedded_cpp.cpp
  40. 10 0
      examples/multidomain/README.md
  41. 5 0
      examples/multidomain/add_domain.conf
  42. 7 0
      examples/multidomain/base_domain.conf
  43. 5 0
      examples/ws_client/build.sh
  44. 409 0
      examples/ws_client/ws_client.c
  45. 16 14
      format.bat
  46. 20 8
      include/CivetServer.h
  47. 137 56
      include/civetweb.h
  48. 9 1
      resources/Makefile.in-duktape
  49. 2 2
      resources/Makefile.in-lua
  50. 81 0
      resources/check_defines.lua
  51. 118 0
      resources/used_defines.txt
  52. 54 41
      src/CMakeLists.txt
  53. 17 0
      src/CivetServer.cpp
  54. 409 216
      src/civetweb.c
  55. 1 1
      src/civetweb_private_lua.h
  56. 0 1
      src/file_ops.inl
  57. 108 82
      src/handle_form.inl
  58. 430 189
      src/main.c
  59. 5 5
      src/md5.inl
  60. 94 34
      src/mod_duktape.inl
  61. 335 149
      src/mod_lua.inl
  62. 125 0
      src/mod_zlib.inl
  63. 4 3
      src/sha1.inl
  64. 8 2
      src/third_party/lsqlite3.c
  65. TEMPAT SAMPAH
      src/third_party/lua-5.3.3/doc/logo.gif
  66. 1 1
      src/third_party/lua-5.3.4/Makefile
  67. 1 1
      src/third_party/lua-5.3.4/README
  68. 4 3
      src/third_party/lua-5.3.4/doc/contents.html
  69. 0 0
      src/third_party/lua-5.3.4/doc/index.css
  70. TEMPAT SAMPAH
      src/third_party/lua-5.3.4/doc/logo.gif
  71. 2 1
      src/third_party/lua-5.3.4/doc/lua.1
  72. 0 0
      src/third_party/lua-5.3.4/doc/lua.css
  73. 0 0
      src/third_party/lua-5.3.4/doc/luac.1
  74. 0 0
      src/third_party/lua-5.3.4/doc/manual.css
  75. 173 98
      src/third_party/lua-5.3.4/doc/manual.html
  76. 0 0
      src/third_party/lua-5.3.4/doc/osi-certified-72x60.png
  77. 3 3
      src/third_party/lua-5.3.4/doc/readme.html
  78. 0 0
      src/third_party/lua-5.3.4/src/Makefile
  79. 0 0
      src/third_party/lua-5.3.4/src/lapi.c
  80. 0 0
      src/third_party/lua-5.3.4/src/lapi.h
  81. 27 19
      src/third_party/lua-5.3.4/src/lauxlib.c
  82. 10 2
      src/third_party/lua-5.3.4/src/lauxlib.h
  83. 2 2
      src/third_party/lua-5.3.4/src/lbaselib.c
  84. 0 0
      src/third_party/lua-5.3.4/src/lbitlib.c
  85. 13 9
      src/third_party/lua-5.3.4/src/lcode.c
  86. 0 0
      src/third_party/lua-5.3.4/src/lcode.h
  87. 0 0
      src/third_party/lua-5.3.4/src/lcorolib.c
  88. 0 0
      src/third_party/lua-5.3.4/src/lctype.c
  89. 0 0
      src/third_party/lua-5.3.4/src/lctype.h
  90. 0 0
      src/third_party/lua-5.3.4/src/ldblib.c
  91. 32 13
      src/third_party/lua-5.3.4/src/ldebug.c
  92. 0 0
      src/third_party/lua-5.3.4/src/ldebug.h
  93. 103 101
      src/third_party/lua-5.3.4/src/ldo.c
  94. 0 0
      src/third_party/lua-5.3.4/src/ldo.h
  95. 0 0
      src/third_party/lua-5.3.4/src/ldump.c
  96. 0 0
      src/third_party/lua-5.3.4/src/lfunc.c
  97. 0 0
      src/third_party/lua-5.3.4/src/lfunc.h
  98. 5 3
      src/third_party/lua-5.3.4/src/lgc.c
  99. 0 0
      src/third_party/lua-5.3.4/src/lgc.h
  100. 3 3
      src/third_party/lua-5.3.4/src/linit.c

+ 1 - 0
.gitignore

@@ -3,6 +3,7 @@ civetweb
 civetweb_test
 libcivetweb.a
 libcivetweb.so
+libcivetweb.so.*
 *-cache
 out
 *.dmg

+ 97 - 74
.travis.yml

@@ -1,16 +1,3 @@
-##############################################################################
-# Travis version specific build environment specification
-##############################################################################
-
-# The "precise" build environment on Travis is in the process of being decommissioned
-# see https://blog.travis-ci.com/2017-08-31-trusty-as-default-status
-# The "precise=true"+"sudo=required" environment seems to lack IPv6 support.
-# According to some tests, all "sudo=required" environments do not support IPv6, see 
-# https://github.com/travis-ci/travis-ci/issues/8361#issuecomment-328263113
-# The container environments for "sudo=false" support IPv6 localhost [::1] 
-# connections for server/client test. Thus, all tests with ENABLE_IPV6=YES
-#
-
 
 ##############################################################################
 # Project specific settings
@@ -53,8 +40,18 @@ install:
     fi
 
 before_script:
+  # Add an IPv6 config - see the corresponding Travis issue
+  # https://github.com/travis-ci/travis-ci/issues/8361
+  - if [ "${ENABLE_IPV6}" == "YES" -a "${TRAVIS_OS_NAME}" == "linux" ]; then 
+      echo "Activating IPv6 on Travis";
+      sudo sh -c 'echo 0 > /proc/sys/net/ipv6/conf/all/disable_ipv6';
+    fi
   # Check some settings of the build server (operating system, IPv6 availability, directory)
   - uname -a
+  - if [ "${TRAVIS_OS_NAME}" == "linux" ]; then
+      lsb_release -a;
+      cat /etc/network/interfaces;
+    fi
   - ifconfig
   - pwd
   - ls -la
@@ -62,10 +59,10 @@ before_script:
       apt-cache search gcc | grep "GNU C compiler";
       apt-cache search clang | grep compiler;
     fi
-  - if [[ "${BUILD_TYPE}" == "OSX_OPENSSL_1_1" ]]; then brew install openssl@1.1 ;fi
+  - if [[ "${BUILD_TYPE}" == "OSX_OPENSSL_1_1" ]]; then HOMEBREW_NO_AUTO_UPDATE=1 brew install openssl@1.1 ;fi
   # Generate the build scripts with CMake
   - mkdir output
-  - gcc test/cgi_test.c -o output/cgi_test.cgi
+  - gcc unittest/cgi_test.c -o output/cgi_test.cgi
   - cd output
   - cmake --version
   - cmake
@@ -81,7 +78,6 @@ before_script:
     -DCIVETWEB_SSL_OPENSSL_API_1_1=${OPENSSL_1_1}
     -DCIVETWEB_ENABLE_WEBSOCKETS=${ENABLE_WEBSOCKETS}
     -DCIVETWEB_ENABLE_CXX=${ENABLE_CXX}
-    -DCIVETWEB_ENABLE_IPV6=${ENABLE_IPV6}
     -DCIVETWEB_ENABLE_SERVER_STATS=${ENABLE_SERVER_STATS}
     -DCIVETWEB_ENABLE_LUA=${ENABLE_LUA}
     -DCIVETWEB_ENABLE_LUA_SHARED=${ENABLE_LUA_SHARED}
@@ -90,10 +86,16 @@ before_script:
     -DCIVETWEB_C_STANDARD=${C_STANDARD}
     -DCIVETWEB_CXX_STANDARD=${CXX_STANDARD}
     -DCIVETWEB_ALLOW_WARNINGS=${ALLOW_WARNINGS}
+    -DCIVETWEB_ENABLE_IPV6=${ENABLE_IPV6}
     ${ADDITIONAL_CMAKE_ARGS}
     ..
   - ls -la
 
+# Modifications due to Travis IPv6 issues:
+# https://github.com/travis-ci/travis-ci/issues/8711
+# https://github.com/travis-ci/travis-ci/issues/8361
+# DCIVETWEB_ENABLE_IPV6=${ENABLE_IPV6} or =NO
+
 script:
   - if [ "${MACOSX_PACKAGE}" == "1" ]; then
       cd "${TRAVIS_BUILD_DIR}";
@@ -101,6 +103,14 @@ script:
     else
       CTEST_OUTPUT_ON_FAILURE=1 make all test;
     fi
+  - pwd
+  - ls -la unittest
+  - echo "Show all test logs:"
+  - if [ "${MACOSX_PACKAGE}" != "1" ]; then
+      for f in unittest/test-*.log; do printf "\n$f:\n"; cat $f; done;
+      for f in unittest/test-*.xml; do printf "\n$f:\n"; cat $f; done;
+    fi
+  - echo "Build and test script DONE"
 
 # Coveralls options: https://github.com/eddyxu/cpp-coveralls/blob/master/README.md
 after_success:
@@ -111,7 +121,7 @@ after_success:
 
 
 ##############################################################################
-# build matrix (auto generated)
+# build matrix
 ##############################################################################
 
 
@@ -226,7 +236,7 @@ matrix:
       ALLOW_WARNINGS=YES
 
   - dist: trusty
-    sudo: false
+    sudo: required
     os: linux
     compiler: clang
     addons:
@@ -262,7 +272,7 @@ matrix:
 
 
   - dist: trusty
-    sudo: false
+    sudo: required
     os: linux
     compiler: gcc
     addons:
@@ -296,6 +306,7 @@ matrix:
       ALLOW_WARNINGS=YES
   
   - os: linux
+    sudo: required
     compiler: gcc
     env:
       idx=6
@@ -321,6 +332,7 @@ matrix:
       ALLOW_WARNINGS=YES
 
   - os: osx
+    sudo: required
     compiler: clang
     env:
       idx=7
@@ -347,6 +359,7 @@ matrix:
 
   -
     os: osx
+    sudo: required
     compiler: clang
     env:
       idx=8
@@ -442,6 +455,7 @@ matrix:
 
   -
     os: osx
+    sudo: required
     compiler: clang
     env:
       idx=11
@@ -468,7 +482,7 @@ matrix:
       MACOSX_PACKAGE=1
 
   - dist: trusty
-    sudo: false
+    sudo: required
     os: linux
     compiler: clang
     addons:
@@ -510,6 +524,7 @@ matrix:
 
   -
     os: linux
+    sudo: required
     compiler: clang
     env:
       idx=13
@@ -634,61 +649,69 @@ matrix:
       NO_CACHING=NO
       ALLOW_WARNINGS=YES
 
+  -
+    os: linux
+    compiler: clang
+    env:
+      idx=18
+      N=Clang3.8-Linux-Complete-NoLua-Debug
+      MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8"
+      BUILD_TYPE=Debug
+      ENABLE_SSL_DYNAMIC_LOADING=YES
+      OPENSSL_1_1=NO
+      ENABLE_CXX=NO
+      ENABLE_LUA_SHARED=YES
+      C_STANDARD=auto
+      CXX_STANDARD=auto
+      FEATURES=31
+      BUILD_SHARED=NO
+      NO_FILES=NO
+      ENABLE_SSL=YES
+      NO_CGI=NO
+      ENABLE_IPV6=YES
+      ENABLE_WEBSOCKETS=YES
+      ENABLE_SERVER_STATS=YES
+      ENABLE_LUA=NO
+      ENABLE_DUKTAPE=NO
+      NO_CACHING=YES
+      ALLOW_WARNINGS=YES
 
-#### Now all define combinations, but only for Linux clang
-##### Generated with Lua:
-#
-#  function YN(i,b)
-#    local bits = {}
-#    while (i > 0.5) do
-#      i = math.floor(i)
-#      bits[#bits+1] = (math.mod(i, 2) == 1)
-#      i = i/2
-#    end
-#    if (bits[b]) then
-#      return "YES"
-#    end
-#    return "NO"
-#  end
-#  function INV(t)
-#    if t=="YES" then
-#      return "NO"
-#    elseif t=="NO" then
-#      return "YES"
-#    else
-#      assert("ERROR in INV!")
-#    end
-#  end
-#  for i=0,511 do
-#    if (YN(i, 6)=="NO") and (YN(i, 7)=="NO") then
-#      print("  -")
-#      print("    os: linux")
-#      print("    compiler: clang")
-#      print("    env:")
-#      print("      N=C" .. tostring(i) .. "_")
-#      print("      BUILD_TYPE=Release")
-#      print("      ENABLE_SSL_DYNAMIC_LOADING=YES")
-#      print("      OPENSSL_1_1=NO")
-#      print("      ENABLE_CXX=NO")
-#      print("      C_STANDARD=auto")
-#      print("      CXX_STANDARD=auto")
-#      print("      ENABLE_LUA_SHARED=NO")
-#      print("      FEATURES=" .. tostring(i))
-#      print("      BUILD_SHARED=NO")
-#      print("      NO_FILES=" .. INV(YN(i, 1)))
-#      print("      ENABLE_SSL=" .. YN(i, 2))
-#      print("      NO_CGI=" .. INV(YN(i, 3)))
-#      print("      ENABLE_IPV6=" .. YN(i, 4))
-#      print("      ENABLE_WEBSOCKETS=" .. YN(i, 5))
-#      print("      ENABLE_LUA=" .. YN(i, 6))
-#      print("      ENABLE_DUKTAPE=" .. YN(i, 7))
-#      print("      NO_CACHING=" .. INV(YN(i, 8)))
-#      print("      ENABLE_SERVER_STATS=" .. YN(i, 9))
-#      print("")
-#    end
-#  end
+# Remove Lua build, until someone knows how to fix the CMake files
 #
-
-# TODO: Regenerate this matrix, once a stable Travis build is re-established
+#  - dist: trusty
+#    sudo: required
+#    os: linux
+#    compiler: clang
+#    addons:
+#      apt:
+#        sources:
+#          - ubuntu-toolchain-r-test
+#          - llvm-toolchain-precise-3.8
+#        packages:
+#          - clang-3.8
+#          - lua5.2
+#    env:
+#      idx=19
+#      N=Clang3.8-Linux-Complete-WithLua-Debug
+#      MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8"
+#      BUILD_TYPE=Debug
+#      ENABLE_SSL_DYNAMIC_LOADING=YES
+#      OPENSSL_1_1=NO
+#      ENABLE_CXX=NO
+#      ENABLE_LUA_SHARED=YES
+#      C_STANDARD=auto
+#      CXX_STANDARD=auto
+#      FEATURES=63
+#      BUILD_SHARED=NO
+#      NO_FILES=NO
+#      ENABLE_SSL=YES
+#      NO_CGI=NO
+#      ENABLE_IPV6=YES
+#      ENABLE_WEBSOCKETS=YES
+#      ENABLE_SERVER_STATS=YES
+#      ENABLE_LUA=YES
+#      ENABLE_DUKTAPE=NO
+#      NO_CACHING=YES
+#      ALLOW_WARNINGS=YES
 
 

+ 23 - 7
CMakeLists.txt

@@ -26,7 +26,7 @@ include(CMakeDependentOption)
 
 # Set up the project
 project (civetweb)
-set(CIVETWEB_VERSION "1.10.0" CACHE STRING "The version of the civetweb library")
+set(CIVETWEB_VERSION "1.11.0" CACHE STRING "The version of the civetweb library")
 string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)" CIVETWEB_VERSION_MATCH "${CIVETWEB_VERSION}")
 if ("${CIVETWEB_VERSION_MATCH}" STREQUAL "")
   message(FATAL_ERROR "Must specify a semantic version: major.minor.patch")
@@ -45,6 +45,10 @@ elseif(NOT LINUX AND ${CMAKE_SYSTEM_NAME} MATCHES "Linux")
     SET(LINUX YES)
 endif()
 
+# CTest automation
+option(CIVETWEB_BUILD_TESTING "Enable automated testing of civetweb" ON)
+message(STATUS "Enabling tests in the build - ${CIVETWEB_BUILD_TESTING}")
+
 # C++ wrappers
 option(CIVETWEB_ENABLE_THIRD_PARTY_OUTPUT "Shows the output of third party dependency processing" OFF)
 
@@ -54,6 +58,9 @@ set(CIVETWEB_THREAD_STACK_SIZE 102400 CACHE STRING
 set_property(CACHE CIVETWEB_THREAD_STACK_SIZE PROPERTY VALUE ${CIVETWEB_THREAD_STACK_SIZE})
 message(STATUS "Thread Stack Size - ${CIVETWEB_THREAD_STACK_SIZE}")
 
+option(CIVETWEB_ENABLE_SERVER_EXECUTABLE "Enable building of the server executable" ON)
+message(STATUS "Enabling server executable - ${CIVETWEB_ENABLE_SERVER_EXECUTABLE}")
+
 # Serve no files from the web server
 option(CIVETWEB_SERVE_NO_FILES "Configures the server to serve no static files" OFF)
 message(STATUS "Serve no static files - ${CIVETWEB_SERVE_NO_FILES}")
@@ -101,7 +108,7 @@ message(STATUS "Lua CGI support - ${CIVETWEB_ENABLE_LUA}")
 # Enable installing CivetWeb executables
 option(CIVETWEB_INSTALL_EXECUTABLE "Enable installing CivetWeb executable" ON)
 mark_as_advanced(FORCE CIVETWEB_INSTALL_EXECUTABLE) # Advanced users can disable
-message(STATUS "Executable installation - ${CIVETWEB_INSTALL_EXECUTABLE}") 
+message(STATUS "Executable installation - ${CIVETWEB_INSTALL_EXECUTABLE}")
 
 # Allow builds to complete with warnings (do not set -Werror)
 # CivetWeb Linux support is stable:
@@ -113,6 +120,12 @@ message(STATUS "Executable installation - ${CIVETWEB_INSTALL_EXECUTABLE}")
 option(CIVETWEB_ALLOW_WARNINGS "Do not stop build if there are warnings" ON)
 message(STATUS "Build if there are warnings - ${CIVETWEB_ALLOW_WARNINGS}")
 
+if (NOT CIVETWEB_ALLOW_WARNINGS)
+  if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+    message(FATAL_ERROR "Cannot compile with warning as errors, until this GCC bug is solved: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53431")
+  endif()
+endif()
+
 # Link to the shared LUA library
 cmake_dependent_option(
   CIVETWEB_ENABLE_LUA_SHARED  "Link to the shared LUA system library" OFF
@@ -294,8 +307,8 @@ if (MINGW)
 endif()
 if (NOT CIVETWEB_ALLOW_WARNINGS)
   add_c_compiler_flag(-Werror)
+  add_c_compiler_flag(/WX)
 endif()
-add_c_compiler_flag(/WX)
 add_c_compiler_flag(-pedantic-errors)
 add_c_compiler_flag(-fvisibility=hidden)
 add_c_compiler_flag(-fstack-protector-strong RELEASE)
@@ -363,8 +376,8 @@ if (CIVETWEB_ENABLE_CXX)
   endif()
   if (NOT CIVETWEB_ALLOW_WARNINGS)
     add_cxx_compiler_flag(-Werror)
+    add_cxx_compiler_flag(/WX)
   endif()
-  add_cxx_compiler_flag(/WX)
   add_cxx_compiler_flag(-pedantic-errors)
   add_cxx_compiler_flag(-fvisibility=hidden)
   add_cxx_compiler_flag(-fstack-protector-strong RELEASE)
@@ -389,6 +402,8 @@ endif()
 # Set up the definitions
 if (${CMAKE_BUILD_TYPE} MATCHES "[Dd]ebug")
   add_definitions(-DDEBUG)
+  add_definitions(-O0)
+  add_definitions(-g)
 endif()
 if (CIVETWEB_ENABLE_IPV6)
   add_definitions(-DUSE_IPV6)
@@ -448,7 +463,7 @@ add_subdirectory(src)
 
 # Enable the testing of the library/executable
 include(CTest)
-if (BUILD_TESTING)
+if (CIVETWEB_BUILD_TESTING)
   # Check unit testing framework Version
   set(CIVETWEB_CHECK_VERSION 0.11.0 CACHE STRING
     "The version of Check unit testing framework to build and include statically")
@@ -465,13 +480,13 @@ if (BUILD_TESTING)
   mark_as_advanced(CIVETWEB_CHECK_MD5_HASH)
 
   # Build the testing
-  add_subdirectory(test)
+  add_subdirectory(unittest)
 endif()
 
 # Set up CPack
 include(InstallRequiredSystemLibraries)
 set(CPACK_PACKAGE_VENDOR "civetweb Contributors")
-set(CPACK_PACKAGE_CONTACT "civetweb@github.com")
+set(CPACK_PACKAGE_CONTACT "civetweb@users.noreply.github.com")
 set(CPACK_PACKAGE_VERSION_MAJOR "${CIVETWEB_VERSION_MAJOR}")
 set(CPACK_PACKAGE_VERSION_MINOR "${CIVETWEB_VERSION_MINOR}")
 set(CPACK_PACKAGE_VERSION_PATCH "${CIVETWEB_VERSION_PATCH}")
@@ -500,3 +515,4 @@ set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_PACKAGE_DEPENDS}")
 
 # Finalize CPack settings
 include(CPack)
+

+ 13 - 0
CREDITS.md

@@ -1,9 +1,11 @@
 # Civetweb Contributors
 
 * Abhishek Lekshmanan
+* Abramo Bagnara
 * Adam Bailey
 * Alan Somers
 * Alex Kozlov
+* AndreyArsov
 * bel2125
 * Ben M. Ward
 * BigJoe
@@ -18,6 +20,7 @@
 * Christian Mauderer
 * Christopher Galas
 * cjh
+* Colden Cullen
 * Daniel Oaks
 * Daniel Rempel
 * Danny Al-Gaaf
@@ -32,6 +35,7 @@
 * F-Secure Corporation
 * feneuilflo
 * Fernando G. Aranda
+* Frank Hilliger
 * Grahack
 * grenclave
 * grunk
@@ -39,6 +43,7 @@
 * HariKamath Kamath
 * Henry Chang
 * Jack
+* Jacob Repp
 * Jacob Skillin
 * Jan Willem Janssen
 * Jeremy Lin
@@ -54,6 +59,7 @@
 * Joshua D. Boyd
 * kakwa
 * kalphamon
+* Karol Mroz
 * Keith Kyzivat
 * Kevin Branigan
 * Kevin Wojniak
@@ -64,6 +70,7 @@
 * Lianghui
 * Maarten Fremouw
 * makrsmark
+* marco
 * Mark Lakata
 * Martin Gaida
 * Mateusz Gralka
@@ -72,6 +79,8 @@
 * Morgan McGuire
 * mrdvlpr.xnu
 * Neil Jensen
+* newsoft
+* nfrmtkr
 * Nick Hildebrant
 * Nigel Stewart
 * nihildeb
@@ -87,6 +96,7 @@
 * Peter Foerster
 * Philipp Friedenberger
 * Philipp Hasper
+* Radoslaw Zarzynski
 * Red54
 * Richard Screene
 * pkvamme
@@ -100,10 +110,13 @@
 * slidertom
 * SpaceLord
 * sunfch
+* suzukibitman
 * thewaterymoon
 * THILMANT, Bernard
 * Thomas Davis
+* Thorsten Horstmann
 * tnoho
+* Tomas Andrle
 * Toni Wilk
 * Ulrich Hertlein
 * Walt Steverson

+ 39 - 6
LICENSE.md

@@ -11,7 +11,7 @@ Civetweb License
 
 ### Included with all features.
 
-> Copyright (c) 2013-2017 The CivetWeb developers ([CREDITS.md](https://github.com/civetweb/civetweb/blob/master/CREDITS.md))
+> Copyright (c) 2013-2018 The CivetWeb developers ([CREDITS.md](https://github.com/civetweb/civetweb/blob/master/CREDITS.md))
 >
 > Copyright (c) 2004-2013 Sergey Lyubka
 >
@@ -73,7 +73,7 @@ SQLite3 License
 
 http://www.sqlite.org/copyright.html
 
-> 2001 September 15
+> 2001-09-15
 >
 > The author disclaims copyright to this source code.  In place of
 > a legal notice, here is a blessing:
@@ -88,11 +88,11 @@ lsqlite3 License
 
 ### Included only if built with Lua and SQLite support.
 
-> Copyright (C) 2002-2013 Tiago Dionizio, Doug Currie
+> Copyright (C) 2002-2016 Tiago Dionizio, Doug Currie
 > All rights reserved.
 > Author    : Tiago Dionizio <tiago.dionizio@ist.utl.pt>
 > Author    : Doug Currie <doug.currie@alum.mit.edu>
-> Library   : lsqlite3 - a SQLite 3 database binding for Lua 5
+> Library   : lsqlite3 - an SQLite 3 database binding for Lua 5
 >
 > Permission is hereby granted, free of charge, to any person obtaining a copy
 > of this software and associated documentation files (the "Software"), to deal
@@ -120,7 +120,7 @@ Lua File System License
 
 http://keplerproject.github.io/luafilesystem/license.html
 
-> Copyright © 2003 Kepler Project.
+> Copyright Kepler Project 2003 (http://www.keplerproject.org/luafilesystem)
 >
 > Permission is hereby granted, free of charge, to any person obtaining a copy
 > of this software and associated documentation files (the "Software"), to deal
@@ -186,7 +186,7 @@ https://github.com/svaarala/duktape/blob/master/LICENSE.txt
 > 
 > (http://opensource.org/licenses/MIT)
 > 
-> Copyright (c) 2013-2015 by Duktape authors (see AUTHORS.rst)
+> Copyright (c) 2013-2017 by Duktape authors (see AUTHORS.rst)
 >
 > Permission is hereby granted, free of charge, to any person obtaining a copy
 > of this software and associated documentation files (the "Software"), to deal
@@ -206,3 +206,36 @@ https://github.com/svaarala/duktape/blob/master/LICENSE.txt
 > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 > THE SOFTWARE.
 
+
+
+zlib License
+------
+
+### Included only if built with zlib support.
+
+https://www.zlib.net/zlib_license.html
+
+> zlib.h -- interface of the 'zlib' general purpose compression library
+> version 1.2.11, January 15th, 2017
+>
+> Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler
+>
+> This software is provided 'as-is', without any express or implied
+> warranty.  In no event will the authors be held liable for any damages
+> arising from the use of this software.
+>
+> Permission is granted to anyone to use this software for any purpose,
+> including commercial applications, and to alter it and redistribute it
+> freely, subject to the following restrictions:
+>
+> 1. The origin of this software must not be misrepresented; you must not
+>    claim that you wrote the original software. If you use this software
+>    in a product, an acknowledgment in the product documentation would be
+>    appreciated but is not required.
+> 2. Altered source versions must be plainly marked as such, and must not be
+>    misrepresented as being the original software.
+> 3. This notice may not be removed or altered from any source distribution.
+>
+> Jean-loup Gailly        Mark Adler
+> jloup@gzip.org          madler@alumni.caltech.edu
+

+ 52 - 3
Makefile

@@ -17,13 +17,15 @@ BUILD_DIR = out
 
 # Installation directories by convention
 # http://www.gnu.org/prep/standards/html_node/Directory-Variables.html
-PREFIX = /usr/local
+PREFIX ?= /usr/local
 EXEC_PREFIX = $(PREFIX)
 BINDIR = $(EXEC_PREFIX)/bin
 DATAROOTDIR = $(PREFIX)/share
 DOCDIR = $(DATAROOTDIR)/doc/$(CPROG)
 SYSCONFDIR = $(PREFIX)/etc
 HTMLDIR = $(DOCDIR)
+INCLUDEDIR = $(DESTDIR)$(PREFIX)/include
+LIBDIR = $(DESTDIR)$(EXEC_PREFIX)/lib
 
 # build tools
 MKDIR = mkdir -p
@@ -48,6 +50,7 @@ UNIT_TEST_SOURCES = test/unit_test.c
 SOURCE_DIRS =
 
 OBJECTS = $(LIB_SOURCES:.c=.o) $(APP_SOURCES:.c=.o)
+HEADERS = include/civetweb.h
 BUILD_RESOURCES =
 
 # The unit tests include the source files directly to get visibility to the
@@ -72,6 +75,7 @@ endif
 
 ifdef WITH_CPP
   OBJECTS += src/CivetServer.o
+  HEADERS += include/CivetServer.h
   LCC = $(CXX)
 else
   LCC = $(CC)
@@ -83,9 +87,16 @@ ifdef WITH_ALL
   WITH_LUA = 1
   WITH_DUKTAPE = 1
   WITH_SERVER_STATS = 1
+  WITH_ZLIB = 1
+  WITH_EXPERIMENTAL = 1
   #WITH_CPP is not defined, ALL means only real features, not wrappers
 endif
 
+# Use Lua?
+ifdef WITH_LUA_VERSION
+  WITH_LUA = 1
+endif
+
 ifdef WITH_LUA_SHARED
   WITH_LUA = 1
 endif
@@ -100,10 +111,15 @@ ifdef WITH_LUA
   include resources/Makefile.in-lua
 endif
 
+# Use Duktape?
 ifdef WITH_SSJS
   WITH_DUKTAPE = 1
 endif
 
+ifdef WITH_DUKTAPE_VERSION
+  WITH_DUKTAPE = 1
+endif
+
 ifdef WITH_DUKTAPE_SHARED
   WITH_DUKTAPE = 1
 endif
@@ -112,6 +128,20 @@ ifdef WITH_DUKTAPE
   include resources/Makefile.in-duktape
 endif
 
+# Use zlib?
+ifdef WITH_COMPRESSION
+  WITH_ZLIB = 1
+endif
+
+ifdef WITH_ZLIB
+  LIBS += -lz
+endif
+
+# Other features
+ifdef WITH_EXPERIMENTAL
+  CFLAGS += -DMG_EXPERIMENTAL_INTERFACES
+endif
+
 ifdef WITH_IPV6
   CFLAGS += -DUSE_IPV6
 endif
@@ -130,6 +160,7 @@ ifdef WITH_SERVER_STATS
   CFLAGS += -DUSE_SERVER_STATS
 endif
 
+# File names
 ifdef CONFIG_FILE
   CFLAGS += -DCONFIG_FILE=\"$(CONFIG_FILE)\"
 endif
@@ -185,8 +216,11 @@ help:
 	@echo "make build               compile"
 	@echo "make install             install on the system"
 	@echo "make clean               clean up the mess"
+	@echo "make install-headers     install headers"
 	@echo "make lib                 build a static library"
+	@echo "make install-lib         install the static library"
 	@echo "make slib                build a shared library"
+	@echo "make install-slib        install the shared library"
 	@echo "make unit_test           build unit tests executable"
 	@echo ""
 	@echo " Make Options"
@@ -195,12 +229,14 @@ help:
 	@echo "   WITH_LUA_VERSION=502  build with Lua 5.2.x (501 for Lua 5.1.x to 503 for 5.3.x)"
 	@echo "   WITH_DUKTAPE=1        build with Duktape support; include as static library"
 	@echo "   WITH_DUKTAPE_SHARED=1 build with Duktape support; use libduktape1.3.so"
-#	@echo "   WITH_DUKTAPE_VERSION=103 build with Duktape 1.3.x"
+	@echo "   WITH_DUKTAPE_VERSION=108 build with Duktape 1.8.x"
 	@echo "   WITH_DEBUG=1          build with GDB debug support"
 	@echo "   WITH_IPV6=1           with IPV6 support"
 	@echo "   WITH_WEBSOCKET=1      build with web socket support"
 	@echo "   WITH_SERVER_STATS=1   build includes support for server statistics"
+	@echo "   WITH_ZLIB=1           build includes support for on-the-fly compression using zlib"
 	@echo "   WITH_CPP=1            build library with c++ classes"
+	@echo "   WITH_EXPERIMENTAL=1   build with experimental features"
 	@echo "   CONFIG_FILE=file      use 'file' as the config file"
 	@echo "   CONFIG_FILE2=file     use 'file' as the backup config file"
 	@echo "   DOCUMENT_ROOT=/path   document root override when installing"
@@ -217,7 +253,7 @@ help:
 	@echo "   NO_SSL                disable SSL functionality"
 	@echo "   NO_SSL_DL             link against system libssl library"
 	@echo "   NO_FILES              do not serve files from a directory"
-	@echo "   NO_CACHING            disable caching (usefull for systems without timegm())"
+	@echo "   NO_CACHING            disable caching (useful for systems without timegm())"
 	@echo ""
 	@echo " Variables"
 	@echo "   TARGET_OS='$(TARGET_OS)'"
@@ -238,6 +274,19 @@ install: $(HTMLDIR)/index.html $(SYSCONFDIR)/civetweb.conf
 	install -d -m 755 "$(BINDIR)"
 	install -m 755 $(CPROG) "$(BINDIR)/"
 
+install-headers:
+	install -m 644 $(HEADERS) "$(INCLUDEDIR)"
+
+install-lib: lib$(CPROG).a
+	install -m 644 $< "$(LIBDIR)"
+
+install-slib: lib$(CPROG).so
+	$(eval version=$(shell grep -w "define CIVETWEB_VERSION" include/civetweb.h | sed 's|.*VERSION "\(.*\)"|\1|g'))
+	$(eval major=$(shell echo $(version) | cut -d'.' -f1))
+	install -m 644 $< "$(LIBDIR)"
+	install -m 777 $<.$(major) "$(LIBDIR)"
+	install -m 777 $<.$(version).0 "$(LIBDIR)"
+
 # Install target we do not want to overwrite
 # as it may be an upgrade
 $(HTMLDIR)/index.html:

+ 28 - 1
Qt/CivetWeb.pro

@@ -3,6 +3,8 @@ CONFIG += console
 CONFIG -= app_bundle
 CONFIG -= qt
 
+DEFINES += MG_EXPERIMENTAL_INTERFACES
+
 SOURCES += \
     ../src/md5.inl \
     ../src/sha1.inl \
@@ -11,7 +13,8 @@ SOURCES += \
     ../src/mod_duktape.inl \
     ../src/timer.inl \
     ../src/civetweb.c \
-    ../src/main.c
+    ../src/main.c \
+    ../src/mod_zlib.inl
 
 #include(deployment.pri)
 #qtcAddDeployment()
@@ -32,3 +35,27 @@ LIBS += -lpthread -ldl -lm
 DEFINES += USE_IPV6
 DEFINES += USE_WEBSOCKET
 DEFINES += USE_SERVER_STATS
+
+#To build with DEBUG traces:
+#
+#DEFINES += DEBUG
+
+linux {
+INCLUDEPATH +=  \
+    ../src/third_party/ \
+    ../src/third_party/lua-5.2.4/src
+
+DEFINES += USE_LUA
+DEFINES += USE_LUA_SHARED
+LIBS += -llua5.2
+
+DEFINES += USE_ZLIB
+LIBS += -lz
+}
+
+#To build with duktape support:
+#
+#INCLUDEPATH +=  \
+#    ../src/third_party/duktape-1.8.0/src
+#
+#DEFINES += USE_DUKTAPE

+ 2 - 2
README.md

@@ -6,7 +6,7 @@
 [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)
 [![GitHub contributors](https://img.shields.io/github/contributors/civetweb/civetweb.svg)](https://github.com/civetweb/civetweb/blob/master/CREDITS.md)
 
-Continuous integration for Linux and OSX ([Travis CI](https://travis-ci.org/civetweb/civetweb)):
+Continuous integration for Linux and macOS ([Travis CI](https://travis-ci.org/civetweb/civetweb)):
 
 [![Travis Build Status](https://travis-ci.org/civetweb/civetweb.svg?branch=master)](https://travis-ci.org/civetweb/civetweb)
 
@@ -140,7 +140,7 @@ Contributions are welcome provided all contributions carry the MIT license.
 
 DO NOT APPLY fixes copied from Mongoose to this project to prevent GPL tainting.
 Since 2013, CivetWeb and Mongoose are developed independently.
-By now the code base differs, so patches cannot be safely transfered in either direction.
+By now the code base differs, so patches cannot be safely transferred in either direction.
 
 Some guidelines can be found in [docs/Contribution.md](https://github.com/civetweb/civetweb/blob/master/docs/Contribution.md).
 

+ 24 - 2
RELEASE_NOTES.md

@@ -1,3 +1,25 @@
+Release Notes v1.11 (work in progress)
+===
+### Objectives: *Support multiple domains and certificates, support websocket ping-pong*
+
+Changes
+-------
+
+- Add server support for websocket ping pong protocol
+- Fix misspellings in source code and documentation
+- Add error msg to http_error callback
+- Move unit test to a new directory
+- Remove remote\_ip request\_info member (it has been legacy since several versions)
+- Use gmtime_r instead of gmtime, if available
+- Add some functions to C++ wrapper
+- Support multiple domains with different certificate files (TLS server name identification, SNI)
+- Provide client peer certificate (X509) in mg\_client\_cert structure
+- Add new callback (get\_external\_ssl\_ctx) to provide pre-initialized TLS context
+- Improve unit tests
+- Fix ssl init for HTTPS clients
+- Update version number
+
+
 Release Notes v1.10
 ===
 ### Objectives: *OpenSSL 1.1 support, add server statistics and diagnostic data*
@@ -35,7 +57,7 @@ Changes
 - Support for multipart requests without quotes (for some C# clients)
 - Initialize SSL in mg\_init\_library, so https client functions can be used when no server is running
 - Allow "REPORT" HTTP method for REST calls to scripts
-- Allow to compile civetweb.c wih a C++ compiler
+- Allow to compile civetweb.c with a C++ compiler
 - Lua: Remove internal length limits of encode/decode functions
 - Allow sub-resources of index script files
 - Add config parameter allow\_index\_script\_resource the aforementioned feature
@@ -390,6 +412,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/civetweb/civetweb
+- Created a new code repository at https://github.com/civetweb/civetweb
 - Created a distribution site at https://sourceforge.net/projects/civetweb/
 - Basic build testing

+ 13 - 13
VisualStudio/unit_test/unit_test.vcxproj

@@ -12,22 +12,22 @@
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\include\civetweb.h" />
-    <ClInclude Include="..\..\test\civetweb_check.h" />
-    <ClInclude Include="..\..\test\private.h" />
-    <ClInclude Include="..\..\test\private_exe.h" />
-    <ClInclude Include="..\..\test\public_func.h" />
-    <ClInclude Include="..\..\test\public_server.h" />
-    <ClInclude Include="..\..\test\timertest.h" />
-    <ClInclude Include="..\..\test\shared.h" />
+    <ClInclude Include="..\..\unittest\civetweb_check.h" />
+    <ClInclude Include="..\..\unittest\private.h" />
+    <ClInclude Include="..\..\unittest\private_exe.h" />
+    <ClInclude Include="..\..\unittest\public_func.h" />
+    <ClInclude Include="..\..\unittest\public_server.h" />
+    <ClInclude Include="..\..\unittest\timertest.h" />
+    <ClInclude Include="..\..\unittest\shared.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\src\civetweb.c" />
-    <ClCompile Include="..\..\test\private.c" />
-    <ClCompile Include="..\..\test\private_exe.c" />
-    <ClCompile Include="..\..\test\public_func.c" />
-    <ClCompile Include="..\..\test\public_server.c" />
-    <ClInclude Include="..\..\test\timertest.c" />
-    <ClCompile Include="..\..\test\shared.c" />
+    <ClCompile Include="..\..\unittest\private.c" />
+    <ClCompile Include="..\..\unittest\private_exe.c" />
+    <ClCompile Include="..\..\unittest\public_func.c" />
+    <ClCompile Include="..\..\unittest\public_server.c" />
+    <ClInclude Include="..\..\unittest\timertest.c" />
+    <ClCompile Include="..\..\unittest\shared.c" />
   </ItemGroup>
   <PropertyGroup Label="Globals">
     <ProjectGuid>{1AC4A7A6-0100-4287-97F4-B95807BE5607}</ProjectGuid>

+ 13 - 13
VisualStudio/unit_test/unit_test.vcxproj.filters

@@ -18,45 +18,45 @@
     <ClInclude Include="..\..\include\civetweb.h">
       <Filter>Headerdateien</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\test\public_server.h">
+    <ClInclude Include="..\..\unittest\public_server.h">
       <Filter>Headerdateien</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\test\public_func.h">
+    <ClInclude Include="..\..\unittest\public_func.h">
       <Filter>Headerdateien</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\test\private_exe.h">
+    <ClInclude Include="..\..\unittest\private_exe.h">
       <Filter>Headerdateien</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\test\private.h">
+    <ClInclude Include="..\..\unittest\private.h">
       <Filter>Headerdateien</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\test\timertest.h">
+    <ClInclude Include="..\..\unittest\timertest.h">
       <Filter>Headerdateien</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\test\shared.h">
+    <ClInclude Include="..\..\unittest\shared.h">
       <Filter>Headerdateien</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\test\civetweb_check.h">
+    <ClInclude Include="..\..\unittest\civetweb_check.h">
       <Filter>Headerdateien</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\test\timertest.c">
+    <ClInclude Include="..\..\unittest\timertest.c">
       <Filter>Quelldateien</Filter>
     </ClInclude>
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="..\..\test\public_server.c">
+    <ClCompile Include="..\..\unittest\public_server.c">
       <Filter>Quelldateien</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\test\public_func.c">
+    <ClCompile Include="..\..\unittest\public_func.c">
       <Filter>Quelldateien</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\test\private.c">
+    <ClCompile Include="..\..\unittest\private.c">
       <Filter>Quelldateien</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\test\private_exe.c">
+    <ClCompile Include="..\..\unittest\private_exe.c">
       <Filter>Quelldateien</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\test\shared.c">
+    <ClCompile Include="..\..\unittest\shared.c">
       <Filter>Quelldateien</Filter>
     </ClCompile>
     <ClCompile Include="..\..\src\civetweb.c">

+ 33 - 3
appveyor.yml

@@ -32,6 +32,7 @@ environment:
       enable_websockets: NO
       no_cgi: NO
       no_caching: NO
+      enable_stats: NO
       configuration: Release
       platform: x86
     - id: Default-x64
@@ -43,6 +44,7 @@ environment:
       enable_websockets: NO
       no_cgi: NO
       no_caching: NO
+      enable_stats: NO
       configuration: Release
       platform: x64
     # Use default values
@@ -55,6 +57,7 @@ environment:
       enable_websockets: YES
       no_cgi: NO
       no_caching: NO
+      enable_stats: YES
       configuration: Release
       platform: x86
     - id: Full-x64
@@ -66,6 +69,7 @@ environment:
       enable_websockets: YES
       no_cgi: NO
       no_caching: NO
+      enable_stats: YES
       configuration: Release
       platform: x64
     # Debug builds
@@ -78,6 +82,7 @@ environment:
       enable_websockets: YES
       no_cgi: NO
       no_caching: NO
+      enable_stats: YES
       configuration: Debug
       platform: x86
     - id: Full-x64-Debug
@@ -89,6 +94,7 @@ environment:
       enable_websockets: YES
       no_cgi: NO
       no_caching: NO
+      enable_stats: YES
       configuration: Debug
       platform: x64
     # Minimum settings
@@ -100,7 +106,8 @@ environment:
       enable_ssl: NO
       enable_websockets: NO
       no_cgi: YES
-      no_caching: YeS
+      no_caching: YES
+      enable_stats: NO
       configuration: Release
       platform: x86
     - id: Minimal-x64
@@ -112,6 +119,7 @@ environment:
       enable_websockets: NO
       no_cgi: YES
       no_caching: YeS
+      enable_stats: NO
       configuration: Release
       platform: x64
     # Test shared and debug build
@@ -124,6 +132,7 @@ environment:
       enable_websockets: NO
       no_cgi: NO
       no_caching: NO
+      enable_stats: NO
       configuration: Release
       platform: x86
     - id: Shared-default-x64
@@ -135,6 +144,7 @@ environment:
       enable_websockets: NO
       no_cgi: NO
       no_caching: NO
+      enable_stats: NO
       configuration: Release
       platform: x64
     # MinGW
@@ -147,6 +157,7 @@ environment:
       enable_websockets: YES
       no_cgi: NO
       no_caching: NO
+      enable_stats: YES
       configuration: Release
       platform: x64
     # Visual Studio 2010
@@ -159,6 +170,7 @@ environment:
       enable_websockets: YES
       no_cgi: NO
       no_caching: NO
+      enable_stats: YES
       configuration: Release
       platform: x86
     # Visual Studio 2012
@@ -171,6 +183,7 @@ environment:
       enable_websockets: YES
       no_cgi: NO
       no_caching: NO
+      enable_stats: YES
       configuration: Release
       platform: x86
     # Visual Studio 2013
@@ -183,6 +196,7 @@ environment:
       enable_websockets: YES
       no_cgi: NO
       no_caching: NO
+      enable_stats: YES
       configuration: Release
       platform: x86
     - id: Full-VS2013-x64
@@ -194,6 +208,7 @@ environment:
       enable_websockets: YES
       no_cgi: NO
       no_caching: NO
+      enable_stats: YES
       configuration: Release
       platform: x64
     # Visual Studio 2015 is default
@@ -207,6 +222,7 @@ environment:
       enable_websockets: YES
       no_cgi: NO
       no_caching: NO
+      enable_stats: YES
       configuration: Release
       platform: x86
       APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
@@ -219,6 +235,7 @@ environment:
       enable_websockets: YES
       no_cgi: NO
       no_caching: NO
+      enable_stats: YES
       configuration: Release
       platform: x64
       APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
@@ -326,6 +343,7 @@ before_build:
     -DCIVETWEB_ENABLE_CXX=%enable_cxx%
     -DCIVETWEB_ENABLE_LUA=%enable_lua%
     -DCIVETWEB_ENABLE_LUA_SHARED=%enable_lua_shared%
+    -DCIVETWEB_ENABLE_SERVER_STATS=%enable_stats%
     -DCIVETWEB_DISABLE_CACHING=%no_caching%
     -DCIVETWEB_C_STANDARD=%c_standard%
     -DCIVETWEB_CXX_STANDARD=%cxx_standard%
@@ -344,13 +362,25 @@ test_script:
   - cd "%build_path%"
   - appveyor AddMessage -Category Information "Test command '%build%'"
   - set CTEST_OUTPUT_ON_FAILURE=1
-  - cmd /c "%test%"
+  - cmd /c "%test%" & set "test_ret=%ERRORLEVEL%"
+  - echo "Test returned %test_ret%"
+  - dir "%source_path%\output\build\unittest\"
+  - echo "Show all test logs:"
+  - for /r %%i in ("%source_path%\output\build\unittest\test-*.log") do (
+      echo %%i
+      type %%i
+    )
+  - for /r %%i in ("%source_path%\output\build\unittest\test-*.xml") do (
+      echo %%i
+      type %%i
+    )
   - cd "%source_path%"
-
   - set "output_path=%source_path%\output"
   - set "build_path=%output_path%\build"
   - set "install_path=%output_path%\install"
   - set "third_party_dir=C:\third-party"
+  - exit /B %ERRORLEVEL%
+  - echo "Test script DONE"
 
 after_test:
   - echo "Current directory:"

+ 1 - 1
ci/test/README.md

@@ -8,7 +8,7 @@ I have fixed and extended the travis configuration to build on the new sudo-less
 
 * On Check-in or Pull Requests clone the repo
 * Run make WITH_LUA=1 WITH_DEBUG=1 WITH_IPV6=1 WITH_WEBSOCKET=1
-* Build a standalone lua installation (seperate from civetweb or the OS)
+* Build a standalone lua installation (separate from civetweb or the OS)
 * Build LuaRocks in standalone installation
 * Install a few rocks into the standalone installation
 * Start the test script

+ 10 - 8
docs/APIReference.md

@@ -12,7 +12,7 @@ examples directory.
 
 | Macro | Description |
 | :--- | :--- |
-| **`CIVETWEB_VERSION`** | The current version of the software as a string with the major and minor version number seperated with a dot. For version 1.9, this string will have the value "1.9", for thw first patch of this version "1.9.1". |
+| **`CIVETWEB_VERSION`** | The current version of the software as a string with the major and minor version number separated with a dot. For version 1.9, this string will have the value "1.9", for thw first patch of this version "1.9.1". |
 | **`CIVETWEB_VERSION_MAJOR`** | The current major version as number, e.g., (1) for version 1.9. |
 | **`CIVETWEB_VERSION_MINOR`** | The current minor version as number, e.g., (9) for version 1.9. |
 | **`CIVETWEB_VERSION_PATCH`** | The current patch version as number, e.g., (0) for version 1.9 or (1) for version 1.9.1. |
@@ -74,6 +74,13 @@ The content of both structures is not defined in the interface - they are only u
 * [`mg_check_digest_access_authentication( conn, realm, filename );`](api/mg_check_digest_access_authentication.md)
 * [`mg_modify_passwords_file( passwords_file_name, realm, user, password );`](api/mg_modify_passwords_file.md)
 
+* [`mg_get_request_info( conn );`](api/mg_get_request_info.md)
+* [`mg_handle_form_request( conn, fdh );`](api/mg_handle_form_request.md)
+
+* [`mg_send_file( conn, path );`](api/mg_send_file.md)
+* [`mg_send_mime_file( conn, path, mime_type );`](api/mg_send_mime_file.md)
+* [`mg_send_mime_file2( conn, path, mime_type, additional_headers );`](api/mg_send_mime_file2.md)
+* [`mg_websocket_write( conn, opcode, data, data_len );`](api/mg_websocket_write.md)
 
 ## Client API Functions
 
@@ -83,6 +90,8 @@ The content of both structures is not defined in the interface - they are only u
 
 * [`mg_download( host, port, use_ssl, error_buffer, error_buffer_size, fmt, ... );`](api/mg_download.md)
 
+* [`mg_get_response( conn, ebuf, ebuf_len, timeout );`](api/mg_get_response.md)
+
 
 ## Common API Functions
 
@@ -91,22 +100,16 @@ The content of both structures is not defined in the interface - they are only u
 
 * [`mg_get_cookie( cookie, var_name, buf, buf_len );`](api/mg_get_cookie.md)
 * [`mg_get_header( conn, name );`](api/mg_get_header.md)
-* [`mg_get_request_info( conn );`](api/mg_get_request_info.md)
-* [`mg_get_response( conn, ebuf, ebuf_len, timeout );`](api/mg_get_response.md)
 * [`mg_get_response_code_text( conn, response_code );`](api/mg_get_response_code_text.md)
 * [`mg_get_user_connection_data( conn );`](api/mg_get_user_connection_data.md)
 * [`mg_get_valid_options();`](api/mg_get_valid_options.md)
 * [`mg_get_var( data, data_len, var_name, dst, dst_len );`](api/mg_get_var.md)
 * [`mg_get_var2( data, data_len, var_name, dst, dst_len, occurrence );`](api/mg_get_var2.md)
-* [`mg_handle_form_request( conn, fdh );`](api/mg_handle_form_request.md)
 * [`mg_lock_connection( conn );`](api/mg_lock_connection.md)
 * [`mg_md5( buf, ... );`](api/mg_md5.md)
 * [`mg_printf( conn, fmt, ... );`](api/mg_printf.md)
 * [`mg_read( conn, buf, len );`](api/mg_read.md)
 * [`mg_send_chunk( conn, buf, len );`](api/mg_send_chunk.md)
-* [`mg_send_file( conn, path );`](api/mg_send_file.md)
-* [`mg_send_mime_file( conn, path, mime_type );`](api/mg_send_mime_file.md)
-* [`mg_send_mime_file2( conn, path, mime_type, additional_headers );`](api/mg_send_mime_file2.md)
 * [`mg_set_user_connection_data( conn, data );`](api/mg_set_user_connection_data.md)
 * [`mg_start_thread( f, p );`](api/mg_start_thread.md)
 * [`mg_store_body( conn, path );`](api/mg_store_body.md)
@@ -115,7 +118,6 @@ The content of both structures is not defined in the interface - they are only u
 * [`mg_unlock_connection( conn );`](api/mg_unlock_connection.md)
 * [`mg_url_decode( src, src_len, dst, dst_len, is_form_url_encoded );`](api/mg_url_decode.md)
 * [`mg_url_encode( src, dst, dst_len );`](api/mg_url_encode.md)
-* [`mg_websocket_write( conn, opcode, data, data_len );`](api/mg_websocket_write.md)
 * [`mg_write( conn, buf, len );`](api/mg_write.md)
 
 

+ 36 - 14
docs/Building.md

@@ -6,10 +6,10 @@ See [Embedding.md](https://github.com/civetweb/civetweb/blob/master/docs/Embeddi
 
 #### Where to get the source code?
 
-The latest version can be found at
+The latest development version can be found at
 https://github.com/civetweb/civetweb
 
-Released versions can be found at
+Tested and released versions can be found at
 https://github.com/civetweb/civetweb/releases
 
 
@@ -74,6 +74,7 @@ make clean
 ```
 Clean up files generated during the build
 
+
 ## Setting build options
 
 Make options can be set on the command line with the make command like so.
@@ -86,10 +87,14 @@ make build WITH_LUA=1
 | ------------------------- | ----------------------------------------- |
 | WITH_LUA=1                | build with Lua support                    |
 | WITH_DUKTAPE=1            | build with server-side JavaScript support |
-| WITH_DEBUG=1              | build with GDB debug support              |
 | WITH_IPV6=1               | with IPV6 support                         |
 | WITH_WEBSOCKET=1          | build with web socket support             |
 | WITH_SERVER_STATS=1       | build with support for server statistics  |
+| WITH_EXPERIMENTAL=1       | include experimental features (depending  |
+|                           | on the version)                           |
+| WITH_ALL=1                | Include all of the above features         |
+|                           |                                           |
+| WITH_DEBUG=1              | build with GDB debug support              |
 | WITH_CPP=1                | build libraries with c++ classes          |
 | CONFIG_FILE=file          | use 'file' as the config file             |
 | CONFIG_FILE2=file         | use 'file' as the backup config file      |
@@ -105,6 +110,7 @@ make build WITH_LUA=1
 Note that the WITH_* options used for *make* are not identical to the
 preprocessor defines in the source code - usually USE_* is used there.
 
+
 ## Changing PREFIX
 
 To change the target destination pass the `PREFIX` option to the command `make install` (not `make build`). Example usage:
@@ -132,6 +138,7 @@ install -m 755 civetweb "/opt/civetweb/bin/"
 
 If the output looks good: Just remove the `-n` option to actually install the software on your system.
 
+
 ## Setting compile flags
 
 Compile flags can be set using the *COPT* make option like so.
@@ -139,17 +146,32 @@ Compile flags can be set using the *COPT* make option like so.
 make build COPT="-DNDEBUG -DNO_CGI"
 ```
 
-| Compile Flags             | Description                          |
-| ------------------------- | ------------------------------------ |
-| NDEBUG                    | strip off all debug code             |
-| DEBUG                     | build debug version (very noisy)     |
-| NO_CGI                    | disable CGI support                  |
-| NO_CACHING                | disable caching functionality        |
-| NO_SSL                    | disable SSL functionality            |
-| NO_SSL_DL                 | link against system libssl library   |
-| NO_FILES                  | do not serve files from a directory  |
-| SQLITE_DISABLE_LFS        | disables large files (Lua only)      |
-| SSL_ALREADY_INITIALIZED   | do not initialize libcrypto          |
+| Compile Flags              | Description                          |
+| -------------------------- | ------------------------------------ |
+| NDEBUG                     | strip off all debug code             |
+| DEBUG                      | build debug version (very noisy)     |
+|                            |                                      |
+| NO_FILES                   | do not serve files from a directory  |
+| NO_SSL                     | disable SSL functionality            |
+| NO_CGI                     | disable CGI support                  |
+| NO_CACHING                 | disable caching functionality        |
+|                            |                                      |
+| USE_IPV6                   | enable IPv6 support                  |
+| USE_WEBSOCKET              | enable websocket support             |
+| USE_LUA                    | enable Lua support                   |
+| USE_DUKTAPE                | enable server-side JavaScript        |
+|                            | support by including Duktape         |
+| USE_SERVER_STATS           | enable server statistics support     |
+| USE_ZLIB                   | enable on-the-fly compression of     |
+|                            | static content by including zlib     |
+| MG_EXPERIMENTAL_INTERFACES | include experimental interfaces      |
+|                            |                                      |
+| NO_SSL_DL                  | link against system libssl library   |
+| SQLITE_DISABLE_LFS         | disables large files (Lua only)      |
+| SSL_ALREADY_INITIALIZED    | do not initialize libcrypto          |
+
+Note: If `make` is used (with this [Makefile](https://github.com/civetweb/civetweb/blob/master/Makefile)), you should not pass the `USE_<feature>` flags using `COPT`, but use the `WITH_<feature>` syntax above, since additional features may also use additional source code files.
+
 
 ## Cross Compiling
 

+ 33 - 10
docs/Embedding.md

@@ -1,9 +1,11 @@
 Embedding CivetWeb
 =========
 
-CivetWeb is primarily designed so applications can easily add HTTP and HTTPS server as well as WebSocket functionality.  For example, an application server could use CivetWeb to enable a web service interface for automation or remote control.
+CivetWeb is primarily designed so applications can easily add HTTP and HTTPS server as well as WebSocket (WS and WSS) server functionality.
+For example, a C/C++ application could use CivetWeb to enable a web service and configuration interface, to add a HTML5 data visualization interface, for automation or remote control, as a protocol gateway or as a HTTP/WebSocket client for firewall traversal.
+
+It can also be used as a stand-alone executable. It can deliver static files and offers built-in server side Lua, JavaScript and CGI support. Some instructions how to build the stand-alone server can be found in [Building.md](https://github.com/civetweb/civetweb/blob/master/docs/Building.md).
 
-However, it can also be used as a stand-alone executable. It can deliver static files and offers built-in server side Lua, JavaScript and CGI support. Some instructions how to build the stand-alone server can be found in [Building.md](https://github.com/civetweb/civetweb/blob/master/docs/Building.md).
 
 Files
 ------
@@ -11,11 +13,12 @@ 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/CivetWeb/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 clarity as opposed to having .c extensions on files that should not be directly compiled.
 
-#### HTTP Server Source Files
 
+#### HTTP Server Source Files
 These files constitute the CivetWeb library.  They do not contain a `main` function,
 but all functions required to run a HTTP server.
 
@@ -35,19 +38,18 @@ but all functions required to run a HTTP server.
     - src/mod\_*.inl (modules to access third party components from civetweb)
 
 
-Note: The C++ wrapper uses the official C interface (civetweb.h) and does not add new features to the server. Several features available in the C interface are missing in the C++ interface. While all features should be accessible using the C interface, this is not a design goal of the C++ interface.
+Note: The C++ wrapper uses the official C interface (civetweb.h) without adding any features to the server itself. Several features available in the C interface are missing in the C++ interface. While all features should be accessible using the C interface, this is not a design goal of the C++ interface.
 
 
 #### Additional Source Files for Executables
-
 These files can be used to build a server executable. They contain a `main` function
 starting the HTTP server.
 
-  - Stand-alone C Server
+  - Stand-alone C server
       - src/main.c
-  - Reference embedded C Server
+  - Reference embedded C server
       - examples/embedded\_c/embedded\_c.c
-  - Reference embedded C++ Server
+  - Reference embedded C++ server
       - examples/embedded\_cpp/embedded\_cpp.cpp
 
 Note: The "embedded" example is actively maintained, updated, extended and tested. Other examples in the examples/ folder might be outdated and remain there for reference.
@@ -71,13 +73,34 @@ By default, the server will automatically serve up files like a normal HTTP serv
     Not all CivetWeb features available in C are also available in C++.
   - Create CivetHandlers for each URI.
   - Register the handlers with `CivetServer::addHandler()`
-  - `CivetServer` starts on contruction and stops on destruction.
-  - Use contructor *options* to select the port and document root among other things.
+  - `CivetServer` starts on construction and stops on destruction.
+  - Use constructor *options* to select the port and document root among other things.
   - Use constructor *callbacks* to add your own hooks.
 
 Alternative quick start: Have a look at the examples embedded\_c and embedded\_cpp
 
 
+Feature selection
+------
+
+CivetWeb is highly customizable at build time, in addition to configuration at start time.
+
+##### start time options
+Start time options are passed to `mg_start`. They are documented in the [UserManual.md](https://github.com/civetweb/civetweb/blob/master/docs/UserManual.md).
+
+##### callbacks
+Pointers to callback functions are passed to `mg_start` as well. They are documented in [civetweb.h](https://github.com/civetweb/civetweb/blob/master/include/civetweb.h) and the callbacks [API documentation](https://github.com/civetweb/civetweb/blob/master/docs/api/mg_callbacks.md).
+
+##### compiler defines
+Several features can be turned "on" or "off" by setting compile defines. CivetWeb builds with a reasonable default feature set. Optional features not including in the default can be added by adding a `USE\_<feature>` define. Default features can be removed by adding a `NO_<feature>` define. E.g., to build with Lua support, set `#define USE_LUA` (-DUSE_LUA), to build without CGI support set `#define NO_CGI` (-DNO_CGI). A list of feature defines is available in [Building.md](https://github.com/civetweb/civetweb/blob/master/docs/Building.md) - some versions may have additional, undocumented feature defines. Undocumented defines may become unavailable in future versions without notice.
+
+##### externally provided functions
+In some special cases, it might be meaningful to completely replace an internal function in [civetweb.c](https://github.com/civetweb/civetweb/blob/master/src/civetweb.c) with your own implementation.
+Since CivetWeb is free and open source software covered by the MIT license, you can feel free to just edit civetweb.c according to your needs.
+However, this might be annoying when updating the server, pulling new features or bug fixes from the main repository. For some selected functions, it is possible to provide your own implementation using a `MG_EXTERNAL_FUNCTION_<internal_function_name>` define. For details on this mechanism, please look directly into the source code [civetweb.c](https://github.com/civetweb/civetweb/blob/master/src/civetweb.c). Interfaces and even names of internal functions may change without notice - when you use these defines, you have to check this every time you update CivetWeb. It might still be less effort than to apply your patches every time.
+This customization option is currently in an evaluation phase. In case you need additional function defines, please create an issue on GitHub explaining your use case, to discuss if this would be an appropriate solution - in general, other customization options are preferred.
+
+
 Lua Support
 ------
 

+ 82 - 24
docs/Interface_Changes_1.10.md

@@ -1,21 +1,28 @@
 # Interface changes
 
-## Proposed interface changes for 1.10
+## Proposed interface changes for future versions
+
+Interface changes from 1.10 to 1.11 and/or later versions -
+see also [this GitHub issue](https://github.com/civetweb/civetweb/issues/544).
 
-Status: To be discussed
 
 ### Server interface
 
-#### mg\_start / mg\_init\_library
+#### S1: mg\_start / mg\_init\_library
 
 Calling mg\_init\_library is recommended before calling mg\_start.
 
-Compatibility:
+**Compatibility considerations:**
 Initially, mg\_init\_library will be called implicitly if it has 
 not been called before mg\_start.
 If mg\_init\_library was not called, mg\_stop may leave memory leaks.
 
-#### mg\_websocket\_write functions
+**Required Actions:**
+Call mg\_init\_library manually to avoid a small memory leak when
+closing the server.
+
+
+#### S2: mg\_websocket\_write functions
 
 Calling mg\_lock\_connection is no longer called implicitly
 in mg\_websocket\_write functions. 
@@ -25,49 +32,100 @@ other connection.
 
 This is an API harmonization issue.
 
-Compatibility:
+**Compatibility considerations:**
 If a websocket connection was used in only one thread, there is
 no incompatibility. If a websocket connection was used in multiple
 threads, the user has to add the mg\_lock\_connection before and
 the mg\_unlock\_connection after the websocket write call.
 
-#### open\_file member of mg\_callbacks
+**Required Actions:**
+Call mg\_lock\_connection and mg\_unlock\_connection manually
+when using mg\_websocket\_write.
 
-This member is going to be removed.
-It is superseeded by mg\_add\_request\_handler.
 
-Compatibility:
-Current code using open\_file needs to be changed.
-Instructions how to do this will be provided.
+#### S3: open\_file member of mg\_callbacks
 
+Memory mapped files are a relic from before `mg_set_request_handler`
+was introduced in CivetWeb 1.4 (September 2013).
+Is "file in memory" still a useful feature or dead code? See this
+[discussion](https://groups.google.com/forum/#!topic/civetweb/h9HT4CmeYqI).
+Since it is not widely used, and a burden in maintenance, the
+"file in memory" should be completely removed, including removing
+the open\_file member of mg\_callbacks.
 
-### Client interface
 
+**Compatibility considerations:**
+Removing "file in memory" will require code using open\_file to be changed.
+A possible replacement by mg\_set\_request\_handler is sketched in
+[this comment](https://github.com/civetweb/civetweb/issues/440#issuecomment-290531238).
+
+**Required Actions:**
+Modify code using open\_file by using request handlers.
+
+
+#### S4: Support multiple hostnames and SNI
+
+TLS [Server Name Identification (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication)
+allows to host different domains with different X.509 certificates
+on the same physical server (same IP+port). In order to support this,
+some configurations (like authentication\_domain, ssl\_certificate, 
+document\_root and may others) need to be specified multiple times - 
+once for each domain hosted 
+(see [535](https://github.com/civetweb/civetweb/issues/535)).
+
+The current configuration model does not account for SNI, so it needs
+to be extended to support configuration of multiple instances.
+
+**Compatibility considerations:**
+To be defined as soon as possible solutions are evaluated.
 
-#### mg\_init\_library
+
+#### S5: IPv6 support for access\_control\_list and throttle
+
+The current configuration for access\_control\_list and throttle only
+works for IPv4 addresses. If server and client support 
+[IPv6](https://en.wikipedia.org/wiki/IPv6_address) as well,
+there is no way to add a client to the throttle or access list.
+The current configuration syntax isn't really comfortable for IPv4
+either.
+Combined with hosting multiple domains (and SNI), different domains
+may have different block/throttle configurations as well - this has
+to be considered in a new configuration as well.
+
+**Compatibility considerations:**
+To be defined as soon as possible solutions are evaluated.
+
+
+### Client interface
+
+#### C1: mg\_init\_library
 
 Calling mg\_init\_library is required before calling any client
 function. In particular, the TLS initialization must be done
 before using mg\_connect\_client\_secure.
 
-Compatibility:
+**Compatibility considerations:**
 Some parts of the client interface did not work, if mg\_start
-was not called before. Now server and client become independent.
+was not called before. Now it works after calling
+mg\_init\_library - this is not an incompatibility.
 
-#### mg\_connect\_client (family)
 
-mg_connect_client needs several new parameters (options).
+#### C2: mg\_connect\_client (family)
+
+mg\_connect\_client needs several new parameters (options).
 
 Details are to be defined.
 
-mg_connect_client and mg_download should return a different kind of
+mg\_connect\_client and mg\_download should return a different kind of
 mg_connection than used in server callbacks. At least, there should
-be a function mg_get_response_info, instead of using 
-mg_get_request_info, and getting the HTTP response code from the
-server by looking into the uri member of struct mg_request_info.
+be a function mg\_get\_response\_info, instead of using 
+mg\_get\_request\_info, and getting the HTTP response code from the
+server by looking into the uri member of struct mg\_request\_info.
+
 
+### General interfaces
 
-### `size_t` in all interface
+#### G1: `size_t` in all interface
 
 Having `size_t` in interfaces while building for 32 and 64 bit
 complicates maintenance in an unnecessary way 
@@ -76,7 +134,7 @@ complicates maintenance in an unnecessary way
 Replace all data sizes by 64 bit integers.
 
 
-### Pattern definition
+#### G2: Pattern definition
 
 The current definition of pattern matching is problematic
 (see [499](https://github.com/civetweb/civetweb/issues/499)).

+ 1 - 1
docs/OpenSSL.md

@@ -3,7 +3,7 @@ Adding OpenSSL Support
 
 Civetweb supports *HTTPS* connections using the OpenSSL transport layer
 security (TLS) library. OpenSSL is a free, open source library (see
-http://www.openssl.org/).
+http://www.openssl.org/). While there are other TLS libraries beside OpenSSL (like gnuTLS and wolfSSL), new TLS features in CivetWeb are tested only using OpenSSL.
 
 
 Getting Started

+ 5 - 1
docs/README.md

@@ -8,7 +8,7 @@ CivetWeb uses an [MIT license](https://github.com/civetweb/civetweb/blob/master/
 
 It can also be used by end users as a stand-alone web server. It is available as single executable, no installation is required.
 
-The current stable version is 1.9.1 - [release notes](https://github.com/civetweb/civetweb/blob/master/RELEASE_NOTES.md)
+The current stable version is 1.10 - [release notes](https://github.com/civetweb/civetweb/blob/master/RELEASE_NOTES.md)
 
 
 End users can download CivetWeb at SourceForge
@@ -28,6 +28,9 @@ While older support question and discussion threads have been at [Google groups]
 Source releases can be found on GitHub
 [https://github.com/civetweb/civetweb/releases](https://github.com/civetweb/civetweb/releases)
 
+CivetWeb is free of charge, however, donations for maintenance are welcome:
+[![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=88ZLXZ6U77GJU)
+
 
 Documentation
 ---------------
@@ -40,3 +43,4 @@ Documentation
 - [API documentation](api) - Additional documentation on the civetweb application programming interface ([civetweb.h](https://github.com/civetweb/civetweb/blob/master/include/civetweb.h)).
 
 [Authors](https://github.com/civetweb/civetweb/blob/master/CREDITS.md)
+

+ 159 - 66
docs/UserManual.md

@@ -2,9 +2,9 @@
 Overview
 =====
 
-Civetweb is small and easy to use web server.
+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
+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
@@ -14,72 +14,74 @@ software to run. Some Windows users may need to install the
 Installation
 ----
 
-On Windows, UNIX and Mac, the civetweb stand-alone executable may be started
+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]`),
+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.
+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.
+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.
+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`
+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.
 
-When started, civetweb first searches for the configuration file.
+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
+`CivetWeb path_to_config_file`, then specified configuration file is used.
+Otherwise, CivetWeb would search for file `CivetWeb.conf` in the same directory
 the executable is located, and use it. This configuration file is optional.
 
 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:
+Here is the example of `CivetWeb.conf` file:
 
     document_root c:\www
     listening_ports 80,443s
-    ssl_certificate c:\civetweb\ssl_cert.pem
+    ssl_certificate c:\CivetWeb\ssl_cert.pem
 
 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
+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.
+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
 listed in the next section. Thus, the following two setups are equivalent:
 
     # Using command line arguments
-    $ civetweb -listening_ports 1234 -document_root /var/www
+    $ CivetWeb -listening_ports 1234 -document_root /var/www
 
     # Using config file
-    $ cat civetweb.conf
+    $ cat CivetWeb.conf
     listening_ports 1234
     document_root /var/www
-    $ civetweb
+    $ CivetWeb
 
-Civetweb can also be used to modify `.htpasswd` passwords files:
+CivetWeb can also be used to modify `.htpasswd` passwords files:
 
-    civetweb -A <htpasswd_file> <realm> <user> <passwd>
+    CivetWeb -A <htpasswd_file> <realm> <user> <passwd>
 
-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
+
+# Pattern matching
+
+CivetWeb uses shell-like glob patterns for several configuration options,
+e.g., CGI, SSI and Lua script files are recognized by the file name pattern. 
+Pattern match starts at the beginning of the string, so essentially
 patterns are prefix patterns. Syntax is as follows:
 
      **      Matches everything
@@ -94,12 +96,18 @@ All other characters in the pattern match themselves. Examples:
     /foo         Any string that begins with /foo
     **a$|**b$    Any string that ends with a or b
 
+
 # Configuration Options
 
-Below is a list of configuration options understood by Civetweb.
+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.
 
+## Options from `civetweb.c`
+
+The following options are supported in `civetweb.c`. They can be used for
+the stand-alone executable as well as for applications embedding CivetWeb.
+
 ### 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,
@@ -119,16 +127,16 @@ DELETE requests might still be handled by Lua scripts and CGI paged.
 ### cgi\_interpreter
 Path to an executable to use as CGI interpreter for __all__ CGI scripts
 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,
+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
 `#!/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 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.
+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, it is
 more efficient to set `cgi_interpreter` to the path to `php-cgi.exe`.
@@ -160,10 +168,10 @@ 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`. These extentions may be changed using the
+either `.shtml` or `.shtm`. These extensions may be changed using the
 `ssi_pattern` option.
 
-Unknown SSI directives are silently ignored by civetweb. Currently, two SSI
+Unknown SSI directives are silently ignored by CivetWeb. Currently, two SSI
 directives are supported, `<!--#include ...>` and
 `<!--#exec "command">`. Note that the `<!--#include ...>` directive supports
 three path specifications:
@@ -226,7 +234,7 @@ password in digest format:
     user:realm:digest
     test:test.com:ce0220efc2dd2fad6185e1f1af5a4327
 
-Password files may be generated using `civetweb -A` as explained above, or
+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.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php`
@@ -255,7 +263,7 @@ a timeout > 0 is set.
 
 ### access\_control\_list
 An Access Control List (ACL) allows restrictions to be put on the list of IP
-addresses which have access to the web server. In the case of the Civetweb
+addresses which have access to the web server. In the case of the CivetWeb
 web server, the ACL is a comma separated list of IP subnets, where each
 subnet is pre-pended by either a `-` or a `+` sign. A plus sign means allow,
 where a minus sign means deny. If a subnet mask is omitted, such as `-1.2.3.4`,
@@ -336,45 +344,45 @@ and it must have both, private key and certificate, see for example
 A description how to create a certificate can be found in doc/OpenSSL.md
 
 ### num\_threads `50`
-Number of worker threads. Civetweb handles each incoming connection in a
+Number of worker threads. CivetWeb handles each incoming connection in a
 separate thread. Therefore, the value of this option is effectively the number
-of concurrent HTTP connections Civetweb can handle.
+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 ports on UNIX. To do
-that, civetweb needs to be started as root. From a security point of view,
+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 webserver
+    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 any 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,
 `file_or_directory_path` is used, which should be a full path name or
 a path relative to the web server's current working directory. Note that
-`uri_pattern`, as all civetweb patterns, is a prefix pattern.
+`uri_pattern`, as all CivetWeb patterns, is a prefix pattern.
 
 This makes it possible to serve many directories outside from `document_root`,
 redirect all requests to scripts, and do other tricky things. For example,
 to redirect all accesses to `.doc` files to a special script, do:
 
-    civetweb -url_rewrite_patterns **.doc$=/path/to/cgi-bin/handle_doc.cgi
+    CivetWeb -url_rewrite_patterns **.doc$=/path/to/cgi-bin/handle_doc.cgi
 
 Or, to imitate support for user home directories, do:
 
-    civetweb -url_rewrite_patterns /~joe/=/home/joe/,/~bill=/home/bill/
+    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 names. Example:
 
-    civetweb -hide_files_patterns secret.txt|**.hide
+    CivetWeb -hide_files_patterns secret.txt|**.hide
 
 Note: hide\_file\_patterns uses the pattern described above. If you want to
 hide all files with a certain extension, make sure to use **.extension
@@ -411,9 +419,31 @@ Setting the value to -1 will turn off linger.
 If the value is not set (or set to -2), CivetWeb will not set the linger
 option at all.
 
-Note: For consistency with other timeouts, the value is configured in
-milliseconds. However, the TCP socket layer usually only offers a timeout in 
-seconds, so the value should be an integer multiple of 1000.
+Note: For consistency with other timeout configurations, the value is 
+configured in milliseconds. However, the TCP socket layer usually only
+offers a timeout in seconds, so the value should be an integer multiple
+of 1000.
+
+### websocket\_timeout\_ms
+Timeout for network read and network write operations for websockets, WS(S),
+in milliseconds. If this value is not set, the value of request\_timeout\_ms
+is used for HTTP(S) as well as for WS(S). In case websocket\_timeout\_ms is
+set, HTTP(S) and WS(S) can use different timeouts.
+
+Note: This configuration value only exists, if the server has been built 
+with websocket support enabled.
+
+### enable_websocket_ping_pong `no`
+If this configuration value is set to `yes`, the server will send a
+websocket PING message to a websocket client, once the timeout set by
+websocket\_timeout\_ms expires. Clients (Web browsers) supporting this
+feature will reply with a PONG message.
+
+If this configuration value is set to `no`, the websocket server will
+close the connection, once the timeout expires.
+
+Note: This configuration value only exists, if the server has been built 
+with websocket support enabled.
 
 ### lua\_preload\_file
 This configuration option can be used to specify a Lua script file, which
@@ -456,11 +486,11 @@ Can add dynamic parameters to background script.
 Parameters mapped to global 'mg' table 'params' field.
 
 ### websocket\_root
-In case civetweb is built with Lua and websocket support, Lua scripts may
+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.
+the document\_root is used as websocket\_root as well.
 
 
 ### access\_control\_allow\_origin `*`
@@ -500,7 +530,7 @@ 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.
+extension may be one of the extensions specified for the index_files option.
 See the [Wikipedia page on HTTP status codes](http://en.wikipedia.org/wiki/HTTP_status_code).
 
 ### tcp\_nodelay `0`
@@ -634,8 +664,36 @@ Example (used as command line option):
 
 This option can be specified multiple times. All specified header lines will be sent.
 
+## Options from `main.c`
+
+The following options are supported in `main.c`, the additional source file for
+the stand-alone executable. These options are not supported by other applications
+embedding `civetweb.c`, unless they are added explicitly.
+
+The options "title", "icon" and "website" are 
+
+### title
+Use the configured string as a server name.  For Windows, this will be shown as
+the window title.
+
+### icon
+For Windows, show this icon file in the systray, replacing the CivetWeb standard
+icon.  This option has no effect for Linux.
+
+### website
+For Windows, use this website as a link in the systray, replacing the default
+link for CivetWeb.
+
+### add\_domain
+Option to load an additional configuration file, specifying an additional domain
+to host.  To add multiple additional domains, use the add\_domain option 
+multiple times with one configuration file for each domain.  
+A domain configuration file may have the same options as the main server, with
+some exceptions.  The options are passed to the `mg_start_domain` API function.
+
+
 # Lua Scripts and Lua Server Pages
-Pre-built Windows and Mac civetweb binaries have built-in Lua scripting
+Pre-built Windows and Mac CivetWeb binaries have built-in Lua scripting
 support as well as support for Lua Server Pages.
 
 Lua scripts (default extension: *.lua) use plain Lua syntax.
@@ -660,7 +718,7 @@ page, one can write:
       URI is <?=mg.request_info.uri?>
     </p>
 
-Lua is known for it's speed and small size. Civetweb currently uses Lua
+Lua is known for it's speed and small size. CivetWeb currently uses Lua
 version 5.2.4. The documentation for it can be found in the
 [Lua 5.2 reference manual](http://www.lua.org/manual/5.2/).
 
@@ -670,7 +728,7 @@ 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). Lua functions working on files (e.g., `io.open`) use a path
-relative to the working path of the civetweb process. The web server content
+relative to the working path of the CivetWeb process. The web server content
 is located in the path `mg.document_root`.
 Information on the request is available in the `mg.request_info`
 object, like the request method, all HTTP headers, etcetera.
@@ -683,17 +741,17 @@ 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/civetweb/civetweb/blob/master/include/civetweb.h)
+[CivetWeb.h](https://github.com/civetweb/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/)
+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. Examples are given in
 [page.lua](https://github.com/civetweb/civetweb/blob/master/test/page.lua) and
 [page.lp](https://github.com/civetweb/civetweb/blob/master/test/page.lp).
 
 
-Civetweb exports the following functions to Lua:
+CivetWeb exports the following functions to Lua:
 
 mg (table):
 
@@ -704,7 +762,7 @@ mg (table):
                                -- like defined for SSI #include
     mg.redirect(uri)           -- internal redirect to a given URI
     mg.onerror(msg)            -- error handler, can be overridden
-    mg.version                 -- a string that holds Civetweb version
+    mg.version                 -- a string that holds CivetWeb version
     mg.document_root           -- a string that holds the document root directory
     mg.auth_domain             -- a string that holds the HTTP authentication domain
     mg.get_var(str, varname)   -- extract variable from (query) string
@@ -750,23 +808,23 @@ connect (function):
     end
 
 
-All filename arguments are either absolute or relative to the civetweb working
+All filename arguments are either absolute or relative to the CivetWeb working
 directory (not the document root or the Lua script/page file).
     
-**IMPORTANT: Civetweb does not send HTTP headers for Lua pages. Therefore,
+**IMPORTANT: CivetWeb does not send HTTP headers for Lua pages. Therefore,
 every Lua Page must begin with a HTTP reply line and headers**, like this:
 
     <? mg.write('HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n') ?>
     <html><body>
       ... the rest of the web page ...
 
-To serve a Lua Page, civetweb creates a 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 all block that follow.
 
 ## Websockets for Lua
-Civetweb offers support for websockets in Lua as well. In contrast to plain
+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:
@@ -786,12 +844,47 @@ An example is shown in
 [websocket.lua](https://github.com/civetweb/civetweb/blob/master/test/websocket.lua).
 
 
+# Using CGI
+
+Unlike some other web servers, CivetWeb does not require CGI scripts to be located
+in a special directory. CGI scripts files are recognized by the file name pattern
+and can be anywhere.
+
+When using CGI, make sure your CGI file names match the `cgi\_pattern` parameter
+configured for the server.
+Furthermore, you must either configure a `cgi\_interpreter` to be used for all
+CGI scripts, or all scripts must start with `#!` followed by the CGI
+interpreter executable, e.g.: `#!/path/to/perl.exe` or `#!/bin/sh`.
+
+See `cgi\_pattern` and `cgi\_interpreter` for more details.
+
+It is possible to disable CGI completely by building the server with
+the `NO\_CGI` define. Setting this define is required for operating 
+systems not supporting `fork/exec` or `CreateProcess` (since CGI is
+based on creating child processes, it will not be available on such
+operating systems for principle reasons).
+
+Every CGI request will spawn a new child process. Data sent from the
+HTTP client to the server is passed to stdin of the child process,
+while data written to stdout by the child process is sent back to the
+HTTP client.
+
+In case a CGI script cannot handle a particular request, it might
+write a short error message to stderr instead of writing to stdout.
+This error message is added to the server error log.
+
+A script should not write to stderr after writing a reply header
+to stdout. In case CGI libraries are writing to stderr (e.g., for
+logging/debugging), the CGI script should redirect stderr to a 
+user defined log file at the beginning of the script.
+
+
 # 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,
   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 -cgi_interpreter /full/path/to/php-cgi`
 
 - `php-cgi` is unavailable, for example on Mac OS X. As long as the `php` binary is installed, you can run CGI programs in command line mode (see the example below). Note that in this mode, `$_GET` and friends will be unavailable, and you'll have to parse the query string manually using [parse_str](http://php.net/manual/en/function.parse-str.php) and the `QUERY_STRING` environmental variable.
 
@@ -801,14 +894,14 @@ An example is shown in
         echo "Hello World!\n";
         ?>
 
-- Civetweb fails to start. If Civetweb exits immediately when started, 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,
+  Syntax checking is omitted from CivetWeb to keep its size low. However,
   the Manual should be of help. Note: the syntax changes from time to time,
   so updating the config file might be necessary after executable update.
 
 - Embedding with OpenSSL on Windows might fail because of calling convention.
-  To force Civetweb to use `__stdcall` convention, add `/Gz` compilation
+  To force CivetWeb to use `__stdcall` convention, add `/Gz` compilation
   flag in Visual Studio compiler.
 

+ 3 - 3
docs/api/mg_callbacks.md

@@ -9,12 +9,12 @@
 |**`begin_request`**|**`int (*begin_request)( struct mg_connection *conn );`**|
 | |The `begin_request()` callback function is called when CivetWeb has received a new HTTP request. If the callback function does not process the request, it should return 0. In that case CivetWeb will handle the request with the default callback routine. If the callback function returns a value between 1 and 999, CivetWeb does nothing and the callback function should do all the processing, including sending the proper HTTP headers etc. Starting at CivetWeb version 1.7, the function `begin_request()` is called before any authorization is done. If an authorization check is required, `request_handler()` should be used instead. The return value of the callback function is not only used to signal CivetWeb to not further process the request. The returned value is also stored as HTTP status code in the access log. |
 |**`connection_close`**|**`void (*connection_close)( const struct mg_connection *conn );`**|
-| |The callback function `connection_close()` is called when CivetWeb is closing a connection. The per-context mutex is locked when the callback function is invoked. The function is primarly useful for noting when a websocket is closing and removing it from any application-maintained list of clients. *Using this callback for websocket connections is deprecated. Use* `mg_set_websocket_handler()` *instead.*|
+| |The callback function `connection_close()` is called when CivetWeb is closing a connection. The per-context mutex is locked when the callback function is invoked. The function is primarily useful for noting when a websocket is closing and removing it from any application-maintained list of clients. *Using this callback for websocket connections is deprecated. Use* `mg_set_websocket_handler()` *instead.*|
 |**`end_request`**|**`void (*end_request)(const struct mg_connection *conn, int reply_status_code);`**|
 | |The callback function `end_request()` is called by CivetWeb when a request has been completely processed. It sends the reply status code which was sent to the client to the application.|
 |**`exit_context`**|**`void (*exit_context)( const struct mg_context *ctx );`**|
 | |The callback function `exit_context()` is called by CivetWeb when the server is stopped. It allows the application to do some cleanup on the application side.|
-|**`http_error`**|**`int (*http_error)( struct mg_connection *conn, int status );`**|
+|**`http_error`**|**`int (*http_error)( struct mg_connection *conn, int status, const char *msg );`**|
 | |The callback function `http_error()` is called by CivetWeb just before an HTTP error is to be sent to the client. The function allows the application to send a custom error page. The status code of the error is provided as a parameter. If the application sends their own error page, it must return 1 to signal CivetWeb that no further processing is needed. If the returned value is 0, CivetWeb will send a built-in error page to the client.|
 |**`init_context`**|**`void (*init_context)( const struct mg_context *ctx );`**|
 | |The callback function `init_context()` is called after the CivetWeb server has been started and initialized, but before any requests are served. This allowes the application to perform some initialization activities before the first requests are handled.|
@@ -46,7 +46,7 @@
 | | **`data_len`** - The length of the received data block |
 | | If the application wants to keep the websocket open to receive more data, the callback function should return the value **1**. If the value **0** is returned by the callback function, CivetWeb will close the websocket connection and no more frames will be received.|
 |~~`websocket_ready`~~|**`int (*websocket_ready)( struct mg_connection *conn );`**|
-| |*Deprecated. Use* `mg_set_websocket_handler()` *instead.* The callback function `websocket_ready()` is called after the handshake of a websocket connection has succeeded succesfully to signal the application that the connection is ready for use. |
+| |*Deprecated. Use* `mg_set_websocket_handler()` *instead.* The callback function `websocket_ready()` is called after the handshake of a websocket connection has succeeded successfully to signal the application that the connection is ready for use. |
 
 ### Description
 

+ 1 - 1
docs/api/mg_cry.md

@@ -6,7 +6,7 @@
 
 | Parameter | Type | Description |
 | :--- | :--- | :--- |
-|**`conn`**|`const struct mg_connection *`|The connection on which a problem occured|
+|**`conn`**|`const struct mg_connection *`|The connection on which a problem occurred|
 |**`fmt`**|`const char *`|Format string without a line return|
 |**`...`**|*various*|Parameters depending on the format string|
 

+ 1 - 1
docs/api/mg_get_header.md

@@ -17,6 +17,6 @@
 
 ### Description
 
-HTTP and HTTPS clients can send request headers to the server to provide details about the communication. These request headers can for example specify the preferred language in which the server should respond and the supported compression algorithms. The function `mg_get_header()` can be called to return the contents of a specific request header. The function will return a pointer to the value text of the header when succesful, and NULL of no matching request header from the client could be found.
+HTTP and HTTPS clients can send request headers to the server to provide details about the communication. These request headers can for example specify the preferred language in which the server should respond and the supported compression algorithms. The function `mg_get_header()` can be called to return the contents of a specific request header. The function will return a pointer to the value text of the header when successful, and NULL of no matching request header from the client could be found.
 
 ### See Also

+ 2 - 2
docs/api/mg_get_option.md

@@ -13,11 +13,11 @@
 
 | Type | Description |
 | :--- | :--- |
-|`const char *`| A pointer to the option value in text, or NULL if an error occured |
+|`const char *`| A pointer to the option value in text, or NULL if an error occurred |
 
 ### Description
 
-When starting the CivetWeb webserver, options are provided to set the wanted behaviour of the server. The options which were used during startup can be queried through the `mg_get_option()` function. Options are read-only and cannot be changed while the webserver is running. The function returns a pointer to a text string containing the value of the queried option, or NULL if an error occured. It is guaranteed however that if a valid option name is provided as a parameter to this function, that a pointer to a string is returned and not NULL. In case an option was empty or NULL during initialisation, `mg_get_option()` will return a pointer to an empty string.
+When starting the CivetWeb webserver, options are provided to set the wanted behaviour of the server. The options which were used during startup can be queried through the `mg_get_option()` function. Options are read-only and cannot be changed while the webserver is running. The function returns a pointer to a text string containing the value of the queried option, or NULL if an error occurred. It is guaranteed however that if a valid option name is provided as a parameter to this function, that a pointer to a string is returned and not NULL. In case an option was empty or NULL during initialisation, `mg_get_option()` will return a pointer to an empty string.
 
 ### See Also
 

+ 1 - 1
docs/api/mg_get_request_info.md

@@ -12,7 +12,7 @@
 
 | Type | Description |
 | :--- | :--- |
-|`const struct mg_request_info *`|Pointer to the requested info, or NULL if an error occured|
+|`const struct mg_request_info *`|Pointer to the requested info, or NULL if an error occurred|
 
 ### Description
 

+ 1 - 1
docs/api/mg_get_response_info.md

@@ -12,7 +12,7 @@
 
 | Type | Description |
 | :--- | :--- |
-|`const struct mg_request_info *`|Pointer to the requested info, or NULL if an error occured|
+|`const struct mg_request_info *`|Pointer to the requested info, or NULL if an error occurred|
 
 ### Description
 

+ 1 - 1
docs/api/mg_get_server_ports.md

@@ -20,7 +20,7 @@
 
 The `mg_get_server_ports()` returns a list with server ports on which the Civetweb server is listening. The ports are returned for a given context and stored with additional information like the SSL and redirection state in a list of structures. The list of structures must be allocated by the calling routine. The size of the structure is also passed to `mg_get_server_ports()`.
 
-The function returns the number of items in the list, or a negative value if an error occured.
+The function returns the number of items in the list, or a negative value if an error occurred.
 
 ### See Also
 

+ 1 - 1
docs/api/mg_get_user_connection_data.md

@@ -16,7 +16,7 @@
 
 ### Description
 
-The function `mg_get_user_connection_data()` returns the user data associated with a connection. This user data is represented with a pointer which has been prevously registered with a call to [`mg_set_user_connection_data();`](mg_set_user_connection_data.md). With this function it is possible to pass state information between callback functions refering to a specific connection.
+The function `mg_get_user_connection_data()` returns the user data associated with a connection. This user data is represented with a pointer which has been prevously registered with a call to [`mg_set_user_connection_data();`](mg_set_user_connection_data.md). With this function it is possible to pass state information between callback functions referring to a specific connection.
 
 ### See Also
 

+ 1 - 1
docs/api/mg_get_valid_option_names.md

@@ -14,7 +14,7 @@
 
 ### Description
 
-The function `mg_get_valid_option_names()` is depricated. Use [`mg_get_valid_options()`](mg_get_valid_options.md) instead.
+The function `mg_get_valid_option_names()` is deprecated. Use [`mg_get_valid_options()`](mg_get_valid_options.md) instead.
 
 This function returns an array with option/value pairs describing the valid configuration options for Civetweb. En element value of NULL signals the end of the list.
 

+ 1 - 1
docs/api/mg_get_var2.md

@@ -21,7 +21,7 @@
 
 ### Description
 
-The function `mg_get_var2()` can be used to return the contents of a variable passed to the server as either POST data, or in the URI in a GET call. The function is somilar to [`mg_get_var()`](mg_get_var.md) but the difference is that `mg_get_var2()` can be used if the same variable is present multiple times in the data. The `occurence` parameter is used to identify which instance of the variable must be returned where **`0`** is used for the first variable with the specified name, **`1`** for the second and so on.
+The function `mg_get_var2()` can be used to return the contents of a variable passed to the server as either POST data, or in the URI in a GET call. The function is somilar to [`mg_get_var()`](mg_get_var.md) but the difference is that `mg_get_var2()` can be used if the same variable is present multiple times in the data. The `occurrence` parameter is used to identify which instance of the variable must be returned where **`0`** is used for the first variable with the specified name, **`1`** for the second and so on.
 
 The function returns the length of the variable content in the return buffer, **`-1`** if a variable with the specified name could not be found and **`-2`** if the pointer to the result buffer is NULL, the size of the result buffer is zero or when the result buffer is too small to contain the variable content and terminating NUL.
 

+ 1 - 1
docs/api/mg_handle_form_request.md

@@ -17,7 +17,7 @@
 
 ### Description
 
-The function `mg_handle_form_request()` processes form data on a connection. The function uses callback functions for the heavy lifting which are passed to the function as fields in a [`struct mg_form_data_handler`](mg_form_data_handler.md) structure. The number of processed fields is returned by the function, or a negative value when an error occured. I nthe situation where some fields are processed successfully (for example file downloads) and an error occurs later in the form processing, the function still returns a negative value. It is the responsibility of the calling party to do the necessary cleanup. The calling party should also do the cleanup of any files which are created, but not required anymore later.
+The function `mg_handle_form_request()` processes form data on a connection. The function uses callback functions for the heavy lifting which are passed to the function as fields in a [`struct mg_form_data_handler`](mg_form_data_handler.md) structure. The number of processed fields is returned by the function, or a negative value when an error occurred. I nthe situation where some fields are processed successfully (for example file downloads) and an error occurs later in the form processing, the function still returns a negative value. It is the responsibility of the calling party to do the necessary cleanup. The calling party should also do the cleanup of any files which are created, but not required anymore later.
 
 ### See Also
 

+ 1 - 1
docs/api/mg_set_websocket_handler.md

@@ -25,6 +25,6 @@
 
 ### Description
 
-The function `mg_set_websocket_handler()` connects callback functions to a websocket URI. The callback functions are called when a state change is detected on the URI like an incomming connection or data received from a remote peer.
+The function `mg_set_websocket_handler()` connects callback functions to a websocket URI. The callback functions are called when a state change is detected on the URI like an incoming connection or data received from a remote peer.
 
 ### See Also

+ 1 - 1
docs/api/mg_start_thread.md

@@ -19,7 +19,7 @@
 
 ### Description
 
-The function `mg_start_thread()` is a convenience function to create a detached thread. The function returns **0** when successful and another value if an error occured. A pointer to user supplied data can be passed which is then passed further on to the thread function as parameter.
+The function `mg_start_thread()` is a convenience function to create a detached thread. The function returns **0** when successful and another value if an error occurred. A pointer to user supplied data can be passed which is then passed further on to the thread function as parameter.
 
 ### See Also
 

+ 1 - 1
docs/api/mg_websocket_client_write.md

@@ -21,7 +21,7 @@
 
 The function `mg_websocket_client_write()` sends data to a websocket server wrapped in a masked websocket frame. The function issues calls to [`mg_lock_connection()`](mg_lock_connection.md) and [`mg_unlock_connection()`](mg_unlock_connection.md) to ensure that the transmission is not interrupted. Interruption can happen the the application is proactively communicating and responding to a request simultaneously. This function is available only, if Civetweb is compiled with the option `-DUSE_WEBSOCKET`.
 
-The return value is the number of bytes written on success, **0** when the connection has been closed and **-1** if an error occured.
+The return value is the number of bytes written on success, **0** when the connection has been closed and **-1** if an error occurred.
 
 ### See Also
 

+ 2 - 1
docs/yaSSL.md

@@ -6,7 +6,8 @@ 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/).
 
-*Note: The following instructions have not been checked for the most recent versions of CivetWeb and wolfSSL. Some information might be outdated.*
+*Note: The following instructions have not been checked for the most recent versions of CivetWeb and wolfSSL. Some information might be outdated. All current versions of CivetWeb are tested using [OpenSSL](OpenSSL.md). CivetWeb uses the OpenSSL API functions - wolfSSL
+provides an OpenSSL compatibility layer. However, when new TLS features are added to CivetWeb, it is not checked if corresponding functions work the same, or even if they exist at all within this compatibility layer.*
 
 
 Getting Started

+ 4 - 0
examples/README.md

@@ -7,6 +7,10 @@ The C++ wrapper only offers a subset of the full C API, thus the C example is mo
 
 In addition, there is one example how to configure a HTTPS server, to comply with modern security standards ([https](https://github.com/civetweb/civetweb/tree/master/examples/https)). It does not hold any source, but only a configuration file and some documentation how to use it.
 
+The [multidomain](https://github.com/civetweb/civetweb/tree/master/examples/multidomain) example demonstrates how to host multiple domains with different HTTPS certificates. It uses the standalone server (civetweb.c + main.c) and existing certificates.
+
+The [ws_client](https://github.com/civetweb/civetweb/tree/master/examples/ws_client) example shows how to use the websocket client interface to communicate with an (external) websocket server. It uses the "echo demo" of [websocket.org](http://websocket.org/echo.html), and only works if this server is reachable.
+
 Some no longer maintained examples can be found in the ["obsolete"](https://github.com/civetweb/civetweb/tree/master/examples/_obsolete) folder. It is not guaranteed that they work in the current version - they are kept for reference, but might be removed in the future.
 
 All examples are subject to the MIT license (unless noted otherwise) - they come without warranty of any kind.

+ 1 - 1
examples/_obsolete/ws_server/ws_server.c

@@ -214,7 +214,7 @@ static int websocket_data_handler(struct mg_connection *conn, int flags,
             /* If client initiated close, respond with close message in acknowlegement */
             if (!ws_conn[wsd].closing) {
                 mg_websocket_write(conn, WEBSOCKET_OPCODE_CONNECTION_CLOSE, data, data_len);
-                ws_conn[wsd].closing = 1; /* we should not send addional messages when close requested/acknowledged */
+                ws_conn[wsd].closing = 1; /* we should not send additional messages when close requested/acknowledged */
             }
             return 0; /* time to close the connection */
             break;

+ 15 - 15
examples/embedded_c/embedded_c.c

@@ -236,9 +236,9 @@ field_found(const char *key,
 #else
 		snprintf(path, pathlen, "/tmp/%s", filename);
 #endif
-		return FORM_FIELD_STORAGE_STORE;
+		return MG_FORM_FIELD_STORAGE_STORE;
 	}
-	return FORM_FIELD_STORAGE_GET;
+	return MG_FORM_FIELD_STORAGE_GET;
 }
 
 
@@ -354,9 +354,9 @@ field_disp_read_on_the_fly(const char *key,
 		context->file[context->index - 1].name[127] = 0;
 		context->file[context->index - 1].length = 0;
 		md5_init(&(context->file[context->index - 1].chksum));
-		return FORM_FIELD_STORAGE_GET;
+		return MG_FORM_FIELD_STORAGE_GET;
 	}
-	return FORM_FIELD_STORAGE_ABORT;
+	return MG_FORM_FIELD_STORAGE_ABORT;
 }
 
 
@@ -699,7 +699,7 @@ WebSocketReadyHandler(struct mg_connection *conn, void *cbdata)
 	const char *text = "Hello from the websocket ready handler";
 	struct t_ws_client *client = mg_get_user_connection_data(conn);
 
-	mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, text, strlen(text));
+	mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_TEXT, text, strlen(text));
 	fprintf(stdout, "Greeting message sent to websocket client\r\n\r\n");
 	ASSERT(client->conn == conn);
 	ASSERT(client->state == 1);
@@ -721,22 +721,22 @@ WebsocketDataHandler(struct mg_connection *conn,
 
 	fprintf(stdout, "Websocket got %lu bytes of ", (unsigned long)len);
 	switch (((unsigned char)bits) & 0x0F) {
-	case WEBSOCKET_OPCODE_CONTINUATION:
+	case MG_WEBSOCKET_OPCODE_CONTINUATION:
 		fprintf(stdout, "continuation");
 		break;
-	case WEBSOCKET_OPCODE_TEXT:
+	case MG_WEBSOCKET_OPCODE_TEXT:
 		fprintf(stdout, "text");
 		break;
-	case WEBSOCKET_OPCODE_BINARY:
+	case MG_WEBSOCKET_OPCODE_BINARY:
 		fprintf(stdout, "binary");
 		break;
-	case WEBSOCKET_OPCODE_CONNECTION_CLOSE:
+	case MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE:
 		fprintf(stdout, "close");
 		break;
-	case WEBSOCKET_OPCODE_PING:
+	case MG_WEBSOCKET_OPCODE_PING:
 		fprintf(stdout, "ping");
 		break;
-	case WEBSOCKET_OPCODE_PONG:
+	case MG_WEBSOCKET_OPCODE_PONG:
 		fprintf(stdout, "pong");
 		break;
 	default:
@@ -765,7 +765,7 @@ WebSocketCloseHandler(const struct mg_connection *conn, void *cbdata)
 	mg_unlock_context(ctx);
 
 	fprintf(stdout,
-	        "Client droped from the set of webserver connections\r\n\r\n");
+	        "Client dropped from the set of webserver connections\r\n\r\n");
 }
 
 
@@ -782,7 +782,7 @@ InformWebsockets(struct mg_context *ctx)
 	for (i = 0; i < MAX_WS_CLIENTS; i++) {
 		if (ws_clients[i].state == 2) {
 			mg_websocket_write(ws_clients[i].conn,
-			                   WEBSOCKET_OPCODE_TEXT,
+			                   MG_WEBSOCKET_OPCODE_TEXT,
 			                   text,
 			                   strlen(text));
 		}
@@ -978,10 +978,10 @@ main(int argc, char *argv[])
 	mg_set_request_handler(ctx, "/B/A$", BXHandler, (void *)1);
 	mg_set_request_handler(ctx, "/B/B$", BXHandler, (void *)2);
 
-	/* Add handler for all files with .foo extention */
+	/* Add handler for all files with .foo extension */
 	mg_set_request_handler(ctx, "**.foo$", FooHandler, 0);
 
-	/* Add handler for /close extention */
+	/* Add handler for /close extension */
 	mg_set_request_handler(ctx, "/close", CloseHandler, 0);
 
 	/* Add handler for /form  (serve a file outside the document root) */

+ 3 - 3
examples/embedded_cpp/embedded_cpp.cpp

@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017 the Civetweb developers
+/* Copyright (c) 2013-2018 the Civetweb developers
  * Copyright (c) 2013 No Face Press, LLC
  * License http://opensource.org/licenses/mit-license.php MIT License
  */
@@ -342,7 +342,7 @@ class WebSocketHandler : public CivetWebSocketHandler {
 		printf("WS ready\n");
 
 		const char *text = "Hello from the websocket ready handler";
-		mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, text, strlen(text));
+		mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_TEXT, text, strlen(text));
 	}
 
 	virtual bool handleData(CivetServer *server,
@@ -354,7 +354,7 @@ class WebSocketHandler : public CivetWebSocketHandler {
 		fwrite(data, 1, data_len, stdout);
 		printf("\n");
 
-		mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, data, data_len);
+		mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_TEXT, data, data_len);
 		return (data_len<4);
 	}
 

+ 10 - 0
examples/multidomain/README.md

@@ -0,0 +1,10 @@
+Compile CivetWeb to the repository root and run it from there
+
+./civetweb examples/multidomain/base_domain.conf
+
+Check what cerfificate is used
+
+echo | openssl s_client -showcerts -servername default-domain -connect localhost:443 2>/dev/null | openssl x509 -inform pem -noout -text | grep Serial
+
+echo | openssl s_client -showcerts -servername localhost -connect localhost:443 2>/dev/null | openssl x509 -inform pem -noout -text | grep Serial
+

+ 5 - 0
examples/multidomain/add_domain.conf

@@ -0,0 +1,5 @@
+ssl_certificate resources/cert/server_bkup.pem
+authentication_domain localhost
+document_root test/ajax/
+enable_directory_listing no
+

+ 7 - 0
examples/multidomain/base_domain.conf

@@ -0,0 +1,7 @@
+listening_ports 80r,443s,8080
+ssl_certificate resources/cert/server.pem
+authentication_domain default
+add_domain examples/multidomain/add_domain.conf
+document_root test
+enable_directory_listing yes
+

+ 5 - 0
examples/ws_client/build.sh

@@ -0,0 +1,5 @@
+#!/bin/sh
+rm ws_client_example
+cc ws_client.c ../../src/civetweb.c -DUSE_WEBSOCKET -I../../include -lpthread -ldl -g -O0 -DNO_SSL -o ws_client_example -Wall
+ls -la ws_client_example
+

+ 409 - 0
examples/ws_client/ws_client.c

@@ -0,0 +1,409 @@
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "civetweb.h"
+
+/* Get an OS independent definition for sleep() */
+#ifdef _WIN32
+#include <windows.h>
+#define sleep(x) Sleep((x)*1000)
+#else
+#include <unistd.h>
+#endif
+
+
+/* User defined client data structure */
+struct tclient_data {
+
+	time_t started;
+	time_t closed;
+	struct tmsg_list_elem *msgs;
+};
+
+struct tmsg_list_elem {
+	time_t timestamp;
+	void *data;
+	size_t len;
+	struct tmsg_list_elem *next;
+};
+
+
+/* Helper function to get a printable name for websocket opcodes */
+static const char *
+msgtypename(int flags)
+{
+	unsigned f = (unsigned)flags & 0xFu;
+	switch (f) {
+	case MG_WEBSOCKET_OPCODE_CONTINUATION:
+		return "continuation";
+	case MG_WEBSOCKET_OPCODE_TEXT:
+		return "text";
+	case MG_WEBSOCKET_OPCODE_BINARY:
+		return "binary";
+	case MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE:
+		return "clonnection close";
+	case MG_WEBSOCKET_OPCODE_PING:
+		return "PING";
+	case MG_WEBSOCKET_OPCODE_PONG:
+		return "PING";
+	}
+	return "unknown";
+}
+
+
+/* Callback for handling data received from the server */
+static int
+websocket_client_data_handler(struct mg_connection *conn,
+                              int flags,
+                              char *data,
+                              size_t data_len,
+                              void *user_data)
+{
+	struct tclient_data *pclient_data = (struct tclient_data *)user_data;
+	time_t now = time(NULL);
+
+	/* We may get some different message types (websocket opcodes).
+	 * We will handle these messages differently. */
+	int is_text = ((flags & 0xf) == MG_WEBSOCKET_OPCODE_TEXT);
+	int is_bin = ((flags & 0xf) == MG_WEBSOCKET_OPCODE_BINARY);
+	int is_ping = ((flags & 0xf) == MG_WEBSOCKET_OPCODE_PING);
+	int is_pong = ((flags & 0xf) == MG_WEBSOCKET_OPCODE_PONG);
+	int is_close = ((flags & 0xf) == MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE);
+
+	/* Log output: We got some data */
+	printf("%10.0f - Client received %lu bytes of %s data from server%s",
+	       difftime(now, pclient_data->started),
+	       (long unsigned)data_len,
+	       msgtypename(flags),
+	       (is_text ? ": " : ".\n"));
+
+	/* Check if we got a websocket PING request */
+	if (is_ping) {
+		/* PING requests are to check if the connection is broken.
+		 * They should be replied with a PONG with the same data.
+		 */
+		mg_websocket_client_write(conn,
+		                          MG_WEBSOCKET_OPCODE_PONG,
+		                          data,
+		                          data_len);
+		return 1;
+	}
+
+	/* Check if we got a websocket PONG message */
+	if (is_pong) {
+		/* A PONG message may be a response to our PING, but
+		 * it is also allowed to send unsolicited PONG messages
+		 * send by the server to check some lower level TCP
+		 * connections. Just ignore all kinds of PONGs. */
+		return 1;
+	}
+
+	/* It we got a websocket TEXT message, handle it ... */
+	if (is_text) {
+		struct tmsg_list_elem *p;
+		struct tmsg_list_elem **where = &(pclient_data->msgs);
+
+		/* ... by printing it to the log ... */
+		fwrite(data, 1, data_len, stdout);
+		printf("\n");
+
+		/* ... and storing it (OOM ignored for simplicity). */
+		p = (struct tmsg_list_elem *)malloc(sizeof(struct tmsg_list_elem));
+		p->timestamp = now;
+		p->data = malloc(data_len);
+		memcpy(p->data, data, data_len);
+		p->len = data_len;
+		p->next = NULL;
+		while (*where != NULL) {
+			where = &((*where)->next);
+		}
+		*where = p;
+	}
+
+	/* Another option would be BINARY data. */
+	if (is_bin) {
+		/* In this example, we just ignore binary data.
+		 * According to some blogs, discriminating TEXT and
+		 * BINARY may be some remains from earlier drafts
+		 * of the WebSocket protocol.
+		 * Anyway, a real application will usually use
+		 * either TEXT or BINARY. */
+	}
+
+	/* It could be a CLOSE message as well. */
+	if (is_close) {
+		printf("%10.0f - Goodbye\n", difftime(now, pclient_data->started));
+		return 0;
+	}
+
+	/* Return 1 to keep the connection open */
+	return 1;
+}
+
+
+/* Callback for handling a close message received from the server */
+static void
+websocket_client_close_handler(const struct mg_connection *conn,
+                               void *user_data)
+{
+	struct tclient_data *pclient_data = (struct tclient_data *)user_data;
+
+	pclient_data->closed = time(NULL);
+	printf("%10.0f - Client: Close handler\n",
+	       difftime(pclient_data->closed, pclient_data->started));
+}
+
+
+/* Websocket client test function */
+void
+run_websocket_client(const char *host,
+                     int port,
+                     int secure,
+                     const char *path,
+                     const char *greetings)
+{
+	char err_buf[100] = {0};
+	struct mg_connection *client_conn;
+	struct tclient_data *pclient_data;
+	int i;
+
+	/* Allocate some memory for callback specific data.
+	 * For simplicity, we ignore OOM handling in this example. */
+	pclient_data = (struct tclient_data *)malloc(sizeof(struct tclient_data));
+
+	/* Store start time in the private structure */
+	pclient_data->started = time(NULL);
+	pclient_data->closed = 0;
+	pclient_data->msgs = NULL;
+
+	/* Log first action (time = 0.0) */
+	printf("%10.0f - Connecting to %s:%i\n", 0.0, host, port);
+
+	/* Connect to the given WS or WSS (WS secure) server */
+	client_conn = mg_connect_websocket_client(host,
+	                                          port,
+	                                          secure,
+	                                          err_buf,
+	                                          sizeof(err_buf),
+	                                          path,
+	                                          NULL,
+	                                          websocket_client_data_handler,
+	                                          websocket_client_close_handler,
+	                                          pclient_data);
+
+	/* Check if connection is possible */
+	if (client_conn == NULL) {
+		printf("mg_connect_websocket_client error: %s\n", err_buf);
+		return;
+	}
+
+	/* Connection established */
+	printf("%10.0f - Connected\n", difftime(time(NULL), pclient_data->started));
+
+	/* If there are greetings to send, do it now */
+	if (greetings) {
+		printf("%10.0f - Sending greetings\n",
+		       difftime(time(NULL), pclient_data->started));
+
+		mg_websocket_client_write(client_conn,
+		                          MG_WEBSOCKET_OPCODE_TEXT,
+		                          greetings,
+		                          strlen(greetings));
+	}
+
+	/* Wait for some seconds */
+	sleep(5);
+
+	/* Does the server play "ping pong" ? */
+	for (i = 0; i < 5; i++) {
+		/* Send a PING message every 5 seconds. */
+		printf("%10.0f - Sending PING\n",
+		       difftime(time(NULL), pclient_data->started));
+		mg_websocket_client_write(client_conn,
+		                          MG_WEBSOCKET_OPCODE_PING,
+		                          (const char *)&i,
+		                          sizeof(int));
+		sleep(5);
+	}
+
+	/* Wait a while */
+	/* If we do not use "ping pong", the server will probably
+	 * close the connection with a timeout earlier. */
+	sleep(150);
+
+	/* Send greetings again */
+	if (greetings) {
+		printf("%10.0f - Sending greetings again\n",
+		       difftime(time(NULL), pclient_data->started));
+
+		mg_websocket_client_write(client_conn,
+		                          MG_WEBSOCKET_OPCODE_TEXT,
+		                          greetings,
+		                          strlen(greetings));
+	}
+
+	/* Wait for some seconds */
+	sleep(5);
+
+	/* Send some "song text": http://www.99-bottles-of-beer.net/ */
+	{
+		char txt[128];
+		int b = 99; /* start with 99 bottles */
+
+		while (b > 0) {
+			/* Send "b bottles" text line. */
+			sprintf(txt,
+			        "%i bottle%s of beer on the wall, "
+			        "%i bottle%s of beer.",
+			        b,
+			        ((b != 1) ? "s" : ""),
+			        b,
+			        ((b != 1) ? "s" : ""));
+			mg_websocket_client_write(client_conn,
+			                          MG_WEBSOCKET_OPCODE_TEXT,
+			                          txt,
+			                          strlen(txt));
+
+			/* Take a breath. */
+			sleep(1);
+
+			/* Drink a bottle */
+			b--;
+
+			/* Send "remaining bottles" text line. */
+			if (b) {
+				sprintf(txt,
+				        "Take one down and pass it around, "
+				        "%i bottle%s of beer on the wall.",
+				        b,
+				        ((b != 1) ? "s" : ""));
+			} else {
+				strcpy(txt,
+				       "Take one down and pass it around, "
+				       "no more bottles of beer on the wall.");
+			}
+			mg_websocket_client_write(client_conn,
+			                          MG_WEBSOCKET_OPCODE_TEXT,
+			                          txt,
+			                          strlen(txt));
+
+			/* Take a breath. */
+			sleep(2);
+		}
+
+		/* Send "no more bottles" text line. */
+		strcpy(txt,
+		       "No more bottles of beer on the wall, "
+		       "no more bottles of beer.");
+		mg_websocket_client_write(client_conn,
+		                          MG_WEBSOCKET_OPCODE_TEXT,
+		                          txt,
+		                          strlen(txt));
+
+		/* Take a breath. */
+		sleep(1);
+
+		/* Buy new bottles. */
+		b = 99;
+
+		/* Send "buy some more" text line. */
+		sprintf(txt,
+		        "Go to the store and buy some more, "
+		        "%i bottle%s of beer on the wall.",
+		        b,
+		        ((b != 1) ? "s" : ""));
+		mg_websocket_client_write(client_conn,
+		                          MG_WEBSOCKET_OPCODE_TEXT,
+		                          txt,
+		                          strlen(txt));
+	}
+
+	/* Wait for some seconds */
+	sleep(5);
+
+	/* Somewhat boring conversation, isn't it?
+	 * Tell the server we have to leave. */
+	printf("%10.0f - Sending close message\n",
+	       difftime(time(NULL), pclient_data->started));
+	mg_websocket_client_write(client_conn,
+	                          MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE,
+	                          NULL,
+	                          0);
+
+	/* We don't need to wait, this is just to have the log timestamp
+	 * a second later, and to not log from the handlers and from
+	 * here the same time (printf to stdout is not thread-safe, but
+	 * adding flock or mutex or an explicit logging function makes
+	 * this example unnecessarily complex). */
+	sleep(5);
+
+	/* Connection should be closed by now. */
+	printf("%10.0f - Connection state: %s\n",
+	       difftime(time(NULL), pclient_data->started),
+	       ((pclient_data->closed == 0) ? "open" : "closed"));
+
+	/* Close client connection */
+	mg_close_connection(client_conn);
+	printf("%10.0f - End of test\n",
+	       difftime(time(NULL), pclient_data->started));
+
+
+	/* Print collected data */
+	printf("\n\nPrint all text messages from server again:\n");
+	{
+		struct tmsg_list_elem **where = &(pclient_data->msgs);
+		while (*where != NULL) {
+			printf("%10.0f - [%5lu] ",
+			       difftime((*where)->timestamp, pclient_data->started),
+			       (unsigned long)(*where)->len);
+			fwrite((const char *)(*where)->data, 1, (*where)->len, stdout);
+			printf("\n");
+
+			where = &((*where)->next);
+		}
+	}
+
+	/* Free collected data */
+	{
+		struct tmsg_list_elem **where = &(pclient_data->msgs);
+		void *p1 = 0;
+		void *p2 = 0;
+		while (*where != NULL) {
+			free((*where)->data);
+			free(p2);
+			p2 = p1;
+			p1 = *where;
+
+			where = &((*where)->next);
+		}
+		free(p2);
+		free(p1);
+	}
+	free(pclient_data);
+}
+
+
+/* main will initialize the CivetWeb library
+ * and start the WebSocket client test function */
+int
+main(int argc, char *argv[])
+{
+	const char *greetings = "Hello World!";
+
+	const char *host = "echo.websocket.org";
+	const char *path = "/";
+
+#if defined(NO_SSL)
+	const int port = 80;
+	const int secure = 0;
+	mg_init_library(0);
+#else
+	const int port = 443;
+	const int secure = 1;
+	mg_init_library(MG_FEATURES_SSL);
+#endif
+
+	run_websocket_client(host, port, secure, path, greetings);
+}

+ 16 - 14
format.bat

@@ -7,6 +7,7 @@ clang-format -i src/md5.inl
 clang-format -i src/sha1.inl
 clang-format -i src/mod_lua.inl
 clang-format -i src/mod_duktape.inl
+clang-format -i src/mod_zlib.inl
 clang-format -i src/timer.inl
 clang-format -i src/handle_form.inl
 
@@ -15,19 +16,20 @@ clang-format -i src/third_party/civetweb_lua.h
 clang-format -i include/civetweb.h
 clang-format -i include/CivetServer.h
 
-clang-format -i test/public_func.h
-clang-format -i test/public_func.c
-clang-format -i test/public_server.h
-clang-format -i test/public_server.c
-clang-format -i test/private.h
-clang-format -i test/private.c
-clang-format -i test/private_exe.h
-clang-format -i test/private_exe.c
-clang-format -i test/shared.h
-clang-format -i test/shared.c
-clang-format -i test/timertest.h
-clang-format -i test/timertest.c
-clang-format -i test/civetweb_check.h
-clang-format -i test/main.c
+clang-format -i unittest/public_func.h
+clang-format -i unittest/public_func.c
+clang-format -i unittest/public_server.h
+clang-format -i unittest/public_server.c
+clang-format -i unittest/private.h
+clang-format -i unittest/private.c
+clang-format -i unittest/private_exe.h
+clang-format -i unittest/private_exe.c
+clang-format -i unittest/shared.h
+clang-format -i unittest/shared.c
+clang-format -i unittest/timertest.h
+clang-format -i unittest/timertest.c
+clang-format -i unittest/civetweb_check.h
+clang-format -i unittest/main.c
 
 clang-format -i examples/embedded_c/embedded_c.c
+

+ 20 - 8
include/CivetServer.h

@@ -372,7 +372,7 @@ class CIVETWEB_API CivetServer
 	 * getHeader(struct mg_connection *conn, const std::string &headerName)
 	 * @param conn - the connection information
 	 * @param headerName - header name to get the value from
-	 * @returns a char array whcih contains the header value as string
+	 * @returns a char array which contains the header value as string
 	*/
 	static const char *getHeader(struct mg_connection *conn,
 	                             const std::string &headerName);
@@ -380,8 +380,8 @@ class CIVETWEB_API CivetServer
 	/**
 	 * getParam(struct mg_connection *conn, const char *, std::string &, size_t)
 	 *
-	 * Returns a query paramter contained in the supplied buffer.  The
-	 * occurance value is a zero-based index of a particular key name.  This
+	 * Returns a query which contained in the supplied buffer.  The
+	 * occurrence value is a zero-based index of a particular key name.  This
 	 * 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
@@ -408,8 +408,8 @@ class CIVETWEB_API CivetServer
 	/**
 	 * getParam(const std::string &, const char *, std::string &, size_t)
 	 *
-	 * Returns a query paramter contained in the supplied buffer.  The
-	 * occurance value is a zero-based index of a particular key name.  This
+	 * Returns a query parameter contained in the supplied buffer.  The
+	 * occurrence value is a zero-based index of a particular key name.  This
 	 * should not be confused with the index over all of the keys.
 	 *
 	 * @param data - the query string (text)
@@ -431,8 +431,8 @@ class CIVETWEB_API CivetServer
 	/**
 	 * getParam(const char *, size_t, const char *, std::string &, size_t)
 	 *
-	 * Returns a query paramter contained in the supplied buffer.  The
-	 * occurance value is a zero-based index of a particular key name.  This
+	 * Returns a query parameter contained in the supplied buffer.  The
+	 * occurrence value is a zero-based index of a particular key name.  This
 	 * should not be confused with the index over all of the keys.
 	 *
 	 * @param data the - query string (text)
@@ -450,6 +450,18 @@ class CIVETWEB_API CivetServer
 	                     size_t occurrence = 0);
 
 	/**
+	 * getPostData(struct mg_connection *)
+	 *
+	 * Returns response body from a request made as POST. Since the
+	 * connections map is protected, it can't be directly accessed.
+	 * This uses string to store post data to handle big posts.
+	 *
+	 * @param conn - connection from which post data will be read
+	 * @return Post data (empty if not available).
+	 */
+	static std::string getPostData(struct mg_connection *conn);
+
+	/**
 	 * urlDecode(const std::string &, std::string &, bool)
 	 *
 	 * @param src - string to be decoded
@@ -563,7 +575,7 @@ class CIVETWEB_API CivetServer
 	/**
 	 * requestHandler(struct mg_connection *, void *cbdata)
 	 *
-	 * Handles the incomming request.
+	 * Handles the incoming request.
 	 *
 	 * @param conn - the connection information
 	 * @param cbdata - pointer to the CivetHandler instance.

+ 137 - 56
include/civetweb.h

@@ -23,11 +23,10 @@
 #ifndef CIVETWEB_HEADER_INCLUDED
 #define CIVETWEB_HEADER_INCLUDED
 
-#define CIVETWEB_VERSION "1.10"
+#define CIVETWEB_VERSION "1.11"
 #define CIVETWEB_VERSION_MAJOR (1)
-#define CIVETWEB_VERSION_MINOR (10)
+#define CIVETWEB_VERSION_MINOR (11)
 #define CIVETWEB_VERSION_PATCH (0)
-#define CIVETWEB_VERSION_RELEASED
 
 #ifndef CIVETWEB_API
 #if defined(_WIN32)
@@ -53,11 +52,68 @@ extern "C" {
 #endif /* __cplusplus */
 
 
+/* Init Features */
+enum {
+	MG_FEATURES_DEFAULT = 0x0u,
+
+	/* Support files from local directories */
+	/* Will only work, if NO_FILES is not set. */
+	MG_FEATURES_FILES = 0x1u,
+
+	/* Support transport layer security (TLS). */
+	/* SSL is still often used synonymously for TLS. */
+	/* Will only work, if NO_SSL is not set. */
+	MG_FEATURES_TLS = 0x2u,
+	MG_FEATURES_SSL = 0x2u,
+
+	/* Support common gateway interface (CGI). */
+	/* Will only work, if NO_CGI is not set. */
+	MG_FEATURES_CGI = 0x4u,
+
+	/* Support IPv6. */
+	/* Will only work, if USE_IPV6 is set. */
+	MG_FEATURES_IPV6 = 0x8u,
+
+	/* Support WebSocket protocol. */
+	/* Will only work, if USE_WEBSOCKET is set. */
+	MG_FEATURES_WEBSOCKET = 0x10u,
+
+	/* Support server side Lua scripting. */
+	/* Will only work, if USE_LUA is set. */
+	MG_FEATURES_LUA = 0x20u,
+
+	/* Support server side JavaScript scripting. */
+	/* Will only work, if USE_DUKTAPE is set. */
+	MG_FEATURES_SSJS = 0x40u,
+
+	/* Provide data required for caching files. */
+	/* Will only work, if NO_CACHING is not set. */
+	MG_FEATURES_CACHE = 0x80u,
+
+	/* Collect server status information. */
+	/* Will only work, if USE_SERVER_STATS is set. */
+	MG_FEATURES_STATS = 0x100u,
+
+	/* Support on-the-fly compression. */
+	/* Will only work, if USE_ZLIB is set. */
+	MG_FEATURES_COMPRESSION = 0x200u,
+
+	/* Collect server status information. */
+	/* Will only work, if USE_SERVER_STATS is set. */
+	MG_FEATURES_ALL = 0xFFFFu
+};
+
+
 /* Initialize this library. This should be called once before any other
  * function from this library. This function is not guaranteed to be
  * thread safe.
  * Parameters:
  *   features: bit mask for features to be initialized.
+ *             Note: The TLS libraries (like OpenSSL) is initialized
+ *                   only if the MG_FEATURES_TLS bit is set.
+ *                   Currently the other bits do not influence
+ *                   initialization, but this may change in future
+ *                   versions.
  * Return value:
  *   initialized features
  *   0: error
@@ -87,14 +143,14 @@ struct mg_header {
 
 /* This structure contains information about the HTTP request. */
 struct mg_request_info {
-	const char *request_method; /* "GET", "POST", etc */
-	const char *request_uri;    /* URL-decoded URI (absolute or relative,
-	                             * as in the request) */
-	const char *local_uri;      /* URL-decoded URI (relative). Can be NULL
-	                             * if the request_uri does not address a
-	                             * resource at the server host. */
-#if defined(MG_LEGACY_INTERFACE)
-	const char *uri; /* Deprecated: use local_uri instead */
+	const char *request_method;  /* "GET", "POST", etc */
+	const char *request_uri;     /* URL-decoded URI (absolute or relative,
+	                              * as in the request) */
+	const char *local_uri;       /* URL-decoded URI (relative). Can be NULL
+	                              * if the request_uri does not address a
+	                              * resource at the server host. */
+#if defined(MG_LEGACY_INTERFACE) /* 2017-02-04, deprecated 2014-09-14 */
+	const char *uri;             /* Deprecated: use local_uri instead */
 #endif
 	const char *http_version; /* E.g. "1.0", "1.1" */
 	const char *query_string; /* URL part after '?', not including '?', or
@@ -103,11 +159,6 @@ struct mg_request_info {
 	                             used */
 	char remote_addr[48];     /* Client's IP address as a string. */
 
-#if defined(MG_LEGACY_INTERFACE)
-	long remote_ip; /* Client's IP address. Deprecated: use remote_addr instead
-	                   */
-#endif
-
 	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 */
@@ -145,12 +196,14 @@ struct mg_response_info {
 /* Client certificate information (part of mg_request_info) */
 /* New nomenclature. */
 struct mg_client_cert {
+	void *peer_cert;
 	const char *subject;
 	const char *issuer;
 	const char *serial;
 	const char *finger;
 };
 
+#if defined(MG_LEGACY_INTERFACE) /* 2017-10-05 */
 /* Old nomenclature. */
 struct client_cert {
 	const char *subject;
@@ -158,6 +211,7 @@ struct client_cert {
 	const char *serial;
 	const char *finger;
 };
+#endif
 
 
 /* This structure needs to be passed to mg_start(), to let civetweb know
@@ -200,7 +254,21 @@ struct mg_callbacks {
 	    -1: initializing ssl fails. */
 	int (*init_ssl)(void *ssl_context, void *user_data);
 
-#if defined(MG_LEGACY_INTERFACE)
+	/* Called when civetweb is about to create or free a SSL_CTX.
+	Parameters:
+	   ssl_ctx: SSL_CTX pointer. NULL at creation time, Not NULL when mg_context
+	            will be freed
+	     user_data: parameter user_data passed when starting the server.
+	   Return value:
+	     0: civetweb will continue to create the context, just as if the
+	        callback would not be present.
+	        The value in *ssl_ctx when the function returns is ignored.
+	     1: civetweb will copy the value from *ssl_ctx to the civetweb context
+	        and doesn't create its own.
+	    -1: initializing ssl fails.*/
+	int (*external_ssl_ctx)(void **ssl_ctx, void *user_data);
+
+#if defined(MG_LEGACY_INTERFACE) /* 2015-08-19 */
 	/* Called when websocket request is received, before websocket handshake.
 	   Return value:
 	     0: civetweb proceeds with websocket handshake.
@@ -245,40 +313,14 @@ struct mg_callbacks {
 	*/
 	void (*connection_close)(const struct mg_connection *);
 
-#if defined(MG_USE_OPEN_FILE)
-	/* Note: The "file in memory" feature is a deletion candidate, since
-	 * it complicates the code, and does not add any value compared to
-	 * "mg_add_request_handler".
-	 * See this discussion thread:
-	 * https://groups.google.com/forum/#!topic/civetweb/h9HT4CmeYqI
-	 * If you disagree, if there is any situation this is indeed useful
-	 * and cannot trivially be replaced by another existing feature,
-	 * please contribute to this discussion during the next 3 month
-	 * (till end of April 2017), otherwise this feature might be dropped
-	 * in future releases. */
-
-	/* Called when civetweb tries to open a file. Used to intercept file open
-	   calls, and serve file data from memory instead.
-	   Parameters:
-	      path:     Full path to the file to open.
-	      data_len: Placeholder for the file size, if file is served from
-	                memory.
-	   Return value:
-	     NULL: do not serve file from memory, proceed with normal file open.
-	     non-NULL: pointer to the file contents in memory. data_len must be
-	       initialized with the size of the memory block. */
-	const char *(*open_file)(const struct mg_connection *,
-	                         const char *path,
-	                         size_t *data_len);
-#endif
-
 	/* Called when civetweb is about to serve Lua server page, if
 	   Lua support is enabled.
 	   Parameters:
+	     conn: current connection.
 	     lua_context: "lua_State *" pointer. */
-	void (*init_lua)(const struct mg_connection *, void *lua_context);
+	void (*init_lua)(const struct mg_connection *conn, void *lua_context);
 
-#if defined(MG_LEGACY_INTERFACE)
+#if defined(MG_LEGACY_INTERFACE) /* 2016-05-14 */
 	/* Called when civetweb has uploaded a file to a temporary directory as a
 	   result of mg_upload() call.
 	   Note that mg_upload is deprecated. Use mg_handle_form_request instead.
@@ -290,11 +332,15 @@ struct mg_callbacks {
 	/* Called when civetweb is about to send HTTP error to the client.
 	   Implementing this callback allows to create custom error pages.
 	   Parameters:
+	     conn: current connection.
 	     status: HTTP error status code.
+	     errmsg: error message text.
 	   Return value:
 	     1: run civetweb error handler.
 	     0: callback already handled the error. */
-	int (*http_error)(struct mg_connection *, int status);
+	int (*http_error)(struct mg_connection *conn,
+	                  int status,
+	                  const char *errmsg);
 
 	/* Called after civetweb context has been created, before requests
 	   are processed.
@@ -372,6 +418,29 @@ CIVETWEB_API struct mg_context *mg_start(const struct mg_callbacks *callbacks,
 CIVETWEB_API void mg_stop(struct mg_context *);
 
 
+#if defined(MG_EXPERIMENTAL_INTERFACES)
+/* Add an additional domain to an already running web server.
+ *
+ * Parameters:
+ *   ctx: Context handle of a server started by mg_start.
+ *   options: NULL terminated list of option_name, option_value pairs that
+ *            specify CivetWeb configuration parameters.
+ *
+ * Return:
+ *   < 0 in case of an error
+ *    -1 for a parameter error
+ *    -2 invalid options
+ *    -3 initializing SSL failed
+ *    -4 mandatory domain option missing
+ *    -5 duplicate domain
+ *    -6 out of memory
+ *   > 0 index / handle of a new domain
+ */
+CIVETWEB_API int mg_start_domain(struct mg_context *ctx,
+                                 const char **configuration_options);
+#endif
+
+
 /* mg_request_handler
 
    Called when a new request comes in.  This callback is URI based
@@ -531,6 +600,14 @@ CIVETWEB_API void *mg_get_user_data(const struct mg_context *ctx);
 
 
 /* Set user data for the current connection. */
+/* Note: This function is deprecated. Use the init_connection callback
+   instead to initialize the user connection data pointer. It is
+   reccomended to supply a pointer to some user defined data structure
+   as conn_data initializer in init_connection. In case it is required
+   to change some data after the init_connection call, store another
+   data pointer in the user defined data structure and modify that
+   pointer. In either case, after the init_connection callback, only
+   calls to mg_get_user_connection_data should be required. */
 CIVETWEB_API void mg_set_user_connection_data(struct mg_connection *conn,
                                               void *data);
 
@@ -553,7 +630,7 @@ CIVETWEB_API int
 mg_get_request_link(const struct mg_connection *conn, char *buf, size_t buflen);
 
 
-#if defined(MG_LEGACY_INTERFACE)
+#if defined(MG_LEGACY_INTERFACE) /* 2014-02-21 */
 /* Return array of strings that represent valid configuration options.
    For each option, option name and default value is returned, i.e. the
    number of entries in the array equals to number_of_options x 2.
@@ -570,6 +647,7 @@ struct mg_option {
 };
 
 /* Old nomenclature */
+#if defined(MG_LEGACY_INTERFACE) /* 2017-10-05 */
 enum {
 	CONFIG_TYPE_UNKNOWN = 0x0,
 	CONFIG_TYPE_NUMBER = 0x1,
@@ -581,6 +659,7 @@ enum {
 	CONFIG_TYPE_STRING_LIST = 0x7,
 	CONFIG_TYPE_STRING_MULTILINE = 0x8
 };
+#endif
 
 /* New nomenclature */
 enum {
@@ -592,7 +671,8 @@ enum {
 	MG_CONFIG_TYPE_BOOLEAN = 0x5,
 	MG_CONFIG_TYPE_EXT_PATTERN = 0x6,
 	MG_CONFIG_TYPE_STRING_LIST = 0x7,
-	MG_CONFIG_TYPE_STRING_MULTILINE = 0x8
+	MG_CONFIG_TYPE_STRING_MULTILINE = 0x8,
+	MG_CONFIG_TYPE_YES_NO_OPTIONAL = 0x9
 };
 
 /* Return array of struct mg_option, representing all valid configuration
@@ -623,7 +703,7 @@ CIVETWEB_API int mg_get_server_ports(const struct mg_context *ctx,
                                      struct mg_server_ports *ports);
 
 
-#if defined(MG_LEGACY_INTERFACE)
+#if defined(MG_LEGACY_INTERFACE) /* 2017-04-02 */
 /* Deprecated: Use mg_get_server_ports instead. */
 CIVETWEB_API size_t
 mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl);
@@ -726,7 +806,7 @@ 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)
+#if defined(MG_LEGACY_INTERFACE) /* 2014-06-21 */
 #define mg_lock mg_lock_connection
 #define mg_unlock mg_unlock_connection
 #endif
@@ -739,7 +819,7 @@ CIVETWEB_API void mg_unlock_context(struct mg_context *ctx);
 
 
 /* Opcodes, from http://tools.ietf.org/html/rfc6455 */
-/* Old nomenclature */
+#if defined(MG_LEGACY_INTERFACE) /* 2017-10-05 */
 enum {
 	WEBSOCKET_OPCODE_CONTINUATION = 0x0,
 	WEBSOCKET_OPCODE_TEXT = 0x1,
@@ -748,6 +828,7 @@ enum {
 	WEBSOCKET_OPCODE_PING = 0x9,
 	WEBSOCKET_OPCODE_PONG = 0xa
 };
+#endif
 
 /* New nomenclature */
 enum {
@@ -979,7 +1060,7 @@ CIVETWEB_API int mg_get_cookie(const char *cookie,
 /* Download data from the remote web server.
      host: host name to connect to, e.g. "foo.com", or "10.12.40.1".
      port: port number, e.g. 80.
-     use_ssl: wether to use SSL connection.
+     use_ssl: whether to use SSL connection.
      error_buffer, error_buffer_size: error message placeholder.
      request_fmt,...: HTTP request.
    Return:
@@ -1005,7 +1086,7 @@ mg_download(const char *host,
 CIVETWEB_API void mg_close_connection(struct mg_connection *conn);
 
 
-#if defined(MG_LEGACY_INTERFACE)
+#if defined(MG_LEGACY_INTERFACE) /* 2016-05-14 */
 /* File upload functionality. Each uploaded file gets saved into a temporary
    file and MG_UPLOAD event is sent.
    Return number of uploaded files.
@@ -1084,7 +1165,7 @@ struct mg_form_data_handler {
 
 /* Return values definition for the "field_found" callback in
  * mg_form_data_handler. */
-/* Old nomenclature */
+#if defined(MG_LEGACY_INTERFACE) /* 2017-10-05 */
 enum {
 	/* Skip this field (neither get nor store it). Continue with the
      * next field. */
@@ -1096,7 +1177,7 @@ enum {
 	/* Stop parsing this request. Skip the remaining fields. */
 	FORM_FIELD_STORAGE_ABORT = 0x10
 };
-
+#endif
 /* New nomenclature */
 enum {
 	/* Skip this field (neither get nor store it). Continue with the

+ 9 - 1
resources/Makefile.in-duktape

@@ -9,7 +9,7 @@ ifndef WITH_DUKTAPE
 endif
 
 # Duktape default version is 1.5.2 (105)
-WITH_DUKTAPE_VERSION ?= 105
+WITH_DUKTAPE_VERSION ?= 202
 DUKTAPE_VERSION_KNOWN = 0
 
 # Select src and header according to the Duktape version
@@ -37,6 +37,14 @@ ifeq ($(WITH_DUKTAPE_VERSION), 201)
   DUKTAPE_VERSION_KNOWN = 1
 endif
 
+ifeq ($(WITH_DUKTAPE_VERSION), 202)
+  $(info Duktape: Using version 2.2.0)
+  DUKTAPE_DIR = src/third_party/duktape-2.2.0/src
+  DUKTAPE_SHARED_LIB_FLAG = -lduktape2.2
+  DUKTAPE_CFLAGS = -DDUKTAPE_VERSION_MAKEFILE=202
+  DUKTAPE_VERSION_KNOWN = 1
+endif
+
 ifneq ($(DUKTAPE_VERSION_KNOWN), 1)
   $(error Duktape: Unknwon version - $(WITH_DUKTAPE_VERSION))
 endif

+ 2 - 2
resources/Makefile.in-lua

@@ -29,8 +29,8 @@ ifeq ($(WITH_LUA_VERSION), 502)
   LUA_VERSION_KNOWN = 1
 endif
 ifeq ($(WITH_LUA_VERSION), 503)
-  $(info Lua: Using version 5.3.3)
-  LUA_DIR = src/third_party/lua-5.3.3/src
+  $(info Lua: Using version 5.3.4)
+  LUA_DIR = src/third_party/lua-5.3.4/src
   LUA_SHARED_LIB_FLAG = -llua5.3
   LUA_CFLAGS = -DLUA_COMPAT_5_2 -DLUA_VERSION_MAKEFILE=503
   LUA_VERSION_KNOWN = 1

+ 81 - 0
resources/check_defines.lua

@@ -0,0 +1,81 @@
+#!/usr/bin/lua5.2
+
+usedlines = {c={}, n={}}
+useddefs = {c={}, n={}}
+
+function AddElem(tab, q)
+  if (tab.c[q]) then 
+    tab.c[q] = tab.c[q] + 1
+  else
+    tab.c[q] = 1
+    tab.n[#tab.n+1]=q
+  end
+end
+
+function PrintTab(tab)
+  table.sort(tab.n)
+  for _,n in ipairs(tab.n) do
+    --print(tab.c[n], n)
+    print(n)
+  end
+end
+
+
+function noifdef(f)
+  local out = {}
+  local changed = false
+  for l in io.lines(f) do
+    local n = l:gsub("^#ifdef ([%w_]+)", "#if defined(%1)")
+    n = n:gsub("^#ifndef ([%w_]+)", "#if !defined(%1)")
+    out[#out+1] = (n)
+    if l ~= n then
+      --print(l , "-->", n)
+      changed = true
+    end
+
+    if n:match("^#if") then
+      local q = n:gsub("%/%*.+%*%/", "")
+      q = q:gsub("%s+$", "")
+      q = q:gsub("^%s+", "")
+      q = q:gsub("%s+", " ")
+      AddElem(usedlines, q)
+
+      for w in q:gmatch("%(%s*([%w_]+)%s*%)") do
+        AddElem(useddefs, w)
+      end
+    end
+  end
+
+  if changed then
+    local f = io.open(f, "w")
+    for _,l in pairs(out) do
+      f:write(l .. "\n")
+    end
+    f:close()   
+    print(f .. " rewritten")
+  end
+
+  -- print(#out .. " lines processed")
+end
+
+
+path = path or ""
+noifdef(path .. "src/civetweb.c")
+noifdef(path .. "src/civetweb_private_lua.h")
+noifdef(path .. "src/main.c")
+noifdef(path .. "src/md5.inl")
+noifdef(path .. "src/mod_duktape.inl")
+noifdef(path .. "src/mod_lua.inl")
+noifdef(path .. "src/mod_zlib.inl")
+noifdef(path .. "src/sha1.inl")
+noifdef(path .. "src/timer.inl")
+noifdef(path .. "src/wolfssl_extras.inl")
+
+--PrintTab(usedlines)
+
+--print("Defines used")
+PrintTab(useddefs)
+
+
+
+

+ 118 - 0
resources/used_defines.txt

@@ -0,0 +1,118 @@
+ALTERNATIVE_QUEUE
+ANDROID
+ARCH_IS_BIG_ENDIAN
+CIVETWEB_HEADER_INCLUDED
+CIVETWEB_PRIVATE_LUA_H
+CLOCK_MONOTONIC
+CLOCK_PROCESS
+CLOCK_REALTIME
+CLOCK_THREAD
+CONFIG_FILE
+CONFIG_FILE2
+CRYPTO_LIB
+DEBUG
+DEBUG_ASSERT
+DEBUG_TRACE
+ENABLE_CREATE_CONFIG_FILE
+ENABLE_UNUSED_PTHREAD_FUNCTIONS
+EWOULDBLOCK
+HAVE_POLL
+IGNORE_UNUSED_RESULT
+INT64_MAX
+LSP_INCLUDE_MAX_DEPTH
+MAX_TIMERS
+MAX_WORKER_THREADS
+MD5_STATIC
+MEMORY_DEBUGGING
+MGSQLEN
+MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE
+MG_EXPERIMENTAL_INTERFACES
+MG_EXTERNAL_FUNCTION_log_access
+MG_EXTERNAL_FUNCTION_mg_cry_internal_impl
+MG_LEGACY_INTERFACE
+MG_MAX_UNANSWERED_PING
+MG_USE_OPEN_FILE
+MSG_NOSIGNAL
+MUST_IMPLEMENT_CLOCK_GETTIME
+NEED_DEBUG_TRACE_FUNC
+NEED_TIMEGM
+NO_ALTERNATIVE_QUEUE
+NO_ATOMICS
+NO_CACHING
+NO_CGI
+NO_FILES
+NO_NONCE_CHECK
+NO_POPEN
+NO_SOCKLEN_T
+NO_SSL
+NO_SSL_DL
+NO_THREAD_NAME
+OPENSSL_API_1_1
+O_BINARY
+PASSWORDS_FILE_NAME
+PATH_MAX
+POLLIN
+REENTRANT_TIME
+SOCKET_TIMEOUT_QUANTUM
+SOMAXCONN
+SSL_ALREADY_INITIALIZED
+SSL_LIB
+S_ISDIR
+TCP_USER_TIMEOUT
+USE_COCOA
+USE_DUKTAPE
+USE_IPV6
+USE_LUA
+USE_LUA_FILE_SYSTEM
+USE_LUA_LUAXML
+USE_LUA_SQLITE3
+USE_SERVER_STATS
+USE_STACK_SIZE
+USE_TIMERS
+USE_WEBSOCKET
+WIN32
+WIN32_LEAN_AND_MEAN
+WIN_PTHREADS_TIME_H
+WOLFSSL_VERSION
+W_OK
+_CRT_SECURE_NO_DEPRECATE
+_CRT_SECURE_NO_WARNINGS
+_DARWIN_UNLIMITED_SELECT
+_FILE_OFFSET_BITS
+_GNU_SOURCE
+_IN_PORT_T
+_LARGEFILE_SOURCE
+_MSC_VER
+_TIMESPEC_DEFINED
+_WIN32
+_WIN32_WCE
+_WIN32_WINNT
+_WIN64
+_XOPEN_SOURCE
+__CLOCK_AVAILABILITY
+__GNUC__
+__MACH__
+__MINGW32__
+__MINGW64__
+__STDC_FORMAT_MACROS
+__STDC_LIMIT_MACROS
+__STDC_VERSION__
+__SYMBIAN32__
+__clang__
+__clockid_t_defined
+__cplusplus
+__hpux
+__linux__
+__sun
+calloc
+fileno
+free
+in_port_t
+malloc
+md5_INCLUDED
+pclose
+popen
+realloc
+snprintf
+va_copy
+vsnprintf

+ 54 - 41
src/CMakeLists.txt

@@ -1,41 +1,41 @@
 # The C API library
-add_library(c-library civetweb.c)
-set_target_properties(c-library PROPERTIES
+add_library(civetweb-c-library civetweb.c)
+set_target_properties(civetweb-c-library PROPERTIES
   OUTPUT_NAME "civetweb"
   VERSION ${CIVETWEB_VERSION}
   SOVERSION ${CIVETWEB_VERSION}
 )
 if (BUILD_SHARED_LIBS)
-  target_compile_definitions(c-library PRIVATE CIVETWEB_DLL_EXPORTS)
+  target_compile_definitions(civetweb-c-library PRIVATE CIVETWEB_DLL_EXPORTS)
 endif()
 target_include_directories(
-  c-library PUBLIC
+  civetweb-c-library PUBLIC
   ${PROJECT_SOURCE_DIR}/include)
 install(
-  TARGETS c-library
+  TARGETS civetweb-c-library
   ARCHIVE DESTINATION lib
   LIBRARY DESTINATION lib
   RUNTIME DESTINATION bin
-  COMPONENT c-library)
+  COMPONENT civetweb-c-library)
 install(FILES
   ${PROJECT_SOURCE_DIR}/include/civetweb.h
   DESTINATION include
-  COMPONENT c-library)
+  COMPONENT civetweb-c-library)
 
 # Need Windows sockets if available
 find_package(WinSock)
 if (WINSOCK_FOUND)
-  target_link_libraries(c-library WINSOCK::WINSOCK)
+  target_link_libraries(civetweb-c-library WINSOCK::WINSOCK)
 endif()
 
 # We need threading
 find_package(Threads)
-target_link_libraries(c-library ${CMAKE_THREAD_LIBS_INIT})
+target_link_libraries(civetweb-c-library ${CMAKE_THREAD_LIBS_INIT})
 
 # Need the realtime library if we're using timers
 find_package(LibRt)
 if (CIVETWEB_ENABLE_WEBSOCKETS AND CIVETWEB_ENABLE_LUA AND LIBRT_FOUND)
-  target_link_libraries(c-library LIBRT::LIBRT)
+  target_link_libraries(civetweb-c-library LIBRT::LIBRT)
 endif()
 
 # We need to link OpenSSL if not dynamically loading
@@ -43,13 +43,13 @@ if (CIVETWEB_ENABLE_SSL)
   if (CIVETWEB_ENABLE_SSL_DYNAMIC_LOADING)
     find_package(LibDl)
     if (LIBDL_FOUND)
-      target_link_libraries(c-library -ldl)
+      target_link_libraries(civetweb-c-library -ldl)
     endif()
   else()
     find_package(OpenSSL)
     include_directories(${OPENSSL_INCLUDE_DIR})
     message(STATUS "OpenSSL include directory: ${OPENSSL_INCLUDE_DIR}")
-    target_link_libraries(c-library ${OPENSSL_LIBRARIES})
+    target_link_libraries(civetweb-c-library ${OPENSSL_LIBRARIES})
   endif()
 endif()
 
@@ -103,7 +103,7 @@ if (CIVETWEB_ENABLE_LUA)
     link_directories("${LUA_INSTALL_DIR}/lib")
     include_directories("${LUA_INSTALL_DIR}/include")
     set(LUA_LIBRARIES "${LUA_INSTALL_DIR}/lib/liblua.a")
-    add_dependencies(c-library lua)
+    add_dependencies(civetweb-c-library lua)
   else()
     find_package(Lua)
   endif()
@@ -131,7 +131,7 @@ if (CIVETWEB_ENABLE_LUA)
   link_directories("${LUA_FILESYSTEM_INSTALL_DIR}/lib")
   include_directories("${LUA_FILESYSTEM_INSTALL_DIR}/include")
   set(LUA_LIBRARIES "${LUA_LIBRARIES};${LUA_FILESYSTEM_INSTALL_DIR}/lib/libluafilesystem.a")
-  add_dependencies(c-library luafilesystem)
+  add_dependencies(civetweb-c-library luafilesystem)
 
   # Lua SQLite Support
   if (${CIVETWEB_LUA_SQLITE_VERSION} VERSION_EQUAL "0.9.3")
@@ -163,7 +163,7 @@ if (CIVETWEB_ENABLE_LUA)
   unset(INSTALL_DIR)
   link_directories("${LUA_SQLITE_INSTALL_DIR}/lib")
   set(LUA_LIBRARIES "${LUA_LIBRARIES};${LUA_SQLITE_INSTALL_DIR}/lib/libluasqlite.a")
-  add_dependencies(c-library luasqlite)
+  add_dependencies(civetweb-c-library luasqlite)
 
   # Lua XML Support
   if (${CIVETWEB_LUA_XML_VERSION} VERSION_EQUAL "1.8.0")
@@ -174,9 +174,20 @@ if (CIVETWEB_ENABLE_LUA)
     message(FATAL_ERROR "The Lua XML archive filename is unknown for version ${CIVETWEB_LUA_XML_VERSION}")
   endif()
   ExternalProject_Add(luaxml
-    URL "http://viremo.eludi.net/LuaXML/${LUA_XML_FILENAME}"
-    URL_MD5 ${CIVETWEB_LUA_XML_MD5_HASH}
+# Old:
+#    URL "http://viremo.eludi.net/LuaXML/${LUA_XML_FILENAME}"
+#    URL_MD5 ${CIVETWEB_LUA_XML_MD5_HASH}
+#    PREFIX "${CIVETWEB_THIRD_PARTY_DIR}"
+#
+# TODO: find current sourde
+# viremo.eludi.net does no longer exist
+# An extended version is available at https://github.com/n1tehawk/LuaXML
+# but the last commit there was in 2015
+#
+    URL "https://github.com/n1tehawk/LuaXML/archive/v1.8.0.zip"
     PREFIX "${CIVETWEB_THIRD_PARTY_DIR}"
+#
+# TODO: fix this patch command (needs someone with deeper CMake know how)
     PATCH_COMMAND ${CMAKE_COMMAND} -E copy
       "${CMAKE_CURRENT_SOURCE_DIR}/cmake/luaxml/CMakeLists.txt" <SOURCE_DIR>/CMakeLists.txt
     CMAKE_ARGS
@@ -193,7 +204,7 @@ if (CIVETWEB_ENABLE_LUA)
   unset(INSTALL_DIR)
   link_directories("${LUA_XML_INSTALL_DIR}/lib")
   set(LUA_LIBRARIES "${LUA_LIBRARIES};${LUA_XML_INSTALL_DIR}/lib/libluaxml.a")
-  add_dependencies(c-library luaxml)
+  add_dependencies(civetweb-c-library luaxml)
 
   # SQLite Support
   string (REGEX MATCHALL "[0-9]+" SQLITE_VERSION_MATCHES ${CIVETWEB_SQLITE_VERSION})
@@ -222,34 +233,36 @@ if (CIVETWEB_ENABLE_LUA)
   link_directories("${SQLITE_INSTALL_DIR}/lib")
   include_directories("${SQLITE_INSTALL_DIR}/include")
   set(LUA_LIBRARIES "${LUA_LIBRARIES};${SQLITE_INSTALL_DIR}/lib/libsqlite.a")
-  add_dependencies(c-library sqlite)
+  add_dependencies(civetweb-c-library sqlite)
 
   # Link all the Lua libraries
-  target_link_libraries(c-library ${LUA_LIBRARIES})
+  target_link_libraries(civetweb-c-library ${LUA_LIBRARIES})
 endif()
 
 # The web server executable
-add_executable(c-executable main.c)
-set_target_properties(c-executable PROPERTIES
-  OUTPUT_NAME "civetweb"
-)
-if (CIVETWEB_INSTALL_EXECUTABLE)
-  install(
-    TARGETS c-executable
-    ARCHIVE DESTINATION lib
-    LIBRARY DESTINATION lib
-    RUNTIME DESTINATION bin
-    COMPONENT server)
-endif()
-if (BUILD_SHARED_LIBS)
-  target_compile_definitions(c-executable PRIVATE CIVETWEB_DLL_IMPORTS)
-endif()
-target_include_directories(
-  c-executable PUBLIC
-  ${PROJECT_SOURCE_DIR}/include)
-target_link_libraries(c-executable c-library)
-if (LIBRT_FOUND)
-  target_link_libraries(c-executable LIBRT::LIBRT)
+if (CIVETWEB_ENABLE_SERVER_EXECUTABLE)
+    add_executable(civetweb-c-executable main.c)
+    set_target_properties(civetweb-c-executable PROPERTIES
+        OUTPUT_NAME "civetweb"
+    )
+    if (CIVETWEB_INSTALL_EXECUTABLE)
+        install(
+            TARGETS civetweb-c-executable
+            ARCHIVE DESTINATION lib
+            LIBRARY DESTINATION lib
+            RUNTIME DESTINATION bin
+            COMPONENT server)
+    endif()
+    if (BUILD_SHARED_LIBS)
+        target_compile_definitions(civetweb-c-executable PRIVATE CIVETWEB_DLL_IMPORTS)
+    endif()
+    target_include_directories(
+        civetweb-c-executable PUBLIC
+        ${PROJECT_SOURCE_DIR}/include)
+    target_link_libraries(civetweb-c-executable civetweb-c-library)
+    if (LIBRT_FOUND)
+        target_link_libraries(civetweb-c-executable LIBRT::LIBRT)
+    endif()
 endif()
 
 if (CIVETWEB_ENABLE_LUA)

+ 17 - 0
src/CivetServer.cpp

@@ -546,6 +546,23 @@ CivetServer::getParam(const char *data,
 	return false;
 }
 
+std::string
+CivetServer::getPostData(struct mg_connection *conn)
+{
+	mg_lock_connection(conn);
+	std::string postdata;
+	char buf[2048];
+	int r = mg_read(conn, buf, sizeof(buf));
+	while (r > 0) {
+		std::string p = std::string(buf);
+		p.resize(r);
+		postdata += p;
+		r = mg_read(conn, buf, sizeof(buf));
+	}
+	mg_unlock_connection(conn);
+	return postdata;
+}
+
 void
 CivetServer::urlEncode(const char *src, std::string &dst, bool append)
 {

File diff ditekan karena terlalu besar
+ 409 - 216
src/civetweb.c


+ 1 - 1
src/civetweb_private_lua.h

@@ -2,7 +2,7 @@
 /* Project internal header to allow main.c to call a non-public function in
  * mod_lua.inl */
 
-#ifndef CIVETWEB_PRIVATE_LUA_H
+#if !defined(CIVETWEB_PRIVATE_LUA_H)
 #define CIVETWEB_PRIVATE_LUA_H
 
 int run_lua(const char *file_name);

+ 0 - 1
src/file_ops.inl

@@ -1 +0,0 @@
-/* currently not required */

+ 108 - 82
src/handle_form.inl

@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017 the Civetweb developers
+/* Copyright (c) 2016-2018 the Civetweb developers
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -40,7 +40,7 @@ url_encoded_field_found(const struct mg_connection *conn,
 	    mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
 
 	if (((size_t)key_dec_len >= (size_t)sizeof(key_dec)) || (key_dec_len < 0)) {
-		return FORM_FIELD_STORAGE_SKIP;
+		return MG_FORM_FIELD_STORAGE_SKIP;
 	}
 
 	if (filename) {
@@ -53,8 +53,8 @@ url_encoded_field_found(const struct mg_connection *conn,
 		if (((size_t)filename_dec_len >= (size_t)sizeof(filename_dec))
 		    || (filename_dec_len < 0)) {
 			/* Log error message and skip this field. */
-			mg_cry(conn, "%s: Cannot decode filename", __func__);
-			return FORM_FIELD_STORAGE_SKIP;
+			mg_cry_internal(conn, "%s: Cannot decode filename", __func__);
+			return MG_FORM_FIELD_STORAGE_SKIP;
 		}
 	} else {
 		filename_dec[0] = 0;
@@ -63,16 +63,20 @@ url_encoded_field_found(const struct mg_connection *conn,
 	ret =
 	    fdh->field_found(key_dec, filename_dec, path, path_len, fdh->user_data);
 
-	if ((ret & 0xF) == FORM_FIELD_STORAGE_GET) {
+	if ((ret & 0xF) == MG_FORM_FIELD_STORAGE_GET) {
 		if (fdh->field_get == NULL) {
-			mg_cry(conn, "%s: Function \"Get\" not available", __func__);
-			return FORM_FIELD_STORAGE_SKIP;
+			mg_cry_internal(conn,
+			                "%s: Function \"Get\" not available",
+			                __func__);
+			return MG_FORM_FIELD_STORAGE_SKIP;
 		}
 	}
-	if ((ret & 0xF) == FORM_FIELD_STORAGE_STORE) {
+	if ((ret & 0xF) == MG_FORM_FIELD_STORAGE_STORE) {
 		if (fdh->field_store == NULL) {
-			mg_cry(conn, "%s: Function \"Store\" not available", __func__);
-			return FORM_FIELD_STORAGE_SKIP;
+			mg_cry_internal(conn,
+			                "%s: Function \"Store\" not available",
+			                __func__);
+			return MG_FORM_FIELD_STORAGE_SKIP;
 		}
 	}
 
@@ -90,16 +94,16 @@ url_encoded_field_get(const struct mg_connection *conn,
 {
 	char key_dec[1024];
 
-	char *value_dec = (char *)mg_malloc_ctx(value_len + 1, conn->ctx);
+	char *value_dec = (char *)mg_malloc_ctx(value_len + 1, conn->phys_ctx);
 	int value_dec_len, ret;
 
 	if (!value_dec) {
 		/* Log error message and stop parsing the form data. */
-		mg_cry(conn,
-		       "%s: Not enough memory (required: %lu)",
-		       __func__,
-		       (unsigned long)(value_len + 1));
-		return FORM_FIELD_STORAGE_ABORT;
+		mg_cry_internal(conn,
+		                "%s: Not enough memory (required: %lu)",
+		                __func__,
+		                (unsigned long)(value_len + 1));
+		return MG_FORM_FIELD_STORAGE_ABORT;
 	}
 
 	mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
@@ -203,7 +207,7 @@ mg_handle_form_request(struct mg_connection *conn,
 	if (!has_body_data) {
 		const char *data;
 
-		if (strcmp(conn->request_info.request_method, "GET")) {
+		if (0 != strcmp(conn->request_info.request_method, "GET")) {
 			/* No body data, but not a GET request.
 			 * This is not a valid form request. */
 			return -1;
@@ -232,14 +236,16 @@ mg_handle_form_request(struct mg_connection *conn,
 
 			/* In every "field_found" callback we ask what to do with the
 			 * data ("field_storage"). This could be:
-			 * FORM_FIELD_STORAGE_SKIP (0) ... ignore the value of this field
-			 * FORM_FIELD_STORAGE_GET (1) ... read the data and call the get
-			 *                              callback function
-			 * FORM_FIELD_STORAGE_STORE (2) ... store the data in a file
-			 * FORM_FIELD_STORAGE_READ (3) ... let the user read the data
-			 *                               (for parsing long data on the fly)
-			 *                               (currently not implemented)
-			 * FORM_FIELD_STORAGE_ABORT (flag) ... stop parsing
+			 * MG_FORM_FIELD_STORAGE_SKIP (0):
+			 *   ignore the value of this field
+			 * MG_FORM_FIELD_STORAGE_GET (1):
+			 *   read the data and call the get callback function
+			 * MG_FORM_FIELD_STORAGE_STORE (2):
+			 *   store the data in a file
+			 * MG_FORM_FIELD_STORAGE_READ (3):
+			 *   let the user read the data (for parsing long data on the fly)
+			 * MG_FORM_FIELD_STORAGE_ABORT (flag):
+			 *   stop parsing
 			 */
 			memset(path, 0, sizeof(path));
 			field_count++;
@@ -262,12 +268,12 @@ mg_handle_form_request(struct mg_connection *conn,
 				next = val + vallen;
 			}
 
-			if (field_storage == FORM_FIELD_STORAGE_GET) {
+			if (field_storage == MG_FORM_FIELD_STORAGE_GET) {
 				/* Call callback */
 				url_encoded_field_get(
 				    conn, data, (size_t)keylen, val, (size_t)vallen, fdh);
 			}
-			if (field_storage == FORM_FIELD_STORAGE_STORE) {
+			if (field_storage == MG_FORM_FIELD_STORAGE_STORE) {
 				/* Store the content to a file */
 				if (mg_fopen(conn, path, MG_FOPEN_MODE_WRITE, &fstore) == 0) {
 					fstore.access.fp = NULL;
@@ -277,10 +283,10 @@ mg_handle_form_request(struct mg_connection *conn,
 					size_t n = (size_t)
 					    fwrite(val, 1, (size_t)vallen, fstore.access.fp);
 					if ((n != (size_t)vallen) || (ferror(fstore.access.fp))) {
-						mg_cry(conn,
-						       "%s: Cannot write file %s",
-						       __func__,
-						       path);
+						mg_cry_internal(conn,
+						                "%s: Cannot write file %s",
+						                __func__,
+						                path);
 						(void)mg_fclose(&fstore.access);
 						remove_bad_file(conn, path);
 					}
@@ -292,21 +298,24 @@ mg_handle_form_request(struct mg_connection *conn,
 							/* stored successfully */
 							field_stored(conn, path, file_size, fdh);
 						} else {
-							mg_cry(conn,
-							       "%s: Error saving file %s",
-							       __func__,
-							       path);
+							mg_cry_internal(conn,
+							                "%s: Error saving file %s",
+							                __func__,
+							                path);
 							remove_bad_file(conn, path);
 						}
 						fstore.access.fp = NULL;
 					}
 
 				} else {
-					mg_cry(conn, "%s: Cannot create file %s", __func__, path);
+					mg_cry_internal(conn,
+					                "%s: Cannot create file %s",
+					                __func__,
+					                path);
 				}
 			}
 
-			/* if (field_storage == FORM_FIELD_STORAGE_READ) { */
+			/* if (field_storage == MG_FORM_FIELD_STORAGE_READ) { */
 			/* The idea of "field_storage=read" is to let the API user read
 			 * data chunk by chunk and to some data processing on the fly.
 			 * This should avoid the need to store data in the server:
@@ -319,8 +328,8 @@ mg_handle_form_request(struct mg_connection *conn,
 			 */
 			/* } */
 
-			if ((field_storage & FORM_FIELD_STORAGE_ABORT)
-			    == FORM_FIELD_STORAGE_ABORT) {
+			if ((field_storage & MG_FORM_FIELD_STORAGE_ABORT)
+			    == MG_FORM_FIELD_STORAGE_ABORT) {
 				/* Stop parsing the request */
 				break;
 			}
@@ -397,19 +406,22 @@ mg_handle_form_request(struct mg_connection *conn,
 			                                        sizeof(path) - 1,
 			                                        fdh);
 
-			if ((field_storage & FORM_FIELD_STORAGE_ABORT)
-			    == FORM_FIELD_STORAGE_ABORT) {
+			if ((field_storage & MG_FORM_FIELD_STORAGE_ABORT)
+			    == MG_FORM_FIELD_STORAGE_ABORT) {
 				/* Stop parsing the request */
 				break;
 			}
 
-			if (field_storage == FORM_FIELD_STORAGE_STORE) {
+			if (field_storage == MG_FORM_FIELD_STORAGE_STORE) {
 				if (mg_fopen(conn, path, MG_FOPEN_MODE_WRITE, &fstore) == 0) {
 					fstore.access.fp = NULL;
 				}
 				file_size = 0;
 				if (!fstore.access.fp) {
-					mg_cry(conn, "%s: Cannot create file %s", __func__, path);
+					mg_cry_internal(conn,
+					                "%s: Cannot create file %s",
+					                __func__,
+					                path);
 				}
 			}
 
@@ -426,7 +438,7 @@ mg_handle_form_request(struct mg_connection *conn,
 					next = val + vallen;
 				}
 
-				if (field_storage == FORM_FIELD_STORAGE_GET) {
+				if (field_storage == MG_FORM_FIELD_STORAGE_GET) {
 #if 0
 					if (!end_of_key_value_pair_found && !all_data_read) {
 						/* This callback will deliver partial contents */
@@ -449,10 +461,10 @@ mg_handle_form_request(struct mg_connection *conn,
 					size_t n = (size_t)
 					    fwrite(val, 1, (size_t)vallen, fstore.access.fp);
 					if ((n != (size_t)vallen) || (ferror(fstore.access.fp))) {
-						mg_cry(conn,
-						       "%s: Cannot write file %s",
-						       __func__,
-						       path);
+						mg_cry_internal(conn,
+						                "%s: Cannot write file %s",
+						                __func__,
+						                path);
 						mg_fclose(&fstore.access);
 						remove_bad_file(conn, path);
 					}
@@ -471,6 +483,10 @@ mg_handle_form_request(struct mg_connection *conn,
 						r = mg_read(conn, buf + (size_t)buf_fill, to_read);
 						if (r < 0) {
 							/* read error */
+							if (fstore.access.fp) {
+								mg_fclose(&fstore.access);
+								remove_bad_file(conn, path);
+							}
 							return -1;
 						}
 						if (r != (int)to_read) {
@@ -498,7 +514,10 @@ mg_handle_form_request(struct mg_connection *conn,
 					/* stored successfully */
 					field_stored(conn, path, file_size, fdh);
 				} else {
-					mg_cry(conn, "%s: Error saving file %s", __func__, path);
+					mg_cry_internal(conn,
+					                "%s: Error saving file %s",
+					                __func__,
+					                path);
 					remove_bad_file(conn, path);
 				}
 				fstore.access.fp = NULL;
@@ -546,10 +565,10 @@ mg_handle_form_request(struct mg_connection *conn,
 		boundary = (char *)mg_malloc(bl + 1);
 		if (!boundary) {
 			/* Out of memory */
-			mg_cry(conn,
-			       "%s: Cannot allocate memory for boundary [%lu]",
-			       __func__,
-			       (unsigned long)bl);
+			mg_cry_internal(conn,
+			                "%s: Cannot allocate memory for boundary [%lu]",
+			                __func__,
+			                (unsigned long)bl);
 			return -1;
 		}
 		memcpy(boundary, fbeg, bl);
@@ -603,7 +622,7 @@ mg_handle_form_request(struct mg_connection *conn,
 		}
 
 		for (part_no = 0;; part_no++) {
-			size_t towrite, n;
+			size_t towrite, fnlen, n;
 			int get_block;
 
 			r = mg_read(conn,
@@ -639,7 +658,7 @@ mg_handle_form_request(struct mg_connection *conn,
 				mg_free(boundary);
 				return -1;
 			}
-			if (strncmp(buf + 2, boundary, bl)) {
+			if (0 != strncmp(buf + 2, boundary, bl)) {
 				/* Malformed request */
 				mg_free(boundary);
 				return -1;
@@ -774,8 +793,12 @@ mg_handle_form_request(struct mg_connection *conn,
 					fend = fbeg + strcspn(fbeg, ",; \t");
 				}
 			}
+
 			if (!fbeg) {
 				fend = NULL;
+				fnlen = 0;
+			} else {
+				fnlen = (size_t)(fend - fbeg);
 			}
 
 			/* In theory, it could be possible that someone crafts
@@ -793,8 +816,8 @@ mg_handle_form_request(struct mg_connection *conn,
 			field_storage = url_encoded_field_found(conn,
 			                                        nbeg,
 			                                        (size_t)(nend - nbeg),
-			                                        fbeg,
-			                                        (size_t)(fend - fbeg),
+			                                        ((fnlen > 0) ? fbeg : NULL),
+			                                        fnlen,
 			                                        path,
 			                                        sizeof(path) - 1,
 			                                        fdh);
@@ -806,7 +829,7 @@ mg_handle_form_request(struct mg_connection *conn,
 			                       boundary,
 			                       bl);
 
-			if (field_storage == FORM_FIELD_STORAGE_STORE) {
+			if (field_storage == MG_FORM_FIELD_STORAGE_STORE) {
 				/* Store the content to a file */
 				if (mg_fopen(conn, path, MG_FOPEN_MODE_WRITE, &fstore) == 0) {
 					fstore.access.fp = NULL;
@@ -814,7 +837,10 @@ mg_handle_form_request(struct mg_connection *conn,
 				file_size = 0;
 
 				if (!fstore.access.fp) {
-					mg_cry(conn, "%s: Cannot create file %s", __func__, path);
+					mg_cry_internal(conn,
+					                "%s: Cannot create file %s",
+					                __func__,
+					                path);
 				}
 			}
 
@@ -828,7 +854,7 @@ mg_handle_form_request(struct mg_connection *conn,
 				 * in the buffer. */
 				towrite -= bl + 4;
 
-				if (field_storage == FORM_FIELD_STORAGE_GET) {
+				if (field_storage == MG_FORM_FIELD_STORAGE_GET) {
 					unencoded_field_get(conn,
 					                    ((get_block > 0) ? NULL : nbeg),
 					                    ((get_block > 0)
@@ -840,16 +866,16 @@ mg_handle_form_request(struct mg_connection *conn,
 					get_block++;
 				}
 
-				if (field_storage == FORM_FIELD_STORAGE_STORE) {
+				if (field_storage == MG_FORM_FIELD_STORAGE_STORE) {
 					if (fstore.access.fp) {
 
 						/* Store the content of the buffer. */
 						n = (size_t)fwrite(hend, 1, towrite, fstore.access.fp);
 						if ((n != towrite) || (ferror(fstore.access.fp))) {
-							mg_cry(conn,
-							       "%s: Cannot write file %s",
-							       __func__,
-							       path);
+							mg_cry_internal(conn,
+							                "%s: Cannot write file %s",
+							                __func__,
+							                path);
 							mg_fclose(&fstore.access);
 							remove_bad_file(conn, path);
 						}
@@ -867,16 +893,16 @@ mg_handle_form_request(struct mg_connection *conn,
 				            sizeof(buf) - 1 - (size_t)buf_fill);
 				if (r < 0) {
 					/* read error */
+					if (fstore.access.fp) {
+						mg_fclose(&fstore.access);
+						remove_bad_file(conn, path);
+					}
 					mg_free(boundary);
 					return -1;
 				}
 				buf_fill += r;
 				buf[buf_fill] = 0;
-				if (buf_fill < 1) {
-					/* No data */
-					mg_free(boundary);
-					return -1;
-				}
+				/* buf_fill is at least 8 here */
 
 				/* Find boundary */
 				next = search_boundary(buf, (size_t)buf_fill, boundary, bl);
@@ -884,7 +910,7 @@ mg_handle_form_request(struct mg_connection *conn,
 
 			towrite = (size_t)(next - hend);
 
-			if (field_storage == FORM_FIELD_STORAGE_GET) {
+			if (field_storage == MG_FORM_FIELD_STORAGE_GET) {
 				/* Call callback */
 				unencoded_field_get(conn,
 				                    ((get_block > 0) ? NULL : nbeg),
@@ -895,15 +921,15 @@ mg_handle_form_request(struct mg_connection *conn,
 				                    fdh);
 			}
 
-			if (field_storage == FORM_FIELD_STORAGE_STORE) {
+			if (field_storage == MG_FORM_FIELD_STORAGE_STORE) {
 
 				if (fstore.access.fp) {
 					n = (size_t)fwrite(hend, 1, towrite, fstore.access.fp);
 					if ((n != towrite) || (ferror(fstore.access.fp))) {
-						mg_cry(conn,
-						       "%s: Cannot write file %s",
-						       __func__,
-						       path);
+						mg_cry_internal(conn,
+						                "%s: Cannot write file %s",
+						                __func__,
+						                path);
 						mg_fclose(&fstore.access);
 						remove_bad_file(conn, path);
 					} else {
@@ -913,10 +939,10 @@ mg_handle_form_request(struct mg_connection *conn,
 							/* stored successfully */
 							field_stored(conn, path, file_size, fdh);
 						} else {
-							mg_cry(conn,
-							       "%s: Error saving file %s",
-							       __func__,
-							       path);
+							mg_cry_internal(conn,
+							                "%s: Error saving file %s",
+							                __func__,
+							                path);
 							remove_bad_file(conn, path);
 						}
 					}
@@ -924,8 +950,8 @@ mg_handle_form_request(struct mg_connection *conn,
 				}
 			}
 
-			if ((field_storage & FORM_FIELD_STORAGE_ABORT)
-			    == FORM_FIELD_STORAGE_ABORT) {
+			if ((field_storage & MG_FORM_FIELD_STORAGE_ABORT)
+			    == MG_FORM_FIELD_STORAGE_ABORT) {
 				/* Stop parsing the request */
 				break;
 			}

File diff ditekan karena terlalu besar
+ 430 - 189
src/main.c


+ 5 - 5
src/md5.inl

@@ -34,7 +34,7 @@
   1999-05-03 lpd Original version.
  */
 
-#ifndef md5_INCLUDED
+#if !defined(md5_INCLUDED)
 #define md5_INCLUDED
 
 /*
@@ -57,7 +57,7 @@ typedef struct md5_state_s {
 	md5_byte_t buf[64];  /* accumulate block */
 } md5_state_t;
 
-#ifdef __cplusplus
+#if defined(__cplusplus)
 extern "C" {
 #endif
 
@@ -71,7 +71,7 @@ md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes);
 /* Finish the message and return the digest. */
 MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
 
-#ifdef __cplusplus
+#if defined(__cplusplus)
 } /* end extern "C" */
 #endif
 
@@ -130,12 +130,12 @@ MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
   1999-05-03 lpd Original version.
  */
 
-#ifndef MD5_STATIC
+#if !defined(MD5_STATIC)
 #include <string.h>
 #endif
 
 #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
-#ifdef ARCH_IS_BIG_ENDIAN
+#if defined(ARCH_IS_BIG_ENDIAN)
 #define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
 #else
 #define BYTE_ORDER (0)

+ 94 - 34
src/mod_duktape.inl

@@ -1,6 +1,6 @@
 /* This file is part of the CivetWeb web server.
  * See https://github.com/civetweb/civetweb/
- * (C) 2015-2017 by the CivetWeb authors, MIT license.
+ * (C) 2015-2018 by the CivetWeb authors, MIT license.
  */
 
 #include "duktape.h"
@@ -40,7 +40,6 @@ mg_duk_mem_free(void *udata, void *ptr)
 	mg_free(ptr);
 }
 
-
 static void
 mg_duk_fatal_handler(duk_context *duk_ctx, duk_errcode_t code, const char *msg)
 {
@@ -53,9 +52,59 @@ mg_duk_fatal_handler(duk_context *duk_ctx, duk_errcode_t code, const char *msg)
 	duk_get_prop_string(duk_ctx, -1, civetweb_conn_id);
 	conn = (struct mg_connection *)duk_to_pointer(duk_ctx, -1);
 
-	mg_cry(conn, "JavaScript fatal (%u): %s", (unsigned)code, msg);
+	mg_cry_internal(conn, "JavaScript fatal (%u): %s", (unsigned)code, msg);
+}
+
+#if DUK_VERSION >= 20000L
+/* Dropped from interface */
+duk_int_t duk_peval_file(duk_context *duk_ctx, const char *script);
+
+static void
+mg_duk_v2_fatal(void *udata, const char *msg)
+{
+	; /* TODO: How to get "conn" without duk_ctx */
+}
+
+static void
+push_file_as_string(duk_context *ctx, const char *filename)
+{
+	FILE *f;
+	struct stat fst;
+	void *buf;
+	size_t len;
+
+	if (0 != stat(filename, &fst)) {
+		duk_push_undefined(ctx);
+		return;
+	}
+
+	f = fopen(filename, "rb");
+	if (!f) {
+		duk_push_undefined(ctx);
+		return;
+	}
+
+	buf = mg_malloc(fst.st_size);
+	if (!f) {
+		fclose(f);
+		duk_push_undefined(ctx);
+		return;
+	}
+
+	len = fread(buf, 1, fst.st_size, f);
+	fclose(f);
+
+	duk_push_lstring(ctx, (const char *)buf, (duk_size_t)len);
+	mg_free(buf);
 }
 
+duk_int_t
+duk_peval_file(duk_context *duk_ctx, const char *script)
+{
+	push_file_as_string(duk_ctx, script);
+	return duk_peval(duk_ctx);
+}
+#endif
 
 static duk_ret_t
 duk_itf_write(duk_context *duk_ctx)
@@ -76,10 +125,9 @@ duk_itf_write(duk_context *duk_ctx)
 
 	if (!conn) {
 		duk_error(duk_ctx,
-		          DUK_ERR_INTERNAL_ERROR,
+		          DUK_ERR_ERROR,
 		          "function not available without connection object");
-		/* probably never reached, but satisfies static code analysis */
-		return DUK_RET_INTERNAL_ERROR;
+		return DUK_RET_ERROR;
 	}
 
 	ret = mg_write(conn, val, len);
@@ -96,16 +144,15 @@ duk_itf_read(duk_context *duk_ctx)
 	char buf[1024];
 	int len;
 
-	duk_push_global_stash(duk_ctx);
+	duk_push_current_function(duk_ctx);
 	duk_get_prop_string(duk_ctx, -1, civetweb_conn_id);
 	conn = (struct mg_connection *)duk_to_pointer(duk_ctx, -1);
 
 	if (!conn) {
 		duk_error(duk_ctx,
-		          DUK_ERR_INTERNAL_ERROR,
+		          DUK_ERR_ERROR,
 		          "function not available without connection object");
-		/* probably never reached, but satisfies static code analysis */
-		return DUK_RET_INTERNAL_ERROR;
+		return DUK_RET_ERROR;
 	}
 
 	len = mg_read(conn, buf, sizeof(buf));
@@ -118,24 +165,29 @@ duk_itf_read(duk_context *duk_ctx)
 static duk_ret_t
 duk_itf_getoption(duk_context *duk_ctx)
 {
-	struct mg_context *cv_ctx;
+	struct mg_connection *conn;
 	const char *ret;
+	int optidx;
 	duk_size_t len = 0;
 	const char *val = duk_require_lstring(duk_ctx, -1, &len);
 
 	duk_push_current_function(duk_ctx);
-	duk_get_prop_string(duk_ctx, -1, civetweb_ctx_id);
-	cv_ctx = (struct mg_context *)duk_to_pointer(duk_ctx, -1);
+	duk_get_prop_string(duk_ctx, -1, civetweb_conn_id);
+	conn = (struct mg_connection *)duk_to_pointer(duk_ctx, -1);
 
-	if (!cv_ctx) {
+	if (!conn) {
 		duk_error(duk_ctx,
-		          DUK_ERR_INTERNAL_ERROR,
-		          "function not available without connection object");
-		/* probably never reached, but satisfies static code analysis */
-		return DUK_RET_INTERNAL_ERROR;
+		          DUK_ERR_ERROR,
+		          "function not available without context object");
+		return DUK_RET_ERROR;
 	}
 
-	ret = mg_get_option(cv_ctx, val);
+	optidx = get_option_index(val);
+	if (optidx >= 0) {
+		ret = conn->dom_ctx->config[optidx];
+	} else {
+		ret = NULL;
+	}
 	if (ret) {
 		duk_push_string(duk_ctx, ret);
 	} else {
@@ -158,10 +210,15 @@ mg_exec_duktape_script(struct mg_connection *conn, const char *script_name)
 	duk_ctx = duk_create_heap(mg_duk_mem_alloc,
 	                          mg_duk_mem_realloc,
 	                          mg_duk_mem_free,
-	                          (void *)conn->ctx,
-	                          mg_duk_fatal_handler);
+	                          (void *)conn->phys_ctx,
+#if DUK_VERSION >= 20000L
+	                          mg_duk_v2_fatal
+#else
+	                          mg_duk_fatal_handler
+#endif
+	                          );
 	if (!duk_ctx) {
-		mg_cry(conn, "Failed to create a Duktape heap.");
+		mg_cry_internal(conn, "%s", "Failed to create a Duktape heap.");
 		goto exec_duktape_finished;
 	}
 
@@ -169,16 +226,19 @@ mg_exec_duktape_script(struct mg_connection *conn, const char *script_name)
 	duk_push_global_object(duk_ctx);
 	duk_push_object(duk_ctx); /* create a new table/object ("conn") */
 
+	/* add function conn.write */
 	duk_push_c_function(duk_ctx, duk_itf_write, 1 /* 1 = nargs */);
 	duk_push_pointer(duk_ctx, (void *)conn);
 	duk_put_prop_string(duk_ctx, -2, civetweb_conn_id);
-	duk_put_prop_string(duk_ctx, -2, "write"); /* add function conn.write */
+	duk_put_prop_string(duk_ctx, -2, "write");
 
+	/* add function conn.read */
 	duk_push_c_function(duk_ctx, duk_itf_read, 0 /* 0 = nargs */);
 	duk_push_pointer(duk_ctx, (void *)conn);
 	duk_put_prop_string(duk_ctx, -2, civetweb_conn_id);
-	duk_put_prop_string(duk_ctx, -2, "read"); /* add function conn.read */
+	duk_put_prop_string(duk_ctx, -2, "read");
 
+	/* add request_method object */
 	duk_push_string(duk_ctx, conn->request_info.request_method);
 	duk_put_prop_string(duk_ctx,
 	                    -2,
@@ -226,16 +286,16 @@ mg_exec_duktape_script(struct mg_connection *conn, const char *script_name)
 	duk_push_string(duk_ctx, script_name);
 	duk_put_prop_string(duk_ctx, -2, "script_name");
 
-	if (conn->ctx != NULL) {
-		duk_push_c_function(duk_ctx, duk_itf_getoption, 1 /* 1 = nargs */);
-		duk_push_pointer(duk_ctx, (void *)(conn->ctx));
-		duk_put_prop_string(duk_ctx, -2, civetweb_ctx_id);
-		duk_put_prop_string(duk_ctx,
-		                    -2,
-		                    "getoption"); /* add function conn.write */
+	/* add function civetweb.getoption */
+	duk_push_c_function(duk_ctx, duk_itf_getoption, 1 /* 1 = nargs */);
+	duk_push_pointer(duk_ctx, (void *)conn);
+	duk_put_prop_string(duk_ctx, -2, civetweb_conn_id);
+	duk_put_prop_string(duk_ctx, -2, "getoption");
 
-		if (conn->ctx->systemName != NULL) {
-			duk_push_string(duk_ctx, conn->ctx->systemName);
+	if (conn->phys_ctx != NULL) {
+		/* add system name */
+		if (conn->phys_ctx->systemName != NULL) {
+			duk_push_string(duk_ctx, conn->phys_ctx->systemName);
 			duk_put_prop_string(duk_ctx, -2, "system");
 		}
 	}
@@ -249,7 +309,7 @@ mg_exec_duktape_script(struct mg_connection *conn, const char *script_name)
 	duk_put_prop_string(duk_ctx, -2, civetweb_conn_id);
 
 	if (duk_peval_file(duk_ctx, script_name) != 0) {
-		mg_cry(conn, "%s", duk_safe_to_string(duk_ctx, -1));
+		mg_cry_internal(conn, "%s", duk_safe_to_string(duk_ctx, -1));
 		goto exec_duktape_finished;
 	}
 	duk_pop(duk_ctx); /* ignore result */

+ 335 - 149
src/mod_lua.inl

@@ -5,7 +5,7 @@
 #include "civetweb_lua.h"
 #include "civetweb_private_lua.h"
 
-#ifdef _WIN32
+#if defined(_WIN32)
 static void *
 mmap(void *addr, int64_t len, int prot, int flags, int fd, int offset)
 {
@@ -13,7 +13,7 @@ mmap(void *addr, int64_t len, int prot, int flags, int fd, int offset)
 	 * Currently it is sufficient, but there are a lot of unused parameters.
 	 * Better use a function "mg_map" which only has the required parameters,
 	 * and implement it using mmap in Linux and CreateFileMapping in Windows.
-	 * Noone should expect a full mmap for Windows here.
+	 * No one should expect a full mmap for Windows here.
 	 */
 	HANDLE fh = (HANDLE)_get_osfhandle(fd);
 	HANDLE mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0);
@@ -51,7 +51,7 @@ static const char lua_regkey_connlist = 2;
 static const char lua_regkey_lsp_include_history = 3;
 static const char *LUABACKGROUNDPARAMS = "mg";
 
-#ifndef LSP_INCLUDE_MAX_DEPTH
+#if !defined(LSP_INCLUDE_MAX_DEPTH)
 #define LSP_INCLUDE_MAX_DEPTH (32)
 #endif
 
@@ -149,37 +149,41 @@ lua_cry(struct mg_connection *conn,
 	case LUA_YIELD:
 		break;
 	case LUA_ERRRUN:
-		mg_cry(conn,
-		       "%s: %s failed: runtime error: %s",
-		       lua_title,
-		       lua_operation,
-		       lua_tostring(L, -1));
+		mg_cry_internal(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));
+		mg_cry_internal(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);
+		mg_cry_internal(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);
+		mg_cry_internal(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));
+		mg_cry_internal(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);
+		mg_cry_internal(
+		    conn, "%s: %s failed: error %i", lua_title, lua_operation, err);
 		break;
 	}
 }
@@ -358,6 +362,7 @@ struct lsp_var_reader_data {
 };
 
 
+/* Helper function to read the content of variable values */
 static const char *
 lsp_var_reader(lua_State *L, void *ud, size_t *sz)
 {
@@ -365,24 +370,30 @@ lsp_var_reader(lua_State *L, void *ud, size_t *sz)
 	const char *ret;
 	(void)(L); /* unused */
 
+	/* This reader is called multiple times, to fetch the full Lua script */
 	switch (reader->state) {
 	case 0:
+		/* First call: what function to call */
 		ret = "mg.write(";
 		*sz = strlen(ret);
 		break;
 	case 1:
+		/* Second call: forward variable name */
 		ret = reader->begin;
 		*sz = reader->len;
 		break;
 	case 2:
+		/* Third call: close function call */
 		ret = ")";
 		*sz = strlen(ret);
 		break;
 	default:
+		/* Forth/Final call: tell Lua we got the entire script */
 		ret = 0;
 		*sz = 0;
 	}
 
+	/* Step to the next state for the next call */
 	reader->state++;
 	return ret;
 }
@@ -398,44 +409,79 @@ run_lsp(struct mg_connection *conn,
 	int i, j, pos = 0, lines = 1, lualines = 0, is_var, lua_ok;
 	char chunkname[MG_BUF_LEN];
 	struct lsp_var_reader_data data;
+	const char lsp_mark1 = '?'; /* Use <? code ?> */
+	const char lsp_mark2 = '%'; /* Use <% code %> */
 
 	for (i = 0; i < len; i++) {
-		if (p[i] == '\n')
+		if (p[i] == '\n') {
 			lines++;
-		if (((i + 1) < len) && (p[i] == '<') && (p[i + 1] == '?')) {
+		}
+
+		/* Lua pages are normal text, unless there is a "<?" or "<%" tag. */
+		if (((i + 1) < len) && (p[i] == '<')
+		    && ((p[i + 1] == lsp_mark1) || (p[i + 1] == lsp_mark2))) {
+
+			/* Opening tag way "<?" or "<%", closing tag must be the same. */
+			char lsp_mark_used = p[i + 1];
+
+			/* <?= var ?> or <%= var %> means a variable is enclosed and its
+			 * value should be printed */
+			if (0 == memcmp("lua", p + i + 1, 3)) {
+				/* Syntax: <?lua code ?> or <?lua= var ?> */
+				/* This is added for compatibility to other LSP syntax
+				 * definitions. */
+				/* Skip 3 letters ("lua"). */
+				i += 3;
+			}
 
-			/* <?= ?> means a variable is enclosed and its value should be
-			 * printed */
+			/* Check for '=' in "<?= ..." or "<%= ..." or "<?lua= ..." */
 			is_var = (((i + 2) < len) && (p[i + 2] == '='));
 
-			if (is_var)
+			if (is_var) {
+				/* use variable value (print it later) */
 				j = i + 2;
-			else
+			} else {
+				/* execute script code */
 				j = i + 1;
+			}
 
 			while (j < len) {
-				if (p[j] == '\n')
+
+				if (p[j] == '\n') {
+					/* Add line (for line number offset) */
 					lualines++;
-				if (((j + 1) < len) && (p[j] == '?') && (p[j + 1] == '>')) {
+				}
+
+				/* Check for closing tag. */
+				if (((j + 1) < len) && (p[j] == lsp_mark_used)
+				    && (p[j + 1] == '>')) {
+
+					/* There was a closing tag. Print everything before
+					 * the opening tag. */
 					mg_write(conn, p + pos, i - pos);
 
+					/* Set a name for debugging purposes */
 					mg_snprintf(conn,
-					            NULL, /* name only used for debugging */
+					            NULL, /* ignore truncation for debugging */
 					            chunkname,
 					            sizeof(chunkname),
 					            "@%s+%i",
 					            path,
 					            lines);
+
+					/* Prepare data for Lua C functions */
 					lua_pushlightuserdata(L, conn);
 					lua_pushcclosure(L, lsp_error, 1);
 
 					if (is_var) {
+						/* For variables: Print the value */
 						data.begin = p + (i + 3);
 						data.len = j - (i + 3);
 						data.state = 0;
 						lua_ok = mg_lua_load(
 						    L, lsp_var_reader, &data, chunkname, NULL);
 					} else {
+						/* For scripts: Execute them */
 						lua_ok = luaL_loadbuffer(L,
 						                         p + (i + 2),
 						                         j - (i + 2),
@@ -560,17 +606,23 @@ lsp_include(lua_State *L)
 	const char *path_type = (num_args >= 2) ? lua_tostring(L, 2) : NULL;
 	struct lsp_include_history *include_history;
 
-	if ((file_name) && (num_args <= 2)) {
+	if (path_type == NULL) {
+		/* default to "absolute" */
+		path_type = "a";
+	}
+
+	if ((file_name != NULL) && (num_args <= 2)) {
 
 		lua_pushlightuserdata(L, (void *)&lua_regkey_lsp_include_history);
 		lua_gettable(L, LUA_REGISTRYINDEX);
 		include_history = (struct lsp_include_history *)lua_touserdata(L, -1);
 
 		if (include_history->depth >= ((int)(LSP_INCLUDE_MAX_DEPTH))) {
-			mg_cry(conn,
-			       "lsp max include depth of %i reached while including %s",
-			       (int)(LSP_INCLUDE_MAX_DEPTH),
-			       file_name);
+			mg_cry_internal(
+			    conn,
+			    "lsp max include depth of %i reached while including %s",
+			    (int)(LSP_INCLUDE_MAX_DEPTH),
+			    file_name);
 		} else {
 			char file_name_path[512];
 			char *p;
@@ -579,18 +631,17 @@ lsp_include(lua_State *L)
 
 			file_name_path[511] = 0;
 
-			if (path_type && (*path_type == 'v')) {
+			if (*path_type == 'v') {
 				/* "virtual" = relative to document root. */
 				(void)mg_snprintf(conn,
 				                  &truncated,
 				                  file_name_path,
 				                  sizeof(file_name_path),
 				                  "%s/%s",
-				                  conn->ctx->config[DOCUMENT_ROOT],
+				                  conn->dom_ctx->config[DOCUMENT_ROOT],
 				                  file_name);
 
-			} else if ((path_type && (*path_type == 'a'))
-			           || (path_type == NULL)) {
+			} else if (*path_type == 'a') {
 				/* "absolute" = file name is relative to the
 				 * webserver working directory
 				 * or it is absolute system path. */
@@ -602,7 +653,7 @@ lsp_include(lua_State *L)
 				                  "%s",
 				                  file_name);
 
-			} else if (path_type && (*path_type == 'r' || *path_type == 'f')) {
+			} else if ((*path_type == 'r') || (*path_type == 'f')) {
 				/* "relative" = file name is relative to the
 				 * currect document */
 				(void)mg_snprintf(
@@ -634,7 +685,8 @@ lsp_include(lua_State *L)
 
 			if (handle_lsp_request(conn, file_name_path, &file, L)) {
 				/* handle_lsp_request returned an error code, meaning an error
-				* occured in the included page and mg.onerror returned non-zero.
+				* occurred in the included page and mg.onerror returned
+				* non-zero.
 				* Stop processing.
 				*/
 
@@ -660,7 +712,7 @@ lsp_cry(lua_State *L)
 	const char *text = (num_args == 1) ? lua_tostring(L, 1) : NULL;
 
 	if (text) {
-		mg_cry(conn, "%s", lua_tostring(L, -1));
+		mg_cry_internal(conn, "%s", lua_tostring(L, -1));
 	} else {
 		/* Syntax error */
 		return luaL_error(L, "invalid cry() call");
@@ -756,7 +808,7 @@ lsp_get_var(lua_State *L)
 			/* Variable found: return value to Lua */
 			lua_pushstring(L, dst);
 		} else {
-			/* Variable not found (TODO (mid): may be string too long) */
+			/* Variable not found */
 			lua_pushnil(L);
 		}
 		mg_free(dst);
@@ -774,18 +826,16 @@ lsp_get_mime_type(lua_State *L)
 {
 	int num_args = lua_gettop(L);
 	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);
+	struct mg_connection *conn =
+	    (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
 
 	if (num_args == 1) {
 		text = lua_tostring(L, 1);
 		if (text) {
-			if (ctx) {
-				get_mime_type(ctx, text, &mime_type);
+			if (conn) {
+				get_mime_type(conn, text, &mime_type);
 				lua_pushlstring(L, mime_type.ptr, mime_type.len);
 			} else {
 				text = mg_get_builtin_mime_type(text);
@@ -1061,8 +1111,9 @@ lsp_get_response_code_text(lua_State *L)
 			   convert it to the corresponding text. */
 			code = lua_tonumber(L, 1);
 			text = mg_get_response_code_text(NULL, (int)code);
-			if (text)
+			if (text) { /* <-- should be always true */
 				lua_pushstring(L, text);
+			}
 			return text ? 1 : 0;
 		}
 	}
@@ -1115,7 +1166,7 @@ lsp_get_info(lua_State *L)
 				/* Get system info */
 				len = mg_get_system_info(NULL, 0);
 				if (len > 0) {
-					buf = mg_malloc(len + 64);
+					buf = (char *)mg_malloc(len + 64);
 					if (!buf) {
 						return luaL_error(L, "OOM in get_info() call");
 					}
@@ -1137,7 +1188,7 @@ lsp_get_info(lua_State *L)
 				/* Get context info for server context */
 				len = mg_get_context_info(ctx, NULL, 0);
 				if (len > 0) {
-					buf = mg_malloc(len + 64);
+					buf = (char *)mg_malloc(len + 64);
 					if (!buf) {
 						return luaL_error(L, "OOM in get_info() call");
 					}
@@ -1153,7 +1204,7 @@ lsp_get_info(lua_State *L)
 				/* Get context info for NULL context */
 				len = mg_get_context_info(NULL, NULL, 0);
 				if (len > 0) {
-					buf = mg_malloc(len + 64);
+					buf = (char *)mg_malloc(len + 64);
 					if (!buf) {
 						return luaL_error(L, "OOM in get_info() call");
 					}
@@ -1178,6 +1229,7 @@ lsp_get_info(lua_State *L)
 
 			/* Get info according to argument */
 			if (!mg_strcasecmp(arg1, "connection")) {
+				int idx;
 
 				/* Get context */
 				struct mg_context *ctx;
@@ -1186,15 +1238,15 @@ lsp_get_info(lua_State *L)
 				ctx = (struct mg_context *)lua_touserdata(L, -1);
 
 				/* Get connection info for connection idx */
-				int idx = (int)(arg2 + 0.5);
+				idx = (int)(arg2 + 0.5);
 
 				/* Lua uses 1 based index, C uses 0 based index */
 				idx--;
 
-#ifdef MG_EXPERIMENTAL_INTERFACES
+#if defined(MG_EXPERIMENTAL_INTERFACES)
 				len = mg_get_connection_info(ctx, idx, NULL, 0);
 				if (len > 0) {
-					buf = mg_malloc(len + 64);
+					buf = (char *)mg_malloc(len + 64);
 					if (!buf) {
 						return luaL_error(L, "OOM in get_info() call");
 					}
@@ -1229,25 +1281,27 @@ lsp_get_option(lua_State *L)
 	int type1;
 	const char *arg1;
 	const char *data;
+	int optidx;
 
-	/* Get context */
-	struct mg_context *ctx;
-	lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
-	lua_gettable(L, LUA_REGISTRYINDEX);
-	ctx = (struct mg_context *)lua_touserdata(L, -1);
+	/* Get connection */
+	struct mg_connection *conn =
+	    (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
 
 	if (num_args == 0) {
 		const struct mg_option *opts = mg_get_valid_options();
 
-		if (!opts) {
+		if (!opts) { /* <-- should be always false */
 			return 0;
 		}
 
 		lua_newtable(L);
 		while (opts->name) {
-			data = mg_get_option(ctx, opts->name);
-			if (data) {
-				reg_string(L, opts->name, data);
+			optidx = get_option_index(opts->name);
+			if (optidx >= 0) {
+				data = conn->dom_ctx->config[optidx];
+				if (data) {
+					reg_string(L, opts->name, data);
+				}
 			}
 			opts++;
 		}
@@ -1260,10 +1314,13 @@ lsp_get_option(lua_State *L)
 		if (type1 == LUA_TSTRING) {
 			arg1 = lua_tostring(L, 1);
 			/* Get option according to argument */
-			data = mg_get_option(ctx, arg1);
-			if (data) {
-				lua_pushstring(L, data);
-				return 1;
+			optidx = get_option_index(arg1);
+			if (optidx >= 0) {
+				data = conn->dom_ctx->config[optidx];
+				if (data) {
+					lua_pushstring(L, data);
+					return 1;
+				}
 			}
 			return 0;
 		}
@@ -1329,7 +1386,7 @@ lsp_uuid(lua_State *L)
 }
 
 
-#ifdef USE_WEBSOCKET
+#if defined(USE_WEBSOCKET)
 struct lua_websock_data {
 	lua_State *state;
 	char *script;
@@ -1344,7 +1401,7 @@ struct lua_websock_data {
 static int
 lwebsock_write(lua_State *L)
 {
-#ifdef USE_WEBSOCKET
+#if defined(USE_WEBSOCKET)
 	int num_args = lua_gettop(L);
 	struct lua_websock_data *ws;
 	const char *str;
@@ -1362,7 +1419,7 @@ lwebsock_write(lua_State *L)
 	if (num_args == 1) {
 		/* just one text: send it to all client */
 		if (lua_isstring(L, 1)) {
-			opcode = WEBSOCKET_OPCODE_TEXT;
+			opcode = MG_WEBSOCKET_OPCODE_TEXT;
 		}
 	} else if (num_args == 2) {
 		if (lua_isnumber(L, 1)) {
@@ -1372,21 +1429,21 @@ lwebsock_write(lua_State *L)
 			/* opcode string and message text */
 			str = lua_tostring(L, 1);
 			if (!mg_strncasecmp(str, "text", 4))
-				opcode = WEBSOCKET_OPCODE_TEXT;
+				opcode = MG_WEBSOCKET_OPCODE_TEXT;
 			else if (!mg_strncasecmp(str, "bin", 3))
-				opcode = WEBSOCKET_OPCODE_BINARY;
+				opcode = MG_WEBSOCKET_OPCODE_BINARY;
 			else if (!mg_strncasecmp(str, "close", 5))
-				opcode = WEBSOCKET_OPCODE_CONNECTION_CLOSE;
+				opcode = MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE;
 			else if (!mg_strncasecmp(str, "ping", 4))
-				opcode = WEBSOCKET_OPCODE_PING;
+				opcode = MG_WEBSOCKET_OPCODE_PING;
 			else if (!mg_strncasecmp(str, "pong", 4))
-				opcode = WEBSOCKET_OPCODE_PONG;
+				opcode = MG_WEBSOCKET_OPCODE_PONG;
 			else if (!mg_strncasecmp(str, "cont", 4))
-				opcode = WEBSOCKET_OPCODE_CONTINUATION;
+				opcode = MG_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;
+			opcode = MG_WEBSOCKET_OPCODE_TEXT;
 		}
 	} else if (num_args == 3) {
 		if (lua_isuserdata(L, 1)) {
@@ -1398,17 +1455,17 @@ lwebsock_write(lua_State *L)
 				/* client id, opcode string and message text */
 				str = lua_tostring(L, 2);
 				if (!mg_strncasecmp(str, "text", 4))
-					opcode = WEBSOCKET_OPCODE_TEXT;
+					opcode = MG_WEBSOCKET_OPCODE_TEXT;
 				else if (!mg_strncasecmp(str, "bin", 3))
-					opcode = WEBSOCKET_OPCODE_BINARY;
+					opcode = MG_WEBSOCKET_OPCODE_BINARY;
 				else if (!mg_strncasecmp(str, "close", 5))
-					opcode = WEBSOCKET_OPCODE_CONNECTION_CLOSE;
+					opcode = MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE;
 				else if (!mg_strncasecmp(str, "ping", 4))
-					opcode = WEBSOCKET_OPCODE_PING;
+					opcode = MG_WEBSOCKET_OPCODE_PING;
 				else if (!mg_strncasecmp(str, "pong", 4))
-					opcode = WEBSOCKET_OPCODE_PONG;
+					opcode = MG_WEBSOCKET_OPCODE_PONG;
 				else if (!mg_strncasecmp(str, "cont", 4))
-					opcode = WEBSOCKET_OPCODE_CONTINUATION;
+					opcode = MG_WEBSOCKET_OPCODE_CONTINUATION;
 			}
 		}
 	}
@@ -1542,6 +1599,10 @@ lwebsocket_set_timer(lua_State *L, int is_periodic)
 		arg = (struct laction_arg *)mg_malloc_ctx(sizeof(struct laction_arg)
 		                                              + txt_len + 10,
 		                                          ctx);
+		if (!arg) {
+			return luaL_error(L, "out of memory");
+		}
+
 		arg->state = L;
 		arg->script = ws->script;
 		arg->pmutex = &(ws->ws_mutex);
@@ -1590,6 +1651,85 @@ lwebsocket_set_interval(lua_State *L)
 	return lwebsocket_set_timer(L, 1);
 }
 
+
+/* Debug hook */
+static void
+lua_debug_hook(lua_State *L, lua_Debug *ar)
+{
+	int i;
+	int stack_len = lua_gettop(L);
+
+	lua_getinfo(L, "nSlu", ar);
+
+	if (ar->event == LUA_HOOKCALL) {
+		printf("call\n");
+	} else if (ar->event == LUA_HOOKRET) {
+		printf("ret\n");
+#if defined(LUA_HOOKTAILRET)
+	} else if (ar->event == LUA_HOOKTAILRET) {
+		printf("tail ret\n");
+#endif
+#if defined(LUA_HOOKTAILCALL)
+	} else if (ar->event == LUA_HOOKTAILCALL) {
+		printf("tail call\n");
+#endif
+	} else if (ar->event == LUA_HOOKLINE) {
+		printf("line\n");
+	} else if (ar->event == LUA_HOOKCOUNT) {
+		printf("count\n");
+	} else {
+		printf("unknown (%i)\n", ar->event);
+	}
+
+	if (ar->currentline >= 0) {
+		printf("%s:%i\n", ar->source, ar->currentline);
+	}
+
+	printf("%s (%s)\n", ar->name, ar->namewhat);
+
+
+	for (i = 1; i <= stack_len; i++) { /* repeat for each level */
+		int val_type = lua_type(L, i);
+		const char *s;
+		size_t n;
+
+		switch (val_type) {
+
+		case LUA_TNIL:
+			/* nil value  on the stack */
+			printf("nil\n");
+			break;
+
+		case LUA_TBOOLEAN:
+			/* boolean (true / false) */
+			printf("boolean: %s\n", lua_toboolean(L, i) ? "true" : "false");
+			break;
+
+		case LUA_TNUMBER:
+			/* number */
+			printf("number: %g\n", lua_tonumber(L, i));
+			break;
+
+		case LUA_TSTRING:
+			/* string with limited length */
+			s = lua_tolstring(L, i, &n);
+			printf("string: '%.*s%s\n",
+			       (n > 30) ? 28 : s,
+			       (n > 30) ? ".." : "'");
+			break;
+
+		default:
+			/* other values */
+			printf("%s\n", lua_typename(L, val_type));
+			break;
+		}
+	}
+
+	printf("\n");
+}
+
+
+/* Lua Environment */
 enum {
 	LUA_ENV_TYPE_LUA_SERVER_PAGE = 0,
 	LUA_ENV_TYPE_PLAIN_LUA_PAGE = 1,
@@ -1611,12 +1751,6 @@ prepare_lua_request_info(struct mg_connection *conn, lua_State *L)
 	reg_string(L, "uri", conn->request_info.local_uri);
 	reg_string(L, "http_version", conn->request_info.http_version);
 	reg_string(L, "query_string", conn->request_info.query_string);
-#if defined(MG_LEGACY_INTERFACE)
-	reg_int(L, "remote_ip", conn->request_info.remote_ip); /* remote_ip is
-	                                                          deprecated, use
-	                                                          remote_addr
-	                                                          instead */
-#endif
 	reg_string(L, "remote_addr", conn->request_info.remote_addr);
 	/* TODO (high): ip version */
 	reg_int(L, "remote_port", conn->request_info.remote_port);
@@ -1673,34 +1807,24 @@ civetweb_open_lua_libs(lua_State *L)
 		luaL_openlibs(L);
 	}
 
-#ifdef USE_LUA_SQLITE3
+#if defined(USE_LUA_SQLITE3)
 	{
 		extern int luaopen_lsqlite3(lua_State *);
 		luaopen_lsqlite3(L);
 	}
 #endif
-#ifdef USE_LUA_LUAXML
+#if defined(USE_LUA_LUAXML)
 	{
 		extern int luaopen_LuaXML_lib(lua_State *);
 		luaopen_LuaXML_lib(L);
 	}
 #endif
-#ifdef USE_LUA_FILE_SYSTEM
+#if defined(USE_LUA_FILE_SYSTEM)
 	{
 		extern int luaopen_lfs(lua_State *);
 		luaopen_lfs(L);
 	}
 #endif
-#ifdef USE_LUA_BINARY
-	{
-		/* TODO (low): Test if this could be used as a replacement for bit32.
-		 * Check again with Lua 5.3 later. */
-		extern int luaopen_binary(lua_State *);
-
-		luaL_requiref(L, "binary", luaopen_binary, 1);
-		lua_pop(L, 1);
-	}
-#endif
 }
 
 
@@ -1712,8 +1836,18 @@ prepare_lua_environment(struct mg_context *ctx,
                         const char *script_name,
                         int lua_env_type)
 {
+	const char *preload_file_name = NULL;
+	const char *debug_params = NULL;
+
 	civetweb_open_lua_libs(L);
 
+#if defined(MG_EXPERIMENTAL_INTERFACES)
+	/* Check if debugging should be enabled */
+	if ((conn != NULL) && (conn->dom_ctx != NULL)) {
+		debug_params = conn->dom_ctx->config[LUA_DEBUG_PARAMS];
+	}
+#endif
+
 #if LUA_VERSION_NUM == 502
 	/* Keep the "connect" method for compatibility,
 	 * but do not backport it to Lua 5.1.
@@ -1781,16 +1915,18 @@ prepare_lua_environment(struct mg_context *ctx,
 
 	if (lua_env_type == LUA_ENV_TYPE_LUA_WEBSOCKET) {
 		reg_function(L, "write", lwebsock_write);
-#ifdef USE_TIMERS
+#if defined(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_conn_function(L, "get_mime_type", lsp_get_mime_type, conn);
+	reg_conn_function(L, "get_option", lsp_get_option, conn);
+
 	reg_function(L, "time", lsp_get_time);
 	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);
@@ -1800,7 +1936,6 @@ prepare_lua_environment(struct mg_context *ctx,
 	reg_function(L, "get_response_code_text", lsp_get_response_code_text);
 	reg_function(L, "random", lsp_random);
 	reg_function(L, "get_info", lsp_get_info);
-	reg_function(L, "get_option", lsp_get_option);
 
 	if (pf_uuid_generate.f) {
 		reg_function(L, "uuid", lsp_uuid);
@@ -1810,18 +1945,24 @@ prepare_lua_environment(struct mg_context *ctx,
 
 	reg_string(L, "script_name", script_name);
 
-	if (ctx != NULL) {
-		reg_string(L, "document_root", ctx->config[DOCUMENT_ROOT]);
-		reg_string(L, "auth_domain", ctx->config[AUTHENTICATION_DOMAIN]);
+	if ((conn != NULL) && (conn->dom_ctx != NULL)) {
+		reg_string(L, "document_root", conn->dom_ctx->config[DOCUMENT_ROOT]);
+		reg_string(L,
+		           "auth_domain",
+		           conn->dom_ctx->config[AUTHENTICATION_DOMAIN]);
 #if defined(USE_WEBSOCKET)
-		if (ctx->config[WEBSOCKET_ROOT]) {
-			reg_string(L, "websocket_root", ctx->config[WEBSOCKET_ROOT]);
+		if (conn->dom_ctx->config[WEBSOCKET_ROOT]) {
+			reg_string(L,
+			           "websocket_root",
+			           conn->dom_ctx->config[WEBSOCKET_ROOT]);
 		} else {
-			reg_string(L, "websocket_root", ctx->config[DOCUMENT_ROOT]);
+			reg_string(L,
+			           "websocket_root",
+			           conn->dom_ctx->config[DOCUMENT_ROOT]);
 		}
 #endif
 
-		if (ctx->systemName != NULL) {
+		if ((ctx != NULL) && (ctx->systemName != NULL)) {
 			reg_string(L, "system", ctx->systemName);
 		}
 	}
@@ -1839,16 +1980,37 @@ prepare_lua_environment(struct mg_context *ctx,
 	                  "mg.onerror = function(e) mg.write('\\nLua error:\\n', "
 	                  "debug.traceback(e, 1)) end"));
 
-	if (ctx != NULL) {
-		/* Preload */
-		if (ctx->config[LUA_PRELOAD_FILE] != NULL) {
-			IGNORE_UNUSED_RESULT(luaL_dofile(L, ctx->config[LUA_PRELOAD_FILE]));
-		}
+	/* Check if a preload file is available */
+	if ((conn != NULL) && (conn->dom_ctx != NULL)) {
+		preload_file_name = conn->dom_ctx->config[LUA_PRELOAD_FILE];
+	}
+
+	/* Preload file into new Lua environment */
+	if (preload_file_name) {
+		IGNORE_UNUSED_RESULT(luaL_dofile(L, preload_file_name));
+	}
 
+	/* Call user init function */
+	if (ctx != NULL) {
 		if (ctx->callbacks.init_lua != NULL) {
 			ctx->callbacks.init_lua(conn, L);
 		}
 	}
+
+	/* If debugging is enabled, add a hook */
+	if (debug_params) {
+		int mask = 0;
+		if (0 != strchr(debug_params, "c")) {
+			mask |= LUA_MASKCALL;
+		}
+		if (0 != strchr(debug_params, "r")) {
+			mask |= LUA_MASKRET;
+		}
+		if (0 != strchr(debug_params, "l")) {
+			mask |= LUA_MASKLINE;
+		}
+		lua_sethook(L, lua_debug_hook, mask, 0);
+	}
 }
 
 
@@ -1903,9 +2065,10 @@ mg_exec_lua_script(struct mg_connection *conn,
 
 	/* Execute a plain Lua script. */
 	if (path != NULL
-	    && (L = lua_newstate(lua_allocator, (void *)(conn->ctx))) != NULL) {
+	    && (L = lua_newstate(lua_allocator, (void *)(conn->phys_ctx)))
+	           != NULL) {
 		prepare_lua_environment(
-		    conn->ctx, conn, NULL, L, path, LUA_ENV_TYPE_PLAIN_LUA_PAGE);
+		    conn->phys_ctx, conn, NULL, L, path, LUA_ENV_TYPE_PLAIN_LUA_PAGE);
 		lua_pushcclosure(L, &lua_error_handler, 0);
 
 		if (exports != NULL) {
@@ -1947,6 +2110,7 @@ handle_lsp_request(struct mg_connection *conn,
 	lua_State *L = NULL;
 	struct lsp_include_history *include_history;
 	int error = 1;
+	void *file_in_memory; /* TODO(low): remove when removing "file in memory" */
 
 	/* Assume the script does not support keep_alive. The script may change this
 	 * by calling mg.keep_alive(true). */
@@ -1968,8 +2132,16 @@ handle_lsp_request(struct mg_connection *conn,
 		goto cleanup_handle_lsp_request;
 	}
 
+#if defined(MG_USE_OPEN_FILE)
+	/* The "file in memory" feature is going to be removed. For details see
+	 * https://groups.google.com/forum/#!topic/civetweb/h9HT4CmeYqI */
+	file_in_memory = filep->access.membuf;
+#else
+	file_in_memory = NULL;
+#endif
+
 	/* Map file in memory (size is known). */
-	if (filep->access.membuf == NULL
+	if (file_in_memory == NULL
 	    && (p = mmap(NULL,
 	                 (size_t)filep->stat.size,
 	                 PROT_READ,
@@ -1999,7 +2171,7 @@ handle_lsp_request(struct mg_connection *conn,
 	if (ls != NULL) {
 		L = ls;
 	} else {
-		L = lua_newstate(lua_allocator, (void *)(conn->ctx));
+		L = lua_newstate(lua_allocator, (void *)(conn->phys_ctx));
 		if (L == NULL) {
 			mg_send_http_error(
 			    conn,
@@ -2010,7 +2182,7 @@ handle_lsp_request(struct mg_connection *conn,
 			goto cleanup_handle_lsp_request;
 		}
 		prepare_lua_environment(
-		    conn->ctx, conn, NULL, L, path, LUA_ENV_TYPE_LUA_SERVER_PAGE);
+		    conn->phys_ctx, conn, NULL, L, path, LUA_ENV_TYPE_LUA_SERVER_PAGE);
 	}
 
 	/* Get LSP include history table */
@@ -2026,9 +2198,8 @@ handle_lsp_request(struct mg_connection *conn,
 	/* We're not sending HTTP headers here, Lua page must do it. */
 	error = run_lsp(conn,
 	                path,
-	                (filep->access.membuf == NULL)
-	                    ? (const char *)p
-	                    : (const char *)filep->access.membuf,
+	                (file_in_memory == NULL) ? (const char *)p
+	                                         : (const char *)file_in_memory,
 	                filep->stat.size,
 	                L);
 
@@ -2044,7 +2215,7 @@ cleanup_handle_lsp_request:
 }
 
 
-#ifdef USE_WEBSOCKET
+#if defined(USE_WEBSOCKET)
 struct mg_shared_lua_websocket_list {
 	struct lua_websock_data ws;
 	struct mg_shared_lua_websocket_list *next;
@@ -2055,14 +2226,14 @@ static void *
 lua_websocket_new(const char *script, struct mg_connection *conn)
 {
 	struct mg_shared_lua_websocket_list **shared_websock_list =
-	    &(conn->ctx->shared_lua_websockets);
+	    &(conn->dom_ctx->shared_lua_websockets);
 	struct lua_websock_data *ws;
 	int err, ok = 0;
 
-	assert(conn->lua_websocket_state == NULL);
+	DEBUG_ASSERT(conn->lua_websocket_state == NULL);
 
 	/* lock list (mg_context global) */
-	mg_lock_context(conn->ctx);
+	mg_lock_context(conn->phys_ctx);
 	while (*shared_websock_list) {
 		/* check if ws already in list */
 		if (0 == strcmp(script, (*shared_websock_list)->ws.script)) {
@@ -2075,22 +2246,37 @@ lua_websocket_new(const char *script, struct mg_connection *conn)
 		/* add ws to list */
 		*shared_websock_list =
 		    (struct mg_shared_lua_websocket_list *)mg_calloc_ctx(
-		        sizeof(struct mg_shared_lua_websocket_list), 1, conn->ctx);
+		        sizeof(struct mg_shared_lua_websocket_list), 1, conn->phys_ctx);
 		if (*shared_websock_list == NULL) {
-			mg_unlock_context(conn->ctx);
-			mg_cry(conn, "Cannot create shared websocket struct, OOM");
+			conn->must_close = 1;
+			mg_unlock_context(conn->phys_ctx);
+			mg_cry_internal(conn,
+			                "%s",
+			                "Cannot create shared websocket struct, OOM");
 			return NULL;
 		}
 		/* init ws list element */
 		ws = &(*shared_websock_list)->ws;
-		ws->script = mg_strdup(script); /* TODO (low): handle OOM */
+		ws->script = mg_strdup_ctx(script, conn->phys_ctx);
+		if (!ws->script) {
+			conn->must_close = 1;
+			mg_unlock_context(conn->phys_ctx);
+			mg_cry_internal(conn,
+			                "%s",
+			                "Cannot create shared websocket script, OOM");
+			return NULL;
+		}
 		pthread_mutex_init(&(ws->ws_mutex), &pthread_mutex_attr);
 		(void)pthread_mutex_lock(&(ws->ws_mutex));
-		ws->state = lua_newstate(lua_allocator, (void *)(conn->ctx));
+		ws->state = lua_newstate(lua_allocator, (void *)(conn->phys_ctx));
 		ws->conn[0] = conn;
 		ws->references = 1;
-		prepare_lua_environment(
-		    conn->ctx, NULL, ws, ws->state, script, LUA_ENV_TYPE_LUA_WEBSOCKET);
+		prepare_lua_environment(conn->phys_ctx,
+		                        conn,
+		                        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");
@@ -2105,7 +2291,7 @@ lua_websocket_new(const char *script, struct mg_connection *conn)
 		(void)pthread_mutex_lock(&(ws->ws_mutex));
 		(*shared_websock_list)->ws.conn[(ws->references)++] = conn;
 	}
-	mg_unlock_context(conn->ctx);
+	mg_unlock_context(conn->phys_ctx);
 
 	/* call add */
 	lua_getglobal(ws->state, "open");
@@ -2147,8 +2333,8 @@ lua_websocket_data(struct mg_connection *conn,
 	struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
 	int err, ok = 0;
 
-	assert(ws != NULL);
-	assert(ws->state != NULL);
+	DEBUG_ASSERT(ws != NULL);
+	DEBUG_ASSERT(ws->state != NULL);
 
 	(void)pthread_mutex_lock(&(ws->ws_mutex));
 
@@ -2188,8 +2374,8 @@ lua_websocket_ready(struct mg_connection *conn, void *ws_arg)
 	struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
 	int err, ok = 0;
 
-	assert(ws != NULL);
-	assert(ws->state != NULL);
+	DEBUG_ASSERT(ws != NULL);
+	DEBUG_ASSERT(ws->state != NULL);
 
 	(void)pthread_mutex_lock(&(ws->ws_mutex));
 
@@ -2219,12 +2405,12 @@ lua_websocket_close(struct mg_connection *conn, void *ws_arg)
 {
 	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);
+	    &(conn->dom_ctx->shared_lua_websockets);
 	int err = 0;
 	unsigned i;
 
-	assert(ws != NULL);
-	assert(ws->state != NULL);
+	DEBUG_ASSERT(ws != NULL);
+	DEBUG_ASSERT(ws->state != NULL);
 
 	(void)pthread_mutex_lock(&(ws->ws_mutex));
 

+ 125 - 0
src/mod_zlib.inl

@@ -0,0 +1,125 @@
+/* Experimental implementation for on-the-fly compression */
+#if !defined(USE_ZLIB)
+#error "This file must only be included, if USE_ZLIB is set"
+#endif
+
+#include "zconf.h"
+#include "zlib.h"
+
+#if !defined(MEM_LEVEL)
+#define MEM_LEVEL (8)
+#endif
+
+static void *
+zalloc(void *opaque, uInt items, uInt size)
+{
+	struct mg_connection *conn = (struct mg_connection *)opaque;
+	void *ret = mg_calloc_ctx(items, size, conn->phys_ctx);
+
+	return ret;
+}
+
+
+static void
+zfree(void *opaque, void *address)
+{
+	struct mg_connection *conn = (struct mg_connection *)opaque;
+	(void)conn; /* not required */
+
+	mg_free(address);
+}
+
+
+static void
+send_compressed_data(struct mg_connection *conn, struct mg_file *filep)
+{
+
+	int zret;
+	z_stream zstream;
+	int do_flush;
+	unsigned bytes_avail;
+	unsigned char in_buf[MG_BUF_LEN];
+	unsigned char out_buf[MG_BUF_LEN];
+	FILE *in_file = filep->access.fp;
+
+	/* Prepare state buffer. User server context memory allocation. */
+	memset(&zstream, 0, sizeof(zstream));
+	zstream.zalloc = zalloc;
+	zstream.zfree = zfree;
+	zstream.opaque = (void *)conn;
+
+	/* Initialize for GZIP compression (MAX_WBITS | 16) */
+	zret = deflateInit2(&zstream,
+	                    Z_BEST_COMPRESSION,
+	                    Z_DEFLATED,
+	                    MAX_WBITS | 16,
+	                    MEM_LEVEL,
+	                    Z_DEFAULT_STRATEGY);
+
+	if (zret != Z_OK) {
+		mg_cry_internal(conn,
+		                "GZIP init failed (%i): %s",
+		                zret,
+		                (zstream.msg ? zstream.msg : "<no error message>"));
+		deflateEnd(&zstream);
+		return;
+	}
+
+	/* Read until end of file */
+	do {
+		zstream.avail_in = fread(in_buf, 1, MG_BUF_LEN, in_file);
+		if (ferror(in_file)) {
+			mg_cry_internal(conn, "fread failed: %s", strerror(ERRNO));
+			(void)deflateEnd(&zstream);
+			return;
+		}
+
+		do_flush = (feof(in_file) ? Z_FINISH : Z_NO_FLUSH);
+		zstream.next_in = in_buf;
+
+		/* run deflate() on input until output buffer not full, finish
+		 * compression if all of source has been read in */
+		do {
+			zstream.avail_out = MG_BUF_LEN;
+			zstream.next_out = out_buf;
+			zret = deflate(&zstream, do_flush);
+
+			if (zret == Z_STREAM_ERROR) {
+				/* deflate error */
+				zret = -97;
+				break;
+			}
+
+			bytes_avail = MG_BUF_LEN - zstream.avail_out;
+
+			if (mg_send_chunk(conn, (char *)out_buf, bytes_avail) < 0) {
+				zret = -98;
+				break;
+			}
+
+		} while (zstream.avail_out == 0);
+
+		if (zret < -90) {
+			/* Forward write error */
+			break;
+		}
+
+		if (zstream.avail_in != 0) {
+			/* all input will be used, otherwise GZIP is incomplete */
+			zret = -99;
+			break;
+		}
+
+		/* done when last data in file processed */
+	} while (do_flush != Z_FINISH);
+
+	if (zret != Z_STREAM_END) {
+		/* Error: We did not compress everything. */
+		mg_cry_internal(conn,
+		                "GZIP incomplete (%i): %s",
+		                zret,
+		                (zstream.msg ? zstream.msg : "<no error message>"));
+	}
+
+	deflateEnd(&zstream);
+}

+ 4 - 3
src/sha1.inl

@@ -122,9 +122,10 @@ blk0(CHAR64LONG16 *block, int i)
 }
 
 #define blk(block, i)                                                          \
-	(block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15]   \
-	                            ^ block->l[(i + 2) & 15] ^ block->l[i & 15],   \
-	                        1))
+	((block)->l[(i)&15] =                                                      \
+	     rol((block)->l[((i) + 13) & 15] ^ (block)->l[((i) + 8) & 15]          \
+	             ^ (block)->l[((i) + 2) & 15] ^ (block)->l[(i)&15],            \
+	         1))
 
 /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
 #define R0(v, w, x, y, z, i)                                                   \

+ 8 - 2
src/third_party/lsqlite3.c

@@ -2373,6 +2373,12 @@ static void create_meta(lua_State *L, const char *name, const luaL_Reg *lib) {
     lua_pop(L, 1);
 }
 
+static int luaopen_sqlitelib (lua_State *L) {
+    luaL_newlibtable(L, sqlitelib);
+    luaL_setfuncs(L, sqlitelib, 0);
+    return 1;
+}
+
 LUALIB_API int luaopen_lsqlite3(lua_State *L) {
     create_meta(L, sqlite_meta, dblib);
     create_meta(L, sqlite_vm_meta, vmlib);
@@ -2382,8 +2388,8 @@ LUALIB_API int luaopen_lsqlite3(lua_State *L) {
     luaL_getmetatable(L, sqlite_ctx_meta);
     sqlite_ctx_meta_ref = luaL_ref(L, LUA_REGISTRYINDEX);
 
-    /* register (local) sqlite metatable */
-    luaL_register(L, "sqlite3", sqlitelib);
+    /* register global sqlite3 library */
+    luaL_requiref(L, "sqlite3", luaopen_sqlitelib, 1);
 
     {
         int i = 0;

TEMPAT SAMPAH
src/third_party/lua-5.3.3/doc/logo.gif


+ 1 - 1
src/third_party/lua-5.3.3/Makefile → src/third_party/lua-5.3.4/Makefile

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

+ 1 - 1
src/third_party/lua-5.3.3/README → src/third_party/lua-5.3.4/README

@@ -1,5 +1,5 @@
 
-This is Lua 5.3.3, released on 30 May 2016.
+This is Lua 5.3.4, released on 12 Jan 2017.
 
 For installation instructions, license details, and
 further information about Lua, see doc/readme.html.

+ 4 - 3
src/third_party/lua-5.3.3/doc/contents.html → src/third_party/lua-5.3.4/doc/contents.html

@@ -32,7 +32,7 @@ For a complete introduction to Lua programming, see the book
 
 <P>
 <SMALL>
-Copyright &copy; 2015&ndash;2016 Lua.org, PUC-Rio.
+Copyright &copy; 2015&ndash;2017 Lua.org, PUC-Rio.
 Freely available under the terms of the
 <A HREF="http://www.lua.org/license.html">Lua license</A>.
 </SMALL>
@@ -512,6 +512,7 @@ Freely available under the terms of the
 <A HREF="manual.html#luaL_newmetatable">luaL_newmetatable</A><BR>
 <A HREF="manual.html#luaL_newstate">luaL_newstate</A><BR>
 <A HREF="manual.html#luaL_openlibs">luaL_openlibs</A><BR>
+<A HREF="manual.html#luaL_opt">luaL_opt</A><BR>
 <A HREF="manual.html#luaL_optinteger">luaL_optinteger</A><BR>
 <A HREF="manual.html#luaL_optlstring">luaL_optlstring</A><BR>
 <A HREF="manual.html#luaL_optnumber">luaL_optnumber</A><BR>
@@ -608,10 +609,10 @@ Freely available under the terms of the
 
 <P CLASS="footer">
 Last update:
-Thu Jan 14 10:14:28 BRST 2016
+Thu Dec 22 18:29:39 BRST 2016
 </P>
 <!--
-Last change: revised for Lua 5.3.3
+Last change: revised for Lua 5.3.4
 -->
 
 </BODY>

+ 0 - 0
src/third_party/lua-5.3.3/doc/index.css → src/third_party/lua-5.3.4/doc/index.css


TEMPAT SAMPAH
src/third_party/lua-5.3.4/doc/logo.gif


+ 2 - 1
src/third_party/lua-5.3.3/doc/lua.1 → src/third_party/lua-5.3.4/doc/lua.1

@@ -1,4 +1,5 @@
-.TH LUA 1 "$Date: 2014/12/10 15:55:45 $"
+.\" $Id: lua.man,v 1.14 2016/10/17 15:43:50 lhf Exp $
+.TH LUA 1 "$Date: 2016/10/17 15:43:50 $"
 .SH NAME
 lua \- Lua interpreter
 .SH SYNOPSIS

+ 0 - 0
src/third_party/lua-5.3.3/doc/lua.css → src/third_party/lua-5.3.4/doc/lua.css


+ 0 - 0
src/third_party/lua-5.3.3/doc/luac.1 → src/third_party/lua-5.3.4/doc/luac.1


+ 0 - 0
src/third_party/lua-5.3.3/doc/manual.css → src/third_party/lua-5.3.4/doc/manual.css


+ 173 - 98
src/third_party/lua-5.3.3/doc/manual.html → src/third_party/lua-5.3.4/doc/manual.html

@@ -19,7 +19,7 @@ by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
 
 <P>
 <SMALL>
-Copyright &copy; 2015&ndash;2016 Lua.org, PUC-Rio.
+Copyright &copy; 2015&ndash;2017 Lua.org, PUC-Rio.
 Freely available under the terms of the
 <a href="http://www.lua.org/license.html">Lua license</a>.
 </SMALL>
@@ -35,7 +35,7 @@ Freely available under the terms of the
 <!-- ====================================================================== -->
 <p>
 
-<!-- $Id: manual.of,v 1.162 2016/05/30 15:57:03 roberto Exp $ -->
+<!-- $Id: manual.of,v 1.167 2017/01/09 15:18:11 roberto Exp $ -->
 
 
 
@@ -216,7 +216,7 @@ an associated value <b>nil</b>.
 
 <p>
 Tables are the sole data-structuring mechanism in Lua;
-they can be used to represent ordinary arrays, sequences,
+they can be used to represent ordinary arrays, lists,
 symbol tables, sets, records, graphs, trees, etc.
 To represent records, Lua uses the field name as an index.
 The language supports this representation by
@@ -226,13 +226,6 @@ There are several convenient ways to create tables in Lua
 
 
 <p>
-We use the term <em>sequence</em> to denote a table where
-the set of all positive numeric keys is equal to {1..<em>n</em>}
-for some non-negative integer <em>n</em>,
-which is called the length of the sequence (see <a href="#3.4.7">&sect;3.4.7</a>).
-
-
-<p>
 Like indices,
 the values of table fields can be of any type.
 In particular,
@@ -378,6 +371,9 @@ so, an error inside the message handler
 will call the message handler again.
 If this loop goes on for too long,
 Lua breaks it and returns an appropriate message.
+(The message handler is called only for regular runtime errors.
+It is not called for memory-allocation errors
+nor for errors while running finalizers.)
 
 
 
@@ -873,7 +869,7 @@ before the change takes effect.
 <p>
 Only objects that have an explicit construction
 are removed from weak tables.
-Values, such as numbers and light C functions,
+Values, such as numbers and light C&nbsp;functions,
 are not subject to garbage collection,
 and therefore are not removed from weak tables
 (unless their associated values are collected).
@@ -1084,7 +1080,7 @@ Lua is a case-sensitive language:
 <code>and</code> is a reserved word, but <code>And</code> and <code>AND</code>
 are two different, valid names.
 As a convention,
-programs should avoid creating 
+programs should avoid creating
 names that start with an underscore followed by
 one or more uppercase letters (such as <a href="#pdf-_VERSION"><code>_VERSION</code></a>).
 
@@ -1101,7 +1097,7 @@ The following strings denote other tokens:
 </pre>
 
 <p>
-<em>Literal strings</em>
+A <em>short literal string</em>
 can be delimited by matching single or double quotes,
 and can contain the following C-like escape sequences:
 '<code>\a</code>' (bell),
@@ -1114,7 +1110,7 @@ and can contain the following C-like escape sequences:
 '<code>\\</code>' (backslash),
 '<code>\"</code>' (quotation mark [double quote]),
 and '<code>\'</code>' (apostrophe [single quote]).
-A backslash followed by a real newline
+A backslash followed by a line break
 results in a newline in the string.
 The escape sequence '<code>\z</code>' skips the following span
 of white-space characters,
@@ -1122,13 +1118,13 @@ including line breaks;
 it is particularly useful to break and indent a long literal string
 into multiple lines without adding the newlines and spaces
 into the string contents.
+A short literal string cannot contain unescaped line breaks
+nor escapes not forming a valid escape sequence.
 
 
 <p>
-Strings in Lua can contain any 8-bit value, including embedded zeros,
-which can be specified as '<code>\0</code>'.
-More generally,
-we can specify any byte in a literal string by its numeric value.
+We can specify any byte in a short literal string by its numeric value
+(including embedded zeros).
 This can be done
 with the escape sequence <code>\x<em>XX</em></code>,
 where <em>XX</em> is a sequence of exactly two hexadecimal digits,
@@ -1172,17 +1168,6 @@ is converted to a simple newline.
 
 
 <p>
-Any byte in a literal string not
-explicitly affected by the previous rules represents itself.
-However, Lua opens files for parsing in text mode,
-and the system file functions may have problems with
-some control characters.
-So, it is safer to represent
-non-text data as a quoted literal with
-explicit escape sequences for the non-text characters.
-
-
-<p>
 For convenience,
 when the opening long bracket is immediately followed by a newline,
 the newline is not included in the string.
@@ -1203,6 +1188,17 @@ the five literal strings below denote the same string:
 </pre>
 
 <p>
+Any byte in a literal string not
+explicitly affected by the previous rules represents itself.
+However, Lua opens files for parsing in text mode,
+and the system file functions may have problems with
+some control characters.
+So, it is safer to represent
+non-text data as a quoted literal with
+explicit escape sequences for the non-text characters.
+
+
+<p>
 A <em>numeric constant</em> (or <em>numeral</em>)
 can be written with an optional fractional part
 and an optional decimal exponent,
@@ -1212,7 +1208,7 @@ which start with <code>0x</code> or <code>0X</code>.
 Hexadecimal constants also accept an optional fractional part
 plus an optional binary exponent,
 marked by a letter '<code>p</code>' or '<code>P</code>'.
-A numeric constant with a radix point or an exponent 
+A numeric constant with a radix point or an exponent
 denotes a float;
 otherwise,
 if its value fits in an integer,
@@ -1897,7 +1893,7 @@ so that it works for non-integer exponents too.
 
 
 <p>
-Floor division (<code>//</code>) is a division 
+Floor division (<code>//</code>) is a division
 that rounds the quotient towards minus infinity,
 that is, the floor of the division of its operands.
 
@@ -1959,7 +1955,7 @@ this is called the <em>usual rule</em>.
 The C API also converts both integers to floats and
 floats to integers, as needed.
 Moreover, string concatenation accepts numbers as arguments,
-besides strings. 
+besides strings.
 
 
 <p>
@@ -1997,7 +1993,7 @@ is converted to the type (float or integer) required by the context
 
 
 <p>
-All conversions from strings to numbers 
+All conversions from strings to numbers
 accept both a dot and the current locale mark
 as the radix character.
 (The Lua lexer, however, accepts only a dot.)
@@ -2140,37 +2136,66 @@ Otherwise, the <code>__concat</code> metamethod is called (see <a href="#2.4">&s
 
 <p>
 The length operator is denoted by the unary prefix operator <code>#</code>.
-The length of a string is its number of bytes
-(that is, the usual meaning of string length when each
-character is one byte).
 
 
 <p>
-A program can modify the behavior of the length operator for
-any value but strings through the <code>__len</code> metamethod (see <a href="#2.4">&sect;2.4</a>).
+The length of a string is its number of bytes
+(that is, the usual meaning of string length when each
+character is one byte).
 
 
 <p>
-Unless a <code>__len</code> metamethod is given,
-the length of a table <code>t</code> is only defined if the
-table is a <em>sequence</em>,
-that is,
-the set of its positive numeric keys is equal to <em>{1..n}</em>
-for some non-negative integer <em>n</em>.
-In that case, <em>n</em> is its length.
-Note that a table like
+The length operator applied on a table
+returns a border in that table.
+A <em>border</em> in a table <code>t</code> is any natural number
+that satisfies the following condition:
 
 <pre>
-     {10, 20, nil, 40}
+     (border == 0 or t[border] ~= nil) and t[border + 1] == nil
 </pre><p>
-is not a sequence, because it has the key <code>4</code>
-but does not have the key <code>3</code>.
-(So, there is no <em>n</em> such that the set <em>{1..n}</em> is equal
-to the set of positive numeric keys of that table.)
-Note, however, that non-numeric keys do not interfere
+In words,
+a border is any (natural) index in a table
+where a non-nil value is followed by a nil value
+(or zero, when index 1 is nil).
+
+
+<p>
+A table with exactly one border is called a <em>sequence</em>.
+For instance, the table <code>{10, 20, 30, 40, 50}</code> is a sequence,
+as it has only one border (5).
+The table <code>{10, 20, 30, nil, 50}</code> has two borders (3 and 5),
+and therefore it is not a sequence.
+The table <code>{nil, 20, 30, nil, nil, 60, nil}</code>
+has three borders (0, 3, and 6),
+so it is not a sequence, too.
+The table <code>{}</code> is a sequence with border 0.
+Note that non-natural keys do not interfere
 with whether a table is a sequence.
 
 
+<p>
+When <code>t</code> is a sequence,
+<code>#t</code> returns its only border,
+which corresponds to the intuitive notion of the length of the sequence.
+When <code>t</code> is not a sequence,
+<code>#t</code> can return any of its borders.
+(The exact one depends on details of
+the internal representation of the table,
+which in turn can depend on how the table was populated and
+the memory addresses of its non-numeric keys.)
+
+
+<p>
+The computation of the length of a table
+has a guaranteed worst time of <em>O(log n)</em>,
+where <em>n</em> is the largest natural key in the table.
+
+
+<p>
+A program can modify the behavior of the length operator for
+any value but strings through the <code>__len</code> metamethod (see <a href="#2.4">&sect;2.4</a>).
+
+
 
 
 
@@ -2585,6 +2610,28 @@ However, you can change this behavior by compiling Lua
 with the macro <a name="pdf-LUA_USE_APICHECK"><code>LUA_USE_APICHECK</code></a> defined.
 
 
+<p>
+The Lua library is fully reentrant:
+it has no global variables.
+It keeps all information it needs in a dynamic structure,
+called the <em>Lua state</em>.
+
+
+<p>
+Each Lua state has one or more threads,
+which correspond to independent, cooperative lines of execution.
+The type <a href="#lua_State"><code>lua_State</code></a> (despite its name) refers to a thread.
+(Indirectly, through the thread, it also refers to the
+Lua state associated to the thread.)
+
+
+<p>
+A pointer to a thread must be passed as the first argument to
+every function in the library, except to <a href="#lua_newstate"><code>lua_newstate</code></a>,
+which creates a Lua state from scratch and returns a pointer
+to the <em>main thread</em> in the new state.
+
+
 
 <h2>4.1 &ndash; <a name="4.1">The Stack</a></h2>
 
@@ -2592,6 +2639,8 @@ with the macro <a name="pdf-LUA_USE_APICHECK"><code>LUA_USE_APICHECK</code></a>
 Lua uses a <em>virtual stack</em> to pass values to and from C.
 Each element in this stack represents a Lua value
 (<b>nil</b>, number, string, etc.).
+Functions in the API can access this stack through the
+Lua state parameter that they receive.
 
 
 <p>
@@ -2599,7 +2648,8 @@ Whenever Lua calls C, the called function gets a new stack,
 which is independent of previous stacks and of stacks of
 C&nbsp;functions that are still active.
 This stack initially contains any arguments to the C&nbsp;function
-and it is where the C&nbsp;function pushes its results
+and it is where the C&nbsp;function can store temporary
+Lua values and must push its results
 to be returned to the caller (see <a href="#lua_CFunction"><code>lua_CFunction</code></a>).
 
 
@@ -2791,8 +2841,7 @@ Internally, Lua uses the C <code>longjmp</code> facility to handle errors.
 (Lua will use exceptions if you compile it as C++;
 search for <code>LUAI_THROW</code> in the source code for details.)
 When Lua faces any error
-(such as a memory allocation error, type errors, syntax errors,
-and runtime errors)
+(such as a memory allocation error or a type error)
 it <em>raises</em> an error;
 that is, it does a long jump.
 A <em>protected environment</em> uses <code>setjmp</code>
@@ -2801,6 +2850,17 @@ any error jumps to the most recent active recovery point.
 
 
 <p>
+Inside a C&nbsp;function you can raise an error by calling <a href="#lua_error"><code>lua_error</code></a>.
+
+
+<p>
+Most functions in the API can raise an error,
+for instance due to a memory allocation error.
+The documentation for each function indicates whether
+it can raise errors.
+
+
+<p>
 If an error happens outside any protected environment,
 Lua calls a <em>panic function</em> (see <a href="#lua_atpanic"><code>lua_atpanic</code></a>)
 and then calls <code>abort</code>,
@@ -2811,6 +2871,23 @@ never returning
 
 
 <p>
+The panic function,
+as its name implies,
+is a mechanism of last resort.
+Programs should avoid it.
+As a general rule,
+when a C&nbsp;function is called by Lua with a Lua state,
+it can do whatever it wants on that Lua state,
+as it should be already protected.
+However,
+when C code operates on other Lua states
+(e.g., a Lua parameter to the function,
+a Lua state stored in the registry, or
+the result of <a href="#lua_newthread"><code>lua_newthread</code></a>),
+it should use them only in API calls that cannot raise errors.
+
+
+<p>
 The panic function runs as if it were a message handler (see <a href="#2.3">&sect;2.3</a>);
 in particular, the error object is at the top of the stack.
 However, there is no guarantee about stack space.
@@ -2818,17 +2895,6 @@ To push anything on the stack,
 the panic function must first check the available space (see <a href="#4.2">&sect;4.2</a>).
 
 
-<p>
-Most functions in the API can raise an error,
-for instance due to a memory allocation error.
-The documentation for each function indicates whether
-it can raise errors.
-
-
-<p>
-Inside a C&nbsp;function you can raise an error by calling <a href="#lua_error"><code>lua_error</code></a>.
-
-
 
 
 
@@ -2836,7 +2902,7 @@ Inside a C&nbsp;function you can raise an error by calling <a href="#lua_error">
 
 <p>
 Internally, Lua uses the C <code>longjmp</code> facility to yield a coroutine.
-Therefore, if a C function <code>foo</code> calls an API function
+Therefore, if a C&nbsp;function <code>foo</code> calls an API function
 and this API function yields
 (directly or indirectly by calling another function that yields),
 Lua cannot return to <code>foo</code> any more,
@@ -2854,7 +2920,7 @@ All those functions receive a <em>continuation function</em>
 
 <p>
 We need to set some terminology to explain continuations.
-We have a C function called from Lua which we will call
+We have a C&nbsp;function called from Lua which we will call
 the <em>original function</em>.
 This original function then calls one of those three functions in the C API,
 which we will call the <em>callee function</em>,
@@ -3169,7 +3235,7 @@ when the function is called.
 The function results are pushed onto the stack when the function returns.
 The number of results is adjusted to <code>nresults</code>,
 unless <code>nresults</code> is <a name="pdf-LUA_MULTRET"><code>LUA_MULTRET</code></a>.
-In this case, all results from the function are pushed.
+In this case, all results from the function are pushed;
 Lua takes care that the returned values fit into the stack space,
 but it does not ensure any extra space in the stack.
 The function results are pushed onto the stack in direct order
@@ -3655,7 +3721,7 @@ in particular, 0&nbsp;means an empty stack.
 <pre>int lua_getuservalue (lua_State *L, int index);</pre>
 
 <p>
-Pushes onto the stack the Lua value associated with the userdata
+Pushes onto the stack the Lua value associated with the full userdata
 at the given index.
 
 
@@ -3998,7 +4064,8 @@ Creates a new thread running in a new, independent state.
 Returns <code>NULL</code> if it cannot create the thread or the state
 (due to lack of memory).
 The argument <code>f</code> is the allocator function;
-Lua does all memory allocation for this state through this function.
+Lua does all memory allocation for this state
+through this function (see <a href="#lua_Alloc"><code>lua_Alloc</code></a>).
 The second argument, <code>ud</code>, is an opaque pointer that Lua
 passes to the allocator in every call.
 
@@ -4202,7 +4269,9 @@ error while running the message handler.
 
 <li><b><a name="pdf-LUA_ERRGCMM"><code>LUA_ERRGCMM</code></a>: </b>
 error while running a <code>__gc</code> metamethod.
-(This error typically has no relation with the function being called.)
+For such errors, Lua does not call the message handler
+(as this kind of error typically has no relation
+with the function being called).
 </li>
 
 </ul>
@@ -4278,7 +4347,7 @@ The maximum value for <code>n</code> is 255.
 
 <p>
 When <code>n</code> is zero,
-this function creates a <em>light C function</em>,
+this function creates a <em>light C&nbsp;function</em>,
 which is just a pointer to the C&nbsp;function.
 In that case, it never raises a memory error.
 
@@ -4292,7 +4361,7 @@ In that case, it never raises a memory error.
 
 <p>
 Pushes a C&nbsp;function onto the stack.
-This function receives a pointer to a C function
+This function receives a pointer to a C&nbsp;function
 and pushes onto the stack a Lua value of type <code>function</code> that,
 when called, invokes the corresponding C&nbsp;function.
 
@@ -4667,7 +4736,7 @@ The reader function may return pieces of any size greater than zero.
 <pre>void lua_register (lua_State *L, const char *name, lua_CFunction f);</pre>
 
 <p>
-Sets the C function <code>f</code> as the new value of global <code>name</code>.
+Sets the C&nbsp;function <code>f</code> as the new value of global <code>name</code>.
 It is defined as a macro:
 
 <pre>
@@ -4888,7 +4957,7 @@ If <code>index</code> is&nbsp;0, then all stack elements are removed.
 
 <p>
 Pops a value from the stack and sets it as
-the new value associated to the userdata at the given index.
+the new value associated to the full userdata at the given index.
 
 
 
@@ -5302,7 +5371,7 @@ that will be passed as results to <a href="#lua_resume"><code>lua_resume</code><
 <p>
 When the coroutine is resumed again,
 Lua calls the given continuation function <code>k</code> to continue
-the execution of the C function that yielded (see <a href="#4.7">&sect;4.7</a>).
+the execution of the C&nbsp;function that yielded (see <a href="#4.7">&sect;4.7</a>).
 This continuation function receives the same stack
 from the previous function,
 with the <code>n</code> results removed and
@@ -6013,7 +6082,7 @@ If it is not, raises an error with a standard message (see <a href="#luaL_argerr
 
 <p>
 Raises an error reporting a problem with argument <code>arg</code>
-of the C function that called it,
+of the C&nbsp;function that called it,
 using a standard message
 that includes <code>extramsg</code> as a comment:
 
@@ -6534,7 +6603,8 @@ The string <code>mode</code> works as in function <a href="#lua_load"><code>lua_
 <p>
 This function returns the same results as <a href="#lua_load"><code>lua_load</code></a>,
 but it has an extra error code <a name="pdf-LUA_ERRFILE"><code>LUA_ERRFILE</code></a>
-if it cannot open/read the file or the file has a wrong mode.
+for file-related errors
+(e.g., it cannot open or read the file).
 
 
 <p>
@@ -6727,6 +6797,11 @@ If the result is <code>NULL</code>
 its length is considered zero.
 
 
+<p>
+This function uses <a href="#lua_tolstring"><code>lua_tolstring</code></a> to get its result,
+so all conversions and caveats of that function apply here.
+
+
 
 
 
@@ -7674,7 +7749,7 @@ Returns true when the running coroutine can yield.
 
 <p>
 A running coroutine is yieldable if it is not the main thread and
-it is not inside a non-yieldable C function.
+it is not inside a non-yieldable C&nbsp;function.
 
 
 
@@ -7876,8 +7951,8 @@ The path used by <a href="#pdf-require"><code>require</code></a> to search for a
 <p>
 Lua initializes the C&nbsp;path <a href="#pdf-package.cpath"><code>package.cpath</code></a> in the same way
 it initializes the Lua path <a href="#pdf-package.path"><code>package.path</code></a>,
-using the environment variable <a name="pdf-LUA_CPATH_5_3"><code>LUA_CPATH_5_3</code></a>
-or the environment variable <a name="pdf-LUA_CPATH"><code>LUA_CPATH</code></a>
+using the environment variable <a name="pdf-LUA_CPATH_5_3"><code>LUA_CPATH_5_3</code></a>,
+or the environment variable <a name="pdf-LUA_CPATH"><code>LUA_CPATH</code></a>,
 or a default path defined in <code>luaconf.h</code>.
 
 
@@ -8434,7 +8509,7 @@ its default value is&nbsp;1 and can be negative.
 <p>
 Returns a binary string containing the values <code>v1</code>, <code>v2</code>, etc.
 packed (that is, serialized in binary form)
-according to the format string <code>fmt</code> (see <a href="#6.4.2">&sect;6.4.2</a>). 
+according to the format string <code>fmt</code> (see <a href="#6.4.2">&sect;6.4.2</a>).
 
 
 
@@ -8485,7 +8560,8 @@ If <code>j</code> is absent, then it is assumed to be equal to -1
 In particular,
 the call <code>string.sub(s,1,j)</code> returns a prefix of <code>s</code>
 with length <code>j</code>,
-and <code>string.sub(s, -i)</code> returns a suffix of <code>s</code>
+and <code>string.sub(s, -i)</code> (for a positive <code>i</code>)
+returns a suffix of <code>s</code>
 with length <code>i</code>.
 
 
@@ -8902,7 +8978,7 @@ Returns the number of UTF-8 characters in string <code>s</code>
 that start between positions <code>i</code> and <code>j</code> (both inclusive).
 The default for <code>i</code> is 1 and for <code>j</code> is -1.
 If it finds any invalid byte sequence,
-returns a false value plus the position of the first invalid byte. 
+returns a false value plus the position of the first invalid byte.
 
 
 
@@ -8946,8 +9022,7 @@ It provides all its functions inside the table <a name="pdf-table"><code>table</
 
 <p>
 Remember that, whenever an operation needs the length of a table,
-the table must be a proper sequence
-or have a <code>__len</code> metamethod (see <a href="#3.4.7">&sect;3.4.7</a>).
+all caveats about the length operator apply (see <a href="#3.4.7">&sect;3.4.7</a>).
 All functions ignore non-numeric keys
 in the tables given as arguments.
 
@@ -9063,9 +9138,8 @@ Otherwise, no valid sort may be possible.
 
 
 <p>
-The sort algorithm is not stable;
-that is, elements not comparable by the given order
-(e.g., equal elements)
+The sort algorithm is not stable:
+elements considered equal by the given order
 may have their relative positions changed by the sort.
 
 
@@ -9401,7 +9475,7 @@ or <b>nil</b> if <code>x</code> is not a number.
 
 <p>
 Returns a boolean,
-true if integer <code>m</code> is below integer <code>n</code> when
+true if and only if integer <code>m</code> is below integer <code>n</code> when
 they are compared as unsigned integers.
 
 
@@ -9987,6 +10061,7 @@ Deletes the file (or empty directory, on POSIX systems)
 with the given name.
 If this function fails, it returns <b>nil</b>,
 plus a string describing the error and the error code.
+Otherwise, it returns true.
 
 
 
@@ -9996,9 +10071,10 @@ plus a string describing the error and the error code.
 
 
 <p>
-Renames file or directory named <code>oldname</code> to <code>newname</code>.
+Renames the file or directory named <code>oldname</code> to <code>newname</code>.
 If this function fails, it returns <b>nil</b>,
 plus a string describing the error and the error code.
+Otherwise, it returns true.
 
 
 
@@ -10291,7 +10367,7 @@ represent variables with no known names
 
 <p>
 Returns the Lua value associated to <code>u</code>.
-If <code>u</code> is not a userdata,
+If <code>u</code> is not a full userdata,
 returns <b>nil</b>.
 
 
@@ -10490,7 +10566,7 @@ and as <code>lua -</code> otherwise.
 
 
 <p>
-When called without option <code>-E</code>, 
+When called without option <code>-E</code>,
 the interpreter checks for an environment variable <a name="pdf-LUA_INIT_5_3"><code>LUA_INIT_5_3</code></a>
 (or <a name="pdf-LUA_INIT"><code>LUA_INIT</code></a> if the versioned name is not defined)
 before running any argument.
@@ -10582,7 +10658,7 @@ its value is used as the secondary prompt
 <p>
 In case of unprotected errors in the script,
 the interpreter reports the error to the standard error stream.
-If the error object is not a string but 
+If the error object is not a string but
 has a metamethod <code>__tostring</code>,
 the interpreter calls this metamethod to produce the final message.
 Otherwise, the interpreter converts the error object to a string
@@ -10897,13 +10973,12 @@ and LiteralString, see <a href="#3.1">&sect;3.1</a>.)
 
 
 
-
 <P CLASS="footer">
 Last update:
-Mon May 30 13:11:08 BRT 2016
+Mon Jan  9 13:30:53 BRST 2017
 </P>
 <!--
-Last change: revised for Lua 5.3.3
+Last change: revised for Lua 5.3.4
 -->
 
 </body></html>

+ 0 - 0
src/third_party/lua-5.3.3/doc/osi-certified-72x60.png → src/third_party/lua-5.3.4/doc/osi-certified-72x60.png


+ 3 - 3
src/third_party/lua-5.3.3/doc/readme.html → src/third_party/lua-5.3.4/doc/readme.html

@@ -328,7 +328,7 @@ For details, see
 <A HREF="http://www.lua.org/license.html">this</A>.
 
 <BLOCKQUOTE STYLE="padding-bottom: 0em">
-Copyright &copy; 1994&ndash;2016 Lua.org, PUC-Rio.
+Copyright &copy; 1994&ndash;2017 Lua.org, PUC-Rio.
 
 <P>
 Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -355,10 +355,10 @@ THE SOFTWARE.
 
 <P CLASS="footer">
 Last update:
-Tue Feb  2 22:25:27 BRST 2016
+Thu Dec 22 18:22:57 BRST 2016
 </P>
 <!--
-Last change: revised for Lua 5.3.3
+Last change: revised for Lua 5.3.4
 -->
 
 </BODY>

+ 0 - 0
src/third_party/lua-5.3.3/src/Makefile → src/third_party/lua-5.3.4/src/Makefile


+ 0 - 0
src/third_party/lua-5.3.3/src/lapi.c → src/third_party/lua-5.3.4/src/lapi.c


+ 0 - 0
src/third_party/lua-5.3.3/src/lapi.h → src/third_party/lua-5.3.4/src/lapi.h


+ 27 - 19
src/third_party/lua-5.3.3/src/lauxlib.c → src/third_party/lua-5.3.4/src/lauxlib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lauxlib.c,v 1.286 2016/01/08 15:33:09 roberto Exp $
+** $Id: lauxlib.c,v 1.289 2016/12/20 18:37:00 roberto Exp $
 ** Auxiliary functions for building Lua libraries
 ** See Copyright Notice in lua.h
 */
@@ -69,12 +69,11 @@ static int findfield (lua_State *L, int objidx, int level) {
 
 /*
 ** Search for a name for a function in all loaded modules
-** (registry._LOADED).
 */
 static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
   int top = lua_gettop(L);
   lua_getinfo(L, "f", ar);  /* push function */
-  lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
+  lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
   if (findfield(L, top + 1, 2)) {
     const char *name = lua_tostring(L, -1);
     if (strncmp(name, "_G.", 3) == 0) {  /* name start with '_G.'? */
@@ -809,13 +808,17 @@ LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) {
 
 
 LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
-  if (!luaL_callmeta(L, idx, "__tostring")) {  /* no metafield? */
+  if (luaL_callmeta(L, idx, "__tostring")) {  /* metafield? */
+    if (!lua_isstring(L, -1))
+      luaL_error(L, "'__tostring' must return a string");
+  }
+  else {
     switch (lua_type(L, idx)) {
       case LUA_TNUMBER: {
         if (lua_isinteger(L, idx))
-          lua_pushfstring(L, "%I", lua_tointeger(L, idx));
+          lua_pushfstring(L, "%I", (LUAI_UACINT)lua_tointeger(L, idx));
         else
-          lua_pushfstring(L, "%f", lua_tonumber(L, idx));
+          lua_pushfstring(L, "%f", (LUAI_UACNUMBER)lua_tonumber(L, idx));
         break;
       }
       case LUA_TSTRING:
@@ -827,10 +830,15 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
       case LUA_TNIL:
         lua_pushliteral(L, "nil");
         break;
-      default:
-        lua_pushfstring(L, "%s: %p", luaL_typename(L, idx),
-                                            lua_topointer(L, idx));
+      default: {
+        int tt = luaL_getmetafield(L, idx, "__name");  /* try name */
+        const char *kind = (tt == LUA_TSTRING) ? lua_tostring(L, -1) :
+                                                 luaL_typename(L, idx);
+        lua_pushfstring(L, "%s: %p", kind, lua_topointer(L, idx));
+        if (tt != LUA_TNIL)
+          lua_remove(L, -2);  /* remove '__name' */
         break;
+      }
     }
   }
   return lua_tolstring(L, -1, len);
@@ -882,23 +890,23 @@ static int libsize (const luaL_Reg *l) {
 
 /*
 ** Find or create a module table with a given name. The function
-** first looks at the _LOADED table and, if that fails, try a
+** first looks at the LOADED table and, if that fails, try a
 ** global variable with that name. In any case, leaves on the stack
 ** the module table.
 */
 LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname,
                                  int sizehint) {
-  luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1);  /* get _LOADED table */
-  if (lua_getfield(L, -1, modname) != LUA_TTABLE) {  /* no _LOADED[modname]? */
+  luaL_findtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE, 1);
+  if (lua_getfield(L, -1, modname) != LUA_TTABLE) {  /* no LOADED[modname]? */
     lua_pop(L, 1);  /* remove previous result */
     /* try global variable (and create one if it does not exist) */
     lua_pushglobaltable(L);
     if (luaL_findtable(L, 0, modname, sizehint) != NULL)
       luaL_error(L, "name conflict for module '%s'", modname);
     lua_pushvalue(L, -1);
-    lua_setfield(L, -3, modname);  /* _LOADED[modname] = new table */
+    lua_setfield(L, -3, modname);  /* LOADED[modname] = new table */
   }
-  lua_remove(L, -2);  /* remove _LOADED table */
+  lua_remove(L, -2);  /* remove LOADED table */
 }
 
 
@@ -962,17 +970,17 @@ LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) {
 */
 LUALIB_API void luaL_requiref (lua_State *L, const char *modname,
                                lua_CFunction openf, int glb) {
-  luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
-  lua_getfield(L, -1, modname);  /* _LOADED[modname] */
+  luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
+  lua_getfield(L, -1, modname);  /* LOADED[modname] */
   if (!lua_toboolean(L, -1)) {  /* package not already loaded? */
     lua_pop(L, 1);  /* remove field */
     lua_pushcfunction(L, openf);
     lua_pushstring(L, modname);  /* argument to open function */
     lua_call(L, 1, 1);  /* call 'openf' to open module */
     lua_pushvalue(L, -1);  /* make copy of module (call result) */
-    lua_setfield(L, -3, modname);  /* _LOADED[modname] = module */
+    lua_setfield(L, -3, modname);  /* LOADED[modname] = module */
   }
-  lua_remove(L, -2);  /* remove _LOADED table */
+  lua_remove(L, -2);  /* remove LOADED table */
   if (glb) {
     lua_pushvalue(L, -1);  /* copy of module */
     lua_setglobal(L, modname);  /* _G[modname] = module */
@@ -1030,6 +1038,6 @@ LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) {
     luaL_error(L, "multiple Lua VMs detected");
   else if (*v != ver)
     luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f",
-                  ver, *v);
+                  (LUAI_UACNUMBER)ver, (LUAI_UACNUMBER)*v);
 }
 

+ 10 - 2
src/third_party/lua-5.3.3/src/lauxlib.h → src/third_party/lua-5.3.4/src/lauxlib.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lauxlib.h,v 1.129 2015/11/23 11:29:43 roberto Exp $
+** $Id: lauxlib.h,v 1.131 2016/12/06 14:54:31 roberto Exp $
 ** Auxiliary functions for building Lua libraries
 ** See Copyright Notice in lua.h
 */
@@ -16,10 +16,18 @@
 
 
 
-/* extra error code for 'luaL_load' */
+/* extra error code for 'luaL_loadfilex' */
 #define LUA_ERRFILE     (LUA_ERRERR+1)
 
 
+/* key, in the registry, for table of loaded modules */
+#define LUA_LOADED_TABLE	"_LOADED"
+
+
+/* key, in the registry, for table of preloaded loaders */
+#define LUA_PRELOAD_TABLE	"_PRELOAD"
+
+
 typedef struct luaL_Reg {
   const char *name;
   lua_CFunction func;

+ 2 - 2
src/third_party/lua-5.3.3/src/lbaselib.c → src/third_party/lua-5.3.4/src/lbaselib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lbaselib.c,v 1.313 2016/04/11 19:18:40 roberto Exp $
+** $Id: lbaselib.c,v 1.314 2016/09/05 19:06:34 roberto Exp $
 ** Basic library
 ** See Copyright Notice in lua.h
 */
@@ -208,8 +208,8 @@ static int luaB_type (lua_State *L) {
 
 static int pairsmeta (lua_State *L, const char *method, int iszero,
                       lua_CFunction iter) {
+  luaL_checkany(L, 1);
   if (luaL_getmetafield(L, 1, method) == LUA_TNIL) {  /* no metamethod? */
-    luaL_checktype(L, 1, LUA_TTABLE);  /* argument must be a table */
     lua_pushcfunction(L, iter);  /* will return generator, */
     lua_pushvalue(L, 1);  /* state, */
     if (iszero) lua_pushinteger(L, 0);  /* and initial value */

+ 0 - 0
src/third_party/lua-5.3.3/src/lbitlib.c → src/third_party/lua-5.3.4/src/lbitlib.c


+ 13 - 9
src/third_party/lua-5.3.3/src/lcode.c → src/third_party/lua-5.3.4/src/lcode.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.c,v 2.109 2016/05/13 19:09:21 roberto Exp $
+** $Id: lcode.c,v 2.112 2016/12/22 13:08:50 roberto Exp $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -40,7 +40,7 @@
 ** If expression is a numeric constant, fills 'v' with its value
 ** and returns 1. Otherwise, returns 0.
 */
-static int tonumeral(expdesc *e, TValue *v) {
+static int tonumeral(const expdesc *e, TValue *v) {
   if (hasjumps(e))
     return 0;  /* not a numeral */
   switch (e->k) {
@@ -86,7 +86,7 @@ void luaK_nil (FuncState *fs, int from, int n) {
 /*
 ** Gets the destination address of a jump instruction. Used to traverse
 ** a list of jumps.
-*/ 
+*/
 static int getjump (FuncState *fs, int pc) {
   int offset = GETARG_sBx(fs->f->code[pc]);
   if (offset == NO_JUMP)  /* point to itself represents end of list */
@@ -754,7 +754,7 @@ void luaK_exp2val (FuncState *fs, expdesc *e) {
 ** (that is, it is either in a register or in 'k' with an index
 ** in the range of R/K indices).
 ** Returns R/K index.
-*/  
+*/
 int luaK_exp2RK (FuncState *fs, expdesc *e) {
   luaK_exp2val(fs, e);
   switch (e->k) {  /* move constants to 'k' */
@@ -975,7 +975,8 @@ static int validop (int op, TValue *v1, TValue *v2) {
 ** Try to "constant-fold" an operation; return 1 iff successful.
 ** (In this case, 'e1' has the final result.)
 */
-static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) {
+static int constfolding (FuncState *fs, int op, expdesc *e1,
+                                                const expdesc *e2) {
   TValue v1, v2, res;
   if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2))
     return 0;  /* non-numeric operands or not safe to fold */
@@ -1014,11 +1015,14 @@ static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) {
 ** (everything but logical operators 'and'/'or' and comparison
 ** operators).
 ** Expression to produce final result will be encoded in 'e1'.
+** Because 'luaK_exp2RK' can free registers, its calls must be
+** in "stack order" (that is, first on 'e2', which may have more
+** recent registers to be released).
 */
 static void codebinexpval (FuncState *fs, OpCode op,
                            expdesc *e1, expdesc *e2, int line) {
-  int rk1 = luaK_exp2RK(fs, e1);  /* both operands are "RK" */
-  int rk2 = luaK_exp2RK(fs, e2);
+  int rk2 = luaK_exp2RK(fs, e2);  /* both operands are "RK" */
+  int rk1 = luaK_exp2RK(fs, e1);
   freeexps(fs, e1, e2);
   e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2);  /* generate opcode */
   e1->k = VRELOCABLE;  /* all those operations are relocatable */
@@ -1060,9 +1064,9 @@ static void codecomp (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
 ** Aplly prefix operation 'op' to expression 'e'.
 */
 void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
-  static expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};  /* fake 2nd operand */
+  static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};
   switch (op) {
-    case OPR_MINUS: case OPR_BNOT:
+    case OPR_MINUS: case OPR_BNOT:  /* use 'ef' as fake 2nd operand */
       if (constfolding(fs, op + LUA_OPUNM, e, &ef))
         break;
       /* FALLTHROUGH */

+ 0 - 0
src/third_party/lua-5.3.3/src/lcode.h → src/third_party/lua-5.3.4/src/lcode.h


+ 0 - 0
src/third_party/lua-5.3.3/src/lcorolib.c → src/third_party/lua-5.3.4/src/lcorolib.c


+ 0 - 0
src/third_party/lua-5.3.3/src/lctype.c → src/third_party/lua-5.3.4/src/lctype.c


+ 0 - 0
src/third_party/lua-5.3.3/src/lctype.h → src/third_party/lua-5.3.4/src/lctype.h


+ 0 - 0
src/third_party/lua-5.3.3/src/ldblib.c → src/third_party/lua-5.3.4/src/ldblib.c


+ 32 - 13
src/third_party/lua-5.3.3/src/ldebug.c → src/third_party/lua-5.3.4/src/ldebug.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldebug.c,v 2.120 2016/03/31 19:01:21 roberto Exp $
+** $Id: ldebug.c,v 2.121 2016/10/19 12:32:10 roberto Exp $
 ** Debug Interface
 ** See Copyright Notice in lua.h
 */
@@ -38,7 +38,8 @@
 #define ci_func(ci)		(clLvalue((ci)->func))
 
 
-static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name);
+static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
+                                    const char **name);
 
 
 static int currentpc (CallInfo *ci) {
@@ -244,6 +245,20 @@ static void collectvalidlines (lua_State *L, Closure *f) {
 }
 
 
+static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
+  if (ci == NULL)  /* no 'ci'? */
+    return NULL;  /* no info */
+  else if (ci->callstatus & CIST_FIN) {  /* is this a finalizer? */
+    *name = "__gc";
+    return "metamethod";  /* report it as such */
+  }
+  /* calling function is a known Lua function? */
+  else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
+    return funcnamefromcode(L, ci->previous, name);
+  else return NULL;  /* no way to find a name */
+}
+
+
 static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
                        Closure *f, CallInfo *ci) {
   int status = 1;
@@ -274,11 +289,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
         break;
       }
       case 'n': {
-        /* calling function is a known Lua function? */
-        if (ci && !(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
-          ar->namewhat = getfuncname(L, ci->previous, &ar->name);
-        else
-          ar->namewhat = NULL;
+        ar->namewhat = getfuncname(L, ci, &ar->name);
         if (ar->namewhat == NULL) {
           ar->namewhat = "";  /* not found */
           ar->name = NULL;
@@ -471,8 +482,15 @@ static const char *getobjname (Proto *p, int lastpc, int reg,
 }
 
 
-static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
-  TMS tm = (TMS)0;  /* to avoid warnings */
+/*
+** Try to find a name for a function based on the code that called it.
+** (Only works when function was called by a Lua function.)
+** Returns what the name is (e.g., "for iterator", "method",
+** "metamethod") and sets '*name' to point to the name.
+*/
+static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
+                                     const char **name) {
+  TMS tm = (TMS)0;  /* (initial value avoids warnings) */
   Proto *p = ci_func(ci)->p;  /* calling function */
   int pc = currentpc(ci);  /* calling instruction index */
   Instruction i = p->code[pc];  /* calling instruction */
@@ -482,13 +500,13 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
   }
   switch (GET_OPCODE(i)) {
     case OP_CALL:
-    case OP_TAILCALL:  /* get function name */
-      return getobjname(p, pc, GETARG_A(i), name);
+    case OP_TAILCALL:
+      return getobjname(p, pc, GETARG_A(i), name);  /* get function name */
     case OP_TFORCALL: {  /* for iterator */
       *name = "for iterator";
        return "for iterator";
     }
-    /* all other instructions can call only through metamethods */
+    /* other instructions can do calls through metamethods */
     case OP_SELF: case OP_GETTABUP: case OP_GETTABLE:
       tm = TM_INDEX;
       break;
@@ -509,7 +527,8 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
     case OP_EQ: tm = TM_EQ; break;
     case OP_LT: tm = TM_LT; break;
     case OP_LE: tm = TM_LE; break;
-    default: lua_assert(0);  /* other instructions cannot call a function */
+    default:
+      return NULL;  /* cannot find a reasonable name */
   }
   *name = getstr(G(L)->tmname[tm]);
   return "metamethod";

+ 0 - 0
src/third_party/lua-5.3.3/src/ldebug.h → src/third_party/lua-5.3.4/src/ldebug.h


+ 103 - 101
src/third_party/lua-5.3.3/src/ldo.c → src/third_party/lua-5.3.4/src/ldo.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.c,v 2.151 2015/12/16 16:40:07 roberto Exp $
+** $Id: ldo.c,v 2.157 2016/12/13 15:52:21 roberto Exp $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -211,9 +211,9 @@ static int stackinuse (lua_State *L) {
   CallInfo *ci;
   StkId lim = L->top;
   for (ci = L->ci; ci != NULL; ci = ci->previous) {
-    lua_assert(ci->top <= L->stack_last);
     if (lim < ci->top) lim = ci->top;
   }
+  lua_assert(lim <= L->stack_last);
   return cast_int(lim - L->stack) + 1;  /* part of stack in use */
 }
 
@@ -221,16 +221,19 @@ static int stackinuse (lua_State *L) {
 void luaD_shrinkstack (lua_State *L) {
   int inuse = stackinuse(L);
   int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
-  if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK;
-  if (L->stacksize > LUAI_MAXSTACK)  /* was handling stack overflow? */
+  if (goodsize > LUAI_MAXSTACK)
+    goodsize = LUAI_MAXSTACK;  /* respect stack limit */
+  if (L->stacksize > LUAI_MAXSTACK)  /* had been handling stack overflow? */
     luaE_freeCI(L);  /* free all CIs (list grew because of an error) */
   else
     luaE_shrinkCI(L);  /* shrink list */
-  if (inuse <= LUAI_MAXSTACK &&  /* not handling stack overflow? */
-      goodsize < L->stacksize)  /* trying to shrink? */
-    luaD_reallocstack(L, goodsize);  /* shrink it */
-  else
-    condmovestack(L,,);  /* don't change stack (change only for debugging) */
+  /* if thread is currently not handling a stack overflow and its
+     good size is smaller than current size, shrink its stack */
+  if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) &&
+      goodsize < L->stacksize)
+    luaD_reallocstack(L, goodsize);
+  else  /* don't change stack */
+    condmovestack(L,{},{});  /* (change only for debugging) */
 }
 
 
@@ -322,6 +325,72 @@ static void tryfuncTM (lua_State *L, StkId func) {
 }
 
 
+/*
+** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'.
+** Handle most typical cases (zero results for commands, one result for
+** expressions, multiple results for tail calls/single parameters)
+** separated.
+*/
+static int moveresults (lua_State *L, const TValue *firstResult, StkId res,
+                                      int nres, int wanted) {
+  switch (wanted) {  /* handle typical cases separately */
+    case 0: break;  /* nothing to move */
+    case 1: {  /* one result needed */
+      if (nres == 0)   /* no results? */
+        firstResult = luaO_nilobject;  /* adjust with nil */
+      setobjs2s(L, res, firstResult);  /* move it to proper place */
+      break;
+    }
+    case LUA_MULTRET: {
+      int i;
+      for (i = 0; i < nres; i++)  /* move all results to correct place */
+        setobjs2s(L, res + i, firstResult + i);
+      L->top = res + nres;
+      return 0;  /* wanted == LUA_MULTRET */
+    }
+    default: {
+      int i;
+      if (wanted <= nres) {  /* enough results? */
+        for (i = 0; i < wanted; i++)  /* move wanted results to correct place */
+          setobjs2s(L, res + i, firstResult + i);
+      }
+      else {  /* not enough results; use all of them plus nils */
+        for (i = 0; i < nres; i++)  /* move all results to correct place */
+          setobjs2s(L, res + i, firstResult + i);
+        for (; i < wanted; i++)  /* complete wanted number of results */
+          setnilvalue(res + i);
+      }
+      break;
+    }
+  }
+  L->top = res + wanted;  /* top points after the last result */
+  return 1;
+}
+
+
+/*
+** Finishes a function call: calls hook if necessary, removes CallInfo,
+** moves current number of results to proper place; returns 0 iff call
+** wanted multiple (variable number of) results.
+*/
+int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) {
+  StkId res;
+  int wanted = ci->nresults;
+  if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
+    if (L->hookmask & LUA_MASKRET) {
+      ptrdiff_t fr = savestack(L, firstResult);  /* hook may change stack */
+      luaD_hook(L, LUA_HOOKRET, -1);
+      firstResult = restorestack(L, fr);
+    }
+    L->oldpc = ci->previous->u.l.savedpc;  /* 'oldpc' for caller function */
+  }
+  res = ci->func;  /* res == final position of 1st result */
+  L->ci = ci->previous;  /* back to caller */
+  /* move results to proper place */
+  return moveresults(L, firstResult, res, nres, wanted);
+}
+
+
 
 #define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))
 
@@ -374,13 +443,13 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
       int n = cast_int(L->top - func) - 1;  /* number of real arguments */
       int fsize = p->maxstacksize;  /* frame size */
       checkstackp(L, fsize, func);
-      if (p->is_vararg != 1) {  /* do not use vararg? */
+      if (p->is_vararg)
+        base = adjust_varargs(L, p, n);
+      else {  /* non vararg function */
         for (; n < p->numparams; n++)
           setnilvalue(L->top++);  /* complete missing arguments */
         base = func + 1;
       }
-      else
-        base = adjust_varargs(L, p, n);
       ci = next_ci(L);  /* now 'enter' new function */
       ci->nresults = nresults;
       ci->func = func;
@@ -403,72 +472,6 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
 
 
 /*
-** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'.
-** Handle most typical cases (zero results for commands, one result for
-** expressions, multiple results for tail calls/single parameters)
-** separated.
-*/
-static int moveresults (lua_State *L, const TValue *firstResult, StkId res,
-                                      int nres, int wanted) {
-  switch (wanted) {  /* handle typical cases separately */
-    case 0: break;  /* nothing to move */
-    case 1: {  /* one result needed */
-      if (nres == 0)   /* no results? */
-        firstResult = luaO_nilobject;  /* adjust with nil */
-      setobjs2s(L, res, firstResult);  /* move it to proper place */
-      break;
-    }
-    case LUA_MULTRET: {
-      int i;
-      for (i = 0; i < nres; i++)  /* move all results to correct place */
-        setobjs2s(L, res + i, firstResult + i);
-      L->top = res + nres;
-      return 0;  /* wanted == LUA_MULTRET */
-    }
-    default: {
-      int i;
-      if (wanted <= nres) {  /* enough results? */
-        for (i = 0; i < wanted; i++)  /* move wanted results to correct place */
-          setobjs2s(L, res + i, firstResult + i);
-      }
-      else {  /* not enough results; use all of them plus nils */
-        for (i = 0; i < nres; i++)  /* move all results to correct place */
-          setobjs2s(L, res + i, firstResult + i);
-        for (; i < wanted; i++)  /* complete wanted number of results */
-          setnilvalue(res + i);
-      }
-      break;
-    }
-  }
-  L->top = res + wanted;  /* top points after the last result */
-  return 1;
-}
-
-
-/*
-** Finishes a function call: calls hook if necessary, removes CallInfo,
-** moves current number of results to proper place; returns 0 iff call
-** wanted multiple (variable number of) results.
-*/
-int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) {
-  StkId res;
-  int wanted = ci->nresults;
-  if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
-    if (L->hookmask & LUA_MASKRET) {
-      ptrdiff_t fr = savestack(L, firstResult);  /* hook may change stack */
-      luaD_hook(L, LUA_HOOKRET, -1);
-      firstResult = restorestack(L, fr);
-    }
-    L->oldpc = ci->previous->u.l.savedpc;  /* 'oldpc' for caller function */
-  }
-  res = ci->func;  /* res == final position of 1st result */
-  L->ci = ci->previous;  /* back to caller */
-  /* move results to proper place */
-  return moveresults(L, firstResult, res, nres, wanted);
-}
-
-
-/*
 ** Check appropriate error for stack overflow ("regular" overflow or
 ** overflow while handling stack overflow). If 'nCalls' is larger than
 ** LUAI_MAXCCALLS (which means it is handling a "regular" overflow) but
@@ -520,19 +523,17 @@ static void finishCcall (lua_State *L, int status) {
   /* error status can only happen in a protected call */
   lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD);
   if (ci->callstatus & CIST_YPCALL) {  /* was inside a pcall? */
-    ci->callstatus &= ~CIST_YPCALL;  /* finish 'lua_pcall' */
-    L->errfunc = ci->u.c.old_errfunc;
+    ci->callstatus &= ~CIST_YPCALL;  /* continuation is also inside it */
+    L->errfunc = ci->u.c.old_errfunc;  /* with the same error function */
   }
   /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already
      handled */
   adjustresults(L, ci->nresults);
-  /* call continuation function */
   lua_unlock(L);
-  n = (*ci->u.c.k)(L, status, ci->u.c.ctx);
+  n = (*ci->u.c.k)(L, status, ci->u.c.ctx);  /* call continuation function */
   lua_lock(L);
   api_checknelems(L, n);
-  /* finish 'luaD_precall' */
-  luaD_poscall(L, ci, L->top - n, n);
+  luaD_poscall(L, ci, L->top - n, n);  /* finish 'luaD_precall' */
 }
 
 
@@ -595,15 +596,16 @@ static int recover (lua_State *L, int status) {
 
 
 /*
-** signal an error in the call to 'resume', not in the execution of the
-** coroutine itself. (Such errors should not be handled by any coroutine
-** error handler and should not kill the coroutine.)
+** Signal an error in the call to 'lua_resume', not in the execution
+** of the coroutine itself. (Such errors should not be handled by any
+** coroutine error handler and should not kill the coroutine.)
 */
-static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
-  L->top = firstArg;  /* remove args from the stack */
+static int resume_error (lua_State *L, const char *msg, int narg) {
+  L->top -= narg;  /* remove args from the stack */
   setsvalue2s(L, L->top, luaS_new(L, msg));  /* push error message */
   api_incr_top(L);
-  luaD_throw(L, -1);  /* jump back to 'lua_resume' */
+  lua_unlock(L);
+  return LUA_ERRRUN;
 }
 
 
@@ -615,22 +617,15 @@ static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
 ** coroutine.
 */
 static void resume (lua_State *L, void *ud) {
-  int nCcalls = L->nCcalls;
   int n = *(cast(int*, ud));  /* number of arguments */
   StkId firstArg = L->top - n;  /* first argument */
   CallInfo *ci = L->ci;
-  if (nCcalls >= LUAI_MAXCCALLS)
-    resume_error(L, "C stack overflow", firstArg);
-  if (L->status == LUA_OK) {  /* may be starting a coroutine */
-    if (ci != &L->base_ci)  /* not in base level? */
-      resume_error(L, "cannot resume non-suspended coroutine", firstArg);
-    /* coroutine is in base level; start running it */
+  if (L->status == LUA_OK) {  /* starting a coroutine? */
     if (!luaD_precall(L, firstArg - 1, LUA_MULTRET))  /* Lua function? */
       luaV_execute(L);  /* call it */
   }
-  else if (L->status != LUA_YIELD)
-    resume_error(L, "cannot resume dead coroutine", firstArg);
   else {  /* resuming from previous yield */
+    lua_assert(L->status == LUA_YIELD);
     L->status = LUA_OK;  /* mark that it is running (again) */
     ci->func = restorestack(L, ci->extra);
     if (isLua(ci))  /* yielded inside a hook? */
@@ -647,7 +642,6 @@ static void resume (lua_State *L, void *ud) {
     }
     unroll(L, NULL);  /* run continuation */
   }
-  lua_assert(nCcalls == L->nCcalls);
 }
 
 
@@ -655,8 +649,16 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
   int status;
   unsigned short oldnny = L->nny;  /* save "number of non-yieldable" calls */
   lua_lock(L);
-  luai_userstateresume(L, nargs);
+  if (L->status == LUA_OK) {  /* may be starting a coroutine */
+    if (L->ci != &L->base_ci)  /* not in base level? */
+      return resume_error(L, "cannot resume non-suspended coroutine", nargs);
+  }
+  else if (L->status != LUA_YIELD)
+    return resume_error(L, "cannot resume dead coroutine", nargs);
   L->nCcalls = (from) ? from->nCcalls + 1 : 1;
+  if (L->nCcalls >= LUAI_MAXCCALLS)
+    return resume_error(L, "C stack overflow", nargs);
+  luai_userstateresume(L, nargs);
   L->nny = 0;  /* allow yields */
   api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
   status = luaD_rawrunprotected(L, resume, &nargs);

+ 0 - 0
src/third_party/lua-5.3.3/src/ldo.h → src/third_party/lua-5.3.4/src/ldo.h


+ 0 - 0
src/third_party/lua-5.3.3/src/ldump.c → src/third_party/lua-5.3.4/src/ldump.c


+ 0 - 0
src/third_party/lua-5.3.3/src/lfunc.c → src/third_party/lua-5.3.4/src/lfunc.c


+ 0 - 0
src/third_party/lua-5.3.3/src/lfunc.h → src/third_party/lua-5.3.4/src/lfunc.h


+ 5 - 3
src/third_party/lua-5.3.3/src/lgc.c → src/third_party/lua-5.3.4/src/lgc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 2.212 2016/03/31 19:02:03 roberto Exp $
+** $Id: lgc.c,v 2.215 2016/12/22 13:08:50 roberto Exp $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -467,7 +467,7 @@ static lu_mem traversetable (global_State *g, Table *h) {
   else  /* not weak */
     traversestrongtable(g, h);
   return sizeof(Table) + sizeof(TValue) * h->sizearray +
-                         sizeof(Node) * cast(size_t, sizenode(h));
+                         sizeof(Node) * cast(size_t, allocsizenode(h));
 }
 
 
@@ -539,7 +539,7 @@ static lu_mem traversethread (global_State *g, lua_State *th) {
     StkId lim = th->stack + th->stacksize;  /* real end of stack */
     for (; o < lim; o++)  /* clear not-marked stack slice */
       setnilvalue(o);
-    /* 'remarkupvals' may have removed thread from 'twups' list */ 
+    /* 'remarkupvals' may have removed thread from 'twups' list */
     if (!isintwups(th) && th->openupval != NULL) {
       th->twups = g->twups;  /* link it back to the list */
       g->twups = th;
@@ -818,7 +818,9 @@ static void GCTM (lua_State *L, int propagateerrors) {
     setobj2s(L, L->top, tm);  /* push finalizer... */
     setobj2s(L, L->top + 1, &v);  /* ... and its argument */
     L->top += 2;  /* and (next line) call the finalizer */
+    L->ci->callstatus |= CIST_FIN;  /* will run a finalizer */
     status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
+    L->ci->callstatus &= ~CIST_FIN;  /* not running a finalizer anymore */
     L->allowhook = oldah;  /* restore hooks */
     g->gcrunning = running;  /* restore state */
     if (status != LUA_OK && propagateerrors) {  /* error while running __gc? */

+ 0 - 0
src/third_party/lua-5.3.3/src/lgc.h → src/third_party/lua-5.3.4/src/lgc.h


+ 3 - 3
src/third_party/lua-5.3.3/src/linit.c → src/third_party/lua-5.3.4/src/linit.c

@@ -1,5 +1,5 @@
 /*
-** $Id: linit.c,v 1.38 2015/01/05 13:48:33 roberto Exp $
+** $Id: linit.c,v 1.39 2016/12/04 20:17:24 roberto Exp $
 ** Initialization of libraries for lua.c and other clients
 ** See Copyright Notice in lua.h
 */
@@ -18,10 +18,10 @@
 ** open the library, which is already linked to the application.
 ** For that, do the following code:
 **
-**  luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
+**  luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
 **  lua_pushcfunction(L, luaopen_modname);
 **  lua_setfield(L, -2, modname);
-**  lua_pop(L, 1);  // remove _PRELOAD table
+**  lua_pop(L, 1);  // remove PRELOAD table
 */
 
 #include "lprefix.h"

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini