Przeglądaj źródła

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

Maarten Fremouw 10 lat temu
rodzic
commit
8a5af9b1f7

+ 24 - 12
Makefile

@@ -55,7 +55,9 @@ BUILD_DIRS += $(BUILD_DIR)/test
 endif
 
 # only set main compile options if none were chosen
-CFLAGS += -W -Wall -O2 -D$(TARGET_OS) -Iinclude $(COPT)
+CFLAGS += -W -Wall -O2 -D$(TARGET_OS) -Iinclude $(COPT) -DUSE_STACK_SIZE=102400
+
+LIBS = -lpthread -lm
 
 ifdef WITH_DEBUG
   CFLAGS += -g -DDEBUG_ENABLED
@@ -69,9 +71,13 @@ ifdef WITH_CPP
 else
   LCC = $(CC)
 endif
+
+ifdef WITH_LUA_SHARED
+  WITH_LUA = 1
+endif
 
 ifdef WITH_LUA
- include resources/Makefile.in-lua
+  include resources/Makefile.in-lua
 endif
 
 ifdef WITH_IPV6
@@ -79,7 +85,11 @@ ifdef WITH_IPV6
 endif
 
 ifdef WITH_WEBSOCKET
-  CFLAGS += -DUSE_WEBSOCKET
+  CFLAGS += -DUSE_WEBSOCKET
+  ifdef WITH_LUA
+    CFLAGS += -DUSE_TIMERS
+    LIBS += -lrt
+  endif
 endif
 
 ifdef CONFIG_FILE
@@ -103,22 +113,23 @@ BUILD_OBJECTS = $(addprefix $(BUILD_DIR)/, $(OBJECTS))
 MAIN_OBJECTS = $(addprefix $(BUILD_DIR)/, $(APP_SOURCES:.c=.o))
 LIB_OBJECTS = $(filter-out $(MAIN_OBJECTS), $(BUILD_OBJECTS))
 
-
-LIBS = -lpthread -lm
-
 ifeq ($(TARGET_OS),LINUX)
-	LIBS += -ldl
+  LIBS += -ldl
 endif
 
 ifeq ($(TARGET_OS),LINUX)
-	CAN_INSTALL = 1
+  CAN_INSTALL = 1
+endif
+
+ifdef WITH_LUA_SHARED
+  LIBS += -llua5.2
 endif
 
 ifneq (, $(findstring MINGW32, $(UNAME)))
-   LIBS += -lws2_32 -lcomdlg32
-   SHARED_LIB=dll
+  LIBS += -lws2_32 -lcomdlg32
+  SHARED_LIB=dll
 else
-   SHARED_LIB=so
+  SHARED_LIB=so
 endif
 
 all: build
@@ -133,7 +144,8 @@ help:
 	@echo "make unit_test           build unit tests executable"
 	@echo ""
 	@echo " Make Options"
-	@echo "   WITH_LUA=1            build with Lua support"
+	@echo "   WITH_LUA=1            build with Lua support; include Lua as static library"
+	@echo "   WITH_LUA_SHARED=1     build with Lua support; use dynamic linking to liblua5.2.so"
 	@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"

+ 14 - 2
VS2012/civetweb.sln

@@ -17,6 +17,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unit_test", "unit_test\unit
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ex_websocket_client", "ex_websocket_client\ex_websocket_client.vcxproj", "{58B93E94-7766-435E-93AE-42A2FB5D99B2}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "upload", "upload\upload.vcxproj", "{882EC43C-2EEE-434B-A711-C845678D29C6}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Mixed Platforms = Debug|Mixed Platforms
@@ -63,8 +65,8 @@ Global
 		{4308C5EE-45E4-45D8-9D73-6C4E2587AD78}.Release|Win32.Build.0 = Release|Win32
 		{4308C5EE-45E4-45D8-9D73-6C4E2587AD78}.Release|x64.ActiveCfg = Release|x64
 		{4308C5EE-45E4-45D8-9D73-6C4E2587AD78}.Release|x64.Build.0 = Release|x64
-		{9BE9C008-E851-42B1-A034-BD4630AE4CD6}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
-		{9BE9C008-E851-42B1-A034-BD4630AE4CD6}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+		{9BE9C008-E851-42B1-A034-BD4630AE4CD6}.Debug|Mixed Platforms.ActiveCfg = Debug CONSOLE|Win32
+		{9BE9C008-E851-42B1-A034-BD4630AE4CD6}.Debug|Mixed Platforms.Build.0 = Debug CONSOLE|Win32
 		{9BE9C008-E851-42B1-A034-BD4630AE4CD6}.Debug|Win32.ActiveCfg = Debug|Win32
 		{9BE9C008-E851-42B1-A034-BD4630AE4CD6}.Debug|Win32.Build.0 = Debug|Win32
 		{9BE9C008-E851-42B1-A034-BD4630AE4CD6}.Debug|x64.ActiveCfg = Debug|x64
@@ -119,6 +121,16 @@ Global
 		{58B93E94-7766-435E-93AE-42A2FB5D99B2}.Release|Win32.ActiveCfg = Release|Win32
 		{58B93E94-7766-435E-93AE-42A2FB5D99B2}.Release|Win32.Build.0 = Release|Win32
 		{58B93E94-7766-435E-93AE-42A2FB5D99B2}.Release|x64.ActiveCfg = Release|Win32
+		{882EC43C-2EEE-434B-A711-C845678D29C6}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+		{882EC43C-2EEE-434B-A711-C845678D29C6}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+		{882EC43C-2EEE-434B-A711-C845678D29C6}.Debug|Win32.ActiveCfg = Debug|Win32
+		{882EC43C-2EEE-434B-A711-C845678D29C6}.Debug|Win32.Build.0 = Debug|Win32
+		{882EC43C-2EEE-434B-A711-C845678D29C6}.Debug|x64.ActiveCfg = Debug|Win32
+		{882EC43C-2EEE-434B-A711-C845678D29C6}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+		{882EC43C-2EEE-434B-A711-C845678D29C6}.Release|Mixed Platforms.Build.0 = Release|Win32
+		{882EC43C-2EEE-434B-A711-C845678D29C6}.Release|Win32.ActiveCfg = Release|Win32
+		{882EC43C-2EEE-434B-A711-C845678D29C6}.Release|Win32.Build.0 = Release|Win32
+		{882EC43C-2EEE-434B-A711-C845678D29C6}.Release|x64.ActiveCfg = Release|Win32
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 2 - 0
VS2012/unit_test/unit_test.vcxproj

@@ -39,9 +39,11 @@
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <LinkIncremental>true</LinkIncremental>
+    <OutDir>$(SolutionDir)\$(Configuration)\$(Platform)\</OutDir>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <LinkIncremental>false</LinkIncremental>
+    <OutDir>$(SolutionDir)\$(Configuration)\$(Platform)\</OutDir>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>

+ 159 - 0
VS2012/upload/upload.vcxproj

@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\examples\upload\upload.c" />
+    <ClCompile Include="..\..\src\civetweb.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\include\civetweb.h" />
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{882EC43C-2EEE-434B-A711-C845678D29C6}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>upload</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v100</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v110</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v110_xp</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v110</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+    <OutDir>$(SolutionDir)\$(Configuration)\$(Platform)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+    <OutDir>$(SolutionDir)\$(Configuration)\$(Platform)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <OutDir>$(SolutionDir)\$(Configuration)\$(Platform)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+    <OutDir>$(SolutionDir)\$(Configuration)\$(Platform)\</OutDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

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

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

+ 1 - 0
examples/embedded_c/embedded_c.c

@@ -106,6 +106,7 @@ int main(int argc, char *argv[])
 #endif
     }
 
+    mg_stop(ctx);
     printf("Bye!\n");
 
     return 0;

+ 2 - 2
examples/websocket/WebSockCallbacks.c

@@ -49,7 +49,7 @@ void websocket_ready_handler(struct mg_connection *conn) {
             break;
         }
     }
-    printf("\nNew websocket attached: %08lx:%u\n", rq->remote_ip, rq->remote_port);
+    printf("\nNew websocket attached: %s:%u\n", rq->remote_addr, rq->remote_port);
     mg_unlock_context(ctx);
 }
 
@@ -66,7 +66,7 @@ static void websocket_done(tWebSockContext *ws_ctx, tWebSockInfo * wsock) {
                 break;
             }
         }
-        printf("\nClose websocket attached: %08lx:%u\n", mg_get_request_info(wsock->conn)->remote_ip, mg_get_request_info(wsock->conn)->remote_port);
+        printf("\nClose websocket attached: %s:%u\n", mg_get_request_info(wsock->conn)->remote_addr, mg_get_request_info(wsock->conn)->remote_port);
         free(wsock);
     }
 }

+ 3 - 1
include/civetweb.h

@@ -61,7 +61,9 @@ struct mg_request_info {
                                    NULL */
     const char *remote_user;    /* Authenticated user, or NULL if no auth
                                    used */
-    long remote_ip;             /* Client's IP address */
+    char remote_addr[48];       /* Client's IP address as a string. */
+    long remote_ip;             /* Client's IP address. Deprecated: use remote_addr instead */
+
     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 */

+ 22 - 6
resources/Makefile.in-lua

@@ -1,11 +1,25 @@
-# 
+#
 # Copyright (c) 2013 No Face Press, LLC
 # License http://opensource.org/licenses/mit-license.php MIT License
 #
+
+ifndef WITH_LUA
+  $(error WITH_LUA is not defined)
+endif
 
 LUA_DIR = src/third_party/lua-5.2.3/src
-
-LUA_SOURCE_FILES = lapi.c  \
+LUA_CFLAGS = -I$(LUA_DIR) -DLUA_COMPAT_ALL -DUSE_LUA
+
+ifdef WITH_LUA_SHARED
+
+  LUA_CFLAGS += -DLUA_USE_POSIX -DLUA_USE_DLOPEN
+  LUA_SOURCE_FILES =
+
+  $(info Lua: using dynamic linking)
+
+else
+
+  LUA_SOURCE_FILES = lapi.c  \
     lauxlib.c \
     lbaselib.c  \
     lbitlib.c  \
@@ -37,10 +51,13 @@ LUA_SOURCE_FILES = lapi.c  \
     lundump.c \
     lvm.c  \
     lzio.c
+
+  $(info Lua: using static library)
+
+endif
 
 LUA_SOURCES = $(addprefix $(LUA_DIR)/, $(LUA_SOURCE_FILES))
 LUA_OBJECTS = $(LUA_SOURCES:.c=.o)
-LUA_CFLAGS = -I$(LUA_DIR) -DLUA_COMPAT_ALL
 
 SQLITE_DIR = src/third_party
 SQLITE_SOURCE_FILES = sqlite3.c lsqlite3.c
@@ -54,8 +71,7 @@ LFS_SOURCES = $(addprefix $(LFS_DIR)/, $(LFS_SOURCE_FILES))
 LFS_OBJECTS = $(LFS_SOURCES:.c=.o)
 LFS_CFLAGS = -I$(LFS_DIR)
 
-
 OBJECTS += $(LUA_OBJECTS) $(SQLITE_OBJECTS) $(LFS_OBJECTS)
-CFLAGS += $(LUA_CFLAGS) $(SQLITE_CFLAGS) $(LFS_CFLAGS) -DUSE_LUA -DUSE_LUA_SQLITE3 -DUSE_LUA_FILE_SYSTEM
+CFLAGS += $(LUA_CFLAGS) $(SQLITE_CFLAGS) $(LFS_CFLAGS) -DUSE_LUA_SQLITE3 -DUSE_LUA_FILE_SYSTEM
 SOURCE_DIRS = $(LUA_DIR) $(SQLITE_DIR) %(LFS_DIR)
 

+ 154 - 75
src/civetweb.c

@@ -767,14 +767,13 @@ struct mg_request_handler_info {
     char *uri;
     size_t uri_len;
     mg_request_handler handler;
+
     void *cbdata;
     struct mg_request_handler_info *next;
 };
 
 struct mg_context {
     volatile int stop_flag;         /* Should we stop event loop */
-    void *ssllib_dll_handle;        /* Store the ssl library handle. */
-    void *cryptolib_dll_handle;     /* Store the crypto library handle. */
     SSL_CTX *ssl_ctx;               /* SSL context */
     char *config[NUM_OPTIONS];      /* Civetweb configuration parameters */
     struct mg_callbacks callbacks;  /* User-defined callback function */
@@ -862,8 +861,36 @@ struct de {
 };
 
 #if defined(USE_WEBSOCKET)
-static int is_websocket_request(const struct mg_connection *conn);
+static int is_websocket_protocol(const struct mg_connection *conn);
+#else
+#define is_websocket_protocol(conn) (0)
+#endif
+
+int mg_atomic_inc(volatile int * addr)
+{
+    int ret;
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+    ret = InterlockedIncrement(addr);
+#elif defined(__GNUC__)
+    ret = __sync_add_and_fetch(addr, 1);
+#else
+    ret = (++(*addr));
+#endif
+    return ret;
+}
+
+int mg_atomic_dec(volatile int * addr)
+{
+    int ret;
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+    ret = InterlockedDecrement(addr);
+#elif defined(__GNUC__)
+    ret = __sync_sub_and_fetch(addr, 1);
+#else
+    ret = (--(*addr));
 #endif
+    return ret;
+}
 
 #if defined(MG_LEGACY_INTERFACE)
 const char **mg_get_valid_option_names(void)
@@ -2283,18 +2310,19 @@ int mg_read(struct mg_connection *conn, void *buf, size_t len)
     nread = 0;
     if (conn->consumed_content < conn->content_len) {
         /* Adjust number of bytes to read. */
-        int64_t to_read = conn->content_len - conn->consumed_content;
-        if (to_read < len64) {
-            len = (size_t) to_read;
+        int64_t left_to_read = conn->content_len - conn->consumed_content;
+        if (left_to_read < len64) {
+            /* Do not reade more than the total content length of the request. */
+            len64 = left_to_read;
         }
 
         /* Return buffered data */
-        body = conn->buf + conn->request_len + conn->consumed_content;
-        buffered_len = (int64_t)(&conn->buf[conn->data_len] - body);
+        buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len - conn->consumed_content;
         if (buffered_len > 0) {
-            if (len64 < (size_t) buffered_len) {
+            if (len64 < buffered_len) {
                 buffered_len = len64;
             }
+            body = conn->buf + conn->request_len + conn->consumed_content;
             memcpy(buf, body, (size_t) buffered_len);
             len64 -= buffered_len;
             conn->consumed_content += buffered_len;
@@ -2629,9 +2657,22 @@ static int base64_decode(const unsigned char *src, int src_len, char *dst, size_
 }
 #endif
 
-static void convert_uri_to_file_name(struct mg_connection *conn, char *buf,
-                                     size_t buf_len, struct file *filep,
-                                     int * is_script_ressource)
+static int is_put_or_delete_method(const struct mg_connection *conn)
+{
+    const char *s = conn->request_info.request_method;
+    return s != NULL && (!strcmp(s, "PUT") ||
+                         !strcmp(s, "DELETE") ||
+                         !strcmp(s, "MKCOL"));
+}
+
+static void interpret_uri(struct mg_connection *conn,    /* in: request */
+                          char *filename,                /* out: filename */
+                          size_t filename_buf_len,       /* in: size of filename buffer */
+                          struct file *filep,            /* out: file structure */
+                          int * is_script_ressource,     /* out: handled by a script? */
+                          int * is_websocket_request,    /* out: websocket connetion? */
+                          int * is_put_or_delete_request /* out: put/delete a file? */
+                          )
 {
     struct vec a, b;
     const char *rewrite, *uri = conn->request_info.uri,
@@ -2642,30 +2683,34 @@ static void convert_uri_to_file_name(struct mg_connection *conn, char *buf,
     char const* accept_encoding;
 
     *is_script_ressource = 0;
+    *is_put_or_delete_request = is_put_or_delete_method(conn);
 
 #if defined(USE_WEBSOCKET)
-    if (is_websocket_request(conn) && conn->ctx->config[WEBSOCKET_ROOT]) {
+    *is_websocket_request = is_websocket_protocol(conn);
+    if (*is_websocket_request && conn->ctx->config[WEBSOCKET_ROOT]) {
         root = conn->ctx->config[WEBSOCKET_ROOT];
     }
+#else
+    *is_websocket_request = 0;
 #endif
 
     /* Using buf_len - 1 because memmove() for PATH_INFO may shift part
        of the path one byte on the right.
        If document_root is NULL, leave the file empty. */
-    mg_snprintf(conn, buf, buf_len - 1, "%s%s",
+    mg_snprintf(conn, filename, filename_buf_len - 1, "%s%s",
                 root == NULL ? "" : root,
                 root == NULL ? "" : uri);
 
     rewrite = conn->ctx->config[REWRITE];
     while ((rewrite = next_option(rewrite, &a, &b)) != NULL) {
         if ((match_len = match_prefix(a.ptr, (int) a.len, uri)) > 0) {
-            mg_snprintf(conn, buf, buf_len - 1, "%.*s%s", (int) b.len, b.ptr,
+            mg_snprintf(conn, filename, filename_buf_len - 1, "%.*s%s", (int) b.len, b.ptr,
                         uri + match_len);
             break;
         }
     }
 
-    if (mg_stat(conn, buf, filep)) return;
+    if (mg_stat(conn, filename, filep)) return;
 
     /* if we can't find the actual file, look for the file
        with the same name but a .gz extension. If we find it,
@@ -2675,7 +2720,7 @@ static void convert_uri_to_file_name(struct mg_connection *conn, char *buf,
        we can only do this if the browser declares support */
     if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) != NULL) {
         if (strstr(accept_encoding,"gzip") != NULL) {
-            snprintf(gz_path, sizeof(gz_path), "%s.gz", buf);
+            snprintf(gz_path, sizeof(gz_path), "%s.gz", filename);
             if (mg_stat(conn, gz_path, filep)) {
                 filep->gzipped = 1;
                 return;
@@ -2684,17 +2729,17 @@ static void convert_uri_to_file_name(struct mg_connection *conn, char *buf,
     }
 
     /* Support PATH_INFO for CGI scripts. */
-    for (p = buf + strlen(buf); p > buf + 1; p--) {
+    for (p = filename + strlen(filename); p > filename + 1; p--) {
         if (*p == '/') {
             *p = '\0';
             if ((match_prefix(conn->ctx->config[CGI_EXTENSIONS],
-                              (int)strlen(conn->ctx->config[CGI_EXTENSIONS]), buf) > 0
+                              (int)strlen(conn->ctx->config[CGI_EXTENSIONS]), filename) > 0
 #ifdef USE_LUA
                  ||
                  match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS],
-                              (int)strlen(conn->ctx->config[LUA_SCRIPT_EXTENSIONS]), buf) > 0
+                              (int)strlen(conn->ctx->config[LUA_SCRIPT_EXTENSIONS]), filename) > 0
 #endif
-                ) && mg_stat(conn, buf, filep)) {
+                ) && mg_stat(conn, filename, filep)) {
                 /* Shift PATH_INFO block one character right, e.g.
                     "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
                    conn->path_info is pointing to the local variable "path"
@@ -3190,7 +3235,7 @@ static int read_auth_file(struct file *filep, struct read_auth_file_struct * wor
     char *p;
     int is_authorized = 0;
     struct file fp;
-    int l;
+    size_t l;
 
     /* Loop over passwords file */
     p = (char *) filep->membuf;
@@ -3957,7 +4002,7 @@ static int parse_http_message(char *buf, int len, struct mg_request_info *ri)
 {
     int is_request, request_length = get_request_len(buf, len);
     if (request_length > 0) {
-        /* Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port */
+        /* Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_addr, remote_port */
         ri->remote_user = ri->request_method = ri->uri = ri->http_version = NULL;
         ri->num_headers = 0;
 
@@ -4074,7 +4119,8 @@ static int forward_body_data(struct mg_connection *conn, FILE *fp,
 {
     const char *expect, *body;
     char buf[MG_BUF_LEN];
-    int to_read, nread, buffered_len, success = 0;
+    int to_read, nread, success = 0;
+    int64_t buffered_len;
 
     expect = mg_get_header(conn, "Expect");
     assert(fp != NULL);
@@ -4088,8 +4134,7 @@ static int forward_body_data(struct mg_connection *conn, FILE *fp,
             (void) mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
         }
 
-        body = conn->buf + conn->request_len + conn->consumed_content;
-        buffered_len = (int)(&conn->buf[conn->data_len] - body);
+        buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len - conn->consumed_content;
         assert(buffered_len >= 0);
         assert(conn->consumed_content == 0);
 
@@ -4097,6 +4142,7 @@ static int forward_body_data(struct mg_connection *conn, FILE *fp,
             if ((int64_t) buffered_len > conn->content_len) {
                 buffered_len = (int) conn->content_len;
             }
+            body = conn->buf + conn->request_len + conn->consumed_content;
             push(fp, sock, ssl, body, (int64_t) buffered_len);
             conn->consumed_content += buffered_len;
         }
@@ -5346,20 +5392,24 @@ static void handle_websocket_request(struct mg_connection *conn, const char *pat
     }
 }
 
-static int is_websocket_request(const struct mg_connection *conn)
+static int is_websocket_protocol(const struct mg_connection *conn)
 {
     const char *host, *upgrade, *connection, *version, *key;
 
-    host = mg_get_header(conn, "Host");
     upgrade = mg_get_header(conn, "Upgrade");
+    if (upgrade == NULL) return 0; /* fail early, don't waste time checking other header fields */
+    if (!mg_strcasestr(upgrade, "websocket")) return 0;
+
     connection = mg_get_header(conn, "Connection");
+    if (connection == NULL) return 0;
+    if (!mg_strcasestr(connection, "upgrade")) return 0;
+
+    host = mg_get_header(conn, "Host");
     key = mg_get_header(conn, "Sec-WebSocket-Key");
     version = mg_get_header(conn, "Sec-WebSocket-Version");
 
-    return host != NULL && upgrade != NULL && connection != NULL &&
-           key != NULL && version != NULL &&
-           mg_strcasestr(upgrade, "websocket") != NULL &&
-           mg_strcasestr(connection, "Upgrade") != NULL;
+    return host != NULL &&
+           key != NULL && version != NULL;
 }
 #endif /* !USE_WEBSOCKET */
 
@@ -5539,14 +5589,6 @@ int mg_upload(struct mg_connection *conn, const char *destination_dir)
     return num_uploaded_files;
 }
 
-static int is_put_or_delete_request(const struct mg_connection *conn)
-{
-    const char *s = conn->request_info.request_method;
-    return s != NULL && (!strcmp(s, "PUT") ||
-                         !strcmp(s, "DELETE") ||
-                         !strcmp(s, "MKCOL"));
-}
-
 static int get_first_ssl_listener_index(const struct mg_context *ctx)
 {
     int i, idx = -1;
@@ -5674,7 +5716,7 @@ static int use_request_handler(struct mg_connection *conn)
         }
 
         /* try for pattern match */
-        if (match_prefix(tmp_rh->uri, tmp_rh->uri_len, uri) > 0) {
+        if (match_prefix(tmp_rh->uri, (int)tmp_rh->uri_len, uri) > 0) {
            return tmp_rh->handler(conn, tmp_rh->cbdata);
         }
 
@@ -5691,7 +5733,7 @@ static void handle_request(struct mg_connection *conn)
 {
     struct mg_request_info *ri = &conn->request_info;
     char path[PATH_MAX];
-    int uri_len, ssl_index, is_script_resource;
+    int uri_len, ssl_index, is_script_resource, is_websocket_request, is_put_or_delete_request;
     struct file file = STRUCT_FILE_INITIALIZER;
     char date[64];
     time_t curtime = time(NULL);
@@ -5706,7 +5748,7 @@ static void handle_request(struct mg_connection *conn)
     }
     remove_double_dots_and_double_slashes((char *) ri->uri);
     path[0] = '\0';
-    convert_uri_to_file_name(conn, path, sizeof(path), &file, &is_script_resource);
+    interpret_uri(conn, path, sizeof(path), &file, &is_script_resource, &is_websocket_request, &is_put_or_delete_request);
     conn->throttle = set_throttle(conn->ctx->config[THROTTLE],
                                   get_remote_ip(conn), ri->uri);
 
@@ -5717,14 +5759,14 @@ static void handle_request(struct mg_connection *conn)
     if (!conn->client.is_ssl && conn->client.ssl_redir &&
         (ssl_index = get_first_ssl_listener_index(conn->ctx)) > -1) {
         redirect_to_https_port(conn, ssl_index);
-    } else if (!is_script_resource && !is_put_or_delete_request(conn) &&
+    } else if (!is_script_resource && !is_put_or_delete_request &&
                !check_authorization(conn, path)) {
         send_authorization_request(conn);
     } else if (conn->ctx->callbacks.begin_request != NULL &&
                conn->ctx->callbacks.begin_request(conn)) {
         /* Do nothing, callback has served the request */
 #if defined(USE_WEBSOCKET)
-    } else if (is_websocket_request(conn)) {
+    } else if (is_websocket_request) {
         handle_websocket_request(conn, path, is_script_resource);
 #endif
     } else if (conn->ctx->request_handlers != NULL &&
@@ -5736,7 +5778,7 @@ static void handle_request(struct mg_connection *conn)
         send_options(conn);
     } else if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
         send_http_error(conn, 404, "Not Found", "Not Found");
-    } else if (!is_script_resource && is_put_or_delete_request(conn) &&
+    } else if (!is_script_resource && is_put_or_delete_request &&
                (is_authorized_for_put(conn) != 1)) {
         send_authorization_request(conn);
     } else if (!is_script_resource && !strcmp(ri->request_method, "PUT")) {
@@ -6078,7 +6120,7 @@ static int sslize(struct mg_connection *conn, SSL_CTX *s, int (*func)(SSL *))
            func(conn->ssl) == 1;
 }
 
-/* Return OpenSSL error message */
+/* Return OpenSSL error message (from CRYPTO lib) */
 static const char *ssl_error(void)
 {
     unsigned long err;
@@ -6141,12 +6183,50 @@ static void *load_dll(struct mg_context *ctx, const char *dll_name,
 
     return dll_handle;
 }
+
+static void *ssllib_dll_handle;        /* Store the ssl library handle. */
+static void *cryptolib_dll_handle;     /* Store the crypto library handle. */
+
+#endif /* NO_SSL_DL */
+
+static int cryptolib_users = 0;        /* Refecence counter for crypto library. */
+
+static int initialize_ssl(struct mg_context *ctx)
+{
+    int i, size;
+
+#if !defined(NO_SSL_DL)
+    if (!cryptolib_dll_handle) {
+        cryptolib_dll_handle = load_dll(ctx, CRYPTO_LIB, crypto_sw);
+        if (!cryptolib_dll_handle) {
+            return 0;
+        }
+    }
 #endif /* NO_SSL_DL */
 
+    if (mg_atomic_inc(&cryptolib_users)>1) return 1;
+
+    /* Initialize locking callbacks, needed for thread safety.
+       http://www.openssl.org/support/faq.html#PROG1 */
+    size = sizeof(pthread_mutex_t) * CRYPTO_num_locks();
+    if ((ssl_mutexes = (pthread_mutex_t *) mg_malloc((size_t)size)) == NULL) {
+        mg_cry(fc(ctx), "%s: cannot allocate mutexes: %s", __func__, ssl_error());
+        return 0;
+    }
+
+    for (i = 0; i < CRYPTO_num_locks(); i++) {
+        pthread_mutex_init(&ssl_mutexes[i], NULL);
+    }
+
+    CRYPTO_set_locking_callback(&ssl_locking_callback);
+    CRYPTO_set_id_callback(&ssl_id_callback);
+
+    return 1;
+}
+
 /* Dynamically load SSL library. Set up ctx->ssl_ctx pointer. */
 static int set_ssl_option(struct mg_context *ctx)
 {
-    int i, size;
     const char *pem;
 
     /* If PEM file is not specified and the init_ssl callback
@@ -6156,12 +6236,17 @@ static int set_ssl_option(struct mg_context *ctx)
         return 1;
     }
 
-#if !defined(NO_SSL_DL)
-    ctx->ssllib_dll_handle = load_dll(ctx, SSL_LIB, ssl_sw);
-    ctx->cryptolib_dll_handle = load_dll(ctx, CRYPTO_LIB, crypto_sw);
-    if (!ctx->ssllib_dll_handle || !ctx->cryptolib_dll_handle) {
+    if (!initialize_ssl(ctx)) {
         return 0;
     }
+
+#if !defined(NO_SSL_DL)
+    if (!ssllib_dll_handle) {
+        ssllib_dll_handle = load_dll(ctx, SSL_LIB, ssl_sw);
+        if (!ssllib_dll_handle) {
+            return 0;
+        }
+    }
 #endif /* NO_SSL_DL */
 
     /* Initialize SSL library */
@@ -6187,28 +6272,15 @@ static int set_ssl_option(struct mg_context *ctx)
         (void) SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem);
     }
 
-    /* Initialize locking callbacks, needed for thread safety.
-       http://www.openssl.org/support/faq.html#PROG1 */
-    size = sizeof(pthread_mutex_t) * CRYPTO_num_locks();
-    if ((ssl_mutexes = (pthread_mutex_t *) mg_malloc((size_t)size)) == NULL) {
-        mg_cry(fc(ctx), "%s: cannot allocate mutexes: %s", __func__, ssl_error());
-        return 0;
-    }
-
-    for (i = 0; i < CRYPTO_num_locks(); i++) {
-        pthread_mutex_init(&ssl_mutexes[i], NULL);
-    }
-
-    CRYPTO_set_locking_callback(&ssl_locking_callback);
-    CRYPTO_set_id_callback(&ssl_id_callback);
-
     return 1;
 }
 
 static void uninitialize_ssl(struct mg_context *ctx)
 {
     int i;
-    if (ctx->ssl_ctx != NULL) {
+    (void)ctx;
+
+    if (mg_atomic_dec(&cryptolib_users)==0) {
         CRYPTO_set_locking_callback(NULL);
         for (i = 0; i < CRYPTO_num_locks(); i++) {
             pthread_mutex_destroy(&ssl_mutexes[i]);
@@ -6495,9 +6567,9 @@ struct mg_connection *mg_connect_websocket_client(const char *host, int port, in
                                                void * user_data)
 {
     struct mg_connection* conn = NULL;
-    struct mg_context * newctx = NULL;
 
 #if defined(USE_WEBSOCKET)
+    struct mg_context * newctx = NULL;
     static const char *magic = "x3JJHMbDL1EzLkh9GBhXDw==";
     static const char *handshake_req;
 
@@ -6687,9 +6759,12 @@ static void *worker_thread_run(void *thread_func_param)
                Thanks to Johannes Winkelmann for the patch.
                TODO(lsm): Fix IPv6 case */
             conn->request_info.remote_port = ntohs(conn->client.rsa.sin.sin_port);
+            sockaddr_to_string(conn->request_info.remote_addr, sizeof(conn->request_info.remote_addr), &conn->client.rsa);
+/* TODO: #if defined(MG_LEGACY_INTERFACE) */
             memcpy(&conn->request_info.remote_ip,
                    &conn->client.rsa.sin.sin_addr.s_addr, 4);
             conn->request_info.remote_ip = ntohl(conn->request_info.remote_ip);
+/* #endif */
             conn->request_info.is_ssl = conn->client.is_ssl;
 
             if (!conn->client.is_ssl
@@ -6891,7 +6966,9 @@ static void master_thread_run(void *thread_func_param)
     }
 
 #if !defined(NO_SSL)
-    uninitialize_ssl(ctx);
+    if (ctx->ssl_ctx != NULL) {
+        uninitialize_ssl(ctx);
+    }
 #endif
     DEBUG_TRACE("exiting");
 
@@ -6980,8 +7057,7 @@ static void free_context(struct mg_context *ctx)
     }
 
     /* Deallocate the tls variable */
-    sTlsInit--;
-    if (sTlsInit==0) {
+    if (mg_atomic_dec(&sTlsInit)==0) {
         pthread_key_delete(sTlsKey);
     }
 
@@ -7051,7 +7127,7 @@ struct mg_context *mg_start(const struct mg_callbacks *callbacks,
     WSADATA data;
     WSAStartup(MAKEWORD(2,2), &data);
 #pragma warning(suppress: 28125)
-    InitializeCriticalSection(&global_log_file_lock);
+    if (!sTlsInit) InitializeCriticalSection(&global_log_file_lock);
 #endif /* _WIN32 && !__SYMBIAN32__ */
 
     /* Check if the config_options and the corresponding enum have compatible sizes. */
@@ -7064,14 +7140,17 @@ struct mg_context *mg_start(const struct mg_callbacks *callbacks,
         return NULL;
     }
 
-    if (sTlsInit==0) {
+    if (mg_atomic_inc(&sTlsInit)==1) {
         if (0 != pthread_key_create(&sTlsKey, NULL)) {
             /* Fatal error - abort start. However, this situation should never occur in practice. */
+            mg_atomic_dec(&sTlsInit);
             mg_cry(fc(ctx), "Cannot initialize thread local storage");
             mg_free(ctx);
             return NULL;
         }
-        sTlsInit++;
+    } else {
+       /* TODO: check if sTlsKey is already initialized */
+       mg_sleep(1);
     }
 
     ok =  0==pthread_mutex_init(&ctx->thread_mutex, NULL);

+ 6 - 9
src/main.c

@@ -548,6 +548,7 @@ static void set_absolute_path(char *options[], const char *option_name,
 #ifdef USE_LUA
 #define main luatest_main
 #define luaL_openlibs lua_civet_openlibs
+struct lua_State;
 extern void lua_civet_openlibs(struct lua_State *L);
 #include "../src/third_party/lua-5.2.3/src/lua.c"
 #undef main
@@ -1500,20 +1501,16 @@ static int MakeConsole() {
 
         ok = (GetConsoleWindow() != NULL);
         if (ok) {
-            freopen("CON", "a", stdin);
-            freopen("CON", "a", stdout);
-            freopen("CON", "a", stderr);
+            freopen("CONIN$", "r", stdin); 
+            freopen("CONOUT$", "w", stdout); 
+            freopen("CONOUT$", "w", stderr); 
         }
     }
-    if (ok) {
-        CONSOLE_SCREEN_BUFFER_INFO coninfo;
 
+    if (ok) {
         SetConsoleTitle(server_name);
-
-        GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
-        if (coninfo.dwSize.Y<500) coninfo.dwSize.Y = 500;
-        SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
     }
+
     return ok;
 }
 

+ 5 - 7
src/mod_lua.inl

@@ -894,12 +894,9 @@ enum {
 
 static void prepare_lua_request_info(struct mg_connection *conn, lua_State *L)
 {
-    char src_addr[IP_ADDR_STR_LEN] = "";
     const char *s;
     int i;
 
-    sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
-
     /* Export mg.request_info */
     lua_pushstring(L, "request_info");
     lua_newtable(L);
@@ -907,8 +904,10 @@ static void prepare_lua_request_info(struct mg_connection *conn, lua_State *L)
     reg_string(L, "uri", conn->request_info.uri);
     reg_string(L, "http_version", conn->request_info.http_version);
     reg_string(L, "query_string", conn->request_info.query_string);
+#if defined(MG_LEGACY_INTERFACE)
     reg_int(L, "remote_ip", conn->request_info.remote_ip); /* remote_ip is deprecated, use remote_addr instead */
-    reg_string(L, "remote_addr", src_addr);
+#endif
+    reg_string(L, "remote_addr", conn->request_info.remote_addr);
     /* TODO: ip version */
     reg_int(L, "remote_port", conn->request_info.remote_port);
     reg_int(L, "num_headers", conn->request_info.num_headers);
@@ -1267,13 +1266,12 @@ static void * lua_websocket_new(const char * script, struct mg_connection *conn)
     if (!ok) {
         /* Remove from ws connection list. */
         /* TODO: Check if list entry and Lua state needs to be deleted (see websocket_close). */
-        (*shared_websock_list)->ws.conn[--(ws->references)] = 0;
-        ws = NULL;
+        (*shared_websock_list)->ws.conn[--(ws->references)] = 0;    
     }
 
     (void)pthread_mutex_unlock(&(ws->ws_mutex));
 
-    return (void*)ws;
+    return ok ? (void*)ws : NULL;
 }
 
 static int lua_websocket_data(struct mg_connection * conn, void *ws_arg, int bits, char *data, size_t data_len)

+ 1 - 1
test/unit_test.c

@@ -851,7 +851,7 @@ static int api_callback(struct mg_connection *conn) {
     ASSERT(mg_read(conn, post_data, sizeof(post_data)) == 3);
     ASSERT(memcmp(post_data, "b=1", 3) == 0);
     ASSERT(ri->query_string != NULL);
-    ASSERT(ri->remote_ip > 0);
+    ASSERT(ri->remote_addr[0] != 0);
     ASSERT(ri->remote_port > 0);
     ASSERT(strcmp(ri->http_version, "1.0") == 0);