mirror of
https://github.com/lammertb/libhttp.git
synced 2025-09-04 12:42:09 +03:00
Merge branch 'master' of https://github.com/bel2125/civetweb into unit_test
This commit is contained in:
23
Makefile
23
Makefile
@@ -1,4 +1,4 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2013 No Face Press, LLC
|
# Copyright (c) 2013 No Face Press, LLC
|
||||||
# License http://opensource.org/licenses/mit-license.php MIT License
|
# License http://opensource.org/licenses/mit-license.php MIT License
|
||||||
#
|
#
|
||||||
@@ -24,6 +24,8 @@ DOCDIR = $(DATAROOTDIR)/doc/$(CPROG)
|
|||||||
SYSCONFDIR = $(PREFIX)/etc
|
SYSCONFDIR = $(PREFIX)/etc
|
||||||
HTMLDIR = $(DOCDIR)
|
HTMLDIR = $(DOCDIR)
|
||||||
|
|
||||||
|
UNAME := $(shell uname)
|
||||||
|
|
||||||
# desired configuration of the document root
|
# desired configuration of the document root
|
||||||
# never assume that the document_root actually
|
# never assume that the document_root actually
|
||||||
# exists on the build machine. When building
|
# exists on the build machine. When building
|
||||||
@@ -92,7 +94,7 @@ LIB_OBJECTS = $(filter-out $(MAIN_OBJECTS), $(BUILD_OBJECTS))
|
|||||||
|
|
||||||
LIBS = -lpthread -lm
|
LIBS = -lpthread -lm
|
||||||
|
|
||||||
ifeq ($(TARGET_OS),LINUX)
|
ifeq ($(TARGET_OS),LINUX)
|
||||||
LIBS += -ldl
|
LIBS += -ldl
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -100,6 +102,13 @@ ifeq ($(TARGET_OS),LINUX)
|
|||||||
CAN_INSTALL = 1
|
CAN_INSTALL = 1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq (, $(findstring MINGW32, $(UNAME)))
|
||||||
|
LIBS += -lws2_32 -lcomdlg32
|
||||||
|
SHARED_LIB=dll
|
||||||
|
else
|
||||||
|
SHARED_LIB=so
|
||||||
|
endif
|
||||||
|
|
||||||
all: build
|
all: build
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@@ -174,7 +183,7 @@ endif
|
|||||||
|
|
||||||
lib: lib$(CPROG).a
|
lib: lib$(CPROG).a
|
||||||
|
|
||||||
slib: lib$(CPROG).so
|
slib: lib$(CPROG).$(SHARED_LIB)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(BUILD_DIR)
|
rm -rf $(BUILD_DIR)
|
||||||
@@ -182,16 +191,20 @@ clean:
|
|||||||
distclean: clean
|
distclean: clean
|
||||||
@rm -rf VS2012/Debug VS2012/*/Debug VS2012/*/*/Debug
|
@rm -rf VS2012/Debug VS2012/*/Debug VS2012/*/*/Debug
|
||||||
@rm -rf VS2012/Release VS2012/*/Release VS2012/*/*/Release
|
@rm -rf VS2012/Release VS2012/*/Release VS2012/*/*/Release
|
||||||
rm -f $(CPROG) lib$(CPROG).so lib$(CPROG).a *.dmg *.msi *.exe
|
rm -f $(CPROG) lib$(CPROG).so lib$(CPROG).a *.dmg *.msi *.exe lib$(CPROG).dll lib$(CPROG).dll.a
|
||||||
|
|
||||||
lib$(CPROG).a: $(LIB_OBJECTS)
|
lib$(CPROG).a: $(LIB_OBJECTS)
|
||||||
@rm -f $@
|
@rm -f $@
|
||||||
ar cq $@ $(LIB_OBJECTS)
|
ar cq $@ $(LIB_OBJECTS)
|
||||||
|
|
||||||
lib$(CPROG).so: CFLAGS += -fPIC
|
lib$(CPROG).so: CFLAGS += -fPIC
|
||||||
lib$(CPROG).so: $(LIB_OBJECTS)
|
lib$(CPROG).so: $(LIB_OBJECTS)
|
||||||
$(LCC) -shared -o $@ $(CFLAGS) $(LDFLAGS) $(LIB_OBJECTS)
|
$(LCC) -shared -o $@ $(CFLAGS) $(LDFLAGS) $(LIB_OBJECTS)
|
||||||
|
|
||||||
|
lib$(CPROG).dll: CFLAGS += -fPIC
|
||||||
|
lib$(CPROG).dll: $(LIB_OBJECTS)
|
||||||
|
$(LCC) -shared -o $@ $(CFLAGS) $(LDFLAGS) $(LIB_OBJECTS) $(LIBS) -Wl,--out-implib,lib$(CPROG).dll.a
|
||||||
|
|
||||||
$(CPROG): $(BUILD_OBJECTS)
|
$(CPROG): $(BUILD_OBJECTS)
|
||||||
$(LCC) -o $@ $(CFLAGS) $(LDFLAGS) $(BUILD_OBJECTS) $(LIBS)
|
$(LCC) -o $@ $(CFLAGS) $(LDFLAGS) $(BUILD_OBJECTS) $(LIBS)
|
||||||
|
|
||||||
|
@@ -1,14 +1,24 @@
|
|||||||
Release Notes v1.6 (Under Development)
|
Release Notes v1.6 (Under Development)
|
||||||
===
|
===
|
||||||
### Objectives: *???*
|
### Objectives: *Enhance Lua support, bug fixes and updates"
|
||||||
|
|
||||||
Changes
|
Changes
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Allow to specify title and tray icon for the Windows standalone server (bel)
|
||||||
|
- Fix minor memory leaks (bel)
|
||||||
|
- Redirect all memory allocation/deallocation through mg functions which may be overwritten (bel)
|
||||||
|
- Support Cross-Origin Resource Sharing (CORS) for static files and scripts (bel)
|
||||||
|
- Win32: Replace dll.def file by export macros in civetweb.h (CSTAJ)
|
||||||
|
- Base64 encode and decode functions for Lua (bel)
|
||||||
|
- Support pre-loaded files for the Lua environment (bel)
|
||||||
|
- Server should check the nonce for http digest access authentication (bel)
|
||||||
|
- Hide read-only flag in file dialogs opened by the Edit Settings dialog for the Windows executable (bel)
|
||||||
|
- Add all functions to dll.def, that are in the header (bel)
|
||||||
- Added Lua extensions: send_file, get_var, get_mime_type, get_cookie, url_decode, url_encode (bel)
|
- Added Lua extensions: send_file, get_var, get_mime_type, get_cookie, url_decode, url_encode (bel)
|
||||||
- mg_set_request_handler() mod to use pattern (bel, Patch from Toni Wilk)
|
- mg_set_request_handler() mod to use pattern (bel, Patch from Toni Wilk)
|
||||||
- Solved, tested and documented SSL support for Windows (bel)
|
- Solved, tested and documented SSL support for Windows (bel)
|
||||||
- Fixed: select for Linux needs the nfds parameter set correctly (bel)
|
- Fixed: select for Linux needs the nfds parameter set correctly (bel)
|
||||||
- Add methods for returning the ports civetweb is listening on (keithel)
|
- Add methods for returning the ports civetweb is listening on (keithel)
|
||||||
- Fixes for Lua Server Pages, as described within the google groups thread. (bel)
|
- Fixes for Lua Server Pages, as described within the google groups thread. (bel)
|
||||||
- Added support for plain Lua Scripts, and an example script. (bel)
|
- Added support for plain Lua Scripts, and an example script. (bel)
|
||||||
@@ -30,7 +40,7 @@ Changes
|
|||||||
|
|
||||||
- Corrected bad mask flag/opcode passing to websocket callback (William Greathouse)
|
- Corrected bad mask flag/opcode passing to websocket callback (William Greathouse)
|
||||||
- Moved CEVITWEB_VERSION define into civetweb.h
|
- Moved CEVITWEB_VERSION define into civetweb.h
|
||||||
- Added new simple zip deployment build for Windows.
|
- Added new simple zip deployment build for Windows.
|
||||||
- Removed windows install package build.
|
- Removed windows install package build.
|
||||||
- Fixes page violation in mod_lua.inl (apkbox)
|
- Fixes page violation in mod_lua.inl (apkbox)
|
||||||
- Use C style comments to enable compiling most of civetweb with -ansi. (F-Secure Corporation)
|
- Use C style comments to enable compiling most of civetweb with -ansi. (F-Secure Corporation)
|
||||||
@@ -79,7 +89,7 @@ Changes
|
|||||||
- Conformed source files to UNIX line endings for consistency.
|
- Conformed source files to UNIX line endings for consistency.
|
||||||
- Unified the coding style to improve reability.
|
- Unified the coding style to improve reability.
|
||||||
|
|
||||||
Release Notes v1.3
|
Release Notes v1.3
|
||||||
===
|
===
|
||||||
### Objectives: *Buildroot Integration*
|
### Objectives: *Buildroot Integration*
|
||||||
|
|
||||||
@@ -91,7 +101,7 @@ Changes
|
|||||||
- Updated documentation
|
- Updated documentation
|
||||||
- Updated Buildroot config example
|
- Updated Buildroot config example
|
||||||
|
|
||||||
Release Notes v1.2
|
Release Notes v1.2
|
||||||
===
|
===
|
||||||
### Objectives: *Installation Improvements, buildroot, cross compile support*
|
### Objectives: *Installation Improvements, buildroot, cross compile support*
|
||||||
The objective of this release is to make installation seamless.
|
The objective of this release is to make installation seamless.
|
||||||
@@ -115,7 +125,7 @@ Known Issues
|
|||||||
|
|
||||||
- The prebuilt Window's version requires [Visual C++ Redistributable for Visual Studio 2012](http://www.microsoft.com/en-us/download/details.aspx?id=30679)
|
- The prebuilt Window's version requires [Visual C++ Redistributable for Visual Studio 2012](http://www.microsoft.com/en-us/download/details.aspx?id=30679)
|
||||||
|
|
||||||
Release Notes v1.1
|
Release Notes v1.1
|
||||||
===
|
===
|
||||||
### Objectives: *Build, Documentation, License Improvements*
|
### Objectives: *Build, Documentation, License Improvements*
|
||||||
The objective of this release is to establish a maintable code base, ensure MIT license rights and improve usability and documentation.
|
The objective of this release is to establish a maintable code base, ensure MIT license rights and improve usability and documentation.
|
||||||
@@ -144,7 +154,7 @@ Changes
|
|||||||
+ Removed yaSSL from the OSX build, not needed.
|
+ Removed yaSSL from the OSX build, not needed.
|
||||||
- Added new Visual Studio projects for Windows builds.
|
- Added new Visual Studio projects for Windows builds.
|
||||||
+ Removed Windows support from Makefiles
|
+ Removed Windows support from Makefiles
|
||||||
+ Provided additional, examples with Lua, and another with yaSSL.
|
+ Provided additional, examples with Lua, and another with yaSSL.
|
||||||
- Changed Zombie Reaping policy to not ignore SIGCHLD.
|
- Changed Zombie Reaping policy to not ignore SIGCHLD.
|
||||||
+ The previous method caused trouble in applciations that spawn children.
|
+ The previous method caused trouble in applciations that spawn children.
|
||||||
|
|
||||||
@@ -154,7 +164,7 @@ Known Issues
|
|||||||
- Build support for VS6 and some other has been deprecated.
|
- Build support for VS6 and some other has been deprecated.
|
||||||
+ This does not impact embedded programs, just the stand-alone build.
|
+ This does not impact embedded programs, just the stand-alone build.
|
||||||
+ The old Makefile was renamed to Makefile.deprecated.
|
+ The old Makefile was renamed to Makefile.deprecated.
|
||||||
+ This is partcially do to lack fo testing.
|
+ This is partcially do to lack fo testing.
|
||||||
+ Need to find out what is actually in demand.
|
+ Need to find out what is actually in demand.
|
||||||
- Build changes may impact current users.
|
- Build changes may impact current users.
|
||||||
+ As with any change of this type, changes may impact some users.
|
+ As with any change of this type, changes may impact some users.
|
||||||
|
@@ -88,7 +88,7 @@
|
|||||||
</PrecompiledHeader>
|
</PrecompiledHeader>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
@@ -102,7 +102,7 @@
|
|||||||
</PrecompiledHeader>
|
</PrecompiledHeader>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
@@ -136,7 +136,7 @@
|
|||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
|
@@ -316,6 +316,13 @@ Timeout for network read and network write operations, in milliseconds.
|
|||||||
If client intends to keep long-running connection, either increase this value
|
If client intends to keep long-running connection, either increase this value
|
||||||
or use keep-alive messages.
|
or use keep-alive messages.
|
||||||
|
|
||||||
|
### lua_preload_file
|
||||||
|
This configuration option can be used to specify a Lua script file, which
|
||||||
|
is executed before the actual web page script (Lua script, Lua server page
|
||||||
|
or Lua websocket). It can be used to modify the Lua environment of all web
|
||||||
|
page scripts, e.g., by loading additional libraries required by all scripts
|
||||||
|
or to achieve backward compatibility by defining obsolete functions.
|
||||||
|
|
||||||
### lua_script_pattern `"**.lua$`
|
### lua_script_pattern `"**.lua$`
|
||||||
A pattern for files that are interpreted as Lua scripts by the server.
|
A pattern for files that are interpreted as Lua scripts by the server.
|
||||||
In contrast to Lua server pages, Lua scripts use plain Lua syntax.
|
In contrast to Lua server pages, Lua scripts use plain Lua syntax.
|
||||||
@@ -402,11 +409,13 @@ mg (table):
|
|||||||
mg.document_root -- a string that holds the document root directory
|
mg.document_root -- a string that holds the document root directory
|
||||||
mg.auth_domain -- a string that holds the HTTP authentication domain
|
mg.auth_domain -- a string that holds the HTTP authentication domain
|
||||||
mg.get_var(str, varname) -- extract variable from (query) string
|
mg.get_var(str, varname) -- extract variable from (query) string
|
||||||
mg.get_cookie(str, cookie) -- extract cookie from a string
|
mg.get_cookie(str, cookie) -- extract cookie from a string
|
||||||
mg.get_mime_type(filename) -- get MIME type of a file
|
mg.get_mime_type(filename) -- get MIME type of a file
|
||||||
mg.send_file(filename) -- send a file, including MIME type
|
mg.send_file(filename) -- send a file, including MIME type
|
||||||
mg.url_encode(str) -- URL encode a string
|
mg.url_encode(str) -- URL encode a string
|
||||||
mg.url_decode(str) -- URL decode a string
|
mg.url_decode(str) -- URL decode a string
|
||||||
|
mg.base64_encode(str) -- BASE64 encode a string
|
||||||
|
mg.base64_decode(str) -- BASE64 decode a string
|
||||||
mg.md5(str) -- return the MD5 hash of a string
|
mg.md5(str) -- return the MD5 hash of a string
|
||||||
mg.keep_alive(bool) -- allow/forbid to use http keep-alive for this request
|
mg.keep_alive(bool) -- allow/forbid to use http keep-alive for this request
|
||||||
mg.request_info -- a table with the following request information
|
mg.request_info -- a table with the following request information
|
||||||
@@ -419,7 +428,7 @@ mg (table):
|
|||||||
.query_string -- query string if present, nil otherwise
|
.query_string -- query string if present, nil otherwise
|
||||||
.script_name -- name of the Lua script
|
.script_name -- name of the Lua script
|
||||||
.https -- true if accessed by https://, false otherwise
|
.https -- true if accessed by https://, false otherwise
|
||||||
.remote_user -- user name if authenticated, nil otherwise
|
.remote_user -- user name if authenticated, nil otherwise
|
||||||
|
|
||||||
connect (function):
|
connect (function):
|
||||||
-- Connect to the remote TCP server. This function is an implementation
|
-- Connect to the remote TCP server. This function is an implementation
|
||||||
|
@@ -3,6 +3,10 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "WebSockCallbacks.h"
|
#include "WebSockCallbacks.h"
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
typedef HANDLE pthread_mutex_t;
|
typedef HANDLE pthread_mutex_t;
|
||||||
@@ -73,7 +77,7 @@ void websocket_ready_handler(struct mg_connection *conn) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("\nNew websocket attached: %08x:%u\n", rq->remote_ip, rq->remote_port);
|
printf("\nNew websocket attached: %08lx:%u\n", rq->remote_ip, rq->remote_port);
|
||||||
pthread_mutex_unlock(&sMutex);
|
pthread_mutex_unlock(&sMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +92,7 @@ static void websocket_done(tWebSockInfo * wsock) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("\nClose websocket attached: %08x:%u\n", mg_get_request_info(wsock->conn)->remote_ip, mg_get_request_info(wsock->conn)->remote_port);
|
printf("\nClose websocket attached: %08lx:%u\n", mg_get_request_info(wsock->conn)->remote_ip, mg_get_request_info(wsock->conn)->remote_port);
|
||||||
free(wsock);
|
free(wsock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,7 +111,7 @@ int websocket_data_handler(struct mg_connection *conn, int flags, char *data, si
|
|||||||
pthread_mutex_unlock(&sMutex);
|
pthread_mutex_unlock(&sMutex);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if ((data_len>=5) && (data_len<100) && (flags==129) || (flags==130)) {
|
if (((data_len>=5) && (data_len<100) && (flags==129)) || (flags==130)) {
|
||||||
|
|
||||||
// init command
|
// init command
|
||||||
if ((wsock->webSockState==1) && (!memcmp(data,"init ",5))) {
|
if ((wsock->webSockState==1) && (!memcmp(data,"init ",5))) {
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
/* Copyright (c) 2004-2013 Sergey Lyubka
|
/* Copyright (c) 2013-2014 the Civetweb developers
|
||||||
|
* Copyright (c) 2004-2013 Sergey Lyubka
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -26,6 +27,20 @@
|
|||||||
#define CIVETWEB_VERSION "1.6"
|
#define CIVETWEB_VERSION "1.6"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CIVETWEB_API
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#if defined(CIVETWEB_DLL_EXPORTS)
|
||||||
|
#define CIVETWEB_API __declspec(dllexport)
|
||||||
|
#elif defined(CIVETWEB_DLL_IMPORTS)
|
||||||
|
#define CIVETWEB_API __declspec(dllimport)
|
||||||
|
#else
|
||||||
|
#define CIVETWEB_API
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define CIVETWEB_API
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
@@ -140,6 +155,7 @@ struct mg_callbacks {
|
|||||||
int (*http_error)(struct mg_connection *, int status);
|
int (*http_error)(struct mg_connection *, int status);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Start web server.
|
/* Start web server.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@@ -165,7 +181,7 @@ struct mg_callbacks {
|
|||||||
|
|
||||||
Return:
|
Return:
|
||||||
web server context, or NULL on error. */
|
web server context, or NULL on error. */
|
||||||
struct mg_context *mg_start(const struct mg_callbacks *callbacks,
|
CIVETWEB_API struct mg_context *mg_start(const struct mg_callbacks *callbacks,
|
||||||
void *user_data,
|
void *user_data,
|
||||||
const char **configuration_options);
|
const char **configuration_options);
|
||||||
|
|
||||||
@@ -175,7 +191,8 @@ struct mg_context *mg_start(const struct mg_callbacks *callbacks,
|
|||||||
Must be called last, when an application wants to stop the web server and
|
Must be called last, when an application wants to stop the web server and
|
||||||
release all associated resources. This function blocks until all Civetweb
|
release all associated resources. This function blocks until all Civetweb
|
||||||
threads are stopped. Context pointer becomes invalid. */
|
threads are stopped. Context pointer becomes invalid. */
|
||||||
void mg_stop(struct mg_context *);
|
CIVETWEB_API void mg_stop(struct mg_context *);
|
||||||
|
|
||||||
|
|
||||||
/* mg_request_handler
|
/* mg_request_handler
|
||||||
|
|
||||||
@@ -190,6 +207,7 @@ void mg_stop(struct mg_context *);
|
|||||||
1: the handler processed the request. */
|
1: the handler processed the request. */
|
||||||
typedef int (* mg_request_handler)(struct mg_connection *conn, void *cbdata);
|
typedef int (* mg_request_handler)(struct mg_connection *conn, void *cbdata);
|
||||||
|
|
||||||
|
|
||||||
/* mg_set_request_handler
|
/* mg_set_request_handler
|
||||||
|
|
||||||
Sets or removes a URI mapping for a request handler.
|
Sets or removes a URI mapping for a request handler.
|
||||||
@@ -206,7 +224,7 @@ typedef int (* mg_request_handler)(struct mg_connection *conn, void *cbdata);
|
|||||||
handler: the callback handler to use when the URI is requested.
|
handler: the callback handler to use when the URI is requested.
|
||||||
If NULL, the URI will be removed.
|
If NULL, the URI will be removed.
|
||||||
cbdata: the callback data to give to the handler when it s requested. */
|
cbdata: the callback data to give to the handler when it s requested. */
|
||||||
void mg_set_request_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata);
|
CIVETWEB_API void mg_set_request_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata);
|
||||||
|
|
||||||
|
|
||||||
/* Get the value of particular configuration parameter.
|
/* Get the value of particular configuration parameter.
|
||||||
@@ -215,14 +233,41 @@ void mg_set_request_handler(struct mg_context *ctx, const char *uri, mg_request_
|
|||||||
If given parameter name is not valid, NULL is returned. For valid
|
If given parameter name is not valid, NULL is returned. For valid
|
||||||
names, return value is guaranteed to be non-NULL. If parameter is not
|
names, return value is guaranteed to be non-NULL. If parameter is not
|
||||||
set, zero-length string is returned. */
|
set, zero-length string is returned. */
|
||||||
const char *mg_get_option(const struct mg_context *ctx, const char *name);
|
CIVETWEB_API const char *mg_get_option(const struct mg_context *ctx, const char *name);
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(MG_LEGACY_INTERFACE)
|
||||||
/* Return array of strings that represent valid configuration options.
|
/* Return array of strings that represent valid configuration options.
|
||||||
For each option, option name and default value is returned, i.e. the
|
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.
|
number of entries in the array equals to number_of_options x 2.
|
||||||
Array is NULL terminated. */
|
Array is NULL terminated. */
|
||||||
const char **mg_get_valid_option_names(void);
|
/* Deprecated: Use mg_get_valid_options instead. */
|
||||||
|
CIVETWEB_API const char **mg_get_valid_option_names(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
struct mg_option {
|
||||||
|
const char * name;
|
||||||
|
int type;
|
||||||
|
const char * default_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CONFIG_TYPE_UNKNOWN = 0x0,
|
||||||
|
CONFIG_TYPE_NUMBER = 0x1,
|
||||||
|
CONFIG_TYPE_STRING = 0x2,
|
||||||
|
CONFIG_TYPE_FILE = 0x3,
|
||||||
|
CONFIG_TYPE_DIRECTORY = 0x4,
|
||||||
|
CONFIG_TYPE_BOOLEAN = 0x5,
|
||||||
|
CONFIG_TYPE_EXT_PATTERN = 0x6
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Return array of struct mg_option, representing all valid configuration
|
||||||
|
options of civetweb.c.
|
||||||
|
The array is terminated by a NULL name option. */
|
||||||
|
CIVETWEB_API const struct mg_option *mg_get_valid_options(void);
|
||||||
|
|
||||||
|
|
||||||
/* Get the list of ports that civetweb is listening on.
|
/* Get the list of ports that civetweb is listening on.
|
||||||
size is the size of the ports int array and ssl int array to fill.
|
size is the size of the ports int array and ssl int array to fill.
|
||||||
@@ -231,7 +276,8 @@ const char **mg_get_valid_option_names(void);
|
|||||||
Return value is the number of ports and ssl information filled in.
|
Return value is the number of ports and ssl information filled in.
|
||||||
The value returned is read-only. Civetweb does not allow changing
|
The value returned is read-only. Civetweb does not allow changing
|
||||||
configuration at run time. */
|
configuration at run time. */
|
||||||
size_t mg_get_ports(const struct mg_context *ctx, size_t size, int* ports, int* ssl);
|
CIVETWEB_API size_t mg_get_ports(const struct mg_context *ctx, size_t size, int* ports, int* ssl);
|
||||||
|
|
||||||
|
|
||||||
/* Add, edit or delete the entry in the passwords file.
|
/* Add, edit or delete the entry in the passwords file.
|
||||||
|
|
||||||
@@ -245,14 +291,14 @@ size_t mg_get_ports(const struct mg_context *ctx, size_t size, int* ports, int*
|
|||||||
|
|
||||||
Return:
|
Return:
|
||||||
1 on success, 0 on error. */
|
1 on success, 0 on error. */
|
||||||
int mg_modify_passwords_file(const char *passwords_file_name,
|
CIVETWEB_API int mg_modify_passwords_file(const char *passwords_file_name,
|
||||||
const char *domain,
|
const char *domain,
|
||||||
const char *user,
|
const char *user,
|
||||||
const char *password);
|
const char *password);
|
||||||
|
|
||||||
|
|
||||||
/* Return information associated with the request. */
|
/* Return information associated with the request. */
|
||||||
struct mg_request_info *mg_get_request_info(struct mg_connection *);
|
CIVETWEB_API struct mg_request_info *mg_get_request_info(struct mg_connection *);
|
||||||
|
|
||||||
|
|
||||||
/* Send data to the client.
|
/* Send data to the client.
|
||||||
@@ -260,7 +306,7 @@ struct mg_request_info *mg_get_request_info(struct mg_connection *);
|
|||||||
0 when the connection has been closed
|
0 when the connection has been closed
|
||||||
-1 on error
|
-1 on error
|
||||||
>0 number of bytes written on success */
|
>0 number of bytes written on success */
|
||||||
int mg_write(struct mg_connection *, const void *buf, size_t len);
|
CIVETWEB_API int mg_write(struct mg_connection *, const void *buf, size_t len);
|
||||||
|
|
||||||
|
|
||||||
/* Send data to a websocket client wrapped in a websocket frame. Uses mg_lock
|
/* Send data to a websocket client wrapped in a websocket frame. Uses mg_lock
|
||||||
@@ -275,16 +321,18 @@ int mg_write(struct mg_connection *, const void *buf, size_t len);
|
|||||||
0 when the connection has been closed
|
0 when the connection has been closed
|
||||||
-1 on error
|
-1 on error
|
||||||
>0 number of bytes written on success */
|
>0 number of bytes written on success */
|
||||||
int mg_websocket_write(struct mg_connection* conn, int opcode,
|
CIVETWEB_API int mg_websocket_write(struct mg_connection* conn, int opcode,
|
||||||
const char *data, size_t data_len);
|
const char *data, size_t data_len);
|
||||||
|
|
||||||
|
|
||||||
/* Blocks until unique access is obtained to this connection. Intended for use
|
/* Blocks until unique access is obtained to this connection. Intended for use
|
||||||
with websockets only.
|
with websockets only.
|
||||||
Invoke this before mg_write or mg_printf when communicating with a
|
Invoke this before mg_write or mg_printf when communicating with a
|
||||||
websocket if your code has server-initiated communication as well as
|
websocket if your code has server-initiated communication as well as
|
||||||
communication in direct response to a message. */
|
communication in direct response to a message. */
|
||||||
void mg_lock(struct mg_connection* conn);
|
CIVETWEB_API void mg_lock(struct mg_connection* conn);
|
||||||
void mg_unlock(struct mg_connection* conn);
|
CIVETWEB_API void mg_unlock(struct mg_connection* conn);
|
||||||
|
|
||||||
|
|
||||||
/* Opcodes, from http://tools.ietf.org/html/rfc6455 */
|
/* Opcodes, from http://tools.ietf.org/html/rfc6455 */
|
||||||
enum {
|
enum {
|
||||||
@@ -317,14 +365,13 @@ enum {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Send data to the client using printf() semantics.
|
/* Send data to the client using printf() semantics.
|
||||||
|
|
||||||
Works exactly like mg_write(), but allows to do message formatting. */
|
Works exactly like mg_write(), but allows to do message formatting. */
|
||||||
int mg_printf(struct mg_connection *,
|
CIVETWEB_API int mg_printf(struct mg_connection *,
|
||||||
PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
|
PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
|
||||||
|
|
||||||
|
|
||||||
/* Send contents of the entire file together with HTTP headers. */
|
/* Send contents of the entire file together with HTTP headers. */
|
||||||
void mg_send_file(struct mg_connection *conn, const char *path);
|
CIVETWEB_API void mg_send_file(struct mg_connection *conn, const char *path);
|
||||||
|
|
||||||
|
|
||||||
/* Read data from the remote end, return number of bytes read.
|
/* Read data from the remote end, return number of bytes read.
|
||||||
@@ -332,7 +379,7 @@ void mg_send_file(struct mg_connection *conn, const char *path);
|
|||||||
0 connection has been closed by peer. No more data could be read.
|
0 connection has been closed by peer. No more data could be read.
|
||||||
< 0 read error. No more data could be read from the connection.
|
< 0 read error. No more data could be read from the connection.
|
||||||
> 0 number of bytes read into the buffer. */
|
> 0 number of bytes read into the buffer. */
|
||||||
int mg_read(struct mg_connection *, void *buf, size_t len);
|
CIVETWEB_API int mg_read(struct mg_connection *, void *buf, size_t len);
|
||||||
|
|
||||||
|
|
||||||
/* Get the value of particular HTTP header.
|
/* Get the value of particular HTTP header.
|
||||||
@@ -340,7 +387,7 @@ int mg_read(struct mg_connection *, void *buf, size_t len);
|
|||||||
This is a helper function. It traverses request_info->http_headers array,
|
This is a helper function. It traverses request_info->http_headers array,
|
||||||
and if the header is present in the array, returns its value. If it is
|
and if the header is present in the array, returns its value. If it is
|
||||||
not present, NULL is returned. */
|
not present, NULL is returned. */
|
||||||
const char *mg_get_header(const struct mg_connection *, const char *name);
|
CIVETWEB_API const char *mg_get_header(const struct mg_connection *, const char *name);
|
||||||
|
|
||||||
|
|
||||||
/* Get a value of particular form variable.
|
/* Get a value of particular form variable.
|
||||||
@@ -362,8 +409,9 @@ const char *mg_get_header(const struct mg_connection *, const char *name);
|
|||||||
|
|
||||||
Destination buffer is guaranteed to be '\0' - terminated if it is not
|
Destination buffer is guaranteed to be '\0' - terminated if it is not
|
||||||
NULL or zero length. */
|
NULL or zero length. */
|
||||||
int mg_get_var(const char *data, size_t data_len,
|
CIVETWEB_API int mg_get_var(const char *data, size_t data_len,
|
||||||
const char *var_name, char *dst, size_t dst_len);
|
const char *var_name, char *dst, size_t dst_len);
|
||||||
|
|
||||||
|
|
||||||
/* Get a value of particular form variable.
|
/* Get a value of particular form variable.
|
||||||
|
|
||||||
@@ -388,8 +436,9 @@ int mg_get_var(const char *data, size_t data_len,
|
|||||||
|
|
||||||
Destination buffer is guaranteed to be '\0' - terminated if it is not
|
Destination buffer is guaranteed to be '\0' - terminated if it is not
|
||||||
NULL or zero length. */
|
NULL or zero length. */
|
||||||
int mg_get_var2(const char *data, size_t data_len,
|
CIVETWEB_API int mg_get_var2(const char *data, size_t data_len,
|
||||||
const char *var_name, char *dst, size_t dst_len, size_t occurrence);
|
const char *var_name, char *dst, size_t dst_len, size_t occurrence);
|
||||||
|
|
||||||
|
|
||||||
/* Fetch value of certain cookie variable into the destination buffer.
|
/* Fetch value of certain cookie variable into the destination buffer.
|
||||||
|
|
||||||
@@ -404,8 +453,8 @@ int mg_get_var2(const char *data, size_t data_len,
|
|||||||
parameter is not found).
|
parameter is not found).
|
||||||
-2 (destination buffer is NULL, zero length or too small to hold the
|
-2 (destination buffer is NULL, zero length or too small to hold the
|
||||||
value). */
|
value). */
|
||||||
int mg_get_cookie(const char *cookie, const char *var_name,
|
CIVETWEB_API int mg_get_cookie(const char *cookie, const char *var_name,
|
||||||
char *buf, size_t buf_len);
|
char *buf, size_t buf_len);
|
||||||
|
|
||||||
|
|
||||||
/* Download data from the remote web server.
|
/* Download data from the remote web server.
|
||||||
@@ -423,35 +472,36 @@ int mg_get_cookie(const char *cookie, const char *var_name,
|
|||||||
conn = mg_download("google.com", 80, 0, ebuf, sizeof(ebuf),
|
conn = mg_download("google.com", 80, 0, ebuf, sizeof(ebuf),
|
||||||
"%s", "GET / HTTP/1.0\r\nHost: google.com\r\n\r\n");
|
"%s", "GET / HTTP/1.0\r\nHost: google.com\r\n\r\n");
|
||||||
*/
|
*/
|
||||||
struct mg_connection *mg_download(const char *host, int port, int use_ssl,
|
CIVETWEB_API struct mg_connection *mg_download(const char *host, int port, int use_ssl,
|
||||||
char *error_buffer, size_t error_buffer_size,
|
char *error_buffer, size_t error_buffer_size,
|
||||||
PRINTF_FORMAT_STRING(const char *request_fmt),
|
PRINTF_FORMAT_STRING(const char *request_fmt),
|
||||||
...) PRINTF_ARGS(6, 7);
|
...) PRINTF_ARGS(6, 7);
|
||||||
|
|
||||||
|
|
||||||
/* Close the connection opened by mg_download(). */
|
/* Close the connection opened by mg_download(). */
|
||||||
void mg_close_connection(struct mg_connection *conn);
|
CIVETWEB_API void mg_close_connection(struct mg_connection *conn);
|
||||||
|
|
||||||
|
|
||||||
/* File upload functionality. Each uploaded file gets saved into a temporary
|
/* File upload functionality. Each uploaded file gets saved into a temporary
|
||||||
file and MG_UPLOAD event is sent.
|
file and MG_UPLOAD event is sent.
|
||||||
Return number of uploaded files. */
|
Return number of uploaded files. */
|
||||||
int mg_upload(struct mg_connection *conn, const char *destination_dir);
|
CIVETWEB_API int mg_upload(struct mg_connection *conn, const char *destination_dir);
|
||||||
|
|
||||||
|
|
||||||
/* Convenience function -- create detached thread.
|
/* Convenience function -- create detached thread.
|
||||||
Return: 0 on success, non-0 on error. */
|
Return: 0 on success, non-0 on error. */
|
||||||
typedef void * (*mg_thread_func_t)(void *);
|
typedef void * (*mg_thread_func_t)(void *);
|
||||||
int mg_start_thread(mg_thread_func_t f, void *p);
|
CIVETWEB_API int mg_start_thread(mg_thread_func_t f, void *p);
|
||||||
|
|
||||||
|
|
||||||
/* Return builtin mime type for the given file name.
|
/* Return builtin mime type for the given file name.
|
||||||
For unrecognized extensions, "text/plain" is returned. */
|
For unrecognized extensions, "text/plain" is returned. */
|
||||||
const char *mg_get_builtin_mime_type(const char *file_name);
|
CIVETWEB_API const char *mg_get_builtin_mime_type(const char *file_name);
|
||||||
|
|
||||||
|
|
||||||
/* Return Civetweb version. */
|
/* Return Civetweb version. */
|
||||||
const char *mg_version(void);
|
CIVETWEB_API const char *mg_version(void);
|
||||||
|
|
||||||
|
|
||||||
/* URL-decode input buffer into destination buffer.
|
/* URL-decode input buffer into destination buffer.
|
||||||
0-terminate the destination buffer.
|
0-terminate the destination buffer.
|
||||||
@@ -459,13 +509,15 @@ const char *mg_version(void);
|
|||||||
uses '+' as character for space, see RFC 1866 section 8.2.1
|
uses '+' as character for space, see RFC 1866 section 8.2.1
|
||||||
http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
|
http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
|
||||||
Return: length of the decoded data, or -1 if dst buffer is too small. */
|
Return: length of the decoded data, or -1 if dst buffer is too small. */
|
||||||
int mg_url_decode(const char *src, int src_len, char *dst,
|
CIVETWEB_API int mg_url_decode(const char *src, int src_len, char *dst,
|
||||||
int dst_len, int is_form_url_encoded);
|
int dst_len, int is_form_url_encoded);
|
||||||
|
|
||||||
|
|
||||||
/* URL-encode input buffer into destination buffer.
|
/* URL-encode input buffer into destination buffer.
|
||||||
returns the length of the resulting buffer or -1
|
returns the length of the resulting buffer or -1
|
||||||
is the buffer is too small. */
|
is the buffer is too small. */
|
||||||
int mg_url_encode(const char *src, char *dst, size_t dst_len);
|
CIVETWEB_API int mg_url_encode(const char *src, char *dst, size_t dst_len);
|
||||||
|
|
||||||
|
|
||||||
/* MD5 hash given strings.
|
/* MD5 hash given strings.
|
||||||
Buffer 'buf' must be 33 bytes long. Varargs is a NULL terminated list of
|
Buffer 'buf' must be 33 bytes long. Varargs is a NULL terminated list of
|
||||||
@@ -473,7 +525,7 @@ int mg_url_encode(const char *src, char *dst, size_t dst_len);
|
|||||||
MD5 hash. Example:
|
MD5 hash. Example:
|
||||||
char buf[33];
|
char buf[33];
|
||||||
mg_md5(buf, "aa", "bb", NULL); */
|
mg_md5(buf, "aa", "bb", NULL); */
|
||||||
char *mg_md5(char buf[33], ...);
|
CIVETWEB_API char *mg_md5(char buf[33], ...);
|
||||||
|
|
||||||
|
|
||||||
/* Print error message to the opened error log stream.
|
/* Print error message to the opened error log stream.
|
||||||
@@ -483,11 +535,13 @@ char *mg_md5(char buf[33], ...);
|
|||||||
...: variable argument list
|
...: variable argument list
|
||||||
Example:
|
Example:
|
||||||
mg_cry(conn,"i like %s", "logging"); */
|
mg_cry(conn,"i like %s", "logging"); */
|
||||||
void mg_cry(struct mg_connection *conn,
|
CIVETWEB_API void mg_cry(struct mg_connection *conn,
|
||||||
PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
|
PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
|
||||||
|
|
||||||
|
|
||||||
/* utility method to compare two buffers, case incensitive. */
|
/* utility method to compare two buffers, case incensitive. */
|
||||||
int mg_strncasecmp(const char *s1, const char *s2, size_t len);
|
CIVETWEB_API int mg_strncasecmp(const char *s1, const char *s2, size_t len);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@@ -1,15 +0,0 @@
|
|||||||
LIBRARY
|
|
||||||
EXPORTS
|
|
||||||
mg_start
|
|
||||||
mg_stop
|
|
||||||
mg_read
|
|
||||||
mg_write
|
|
||||||
mg_printf
|
|
||||||
mg_get_header
|
|
||||||
mg_get_var
|
|
||||||
mg_get_cookie
|
|
||||||
mg_get_option
|
|
||||||
mg_get_valid_option_names
|
|
||||||
mg_version
|
|
||||||
mg_modify_passwords_file
|
|
||||||
mg_md5
|
|
@@ -150,8 +150,19 @@ bool
|
|||||||
CivetServer::getParam(struct mg_connection *conn, const char *name,
|
CivetServer::getParam(struct mg_connection *conn, const char *name,
|
||||||
std::string &dst, size_t occurrence)
|
std::string &dst, size_t occurrence)
|
||||||
{
|
{
|
||||||
const char *query = mg_get_request_info(conn)->query_string;
|
const char *formParams = NULL;
|
||||||
return getParam(query, strlen(query), name, dst, occurrence);
|
mg_request_info * ri = mg_get_request_info(conn);
|
||||||
|
|
||||||
|
if (ri) {
|
||||||
|
// get requests do store html <form> field values in the http query_string
|
||||||
|
formParams = ri->query_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (formParams) {
|
||||||
|
return getParam(formParams, strlen(formParams), name, dst, occurrence);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
628
src/civetweb.c
628
src/civetweb.c
File diff suppressed because it is too large
Load Diff
308
src/main.c
308
src/main.c
@@ -1,4 +1,5 @@
|
|||||||
/* Copyright (c) 2004-2013 Sergey Lyubka
|
/* Copyright (c) 2013-2014 the Civetweb developers
|
||||||
|
* Copyright (c) 2004-2013 Sergey Lyubka
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -39,6 +40,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "civetweb.h"
|
#include "civetweb.h"
|
||||||
|
|
||||||
@@ -76,10 +78,11 @@ extern char *_getcwd(char *buf, size_t size);
|
|||||||
#define MAX_CONF_FILE_LINE_SIZE (8 * 1024)
|
#define MAX_CONF_FILE_LINE_SIZE (8 * 1024)
|
||||||
|
|
||||||
static int exit_flag;
|
static int exit_flag;
|
||||||
static char server_name[40]; /* Set by init_server_name() */
|
static char server_base_name[40]; /* Set by init_server_name() */
|
||||||
static char config_file[PATH_MAX] = ""; /* Set by
|
static char *server_name; /* Set by init_server_name() */
|
||||||
process_command_line_arguments() */
|
static char *icon_name; /* Set by init_server_name() */
|
||||||
static struct mg_context *ctx; /* Set by start_civetweb() */
|
static char config_file[PATH_MAX] = ""; /* Set by process_command_line_arguments() */
|
||||||
|
static struct mg_context *ctx; /* Set by start_civetweb() */
|
||||||
|
|
||||||
#if !defined(CONFIG_FILE)
|
#if !defined(CONFIG_FILE)
|
||||||
#define CONFIG_FILE "civetweb.conf"
|
#define CONFIG_FILE "civetweb.conf"
|
||||||
@@ -90,6 +93,18 @@ static struct mg_context *ctx; /* Set by start_civetweb() */
|
|||||||
#define CONFIG_FILE2 "/usr/local/etc/civetweb.conf"
|
#define CONFIG_FILE2 "/usr/local/etc/civetweb.conf"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum {
|
||||||
|
OPTION_TITLE,
|
||||||
|
OPTION_ICON,
|
||||||
|
NUM_MAIN_OPTIONS
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct mg_option main_config_options[] = {
|
||||||
|
{"title", CONFIG_TYPE_STRING, NULL},
|
||||||
|
{"icon", CONFIG_TYPE_STRING, NULL},
|
||||||
|
{NULL, CONFIG_TYPE_UNKNOWN, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
static void WINCDECL signal_handler(int sig_num)
|
static void WINCDECL signal_handler(int sig_num)
|
||||||
{
|
{
|
||||||
exit_flag = sig_num;
|
exit_flag = sig_num;
|
||||||
@@ -116,9 +131,18 @@ static void die(const char *fmt, ...)
|
|||||||
|
|
||||||
static void show_usage_and_exit(void)
|
static void show_usage_and_exit(void)
|
||||||
{
|
{
|
||||||
const char **names;
|
const struct mg_option *options;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
if (!AttachConsole(ATTACH_PARENT_PROCESS)) {
|
||||||
|
AllocConsole();
|
||||||
|
AttachConsole(GetCurrentProcessId());
|
||||||
|
}
|
||||||
|
freopen("CON", "a", stdout);
|
||||||
|
freopen("CON", "a", stderr);
|
||||||
|
#endif
|
||||||
|
|
||||||
fprintf(stderr, "Civetweb v%s, built on %s\n",
|
fprintf(stderr, "Civetweb v%s, built on %s\n",
|
||||||
mg_version(), __DATE__);
|
mg_version(), __DATE__);
|
||||||
fprintf(stderr, "Usage:\n");
|
fprintf(stderr, "Usage:\n");
|
||||||
@@ -127,11 +151,16 @@ static void show_usage_and_exit(void)
|
|||||||
fprintf(stderr, " civetweb [-option value ...]\n");
|
fprintf(stderr, " civetweb [-option value ...]\n");
|
||||||
fprintf(stderr, "\nOPTIONS:\n");
|
fprintf(stderr, "\nOPTIONS:\n");
|
||||||
|
|
||||||
names = mg_get_valid_option_names();
|
options = mg_get_valid_options();
|
||||||
for (i = 0; names[i] != NULL; i += 2) {
|
for (i = 0; options[i].name != NULL; i++) {
|
||||||
fprintf(stderr, " -%s %s\n",
|
fprintf(stderr, " -%s %s\n", options[i].name, ((options[i].default_value == NULL) ? "<empty>" : options[i].default_value));
|
||||||
names[i], names[i + 1] == NULL ? "<empty>" : names[i + 1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
options = main_config_options;
|
||||||
|
for (i = 0; options[i].name != NULL; i++) {
|
||||||
|
fprintf(stderr, " -%s %s\n", options[i].name, ((options[i].default_value == NULL) ? "<empty>" : options[i].default_value));
|
||||||
|
}
|
||||||
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +194,8 @@ static const char *get_url_to_first_open_port(const struct mg_context *ctx)
|
|||||||
|
|
||||||
static void create_config_file(const char *path)
|
static void create_config_file(const char *path)
|
||||||
{
|
{
|
||||||
const char **names, *value;
|
const struct mg_option *options;
|
||||||
|
const char *value;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -174,10 +204,10 @@ static void create_config_file(const char *path)
|
|||||||
fclose(fp);
|
fclose(fp);
|
||||||
} else if ((fp = fopen(path, "a+")) != NULL) {
|
} else if ((fp = fopen(path, "a+")) != NULL) {
|
||||||
fprintf(fp, "%s", config_file_top_comment);
|
fprintf(fp, "%s", config_file_top_comment);
|
||||||
names = mg_get_valid_option_names();
|
options = mg_get_valid_options();
|
||||||
for (i = 0; names[i * 2] != NULL; i++) {
|
for (i = 0; options[i].name != NULL; i++) {
|
||||||
value = mg_get_option(ctx, names[i * 2]);
|
value = mg_get_option(ctx, options[i].name);
|
||||||
fprintf(fp, "# %s %s\n", names[i * 2], value ? value : "<value>");
|
fprintf(fp, "# %s %s\n", options[i].name, value ? value : "<value>");
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
@@ -196,9 +226,41 @@ static char *sdup(const char *str)
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_option(char **options, const char *name, const char *value)
|
static int set_option(char **options, const char *name, const char *value)
|
||||||
{
|
{
|
||||||
int i;
|
int i, type;
|
||||||
|
const struct mg_option *default_options = mg_get_valid_options();
|
||||||
|
|
||||||
|
for (i = 0; main_config_options[i].name != 0; i++) {
|
||||||
|
if (0==strcmp(name, main_config_options[i].name)) {
|
||||||
|
/* This option is evaluated by main.c, not civetweb.c - just skip it and return OK */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type = CONFIG_TYPE_UNKNOWN;
|
||||||
|
for (i = 0; default_options[i].name != 0; i++) {
|
||||||
|
if (!strcmp(default_options[i].name, name)) {
|
||||||
|
type = default_options[i].type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (type) {
|
||||||
|
case CONFIG_TYPE_UNKNOWN:
|
||||||
|
/* unknown option */
|
||||||
|
return 0;
|
||||||
|
case CONFIG_TYPE_NUMBER:
|
||||||
|
if (atol(value)<1) {
|
||||||
|
/* invalid number */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CONFIG_TYPE_BOOLEAN:
|
||||||
|
if ((0!=strcmp(value,"yes")) && (0!=strcmp(value,"no"))) {
|
||||||
|
/* invalid boolean */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < MAX_OPTIONS - 3; i++) {
|
for (i = 0; i < MAX_OPTIONS - 3; i++) {
|
||||||
if (options[i] == NULL) {
|
if (options[i] == NULL) {
|
||||||
@@ -216,14 +278,16 @@ static void set_option(char **options, const char *name, const char *value)
|
|||||||
if (i == MAX_OPTIONS - 3) {
|
if (i == MAX_OPTIONS - 3) {
|
||||||
die("%s", "Too many options specified");
|
die("%s", "Too many options specified");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
/* TODO: check if this option is defined and the correct data type, return 1 (OK) or 0 (false) */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void read_config_file(const char *config_file, char **options)
|
static void read_config_file(const char *config_file, char **options)
|
||||||
{
|
{
|
||||||
char line[MAX_CONF_FILE_LINE_SIZE], opt[sizeof(line)], val[sizeof(line)], *p;
|
char line[MAX_CONF_FILE_LINE_SIZE], *p;
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
size_t i, cmd_line_opts_start = 1, line_no = 0;
|
size_t i, j, cmd_line_opts_start = 1, line_no = 0;
|
||||||
|
|
||||||
fp = fopen(config_file, "r");
|
fp = fopen(config_file, "r");
|
||||||
|
|
||||||
@@ -253,11 +317,23 @@ static void read_config_file(const char *config_file, char **options)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sscanf(p, "%s %[^\r\n#]", opt, val) != 2) {
|
/* Skip spaces, \r and \n at the end of the line */
|
||||||
|
for (j = strlen(line)-1; isspace(* (unsigned char *) &line[j]) || iscntrl(* (unsigned char *) &line[j]); ) line[j--]=0;
|
||||||
|
|
||||||
|
/* Find the space character between option name and value */
|
||||||
|
for (j=i; !isspace(* (unsigned char *) &line[j]) && (line[j]!=0); ) j++;
|
||||||
|
|
||||||
|
/* Terminate the string - then the string at (line+i) contains the option name */
|
||||||
|
line[j] = 0;
|
||||||
|
j++;
|
||||||
|
|
||||||
|
/* Trim additional spaces between option name and value - then (line+j) contains the option value */
|
||||||
|
while (isspace(line[j])) j++;
|
||||||
|
|
||||||
|
/* Set option */
|
||||||
|
if (!set_option(options, line+i, line+j)) {
|
||||||
printf("%s: line %d is invalid, ignoring it:\n %s",
|
printf("%s: line %d is invalid, ignoring it:\n %s",
|
||||||
config_file, (int) line_no, p);
|
config_file, (int) line_no, p);
|
||||||
} else {
|
|
||||||
set_option(options, opt, val);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,7 +341,6 @@ static void read_config_file(const char *config_file, char **options)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void process_command_line_arguments(char *argv[], char **options)
|
static void process_command_line_arguments(char *argv[], char **options)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
@@ -314,15 +389,34 @@ static void process_command_line_arguments(char *argv[], char **options)
|
|||||||
if (argv[i][0] != '-' || argv[i + 1] == NULL) {
|
if (argv[i][0] != '-' || argv[i + 1] == NULL) {
|
||||||
show_usage_and_exit();
|
show_usage_and_exit();
|
||||||
}
|
}
|
||||||
set_option(options, &argv[i][1], argv[i + 1]);
|
if (!set_option(options, &argv[i][1], argv[i + 1])) {
|
||||||
|
printf("command line option is invalid, ignoring it:\n %s %s\n",
|
||||||
|
argv[i], argv[i + 1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_server_name(void)
|
static void init_server_name(int argc, const char *argv[])
|
||||||
{
|
{
|
||||||
snprintf(server_name, sizeof(server_name), "Civetweb v%s",
|
int i;
|
||||||
|
assert(sizeof(main_config_options)/sizeof(main_config_options[0]) == NUM_MAIN_OPTIONS+1);
|
||||||
|
assert((strlen(mg_version())+12)<sizeof(server_base_name));
|
||||||
|
snprintf(server_base_name, sizeof(server_base_name), "Civetweb V%s",
|
||||||
mg_version());
|
mg_version());
|
||||||
|
|
||||||
|
server_name = server_base_name;
|
||||||
|
for (i=0; i<argc-1; i++) {
|
||||||
|
if ((argv[i][0]=='-') && (0==strcmp(argv[i]+1, main_config_options[OPTION_TITLE].name))) {
|
||||||
|
server_name = (char*)(argv[i+1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
icon_name = 0;
|
||||||
|
for (i=0; i<argc-1; i++) {
|
||||||
|
if ((argv[i][0]=='-') && (0==strcmp(argv[i]+1, main_config_options[OPTION_ICON].name))) {
|
||||||
|
icon_name = (char*)(argv[i+1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int log_message(const struct mg_connection *conn, const char *message)
|
static int log_message(const struct mg_connection *conn, const char *message)
|
||||||
@@ -448,12 +542,18 @@ static void start_civetweb(int argc, char *argv[])
|
|||||||
set_absolute_path(options, "access_log_file", argv[0]);
|
set_absolute_path(options, "access_log_file", argv[0]);
|
||||||
set_absolute_path(options, "error_log_file", argv[0]);
|
set_absolute_path(options, "error_log_file", argv[0]);
|
||||||
set_absolute_path(options, "global_auth_file", argv[0]);
|
set_absolute_path(options, "global_auth_file", argv[0]);
|
||||||
|
#ifdef USE_LUA
|
||||||
|
set_absolute_path(options, "lua_preload_file", argv[0]);
|
||||||
|
#endif
|
||||||
set_absolute_path(options, "ssl_certificate", argv[0]);
|
set_absolute_path(options, "ssl_certificate", argv[0]);
|
||||||
|
|
||||||
/* Make extra verification for certain options */
|
/* Make extra verification for certain options */
|
||||||
verify_existence(options, "document_root", 1);
|
verify_existence(options, "document_root", 1);
|
||||||
verify_existence(options, "cgi_interpreter", 0);
|
verify_existence(options, "cgi_interpreter", 0);
|
||||||
verify_existence(options, "ssl_certificate", 0);
|
verify_existence(options, "ssl_certificate", 0);
|
||||||
|
#ifdef USE_LUA
|
||||||
|
verify_existence(options, "lua_preload_file", 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Setup signal handler: quit on Ctrl-C */
|
/* Setup signal handler: quit on Ctrl-C */
|
||||||
signal(SIGTERM, signal_handler);
|
signal(SIGTERM, signal_handler);
|
||||||
@@ -541,54 +641,28 @@ static void *align(void *ptr, DWORD alig)
|
|||||||
return ((void *) ul);
|
return ((void *) ul);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_boolean_option(const char *option_name)
|
|
||||||
{
|
|
||||||
return !strcmp(option_name, "enable_directory_listing") ||
|
|
||||||
!strcmp(option_name, "enable_keep_alive");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int is_filename_option(const char *option_name)
|
|
||||||
{
|
|
||||||
return !strcmp(option_name, "cgi_interpreter") ||
|
|
||||||
!strcmp(option_name, "global_auth_file") ||
|
|
||||||
!strcmp(option_name, "put_delete_auth_file") ||
|
|
||||||
!strcmp(option_name, "access_log_file") ||
|
|
||||||
!strcmp(option_name, "error_log_file") ||
|
|
||||||
!strcmp(option_name, "ssl_certificate");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int is_directory_option(const char *option_name)
|
|
||||||
{
|
|
||||||
return !strcmp(option_name, "document_root");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int is_numeric_options(const char *option_name)
|
|
||||||
{
|
|
||||||
return !strcmp(option_name, "num_threads");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void save_config(HWND hDlg, FILE *fp)
|
static void save_config(HWND hDlg, FILE *fp)
|
||||||
{
|
{
|
||||||
char value[2000] = "";
|
char value[2000] = "";
|
||||||
const char **options, *name, *default_value;
|
const char *default_value;
|
||||||
|
const struct mg_option *options;
|
||||||
int i, id;
|
int i, id;
|
||||||
|
|
||||||
fprintf(fp, "%s", config_file_top_comment);
|
fprintf(fp, "%s", config_file_top_comment);
|
||||||
options = mg_get_valid_option_names();
|
options = mg_get_valid_options();
|
||||||
for (i = 0; options[i * 2] != NULL; i++) {
|
for (i = 0; options[i].name != NULL; i++) {
|
||||||
name = options[i * 2];
|
|
||||||
id = ID_CONTROLS + i;
|
id = ID_CONTROLS + i;
|
||||||
if (is_boolean_option(name)) {
|
if (options[i].type == CONFIG_TYPE_BOOLEAN) {
|
||||||
snprintf(value, sizeof(value)-1, "%s",
|
snprintf(value, sizeof(value)-1, "%s",
|
||||||
IsDlgButtonChecked(hDlg, id) ? "yes" : "no");
|
IsDlgButtonChecked(hDlg, id) ? "yes" : "no");
|
||||||
value[sizeof(value)-1] = 0;
|
value[sizeof(value)-1] = 0;
|
||||||
} else {
|
} else {
|
||||||
GetDlgItemText(hDlg, id, value, sizeof(value));
|
GetDlgItemText(hDlg, id, value, sizeof(value));
|
||||||
}
|
}
|
||||||
default_value = options[i * 2 + 1] == NULL ? "" : options[i * 2 + 1];
|
default_value = options[i].default_value == NULL ? "" : options[i].default_value;
|
||||||
/* If value is the same as default, skip it */
|
/* If value is the same as default, skip it */
|
||||||
if (strcmp(value, default_value) != 0) {
|
if (strcmp(value, default_value) != 0) {
|
||||||
fprintf(fp, "%s %s\n", name, value);
|
fprintf(fp, "%s %s\n", options[i].name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -598,8 +672,9 @@ static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
|
|||||||
FILE *fp;
|
FILE *fp;
|
||||||
int i, j;
|
int i, j;
|
||||||
const char *name, *value;
|
const char *name, *value;
|
||||||
const char **default_options = mg_get_valid_option_names();
|
const struct mg_option *default_options = mg_get_valid_options();
|
||||||
char *file_options[MAX_OPTIONS] = {0};
|
char *file_options[MAX_OPTIONS] = {0};
|
||||||
|
char *title;
|
||||||
|
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
case WM_CLOSE:
|
case WM_CLOSE:
|
||||||
@@ -608,6 +683,7 @@ static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
|
|||||||
|
|
||||||
case WM_COMMAND:
|
case WM_COMMAND:
|
||||||
switch (LOWORD(wParam)) {
|
switch (LOWORD(wParam)) {
|
||||||
|
|
||||||
case ID_SAVE:
|
case ID_SAVE:
|
||||||
EnableWindow(GetDlgItem(hDlg, ID_SAVE), FALSE);
|
EnableWindow(GetDlgItem(hDlg, ID_SAVE), FALSE);
|
||||||
if ((fp = fopen(config_file, "w+")) != NULL) {
|
if ((fp = fopen(config_file, "w+")) != NULL) {
|
||||||
@@ -618,11 +694,12 @@ static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
|
|||||||
}
|
}
|
||||||
EnableWindow(GetDlgItem(hDlg, ID_SAVE), TRUE);
|
EnableWindow(GetDlgItem(hDlg, ID_SAVE), TRUE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ID_RESET_DEFAULTS:
|
case ID_RESET_DEFAULTS:
|
||||||
for (i = 0; default_options[i * 2] != NULL; i++) {
|
for (i = 0; default_options[i].name != NULL; i++) {
|
||||||
name = default_options[i * 2];
|
name = default_options[i].name;
|
||||||
value = default_options[i * 2 + 1] == NULL ? "" : default_options[i * 2 + 1];
|
value = default_options[i].default_value == NULL ? "" : default_options[i].default_value;
|
||||||
if (is_boolean_option(name)) {
|
if (default_options[i].type == CONFIG_TYPE_BOOLEAN) {
|
||||||
CheckDlgButton(hDlg, ID_CONTROLS + i, !strcmp(value, "yes") ?
|
CheckDlgButton(hDlg, ID_CONTROLS + i, !strcmp(value, "yes") ?
|
||||||
BST_CHECKED : BST_UNCHECKED);
|
BST_CHECKED : BST_UNCHECKED);
|
||||||
} else {
|
} else {
|
||||||
@@ -630,11 +707,12 @@ static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ID_RESET_FILE:
|
case ID_RESET_FILE:
|
||||||
read_config_file(config_file, file_options);
|
read_config_file(config_file, file_options);
|
||||||
for (i = 0; default_options[i * 2] != NULL; i++) {
|
for (i = 0; default_options[i].name != NULL; i++) {
|
||||||
name = default_options[i * 2];
|
name = default_options[i].name;
|
||||||
value = default_options[i * 2 + 1];
|
value = default_options[i].default_value;
|
||||||
for (j = 0; file_options[j * 2] != NULL; j++) {
|
for (j = 0; file_options[j * 2] != NULL; j++) {
|
||||||
if (!strcmp(name, file_options[j * 2])) {
|
if (!strcmp(name, file_options[j * 2])) {
|
||||||
value = file_options[j * 2 + 1];
|
value = file_options[j * 2 + 1];
|
||||||
@@ -643,7 +721,7 @@ static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
|
|||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
value = "";
|
value = "";
|
||||||
}
|
}
|
||||||
if (is_boolean_option(name)) {
|
if (default_options[i].type == CONFIG_TYPE_BOOLEAN) {
|
||||||
CheckDlgButton(hDlg, ID_CONTROLS + i, !strcmp(value, "yes") ? BST_CHECKED : BST_UNCHECKED);
|
CheckDlgButton(hDlg, ID_CONTROLS + i, !strcmp(value, "yes") ? BST_CHECKED : BST_UNCHECKED);
|
||||||
} else {
|
} else {
|
||||||
SetWindowText(GetDlgItem(hDlg, ID_CONTROLS + i), value);
|
SetWindowText(GetDlgItem(hDlg, ID_CONTROLS + i), value);
|
||||||
@@ -653,11 +731,12 @@ static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
|
|||||||
free(file_options[i]);
|
free(file_options[i]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ID_RESET_ACTIVE:
|
case ID_RESET_ACTIVE:
|
||||||
for (i = 0; default_options[i * 2] != NULL; i++) {
|
for (i = 0; default_options[i].name != NULL; i++) {
|
||||||
name = default_options[i * 2];
|
name = default_options[i].name;
|
||||||
value = mg_get_option(ctx, name);
|
value = mg_get_option(ctx, name);
|
||||||
if (is_boolean_option(name)) {
|
if (default_options[i].type == CONFIG_TYPE_BOOLEAN) {
|
||||||
CheckDlgButton(hDlg, ID_CONTROLS + i, !strcmp(value, "yes") ?
|
CheckDlgButton(hDlg, ID_CONTROLS + i, !strcmp(value, "yes") ?
|
||||||
BST_CHECKED : BST_UNCHECKED);
|
BST_CHECKED : BST_UNCHECKED);
|
||||||
} else {
|
} else {
|
||||||
@@ -667,9 +746,9 @@ static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; default_options[i * 2] != NULL; i++) {
|
for (i = 0; default_options[i].name != NULL; i++) {
|
||||||
name = default_options[i * 2];
|
name = default_options[i].name;
|
||||||
if ((is_filename_option(name) || is_directory_option(name)) &&
|
if (((default_options[i].type == CONFIG_TYPE_FILE) || (default_options[i].type == CONFIG_TYPE_DIRECTORY)) &&
|
||||||
LOWORD(wParam) == ID_CONTROLS + i + ID_FILE_BUTTONS_DELTA) {
|
LOWORD(wParam) == ID_CONTROLS + i + ID_FILE_BUTTONS_DELTA) {
|
||||||
OPENFILENAME of;
|
OPENFILENAME of;
|
||||||
BROWSEINFO bi;
|
BROWSEINFO bi;
|
||||||
@@ -681,14 +760,14 @@ static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
|
|||||||
of.lpstrFile = path;
|
of.lpstrFile = path;
|
||||||
of.nMaxFile = sizeof(path);
|
of.nMaxFile = sizeof(path);
|
||||||
of.lpstrInitialDir = mg_get_option(ctx, "document_root");
|
of.lpstrInitialDir = mg_get_option(ctx, "document_root");
|
||||||
of.Flags = OFN_CREATEPROMPT | OFN_NOCHANGEDIR;
|
of.Flags = OFN_CREATEPROMPT | OFN_NOCHANGEDIR | OFN_HIDEREADONLY;
|
||||||
|
|
||||||
memset(&bi, 0, sizeof(bi));
|
memset(&bi, 0, sizeof(bi));
|
||||||
bi.hwndOwner = (HWND) hDlg;
|
bi.hwndOwner = (HWND) hDlg;
|
||||||
bi.lpszTitle = "Choose WWW root directory:";
|
bi.lpszTitle = "Choose WWW root directory:";
|
||||||
bi.ulFlags = BIF_RETURNONLYFSDIRS;
|
bi.ulFlags = BIF_RETURNONLYFSDIRS;
|
||||||
|
|
||||||
if (is_directory_option(name)) {
|
if (default_options[i].type == CONFIG_TYPE_DIRECTORY) {
|
||||||
SHGetPathFromIDList(SHBrowseForFolder(&bi), path);
|
SHGetPathFromIDList(SHBrowseForFolder(&bi), path);
|
||||||
} else {
|
} else {
|
||||||
GetOpenFileName(&of);
|
GetOpenFileName(&of);
|
||||||
@@ -699,18 +778,23 @@ static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_INITDIALOG:
|
case WM_INITDIALOG:
|
||||||
SendMessage(hDlg, WM_SETICON,(WPARAM) ICON_SMALL, (LPARAM) hIcon);
|
SendMessage(hDlg, WM_SETICON,(WPARAM) ICON_SMALL, (LPARAM) hIcon);
|
||||||
SendMessage(hDlg, WM_SETICON,(WPARAM) ICON_BIG, (LPARAM) hIcon);
|
SendMessage(hDlg, WM_SETICON,(WPARAM) ICON_BIG, (LPARAM) hIcon);
|
||||||
SetWindowText(hDlg, "Civetweb settings");
|
title = malloc(strlen(server_name)+16);
|
||||||
|
if (title) {
|
||||||
|
strcpy(title, server_name);
|
||||||
|
strcat(title, " settings");
|
||||||
|
SetWindowText(hDlg, title);
|
||||||
|
free(title);
|
||||||
|
}
|
||||||
SetFocus(GetDlgItem(hDlg, ID_SAVE));
|
SetFocus(GetDlgItem(hDlg, ID_SAVE));
|
||||||
for (i = 0; default_options[i * 2] != NULL; i++) {
|
for (i = 0; default_options[i].name != NULL; i++) {
|
||||||
name = default_options[i * 2];
|
name = default_options[i].name;
|
||||||
value = mg_get_option(ctx, name);
|
value = mg_get_option(ctx, name);
|
||||||
if (is_boolean_option(name)) {
|
if (default_options[i].type == CONFIG_TYPE_BOOLEAN) {
|
||||||
CheckDlgButton(hDlg, ID_CONTROLS + i, !strcmp(value, "yes") ?
|
CheckDlgButton(hDlg, ID_CONTROLS + i, !strcmp(value, "yes") ?
|
||||||
BST_CHECKED : BST_UNCHECKED);
|
BST_CHECKED : BST_UNCHECKED);
|
||||||
} else {
|
} else {
|
||||||
@@ -718,6 +802,7 @@ static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -762,15 +847,15 @@ static void add_control(unsigned char **mem, DLGTEMPLATE *dia, WORD type,
|
|||||||
static void show_settings_dialog()
|
static void show_settings_dialog()
|
||||||
{
|
{
|
||||||
#define HEIGHT 15
|
#define HEIGHT 15
|
||||||
#define WIDTH 400
|
#define WIDTH 460
|
||||||
#define LABEL_WIDTH 80
|
#define LABEL_WIDTH 90
|
||||||
|
|
||||||
unsigned char mem[4096], *p;
|
unsigned char mem[4096], *p;
|
||||||
const char **option_names, *long_option_name;
|
const struct mg_option *options;
|
||||||
DWORD style;
|
DWORD style;
|
||||||
DLGTEMPLATE *dia = (DLGTEMPLATE *) mem;
|
DLGTEMPLATE *dia = (DLGTEMPLATE *) mem;
|
||||||
WORD i, cl, x, y, width, nelems = 0;
|
WORD i, cl, x, y, width, nelems = 0;
|
||||||
static int guard;
|
static int guard = 0; /* test if dialog is already open */
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
DLGTEMPLATE template; /* 18 bytes */
|
DLGTEMPLATE template; /* 18 bytes */
|
||||||
@@ -795,22 +880,21 @@ static void show_settings_dialog()
|
|||||||
(void) memcpy(mem, &dialog_header, sizeof(dialog_header));
|
(void) memcpy(mem, &dialog_header, sizeof(dialog_header));
|
||||||
p = mem + sizeof(dialog_header);
|
p = mem + sizeof(dialog_header);
|
||||||
|
|
||||||
option_names = mg_get_valid_option_names();
|
options = mg_get_valid_options();
|
||||||
for (i = 0; option_names[i * 2] != NULL; i++) {
|
for (i = 0; options[i].name != NULL; i++) {
|
||||||
long_option_name = option_names[i * 2];
|
|
||||||
style = WS_CHILD | WS_VISIBLE | WS_TABSTOP;
|
style = WS_CHILD | WS_VISIBLE | WS_TABSTOP;
|
||||||
x = 10 + (WIDTH / 2) * (nelems % 2);
|
x = 10 + (WIDTH / 2) * (nelems % 2);
|
||||||
y = (nelems/2 + 1) * HEIGHT + 5;
|
y = (nelems/2 + 1) * HEIGHT + 5;
|
||||||
width = WIDTH / 2 - 20 - LABEL_WIDTH;
|
width = WIDTH / 2 - 20 - LABEL_WIDTH;
|
||||||
if (is_numeric_options(long_option_name)) {
|
if (options[i].type == CONFIG_TYPE_NUMBER) {
|
||||||
style |= ES_NUMBER;
|
style |= ES_NUMBER;
|
||||||
cl = 0x81;
|
cl = 0x81;
|
||||||
style |= WS_BORDER | ES_AUTOHSCROLL;
|
style |= WS_BORDER | ES_AUTOHSCROLL;
|
||||||
} else if (is_boolean_option(long_option_name)) {
|
} else if (options[i].type == CONFIG_TYPE_BOOLEAN) {
|
||||||
cl = 0x80;
|
cl = 0x80;
|
||||||
style |= BS_AUTOCHECKBOX;
|
style |= BS_AUTOCHECKBOX;
|
||||||
} else if (is_filename_option(long_option_name) ||
|
} else if ((options[i].type == CONFIG_TYPE_FILE) ||
|
||||||
is_directory_option(long_option_name)) {
|
(options[i].type == CONFIG_TYPE_DIRECTORY)) {
|
||||||
style |= WS_BORDER | ES_AUTOHSCROLL;
|
style |= WS_BORDER | ES_AUTOHSCROLL;
|
||||||
width -= 20;
|
width -= 20;
|
||||||
cl = 0x81;
|
cl = 0x81;
|
||||||
@@ -824,10 +908,12 @@ static void show_settings_dialog()
|
|||||||
style |= WS_BORDER | ES_AUTOHSCROLL;
|
style |= WS_BORDER | ES_AUTOHSCROLL;
|
||||||
}
|
}
|
||||||
add_control(&p, dia, 0x82, ID_STATIC, WS_VISIBLE | WS_CHILD,
|
add_control(&p, dia, 0x82, ID_STATIC, WS_VISIBLE | WS_CHILD,
|
||||||
x, y, LABEL_WIDTH, HEIGHT, long_option_name);
|
x, y, LABEL_WIDTH, HEIGHT, options[i].name);
|
||||||
add_control(&p, dia, cl, ID_CONTROLS + i, style,
|
add_control(&p, dia, cl, ID_CONTROLS + i, style,
|
||||||
(WORD) (x + LABEL_WIDTH), y, width, 12, "");
|
(WORD) (x + LABEL_WIDTH), y, width, 12, "");
|
||||||
nelems++;
|
nelems++;
|
||||||
|
|
||||||
|
assert((int)p - (int)mem < sizeof(mem));
|
||||||
}
|
}
|
||||||
|
|
||||||
y = (WORD) (((nelems + 1) / 2 + 1) * HEIGHT + 5);
|
y = (WORD) (((nelems + 1) / 2 + 1) * HEIGHT + 5);
|
||||||
@@ -848,7 +934,9 @@ static void show_settings_dialog()
|
|||||||
WIDTH - 280, y, 65, 12, "Reload active");
|
WIDTH - 280, y, 65, 12, "Reload active");
|
||||||
add_control(&p, dia, 0x82, ID_STATIC,
|
add_control(&p, dia, 0x82, ID_STATIC,
|
||||||
WS_CHILD | WS_VISIBLE | WS_DISABLED,
|
WS_CHILD | WS_VISIBLE | WS_DISABLED,
|
||||||
5, y, 100, 12, server_name);
|
5, y, 100, 12, server_base_name);
|
||||||
|
|
||||||
|
assert((int)p - (int)mem < sizeof(mem));
|
||||||
|
|
||||||
dia->cy = ((nelems + 1) / 2 + 1) * HEIGHT + 30;
|
dia->cy = ((nelems + 1) / 2 + 1) * HEIGHT + 30;
|
||||||
DialogBoxIndirectParam(NULL, dia, NULL, DlgProc, (LPARAM) NULL);
|
DialogBoxIndirectParam(NULL, dia, NULL, DlgProc, (LPARAM) NULL);
|
||||||
@@ -857,7 +945,7 @@ static void show_settings_dialog()
|
|||||||
|
|
||||||
static int manage_service(int action)
|
static int manage_service(int action)
|
||||||
{
|
{
|
||||||
static const char *service_name = "Civetweb";
|
static const char *service_name = "Civetweb"; /* TODO: check using server_name instead of service_name */
|
||||||
SC_HANDLE hSCM = NULL, hService = NULL;
|
SC_HANDLE hSCM = NULL, hService = NULL;
|
||||||
SERVICE_DESCRIPTION descr = {server_name};
|
SERVICE_DESCRIPTION descr = {server_name};
|
||||||
char path[PATH_MAX + 20] = "";/* Path to executable plus magic argument */
|
char path[PATH_MAX + 20] = "";/* Path to executable plus magic argument */
|
||||||
@@ -902,16 +990,16 @@ static int manage_service(int action)
|
|||||||
static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
|
static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
|
||||||
LPARAM lParam)
|
LPARAM lParam)
|
||||||
{
|
{
|
||||||
static SERVICE_TABLE_ENTRY service_table[] = {
|
static SERVICE_TABLE_ENTRY service_table[2] = {0};
|
||||||
{server_name, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
|
|
||||||
{NULL, NULL}
|
|
||||||
};
|
|
||||||
int service_installed;
|
int service_installed;
|
||||||
char buf[200], *service_argv[] = {__argv[0], NULL};
|
char buf[200], *service_argv[] = {__argv[0], NULL};
|
||||||
POINT pt;
|
POINT pt;
|
||||||
HMENU hMenu;
|
HMENU hMenu;
|
||||||
static UINT s_uTaskbarRestart; /* for taskbar creation */
|
static UINT s_uTaskbarRestart; /* for taskbar creation */
|
||||||
|
|
||||||
|
service_table[0].lpServiceName = server_name;
|
||||||
|
service_table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
|
||||||
|
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
case WM_CREATE:
|
case WM_CREATE:
|
||||||
if (__argv[1] != NULL &&
|
if (__argv[1] != NULL &&
|
||||||
@@ -964,7 +1052,7 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
|
|||||||
ID_REMOVE_SERVICE, "Deinstall service");
|
ID_REMOVE_SERVICE, "Deinstall service");
|
||||||
AppendMenu(hMenu, MF_SEPARATOR, ID_SEPARATOR, "");
|
AppendMenu(hMenu, MF_SEPARATOR, ID_SEPARATOR, "");
|
||||||
AppendMenu(hMenu, MF_STRING, ID_CONNECT, "Start browser");
|
AppendMenu(hMenu, MF_STRING, ID_CONNECT, "Start browser");
|
||||||
AppendMenu(hMenu, MF_STRING, ID_SETTINGS, "Edit Settings");
|
AppendMenu(hMenu, MF_STRING, ID_SETTINGS, "Edit settings");
|
||||||
AppendMenu(hMenu, MF_SEPARATOR, ID_SEPARATOR, "");
|
AppendMenu(hMenu, MF_SEPARATOR, ID_SEPARATOR, "");
|
||||||
AppendMenu(hMenu, MF_STRING, ID_QUIT, "Exit");
|
AppendMenu(hMenu, MF_STRING, ID_QUIT, "Exit");
|
||||||
GetCursorPos(&pt);
|
GetCursorPos(&pt);
|
||||||
@@ -994,23 +1082,27 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdline, int show)
|
|||||||
HWND hWnd;
|
HWND hWnd;
|
||||||
MSG msg;
|
MSG msg;
|
||||||
|
|
||||||
init_server_name();
|
init_server_name(__argc, __argv);
|
||||||
memset(&cls, 0, sizeof(cls));
|
memset(&cls, 0, sizeof(cls));
|
||||||
cls.lpfnWndProc = (WNDPROC) WindowProc;
|
cls.lpfnWndProc = (WNDPROC) WindowProc;
|
||||||
cls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
cls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
||||||
cls.lpszClassName = server_name;
|
cls.lpszClassName = server_base_name;
|
||||||
|
|
||||||
RegisterClass(&cls);
|
RegisterClass(&cls);
|
||||||
hWnd = CreateWindow(cls.lpszClassName, server_name, WS_OVERLAPPEDWINDOW,
|
hWnd = CreateWindow(cls.lpszClassName, server_name, WS_OVERLAPPEDWINDOW,
|
||||||
0, 0, 0, 0, NULL, NULL, NULL, NULL);
|
0, 0, 0, 0, NULL, NULL, NULL, NULL);
|
||||||
ShowWindow(hWnd, SW_HIDE);
|
ShowWindow(hWnd, SW_HIDE);
|
||||||
|
|
||||||
|
if (icon_name) {
|
||||||
|
hIcon = LoadImage(NULL, icon_name, IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
|
||||||
|
} else {
|
||||||
|
hIcon = LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(ID_ICON), IMAGE_ICON, 16, 16, 0);
|
||||||
|
}
|
||||||
|
|
||||||
TrayIcon.cbSize = sizeof(TrayIcon);
|
TrayIcon.cbSize = sizeof(TrayIcon);
|
||||||
TrayIcon.uID = ID_ICON;
|
TrayIcon.uID = ID_ICON;
|
||||||
TrayIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
|
TrayIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
|
||||||
TrayIcon.hIcon = hIcon = LoadImage(GetModuleHandle(NULL),
|
TrayIcon.hIcon = hIcon;
|
||||||
MAKEINTRESOURCE(ID_ICON),
|
|
||||||
IMAGE_ICON, 16, 16, 0);
|
|
||||||
TrayIcon.hWnd = hWnd;
|
TrayIcon.hWnd = hWnd;
|
||||||
snprintf(TrayIcon.szTip, sizeof(TrayIcon.szTip), "%s", server_name);
|
snprintf(TrayIcon.szTip, sizeof(TrayIcon.szTip), "%s", server_name);
|
||||||
TrayIcon.uCallbackMessage = WM_USER;
|
TrayIcon.uCallbackMessage = WM_USER;
|
||||||
@@ -1052,7 +1144,7 @@ withApplication:@"TextEdit"];
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
init_server_name();
|
init_server_name(argc, argv);
|
||||||
start_civetweb(argc, argv);
|
start_civetweb(argc, argv);
|
||||||
|
|
||||||
[NSAutoreleasePool new];
|
[NSAutoreleasePool new];
|
||||||
@@ -1112,7 +1204,7 @@ int main(int argc, char *argv[])
|
|||||||
#else
|
#else
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
init_server_name();
|
init_server_name(argc, argv);
|
||||||
start_civetweb(argc, argv);
|
start_civetweb(argc, argv);
|
||||||
printf("%s started on port(s) %s with web root [%s]\n",
|
printf("%s started on port(s) %s with web root [%s]\n",
|
||||||
server_name, mg_get_option(ctx, "listening_ports"),
|
server_name, mg_get_option(ctx, "listening_ports"),
|
||||||
|
204
src/mod_lua.inl
204
src/mod_lua.inl
@@ -559,6 +559,70 @@ static int lsp_url_decode(lua_State *L)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* mg.base64_encode */
|
||||||
|
static int lsp_base64_encode(lua_State *L)
|
||||||
|
{
|
||||||
|
int num_args = lua_gettop(L);
|
||||||
|
const char *text;
|
||||||
|
size_t text_len;
|
||||||
|
char *dst;
|
||||||
|
|
||||||
|
if (num_args==1) {
|
||||||
|
text = lua_tolstring(L, 1, &text_len);
|
||||||
|
if (text) {
|
||||||
|
dst = mg_malloc(text_len*8/6+4);
|
||||||
|
if (dst) {
|
||||||
|
base64_encode(text, text_len, dst);
|
||||||
|
lua_pushstring(L, dst);
|
||||||
|
mg_free(dst);
|
||||||
|
} else {
|
||||||
|
return luaL_error(L, "out of memory in base64_encode() call");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lua_pushnil(L);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Syntax error */
|
||||||
|
return luaL_error(L, "invalid base64_encode() call");
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mg.base64_encode */
|
||||||
|
static int lsp_base64_decode(lua_State *L)
|
||||||
|
{
|
||||||
|
int num_args = lua_gettop(L);
|
||||||
|
const char *text;
|
||||||
|
size_t text_len, dst_len;
|
||||||
|
int ret;
|
||||||
|
char *dst;
|
||||||
|
|
||||||
|
if (num_args==1) {
|
||||||
|
text = lua_tolstring(L, 1, &text_len);
|
||||||
|
if (text) {
|
||||||
|
dst = mg_malloc(text_len);
|
||||||
|
if (dst) {
|
||||||
|
ret = base64_decode(text, text_len, dst, &dst_len);
|
||||||
|
if (ret != -1) {
|
||||||
|
mg_free(dst);
|
||||||
|
return luaL_error(L, "illegal character in lsp_base64_decode() call");
|
||||||
|
} else {
|
||||||
|
lua_pushlstring(L, dst, dst_len);
|
||||||
|
mg_free(dst);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return luaL_error(L, "out of memory in lsp_base64_decode() call");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lua_pushnil(L);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Syntax error */
|
||||||
|
return luaL_error(L, "invalid lsp_base64_decode() call");
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* mg.write for websockets */
|
/* mg.write for websockets */
|
||||||
static int lwebsock_write(lua_State *L)
|
static int lwebsock_write(lua_State *L)
|
||||||
{
|
{
|
||||||
@@ -605,6 +669,7 @@ static void prepare_lua_environment(struct mg_connection *conn, lua_State *L, co
|
|||||||
{
|
{
|
||||||
const struct mg_request_info *ri = mg_get_request_info(conn);
|
const struct mg_request_info *ri = mg_get_request_info(conn);
|
||||||
char src_addr[IP_ADDR_STR_LEN];
|
char src_addr[IP_ADDR_STR_LEN];
|
||||||
|
const char * preload_file = conn->ctx->config[LUA_PRELOAD_FILE];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
extern void luaL_openlibs(lua_State *);
|
extern void luaL_openlibs(lua_State *);
|
||||||
@@ -676,6 +741,8 @@ static void prepare_lua_environment(struct mg_connection *conn, lua_State *L, co
|
|||||||
reg_function(L, "md5", lsp_md5, conn);
|
reg_function(L, "md5", lsp_md5, conn);
|
||||||
reg_function(L, "url_encode", lsp_url_encode, conn);
|
reg_function(L, "url_encode", lsp_url_encode, conn);
|
||||||
reg_function(L, "url_decode", lsp_url_decode, conn);
|
reg_function(L, "url_decode", lsp_url_decode, conn);
|
||||||
|
reg_function(L, "base64_encode", lsp_base64_encode, conn);
|
||||||
|
reg_function(L, "base64_decode", lsp_base64_decode, conn);
|
||||||
|
|
||||||
reg_string(L, "version", CIVETWEB_VERSION);
|
reg_string(L, "version", CIVETWEB_VERSION);
|
||||||
reg_string(L, "document_root", conn->ctx->config[DOCUMENT_ROOT]);
|
reg_string(L, "document_root", conn->ctx->config[DOCUMENT_ROOT]);
|
||||||
@@ -684,6 +751,10 @@ static void prepare_lua_environment(struct mg_connection *conn, lua_State *L, co
|
|||||||
reg_string(L, "websocket_root", conn->ctx->config[WEBSOCKET_ROOT]);
|
reg_string(L, "websocket_root", conn->ctx->config[WEBSOCKET_ROOT]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (conn->ctx->systemName) {
|
||||||
|
reg_string(L, "system", conn->ctx->systemName);
|
||||||
|
}
|
||||||
|
|
||||||
/* Export request_info */
|
/* Export request_info */
|
||||||
lua_pushstring(L, "request_info");
|
lua_pushstring(L, "request_info");
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
@@ -719,6 +790,11 @@ static void prepare_lua_environment(struct mg_connection *conn, lua_State *L, co
|
|||||||
/* Register default mg.onerror function */
|
/* Register default mg.onerror function */
|
||||||
IGNORE_UNUSED_RESULT(luaL_dostring(L, "mg.onerror = function(e) mg.write('\\nLua error:\\n', "
|
IGNORE_UNUSED_RESULT(luaL_dostring(L, "mg.onerror = function(e) mg.write('\\nLua error:\\n', "
|
||||||
"debug.traceback(e, 1)) end"));
|
"debug.traceback(e, 1)) end"));
|
||||||
|
|
||||||
|
/* Preload */
|
||||||
|
if ((preload_file != NULL) && (*preload_file != 0)) {
|
||||||
|
IGNORE_UNUSED_RESULT(luaL_dofile(L, preload_file));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lua_error_handler(lua_State *L)
|
static int lua_error_handler(lua_State *L)
|
||||||
@@ -741,6 +817,17 @@ static int lua_error_handler(lua_State *L)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void * lua_allocator(void *ud, void *ptr, size_t osize, size_t nsize) {
|
||||||
|
|
||||||
|
(void)ud; (void)osize; /* not used */
|
||||||
|
|
||||||
|
if (nsize == 0) {
|
||||||
|
mg_free(ptr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return mg_realloc(ptr, nsize);
|
||||||
|
}
|
||||||
|
|
||||||
void mg_exec_lua_script(struct mg_connection *conn, const char *path,
|
void mg_exec_lua_script(struct mg_connection *conn, const char *path,
|
||||||
const void **exports)
|
const void **exports)
|
||||||
{
|
{
|
||||||
@@ -751,7 +838,7 @@ void mg_exec_lua_script(struct mg_connection *conn, const char *path,
|
|||||||
conn->must_close=1;
|
conn->must_close=1;
|
||||||
|
|
||||||
/* Execute a plain Lua script. */
|
/* Execute a plain Lua script. */
|
||||||
if (path != NULL && (L = luaL_newstate()) != NULL) {
|
if (path != NULL && (L = lua_newstate(lua_allocator, NULL)) != NULL) {
|
||||||
prepare_lua_environment(conn, L, path, LUA_ENV_TYPE_PLAIN_LUA_PAGE);
|
prepare_lua_environment(conn, L, path, LUA_ENV_TYPE_PLAIN_LUA_PAGE);
|
||||||
lua_pushcclosure(L, &lua_error_handler, 0);
|
lua_pushcclosure(L, &lua_error_handler, 0);
|
||||||
|
|
||||||
@@ -809,7 +896,7 @@ struct file *filep, struct lua_State *ls)
|
|||||||
fileno(filep->fp), 0)) == MAP_FAILED) {
|
fileno(filep->fp), 0)) == MAP_FAILED) {
|
||||||
lsp_send_err(conn, ls, "mmap(%s, %zu, %d): %s", path, (size_t) filep->size,
|
lsp_send_err(conn, ls, "mmap(%s, %zu, %d): %s", path, (size_t) filep->size,
|
||||||
fileno(filep->fp), strerror(errno));
|
fileno(filep->fp), strerror(errno));
|
||||||
} else if ((L = ls != NULL ? ls : luaL_newstate()) == NULL) {
|
} else if ((L = ls != NULL ? ls : lua_newstate(lua_allocator, NULL)) == NULL) {
|
||||||
send_http_error(conn, 500, http_500_error, "%s", "luaL_newstate failed");
|
send_http_error(conn, 500, http_500_error, "%s", "luaL_newstate failed");
|
||||||
} else {
|
} else {
|
||||||
/* We're not sending HTTP headers here, Lua page must do it. */
|
/* We're not sending HTTP headers here, Lua page must do it. */
|
||||||
@@ -833,7 +920,15 @@ struct file *filep, struct lua_State *ls)
|
|||||||
struct lua_websock_data {
|
struct lua_websock_data {
|
||||||
lua_State *main;
|
lua_State *main;
|
||||||
lua_State *thread;
|
lua_State *thread;
|
||||||
|
char * script;
|
||||||
|
unsigned shared;
|
||||||
struct mg_connection *conn;
|
struct mg_connection *conn;
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mg_shared_lua_websocket {
|
||||||
|
struct lua_websock_data *sock;
|
||||||
|
struct mg_shared_lua_websocket *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void websock_cry(struct mg_connection *conn, int err, lua_State * L, const char * ws_operation, const char * lua_operation)
|
static void websock_cry(struct mg_connection *conn, int err, lua_State * L, const char * ws_operation, const char * lua_operation)
|
||||||
@@ -866,22 +961,62 @@ static void websock_cry(struct mg_connection *conn, int err, lua_State * L, cons
|
|||||||
static void * lua_websocket_new(const char * script, struct mg_connection *conn, int is_shared)
|
static void * lua_websocket_new(const char * script, struct mg_connection *conn, int is_shared)
|
||||||
{
|
{
|
||||||
struct lua_websock_data *lws_data;
|
struct lua_websock_data *lws_data;
|
||||||
|
struct mg_shared_lua_websocket **shared_websock_list = &(conn->ctx->shared_lua_websockets);
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
|
int found = 0;
|
||||||
int err, nargs;
|
int err, nargs;
|
||||||
|
|
||||||
assert(conn->lua_websocket_state == NULL);
|
assert(conn->lua_websocket_state == NULL);
|
||||||
lws_data = (struct lua_websock_data *) malloc(sizeof(*lws_data));
|
|
||||||
|
/*
|
||||||
|
lock list (mg_context global)
|
||||||
|
check if in list
|
||||||
|
yes: inc rec counter
|
||||||
|
no: create state, add to list
|
||||||
|
lock list element
|
||||||
|
unlock list (mg_context global)
|
||||||
|
call add
|
||||||
|
unlock list element
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (is_shared) {
|
||||||
|
(void)pthread_mutex_lock(&conn->ctx->mutex);
|
||||||
|
while (*shared_websock_list) {
|
||||||
|
if (!strcmp((*shared_websock_list)->sock->script, script)) {
|
||||||
|
lws_data = (*shared_websock_list)->sock;
|
||||||
|
lws_data->shared++;
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
shared_websock_list = &((*shared_websock_list)->next);
|
||||||
|
}
|
||||||
|
(void)pthread_mutex_unlock(&conn->ctx->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
lws_data = (struct lua_websock_data *) mg_malloc(sizeof(*lws_data));
|
||||||
|
}
|
||||||
|
|
||||||
if (lws_data) {
|
if (lws_data) {
|
||||||
lws_data->conn = conn;
|
if (!found) {
|
||||||
|
lws_data->shared = is_shared;
|
||||||
if (is_shared) {
|
lws_data->conn = conn;
|
||||||
(void)pthread_mutex_lock(&conn->ctx->mutex);
|
lws_data->script = mg_strdup(script);
|
||||||
// TODO: add_to_websocket_list(lws_data);
|
lws_data->main = lua_newstate(lua_allocator, NULL);
|
||||||
(void)pthread_mutex_unlock(&conn->ctx->mutex);
|
if (is_shared) {
|
||||||
|
(void)pthread_mutex_lock(&conn->ctx->mutex);
|
||||||
|
shared_websock_list = &(conn->ctx->shared_lua_websockets);
|
||||||
|
while (*shared_websock_list) {
|
||||||
|
shared_websock_list = &((*shared_websock_list)->next);
|
||||||
|
}
|
||||||
|
*shared_websock_list = (struct mg_shared_lua_websocket *)mg_malloc(sizeof(struct mg_shared_lua_websocket));
|
||||||
|
if (*shared_websock_list) {
|
||||||
|
(*shared_websock_list)->sock = lws_data;
|
||||||
|
(*shared_websock_list)->next = 0;
|
||||||
|
}
|
||||||
|
(void)pthread_mutex_unlock(&conn->ctx->mutex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lws_data->main = luaL_newstate();
|
|
||||||
if (lws_data->main) {
|
if (lws_data->main) {
|
||||||
prepare_lua_environment(conn, lws_data->main, script, LUA_ENV_TYPE_LUA_WEBSOCKET);
|
prepare_lua_environment(conn, lws_data->main, script, LUA_ENV_TYPE_LUA_WEBSOCKET);
|
||||||
if (conn->ctx->callbacks.init_lua != NULL) {
|
if (conn->ctx->callbacks.init_lua != NULL) {
|
||||||
@@ -908,7 +1043,8 @@ static void * lua_websocket_new(const char * script, struct mg_connection *conn,
|
|||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
if (lws_data->main) lua_close(lws_data->main);
|
if (lws_data->main) lua_close(lws_data->main);
|
||||||
free(lws_data);
|
mg_free(lws_data->script);
|
||||||
|
mg_free(lws_data);
|
||||||
lws_data=0;
|
lws_data=0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -928,6 +1064,12 @@ static int lua_websocket_data(struct mg_connection *conn, int bits, char *data,
|
|||||||
assert(lws_data->main != NULL);
|
assert(lws_data->main != NULL);
|
||||||
assert(lws_data->thread != NULL);
|
assert(lws_data->thread != NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
lock list element
|
||||||
|
call data
|
||||||
|
unlock list element
|
||||||
|
*/
|
||||||
|
|
||||||
do {
|
do {
|
||||||
retry=0;
|
retry=0;
|
||||||
|
|
||||||
@@ -978,17 +1120,53 @@ static int lua_websocket_ready(struct mg_connection *conn)
|
|||||||
static void lua_websocket_close(struct mg_connection *conn)
|
static void lua_websocket_close(struct mg_connection *conn)
|
||||||
{
|
{
|
||||||
struct lua_websock_data *lws_data = (struct lua_websock_data *)(conn->lua_websocket_state);
|
struct lua_websock_data *lws_data = (struct lua_websock_data *)(conn->lua_websocket_state);
|
||||||
|
struct mg_shared_lua_websocket **shared_websock_list;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
assert(lws_data != NULL);
|
assert(lws_data != NULL);
|
||||||
assert(lws_data->main != NULL);
|
assert(lws_data->main != NULL);
|
||||||
assert(lws_data->thread != NULL);
|
assert(lws_data->thread != NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
lock list element
|
||||||
|
lock list (mg_context global)
|
||||||
|
call remove
|
||||||
|
dec ref counter
|
||||||
|
if ref counter == 0 close state and remove from list
|
||||||
|
unlock list element
|
||||||
|
unlock list (mg_context global)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
lua_pushboolean(lws_data->thread, 0);
|
lua_pushboolean(lws_data->thread, 0);
|
||||||
err = lua_resume(lws_data->thread, NULL, 1);
|
err = lua_resume(lws_data->thread, NULL, 1);
|
||||||
|
|
||||||
lua_close(lws_data->main);
|
if (lws_data->shared) {
|
||||||
free(lws_data);
|
(void)pthread_mutex_lock(&conn->ctx->mutex);
|
||||||
|
lws_data->shared--;
|
||||||
|
if (lws_data->shared==0) {
|
||||||
|
/*
|
||||||
|
shared_websock_list = &(conn->ctx->shared_lua_websockets);
|
||||||
|
while (*shared_websock_list) {
|
||||||
|
if ((*shared_websock_list)->sock == lws_data) {
|
||||||
|
*shared_websock_list = (*shared_websock_list)->next;
|
||||||
|
} else {
|
||||||
|
shared_websock_list = &((*shared_websock_list)->next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_close(lws_data->main);
|
||||||
|
mg_free(lws_data->script);
|
||||||
|
lws_data->script=0;
|
||||||
|
mg_free(lws_data);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
(void)pthread_mutex_unlock(&conn->ctx->mutex);
|
||||||
|
} else {
|
||||||
|
lua_close(lws_data->main);
|
||||||
|
mg_free(lws_data->script);
|
||||||
|
mg_free(lws_data);
|
||||||
|
}
|
||||||
conn->lua_websocket_state = NULL;
|
conn->lua_websocket_state = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
<?
|
<?
|
||||||
|
-- This *.lp file simply runs the *.lua file in the same directory.
|
||||||
n = string.match(mg.request_info.uri, "^(.*)%.lp$")
|
n = string.match(mg.request_info.uri, "^(.*)%.lp$")
|
||||||
n = string.gsub(n, [[/]], [[\]])
|
if mg.system:find("Windows") then
|
||||||
|
n = string.gsub(n, [[/]], [[\]])
|
||||||
|
end
|
||||||
n = mg.document_root .. n .. ".lua"
|
n = mg.document_root .. n .. ".lua"
|
||||||
dofile(n)
|
dofile(n)
|
||||||
?>
|
?>
|
@@ -24,12 +24,12 @@ resp = resp .. "}";
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
mg.write("HTTP/1.1 200 OK\n")
|
mg.write("HTTP/1.1 200 OK\r\n")
|
||||||
mg.write("Connection: close\n")
|
mg.write("Connection: close\r\n")
|
||||||
mg.write("Content-Type: text/html\n")
|
mg.write("Content-Type: text/html\r\n")
|
||||||
mg.write("Cache-Control: no-cache\n")
|
mg.write("Cache-Control: no-cache\r\n")
|
||||||
--mg.write("Content-Length: " .. resp:len() .. "\n")
|
--mg.write("Content-Length: " .. resp:len() .. "\n")
|
||||||
mg.write("\n")
|
mg.write("\r\n")
|
||||||
|
|
||||||
mg.write(resp)
|
mg.write(resp)
|
||||||
|
|
||||||
|
75
test/cors.html
Normal file
75
test/cors.html
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>CORS test</title>
|
||||||
|
<style>
|
||||||
|
html,body{font:normal 1em arial,helvetica;}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script> // http://www.html5rocks.com/en/tutorials/cors/
|
||||||
|
|
||||||
|
// Create the XHR object.
|
||||||
|
function createCORSRequest(method, url) {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
if ("withCredentials" in xhr) {
|
||||||
|
// XHR for Chrome/Firefox/Opera/Safari.
|
||||||
|
xhr.open(method, url, true);
|
||||||
|
} else if (typeof XDomainRequest != "undefined") {
|
||||||
|
// XDomainRequest for IE.
|
||||||
|
xhr = new XDomainRequest();
|
||||||
|
xhr.open(method, url);
|
||||||
|
} else {
|
||||||
|
// CORS not supported.
|
||||||
|
xhr = null;
|
||||||
|
}
|
||||||
|
return xhr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method to parse the title tag from the response.
|
||||||
|
function getTitle(text) {
|
||||||
|
return text.match('<title>(.*)?</title>')[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the actual CORS request.
|
||||||
|
function makeCorsRequest(method, resource) {
|
||||||
|
var url = "http://localhost/cors.reply." + resource;
|
||||||
|
var xhr = createCORSRequest(method, url);
|
||||||
|
if (!xhr) {
|
||||||
|
alert('ERROR: CORS not supported');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response handlers.
|
||||||
|
xhr.onload = function() {
|
||||||
|
var text = xhr.responseText;
|
||||||
|
var title = getTitle(text);
|
||||||
|
alert('Response from CORS request to ' + url + ':\n' + title);
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.onerror = function() {
|
||||||
|
alert('ERROR: the request failed.');
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function start() {
|
||||||
|
var el = document.getElementById("from");
|
||||||
|
el.innerHTML = "Test CORS from " + document.URL + " to http://localhost/cors.reply.*";
|
||||||
|
if ((document.URL.indexOf("localhost") >= 0) || (document.URL.indexOf("127.0.0.1") >= 0)) {
|
||||||
|
alert("This CORS test is only meaningful, if you open this site with a different url than \'localhost\' (127.0.0.1).\nYou may use a different IP of the same machine.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body onload="start()">
|
||||||
|
<h1>Cross-origin resource sharing test</h1>
|
||||||
|
<p id="from">*** Error: Javascript is not activated. This test will not work. ***</p>
|
||||||
|
<button onclick="makeCorsRequest('GET', 'html')">Run CORS GET request (static resource)</button>
|
||||||
|
<button onclick="makeCorsRequest('GET', 'shtml')">Run CORS GET request (ssi)</button>
|
||||||
|
<button onclick="makeCorsRequest('GET', 'lua/getit')">Run CORS GET request (dynamic resource)</button>
|
||||||
|
<button onclick="makeCorsRequest('PUT', 'lua/putit')">Run CORS PUT request (dynamic resource)</button>
|
||||||
|
<p>More information on CORS: See <a href="http://enable-cors.org/">enable-cors.org</a> and <a href="http://www.html5rocks.com/en/tutorials/cors/">html5rocks.com</a>.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
7
test/cors.reply.html
Normal file
7
test/cors.reply.html
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head><title>CORS test reply - test OK</title></head>
|
||||||
|
<body>
|
||||||
|
Do not load this page directly - use cors.html instead!
|
||||||
|
</body>
|
||||||
|
</html>
|
73
test/cors.reply.lua
Normal file
73
test/cors.reply.lua
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
-- http://www.html5rocks.com/static/images/cors_server_flowchart.png
|
||||||
|
|
||||||
|
if not mg.request_info.http_headers.Origin then
|
||||||
|
mg.write("HTTP/1.0 200 OK\r\n")
|
||||||
|
mg.write("Connection: close\r\n")
|
||||||
|
mg.write("Content-Type: text/html; charset=utf-8\r\n")
|
||||||
|
mg.write("\r\n")
|
||||||
|
mg.write("This test page should not be used directly. Open cors.html instead.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if mg.request_info.request_method == "OPTIONS" then
|
||||||
|
|
||||||
|
local acrm = mg.request_info.http_headers['Access-Control-Request-Method'];
|
||||||
|
if (acrm) then
|
||||||
|
local acrh = nil -- mg.request_info.http_headers['Access-Control-Request-Header'];
|
||||||
|
if (acrm~='PUT') then
|
||||||
|
-- invalid request
|
||||||
|
mg.write("HTTP/1.0 403 Forbidden\r\n")
|
||||||
|
mg.write("Connection: close\r\n")
|
||||||
|
mg.write("\r\n")
|
||||||
|
return
|
||||||
|
else
|
||||||
|
-- preflight request
|
||||||
|
mg.write("HTTP/1.0 200 OK\r\n")
|
||||||
|
mg.write("Access-Control-Allow-Methods: PUT\r\n")
|
||||||
|
if (acrh) then
|
||||||
|
mg.write("Access-Control-Allow-Headers: " .. acrh .. "\r\n")
|
||||||
|
end
|
||||||
|
mg.write("Access-Control-Allow-Origin: *\r\n")
|
||||||
|
mg.write("Connection: close\r\n")
|
||||||
|
mg.write("Content-Type: text/html; charset=utf-8\r\n")
|
||||||
|
mg.write("\r\n")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- actual request
|
||||||
|
if mg.request_info.request_method == "GET" then
|
||||||
|
mg.write("HTTP/1.0 200 OK\r\n")
|
||||||
|
mg.write("Access-Control-Allow-Origin: *\r\n")
|
||||||
|
mg.write("Connection: close\r\n")
|
||||||
|
mg.write("Content-Type: text/html; charset=utf-8\r\n")
|
||||||
|
mg.write("\r\n")
|
||||||
|
mg.write([[<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head><title>CORS dynamic GET test reply - test OK</title></head>
|
||||||
|
<body>This should never be shown</body>
|
||||||
|
</html>
|
||||||
|
]])
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if mg.request_info.request_method == "PUT" then
|
||||||
|
mg.write("HTTP/1.0 200 OK\r\n")
|
||||||
|
mg.write("Access-Control-Allow-Origin: *\r\n")
|
||||||
|
mg.write("Connection: close\r\n")
|
||||||
|
mg.write("Content-Type: text/html; charset=utf-8\r\n")
|
||||||
|
mg.write("\r\n")
|
||||||
|
mg.write([[<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head><title>CORS dynamic PUT test reply - test OK</title></head>
|
||||||
|
<body>This should never be shown</body>
|
||||||
|
</html>
|
||||||
|
]])
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
mg.write("HTTP/1.0 403 Forbidden\r\n")
|
||||||
|
mg.write("Connection: close\r\n")
|
||||||
|
mg.write("\r\n")
|
7
test/cors.reply.shtml
Normal file
7
test/cors.reply.shtml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head><title>CORS test reply - test OK</title></head>
|
||||||
|
<body>
|
||||||
|
Do not load this page directly - use cors.html instead!
|
||||||
|
</body>
|
||||||
|
</html>
|
7
test/lua_preload_file.lua
Normal file
7
test/lua_preload_file.lua
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
--[[
|
||||||
|
Load this test file by adding
|
||||||
|
lua_preload_file ./lua_preload_file.lua
|
||||||
|
to the civetweb.conf file
|
||||||
|
]]
|
||||||
|
|
||||||
|
mg.preload = "lua_preload_file successfully loaded"
|
@@ -11,6 +11,7 @@ end
|
|||||||
mg.write("HTTP/1.0 200 OK\r\n")
|
mg.write("HTTP/1.0 200 OK\r\n")
|
||||||
mg.write("Connection: close\r\n")
|
mg.write("Connection: close\r\n")
|
||||||
mg.write("Content-Type: text/html; charset=utf-8\r\n")
|
mg.write("Content-Type: text/html; charset=utf-8\r\n")
|
||||||
|
mg.write("Cache-Control: max-age=0, must-revalidate\r\n")
|
||||||
if not cookie_value then
|
if not cookie_value then
|
||||||
mg.write("Set-Cookie: " .. cookie_name .. "=" .. tostring(now) .. "\r\n")
|
mg.write("Set-Cookie: " .. cookie_name .. "=" .. tostring(now) .. "\r\n")
|
||||||
end
|
end
|
||||||
@@ -106,23 +107,47 @@ else
|
|||||||
end
|
end
|
||||||
raw_string = [[ !"#$%&'()*+,-./0123456789:;<=>?@]]
|
raw_string = [[ !"#$%&'()*+,-./0123456789:;<=>?@]]
|
||||||
mg.write(" original string: " .. htmlEscape(raw_string) .. "\r\n")
|
mg.write(" original string: " .. htmlEscape(raw_string) .. "\r\n")
|
||||||
url_string = mg.url_encode(raw_string):upper()
|
mg_string = mg.url_encode(raw_string):upper()
|
||||||
ref_string = "%20!%22%23%24%25%26'()*%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40" -- from http://www.w3schools.com/tags/ref_urlencode.asp
|
ref_string = "%20!%22%23%24%25%26'()*%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40" -- from http://www.w3schools.com/tags/ref_urlencode.asp
|
||||||
mg.write(" mg-url: " .. htmlEscape(url_string) .. "\r\n")
|
mg.write(" mg-url: " .. htmlEscape(mg_string) .. "\r\n")
|
||||||
mg.write(" reference url: " .. htmlEscape(ref_string) .. "\r\n")
|
mg.write(" reference url: " .. htmlEscape(ref_string) .. "\r\n")
|
||||||
dec_url_string = mg.url_decode(url_string)
|
dec_mg_string = mg.url_decode(mg_string)
|
||||||
dec_ref_string = mg.url_decode(ref_string)
|
dec_ref_string = mg.url_decode(ref_string)
|
||||||
mg.write(" decoded mg-url: " .. htmlEscape(dec_url_string) .. "\r\n")
|
mg.write(" decoded mg-url: " .. htmlEscape(dec_mg_string) .. "\r\n")
|
||||||
mg.write(" decoded reference url: " .. htmlEscape(dec_ref_string) .. "\r\n")
|
mg.write(" decoded reference url: " .. htmlEscape(dec_ref_string) .. "\r\n")
|
||||||
dec_url_string = mg.url_decode(url_string, false)
|
dec_mg_string = mg.url_decode(mg_string, false)
|
||||||
dec_ref_string = mg.url_decode(ref_string, false)
|
dec_ref_string = mg.url_decode(ref_string, false)
|
||||||
mg.write(" decoded mg-url: " .. htmlEscape(dec_url_string) .. "\r\n")
|
mg.write(" decoded mg-url: " .. htmlEscape(dec_mg_string) .. "\r\n")
|
||||||
mg.write(" decoded reference url: " .. htmlEscape(dec_ref_string) .. "\r\n")
|
mg.write(" decoded reference url: " .. htmlEscape(dec_ref_string) .. "\r\n")
|
||||||
dec_url_string = mg.url_decode(url_string, true)
|
dec_mg_string = mg.url_decode(mg_string, true)
|
||||||
dec_ref_string = mg.url_decode(ref_string, true)
|
dec_ref_string = mg.url_decode(ref_string, true)
|
||||||
mg.write(" decoded mg-url: " .. htmlEscape(dec_url_string) .. "\r\n")
|
mg.write(" decoded mg-url: " .. htmlEscape(dec_mg_string) .. "\r\n")
|
||||||
mg.write(" decoded reference url: " .. htmlEscape(dec_ref_string) .. "\r\n")
|
mg.write(" decoded reference url: " .. htmlEscape(dec_ref_string) .. "\r\n")
|
||||||
mg.write("\r\n")
|
mg.write("\r\n")
|
||||||
|
|
||||||
|
-- base64_encode
|
||||||
|
mg.write("BASE64 encode/decode test:\r\n")
|
||||||
|
raw_string = [[ !"#$%&'()*+,-./0123456789:;<=>?@]]
|
||||||
|
mg.write(" original string: " .. htmlEscape(raw_string) .. "\r\n")
|
||||||
|
mg_string = mg.base64_encode(raw_string)
|
||||||
|
ref_string = "ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9A" -- from http://www.base64encode.org/
|
||||||
|
mg.write(" mg-base64: " .. htmlEscape(mg_string) .. "\r\n")
|
||||||
|
mg.write(" reference base64: " .. htmlEscape(ref_string) .. "\r\n")
|
||||||
|
dec_mg_string = mg.base64_decode(mg_string)
|
||||||
|
dec_ref_string = mg.base64_decode(ref_string)
|
||||||
|
mg.write(" decoded mg-base64: " .. htmlEscape(dec_mg_string) .. "\r\n")
|
||||||
|
mg.write(" decoded reference base64: " .. htmlEscape(dec_ref_string) .. "\r\n")
|
||||||
|
mg.write("\r\n")
|
||||||
|
raw_string = [[<?> -?-]]
|
||||||
|
mg.write(" original string: " .. htmlEscape(raw_string) .. "\r\n")
|
||||||
|
mg_string = mg.base64_encode(raw_string)
|
||||||
|
ref_string = "PD8+IC0/LQ==" -- from http://www.base64encode.org/
|
||||||
|
mg.write(" mg-base64: " .. htmlEscape(mg_string) .. "\r\n")
|
||||||
|
mg.write(" reference base64: " .. htmlEscape(ref_string) .. "\r\n")
|
||||||
|
dec_mg_string = mg.base64_decode(mg_string)
|
||||||
|
dec_ref_string = mg.base64_decode(ref_string)
|
||||||
|
mg.write(" decoded mg-base64: " .. htmlEscape(dec_mg_string) .. "\r\n")
|
||||||
|
mg.write(" decoded reference base64: " .. htmlEscape(dec_ref_string) .. "\r\n")
|
||||||
|
|
||||||
-- end of page
|
-- end of page
|
||||||
mg.write("</pre>\r\n</body>\r\n</html>\r\n")
|
mg.write("</pre>\r\n</body>\r\n</html>\r\n")
|
||||||
|
BIN
test/test.ico
Normal file
BIN
test/test.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
Reference in New Issue
Block a user