浏览代码

Merge pull request #2 from bel2125/master

Update fork
hansipie 10 年之前
父节点
当前提交
1e9bca3831
共有 100 个文件被更改,包括 749 次插入379 次删除
  1. 27 0
      CREDITS.md
  2. 13 5
      RELEASE_NOTES.md
  3. 41 20
      include/CivetServer.h
  4. 62 32
      include/civetweb.h
  5. 59 29
      src/CivetServer.cpp
  6. 77 41
      src/civetweb.c
  7. 2 1
      src/lua_civet.h
  8. 7 7
      src/main.c
  9. 11 9
      src/mod_lua.inl
  10. 199 0
      test/1000images.lua
  11. 168 160
      test/100images.htm
  12. 8 73
      test/ajax/echo.cgi
  13. 73 0
      test/ajax/echo.cgi.old
  14. 2 2
      test/cors.html
  15. 0 0
      test/imagetest/00.png
  16. 0 0
      test/imagetest/01.png
  17. 0 0
      test/imagetest/02.png
  18. 0 0
      test/imagetest/03.png
  19. 0 0
      test/imagetest/04.png
  20. 0 0
      test/imagetest/05.png
  21. 0 0
      test/imagetest/06.png
  22. 0 0
      test/imagetest/07.png
  23. 0 0
      test/imagetest/08.png
  24. 0 0
      test/imagetest/09.png
  25. 0 0
      test/imagetest/10.png
  26. 0 0
      test/imagetest/11.png
  27. 0 0
      test/imagetest/12.png
  28. 0 0
      test/imagetest/13.png
  29. 0 0
      test/imagetest/14.png
  30. 0 0
      test/imagetest/15.png
  31. 0 0
      test/imagetest/16.png
  32. 0 0
      test/imagetest/17.png
  33. 0 0
      test/imagetest/18.png
  34. 0 0
      test/imagetest/19.png
  35. 0 0
      test/imagetest/20.png
  36. 0 0
      test/imagetest/21.png
  37. 0 0
      test/imagetest/22.png
  38. 0 0
      test/imagetest/23.png
  39. 0 0
      test/imagetest/24.png
  40. 0 0
      test/imagetest/25.png
  41. 0 0
      test/imagetest/26.png
  42. 0 0
      test/imagetest/27.png
  43. 0 0
      test/imagetest/28.png
  44. 0 0
      test/imagetest/29.png
  45. 0 0
      test/imagetest/30.png
  46. 0 0
      test/imagetest/31.png
  47. 0 0
      test/imagetest/32.png
  48. 0 0
      test/imagetest/33.png
  49. 0 0
      test/imagetest/34.png
  50. 0 0
      test/imagetest/35.png
  51. 0 0
      test/imagetest/36.png
  52. 0 0
      test/imagetest/37.png
  53. 0 0
      test/imagetest/38.png
  54. 0 0
      test/imagetest/39.png
  55. 0 0
      test/imagetest/40.png
  56. 0 0
      test/imagetest/41.png
  57. 0 0
      test/imagetest/42.png
  58. 0 0
      test/imagetest/43.png
  59. 0 0
      test/imagetest/44.png
  60. 0 0
      test/imagetest/45.png
  61. 0 0
      test/imagetest/46.png
  62. 0 0
      test/imagetest/47.png
  63. 0 0
      test/imagetest/48.png
  64. 0 0
      test/imagetest/49.png
  65. 0 0
      test/imagetest/50.png
  66. 0 0
      test/imagetest/51.png
  67. 0 0
      test/imagetest/52.png
  68. 0 0
      test/imagetest/53.png
  69. 0 0
      test/imagetest/54.png
  70. 0 0
      test/imagetest/55.png
  71. 0 0
      test/imagetest/56.png
  72. 0 0
      test/imagetest/57.png
  73. 0 0
      test/imagetest/58.png
  74. 0 0
      test/imagetest/59.png
  75. 0 0
      test/imagetest/60.png
  76. 0 0
      test/imagetest/61.png
  77. 0 0
      test/imagetest/62.png
  78. 0 0
      test/imagetest/63.png
  79. 0 0
      test/imagetest/64.png
  80. 0 0
      test/imagetest/65.png
  81. 0 0
      test/imagetest/66.png
  82. 0 0
      test/imagetest/67.png
  83. 0 0
      test/imagetest/68.png
  84. 0 0
      test/imagetest/69.png
  85. 0 0
      test/imagetest/70.png
  86. 0 0
      test/imagetest/71.png
  87. 0 0
      test/imagetest/72.png
  88. 0 0
      test/imagetest/73.png
  89. 0 0
      test/imagetest/74.png
  90. 0 0
      test/imagetest/75.png
  91. 0 0
      test/imagetest/76.png
  92. 0 0
      test/imagetest/77.png
  93. 0 0
      test/imagetest/78.png
  94. 0 0
      test/imagetest/79.png
  95. 0 0
      test/imagetest/80.png
  96. 0 0
      test/imagetest/81.png
  97. 0 0
      test/imagetest/82.png
  98. 0 0
      test/imagetest/83.png
  99. 0 0
      test/imagetest/84.png
  100. 0 0
      test/imagetest/85.png

+ 27 - 0
CREDITS.md

@@ -2,27 +2,54 @@
 
 * Alex Kozlov
 * bel2125
+* Ben M. Ward
+* Brian Lambert
 * Brian Spratke
 * cdbishop
 * celeron55
+* cjh
 * Daniel Oaks
 * Danny Al-Gaaf
+* David Arnold
+* David Loffredo
 * Dialga
+* Eric Tsau
 * F-Secure Corporation
+* Fernando G. Aranda
+* Grahack
+* grenclave
 * hansipie
 * HariKamath Kamath
+* Jan Willem Janssen
+* Jeremy Lin
+* Jim Evans
+* jmc-
+* Jordan
 * Jordan Shelley
+* kalphamon
 * Keith Kyzivat
 * Kevin Wojniak
 * Kimmo Mustonen
+* Lianghui
+* Maarten Fremouw
+* Mark Lakata
 * Matt Clarkson
 * Morgan McGuire
+* Nick Hildebrant
+* Nigel Stewart
 * nihildeb
 * No Face Press
 * Paul Sokolovsky
+* Perttu Ahola
+* Philipp Friedenberger
+* Philipp Hasper
 * Richard Screene
+* Sage Weil
+* Sangwhan Moon
+* Scott Nations
 * Thomas Davis
 * Toni Wilk
+* Ulrich Hertlein
 * William Greathouse
 * Yehuda Sadeh
 

+ 13 - 5
RELEASE_NOTES.md

@@ -1,16 +1,24 @@
-Release Notes v1.7 (Under Development)
+Release Notes v1.7
 ===
-### Objectives: *Examples, documentation, additional API functions, rewritten handle_request method, bug fixes and updates*
+### Objectives: *Examples, documentation, additional API functions, some functions rewritten, bug fixes and updates*
 
 Changes
 -------
 
-- URI specific callbacks for websockets
-- Add chunked transfer support (TODO: currently not working)
+- Format source with clang_format
+- Use function 'sendfile' for Linux
+- Fix for CRAMFS in Linux
+- Fix for file modification times in Windows
+- Use SO_EXCLUSIVEADDRUSE instead of SO_REUSEADDR for Windows
+- Rewrite push/pull functions
+- Allow to use Lua as shared objects (WITH_LUA_SHARED)
+- Fixes for many warnings
+- URI specific callbacks and different timeouts for websockets
+- Add chunked transfer support
 - Update LuaFileSystem
 - Update Lua to 5.2.4
 - Fix build for MinGW-x64, TDM-GCC and clang
-- Update SQLite to 3.8.8.3
+- Update SQLite to 3.8.10.2
 - Fix CGI variables SCRIPT_NAME and PATH_TRANSLATED
 - Set TCP_USER_TIMEOUT to deal faster with broken connections
 - Add a Lua form handling example

+ 41 - 20
include/CivetServer.h

@@ -20,7 +20,8 @@ class CivetServer;
 /**
  * Exception class for thrown exceptions within the CivetHandler object.
  */
-class CIVETWEB_API CivetException : public std::runtime_error {
+class CIVETWEB_API CivetException : public std::runtime_error
+{
 	  public:
 	CivetException(const std::string &msg) : std::runtime_error(msg) {}
 };
@@ -29,7 +30,8 @@ class CIVETWEB_API CivetException : public std::runtime_error {
  * Basic interface for a URI request handler.  Handlers implementations
  * must be reentrant.
  */
-class CIVETWEB_API CivetHandler {
+class CIVETWEB_API CivetHandler
+{
 	  public:
 	/**
 	 * Destructor
@@ -87,7 +89,8 @@ class CIVETWEB_API CivetHandler {
  *
  * Basic class for embedded web server.  This has an URL mapping built-in.
  */
-class CIVETWEB_API CivetServer {
+class CIVETWEB_API CivetServer
+{
 	  public:
 	/**
 	 * Constructor
@@ -135,7 +138,8 @@ class CIVETWEB_API CivetServer {
 	 */
 	void addHandler(const std::string &uri, CivetHandler *handler);
 
-	void addHandler(const std::string &uri, CivetHandler &handler) {
+	void addHandler(const std::string &uri, CivetHandler &handler)
+	{
 		addHandler(uri, &handler);
 	}
 
@@ -206,8 +210,10 @@ class CIVETWEB_API CivetServer {
 	 *based).
 	 * @return true if key was found
 	 */
-	static bool getParam(struct mg_connection *conn, const char *name,
-	                     std::string &dst, size_t occurrence = 0);
+	static bool getParam(struct mg_connection *conn,
+	                     const char *name,
+	                     std::string &dst,
+	                     size_t occurrence = 0);
 
 	/**
 	 * getParam(const std::string &, const char *, std::string &, size_t)
@@ -223,8 +229,11 @@ class CIVETWEB_API CivetServer {
 	 *based).
 	 * @return true if key was found
 	 */
-	static bool getParam(const std::string &data, const char *name,
-	                     std::string &dst, size_t occurrence = 0) {
+	static bool getParam(const std::string &data,
+	                     const char *name,
+	                     std::string &dst,
+	                     size_t occurrence = 0)
+	{
 		return getParam(data.c_str(), data.length(), name, dst, occurrence);
 	}
 
@@ -243,8 +252,11 @@ class CIVETWEB_API CivetServer {
 	 *based).
 	 * @return true if key was found
 	 */
-	static bool getParam(const char *data, size_t data_len, const char *name,
-	                     std::string &dst, size_t occurrence = 0);
+	static bool getParam(const char *data,
+	                     size_t data_len,
+	                     const char *name,
+	                     std::string &dst,
+	                     size_t occurrence = 0);
 
 	/**
 	 * urlDecode(const std::string &, std::string &, bool)
@@ -256,8 +268,10 @@ class CIVETWEB_API CivetServer {
 	 *       uses '+' as character for space, see RFC 1866 section 8.2.1
 	 *       http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
 	 */
-	static void urlDecode(const std::string &src, std::string &dst,
-	                      bool is_form_url_encoded = true) {
+	static void urlDecode(const std::string &src,
+	                      std::string &dst,
+	                      bool is_form_url_encoded = true)
+	{
 		urlDecode(src.c_str(), src.length(), dst, is_form_url_encoded);
 	}
 
@@ -272,7 +286,9 @@ class CIVETWEB_API CivetServer {
 	 *       uses '+' as character for space, see RFC 1866 section 8.2.1
 	 *       http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
 	 */
-	static void urlDecode(const char *src, size_t src_len, std::string &dst,
+	static void urlDecode(const char *src,
+	                      size_t src_len,
+	                      std::string &dst,
 	                      bool is_form_url_encoded = true);
 
 	/**
@@ -285,7 +301,8 @@ class CIVETWEB_API CivetServer {
 	 *       uses '+' as character for space, see RFC 1866 section 8.2.1
 	 *       http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
 	 */
-	static void urlDecode(const char *src, std::string &dst,
+	static void urlDecode(const char *src,
+	                      std::string &dst,
 	                      bool is_form_url_encoded = true);
 
 	/**
@@ -295,8 +312,9 @@ class CIVETWEB_API CivetServer {
 	 * @param dst - destination string
 	 * @param append - true if string should not be cleared before encoding.
 	 */
-	static void urlEncode(const std::string &src, std::string &dst,
-	                      bool append = false) {
+	static void
+	urlEncode(const std::string &src, std::string &dst, bool append = false)
+	{
 		urlEncode(src.c_str(), src.length(), dst, append);
 	}
 
@@ -307,8 +325,8 @@ class CIVETWEB_API CivetServer {
 	 * @param dst - destination string
 	 * @param append - true if string should not be cleared before encoding.
 	 */
-	static void urlEncode(const char *src, std::string &dst,
-	                      bool append = false);
+	static void
+	urlEncode(const char *src, std::string &dst, bool append = false);
 
 	/**
 	 * urlEncode(const char *, size_t, std::string &, bool)
@@ -318,11 +336,14 @@ class CIVETWEB_API CivetServer {
 	 * @param dst - destination string
 	 * @param append - true if string should not be cleared before encoding.
 	 */
-	static void urlEncode(const char *src, size_t src_len, std::string &dst,
+	static void urlEncode(const char *src,
+	                      size_t src_len,
+	                      std::string &dst,
 	                      bool append = false);
 
 	  protected:
-	class CivetConnection {
+	class CivetConnection
+	{
 		  public:
 		char *postData;
 		unsigned long postDataLen;

+ 62 - 32
include/civetweb.h

@@ -35,7 +35,7 @@
 #define CIVETWEB_API
 #endif
 #elif __GNUC__ >= 4
-#define CIVETWEB_API __attribute__((visibility ("default")))
+#define CIVETWEB_API __attribute__((visibility("default")))
 #else
 #define CIVETWEB_API
 #endif
@@ -137,7 +137,9 @@ struct mg_callbacks {
 	     1: keep this websocket connection open.
 	     0: close this websocket connection.
 	   This callback is deprecated, use mg_set_websocket_handler instead. */
-	int (*websocket_data)(struct mg_connection *, int bits, char *data,
+	int (*websocket_data)(struct mg_connection *,
+	                      int bits,
+	                      char *data,
 	                      size_t data_len);
 
 	/* Called when civetweb is closing a connection.  The per-context mutex is
@@ -158,7 +160,8 @@ struct mg_callbacks {
 	     NULL: do not serve file from memory, proceed with normal file open.
 	     non-NULL: pointer to the file contents in memory. data_len must be
 	       initilized with the size of the memory block. */
-	const char *(*open_file)(const struct mg_connection *, const char *path,
+	const char *(*open_file)(const struct mg_connection *,
+	                         const char *path,
 	                         size_t *data_len);
 
 	/* Called when civetweb is about to serve Lua server page, if
@@ -297,8 +300,8 @@ CIVETWEB_API void mg_set_request_handler(struct mg_context *ctx,
 typedef int (*mg_websocket_connect_handler)(const struct mg_connection *,
                                             void *);
 typedef void (*mg_websocket_ready_handler)(struct mg_connection *, void *);
-typedef int (*mg_websocket_data_handler)(struct mg_connection *, int, char *,
-                                         size_t, void *);
+typedef int (*mg_websocket_data_handler)(
+    struct mg_connection *, int, char *, size_t, void *);
 typedef void (*mg_websocket_close_handler)(const struct mg_connection *,
                                            void *);
 
@@ -307,7 +310,8 @@ typedef void (*mg_websocket_close_handler)(const struct mg_connection *,
    Set or remove handler functions for websocket connections.
    This function works similar to mg_set_request_handler - see there. */
 CIVETWEB_API void
-mg_set_websocket_handler(struct mg_context *ctx, const char *uri,
+mg_set_websocket_handler(struct mg_context *ctx,
+                         const char *uri,
                          mg_websocket_connect_handler connect_handler,
                          mg_websocket_ready_handler ready_handler,
                          mg_websocket_data_handler data_handler,
@@ -391,7 +395,8 @@ mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl);
    Return:
      1 on success, 0 on error. */
 CIVETWEB_API int mg_modify_passwords_file(const char *passwords_file_name,
-                                          const char *domain, const char *user,
+                                          const char *domain,
+                                          const char *user,
                                           const char *password);
 
 /* Return information associated with the request. */
@@ -417,8 +422,10 @@ CIVETWEB_API int mg_write(struct mg_connection *, const void *buf, size_t len);
     0   when the connection has been closed
     -1  on error
     >0  number of bytes written on success */
-CIVETWEB_API int mg_websocket_write(struct mg_connection *conn, int opcode,
-                                    const char *data, size_t data_len);
+CIVETWEB_API int mg_websocket_write(struct mg_connection *conn,
+                                    int opcode,
+                                    const char *data,
+                                    size_t data_len);
 
 /* Blocks until unique access is obtained to this connection. Intended for use
    with websockets only.
@@ -470,8 +477,8 @@ enum {
 /* Send data to the client using printf() semantics.
    Works exactly like mg_write(), but allows to do message formatting. */
 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. */
 CIVETWEB_API void mg_send_file(struct mg_connection *conn, const char *path);
@@ -510,8 +517,11 @@ CIVETWEB_API const char *mg_get_header(const struct mg_connection *,
 
    Destination buffer is guaranteed to be '\0' - terminated if it is not
    NULL or zero length. */
-CIVETWEB_API int mg_get_var(const char *data, size_t data_len,
-                            const char *var_name, char *dst, size_t dst_len);
+CIVETWEB_API int mg_get_var(const char *data,
+                            size_t data_len,
+                            const char *var_name,
+                            char *dst,
+                            size_t dst_len);
 
 /* Get a value of particular form variable.
 
@@ -536,8 +546,11 @@ CIVETWEB_API int mg_get_var(const char *data, size_t data_len,
 
    Destination buffer is guaranteed to be '\0' - terminated if it is not
    NULL or zero length. */
-CIVETWEB_API int mg_get_var2(const char *data, size_t data_len,
-                             const char *var_name, char *dst, size_t dst_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);
 
 /* Fetch value of certain cookie variable into the destination buffer.
@@ -553,8 +566,10 @@ CIVETWEB_API int mg_get_var2(const char *data, size_t data_len,
             parameter is not found).
         -2 (destination buffer is NULL, zero length or too small to hold the
             value). */
-CIVETWEB_API int mg_get_cookie(const char *cookie, const char *var_name,
-                               char *buf, size_t buf_len);
+CIVETWEB_API int mg_get_cookie(const char *cookie,
+                               const char *var_name,
+                               char *buf,
+                               size_t buf_len);
 
 /* Download data from the remote web server.
      host: host name to connect to, e.g. "foo.com", or "10.12.40.1".
@@ -572,10 +587,13 @@ CIVETWEB_API int mg_get_cookie(const char *cookie, const char *var_name,
                         "%s", "GET / HTTP/1.0\r\nHost: google.com\r\n\r\n");
  */
 CIVETWEB_API struct mg_connection *
-mg_download(const char *host, int port, int use_ssl, char *error_buffer,
+mg_download(const char *host,
+            int port,
+            int use_ssl,
+            char *error_buffer,
             size_t error_buffer_size,
-            PRINTF_FORMAT_STRING(const char *request_fmt), ...)
-    PRINTF_ARGS(6, 7);
+            PRINTF_FORMAT_STRING(const char *request_fmt),
+            ...) PRINTF_ARGS(6, 7);
 
 /* Close the connection opened by mg_download(). */
 CIVETWEB_API void mg_close_connection(struct mg_connection *conn);
@@ -604,8 +622,11 @@ CIVETWEB_API const char *mg_version(void);
    uses '+' as character for space, see RFC 1866 section 8.2.1
    http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
    Return: length of the decoded data, or -1 if dst buffer is too small. */
-CIVETWEB_API int mg_url_decode(const char *src, int src_len, char *dst,
-                               int dst_len, int is_form_url_encoded);
+CIVETWEB_API int mg_url_decode(const char *src,
+                               int src_len,
+                               char *dst,
+                               int dst_len,
+                               int is_form_url_encoded);
 
 /* URL-encode input buffer into destination buffer.
    returns the length of the resulting buffer or -1
@@ -628,8 +649,8 @@ CIVETWEB_API char *mg_md5(char buf[33], ...);
    Example:
      mg_cry(conn,"i like %s", "logging"); */
 CIVETWEB_API void mg_cry(const struct mg_connection *conn,
-                         PRINTF_FORMAT_STRING(const char *fmt), ...)
-    PRINTF_ARGS(2, 3);
+                         PRINTF_FORMAT_STRING(const char *fmt),
+                         ...) PRINTF_ARGS(2, 3);
 
 /* utility method to compare two buffers, case incensitive. */
 CIVETWEB_API int mg_strncasecmp(const char *s1, const char *s2, size_t len);
@@ -653,11 +674,17 @@ CIVETWEB_API int mg_strncasecmp(const char *s1, const char *s2, size_t len);
      On error, NULL. Se error_buffer for details.
 */
 
-CIVETWEB_API struct mg_connection *mg_connect_websocket_client(
-    const char *host, int port, int use_ssl, char *error_buffer,
-    size_t error_buffer_size, const char *path, const char *origin,
-    mg_websocket_data_handler data_func, mg_websocket_close_handler close_func,
-    void *user_data);
+CIVETWEB_API struct mg_connection *
+mg_connect_websocket_client(const char *host,
+                            int port,
+                            int use_ssl,
+                            char *error_buffer,
+                            size_t error_buffer_size,
+                            const char *path,
+                            const char *origin,
+                            mg_websocket_data_handler data_func,
+                            mg_websocket_close_handler close_func,
+                            void *user_data);
 
 /* Connect to a TCP server as a client (can be used to connect to a HTTP server)
    Parameters:
@@ -671,7 +698,8 @@ CIVETWEB_API struct mg_connection *mg_connect_websocket_client(
      On success, valid mg_connection object.
      On error, NULL. Se error_buffer for details.
 */
-CIVETWEB_API struct mg_connection *mg_connect_client(const char *host, int port,
+CIVETWEB_API struct mg_connection *mg_connect_client(const char *host,
+                                                     int port,
                                                      int use_ssl,
                                                      char *error_buffer,
                                                      size_t error_buffer_size);
@@ -689,8 +717,10 @@ enum { TIMEOUT_INFINITE = -1 };
      On success, >= 0
      On error/timeout, < 0
 */
-CIVETWEB_API int mg_get_response(struct mg_connection *conn, char *ebuf,
-                                 size_t ebuf_len, int timeout);
+CIVETWEB_API int mg_get_response(struct mg_connection *conn,
+                                 char *ebuf,
+                                 size_t ebuf_len,
+                                 int timeout);
 
 #ifdef __cplusplus
 }

+ 59 - 29
src/CivetServer.cpp

@@ -15,39 +15,44 @@
 #define UNUSED_PARAMETER(x) (void)(x)
 #endif
 
-bool CivetHandler::handleGet(CivetServer *server, struct mg_connection *conn) {
+bool CivetHandler::handleGet(CivetServer *server, struct mg_connection *conn)
+{
 	UNUSED_PARAMETER(server);
 	UNUSED_PARAMETER(conn);
 	return false;
 }
 
-bool CivetHandler::handlePost(CivetServer *server, struct mg_connection *conn) {
+bool CivetHandler::handlePost(CivetServer *server, struct mg_connection *conn)
+{
 	UNUSED_PARAMETER(server);
 	UNUSED_PARAMETER(conn);
 	return false;
 }
 
-bool CivetHandler::handlePut(CivetServer *server, struct mg_connection *conn) {
+bool CivetHandler::handlePut(CivetServer *server, struct mg_connection *conn)
+{
 	UNUSED_PARAMETER(server);
 	UNUSED_PARAMETER(conn);
 	return false;
 }
 
-bool CivetHandler::handleDelete(CivetServer *server,
-                                struct mg_connection *conn) {
+bool CivetHandler::handleDelete(CivetServer *server, struct mg_connection *conn)
+{
 	UNUSED_PARAMETER(server);
 	UNUSED_PARAMETER(conn);
 	return false;
 }
 
 bool CivetHandler::handleOptions(CivetServer *server,
-                                 struct mg_connection *conn) {
+                                 struct mg_connection *conn)
+{
 	UNUSED_PARAMETER(server);
 	UNUSED_PARAMETER(conn);
 	return false;
 }
 
-int CivetServer::requestHandler(struct mg_connection *conn, void *cbdata) {
+int CivetServer::requestHandler(struct mg_connection *conn, void *cbdata)
+{
 	const struct mg_request_info *request_info = mg_get_request_info(conn);
 	assert(request_info != NULL);
 	CivetServer *me = (CivetServer *)(request_info->user_data);
@@ -82,7 +87,8 @@ int CivetServer::requestHandler(struct mg_connection *conn, void *cbdata) {
 
 CivetServer::CivetServer(const char **options,
                          const struct mg_callbacks *_callbacks)
-    : context(0) {
+    : context(0)
+{
 	struct mg_callbacks callbacks;
 	memset(&callbacks, 0, sizeof(callbacks));
 
@@ -101,7 +107,8 @@ CivetServer::CivetServer(const char **options,
 
 CivetServer::~CivetServer() { close(); }
 
-void CivetServer::closeHandler(const struct mg_connection *conn) {
+void CivetServer::closeHandler(const struct mg_connection *conn)
+{
 	const struct mg_request_info *request_info = mg_get_request_info(conn);
 	assert(request_info != NULL);
 	CivetServer *me = (CivetServer *)(request_info->user_data);
@@ -118,15 +125,18 @@ void CivetServer::closeHandler(const struct mg_connection *conn) {
 	mg_unlock_context(me->context);
 }
 
-void CivetServer::addHandler(const std::string &uri, CivetHandler *handler) {
+void CivetServer::addHandler(const std::string &uri, CivetHandler *handler)
+{
 	mg_set_request_handler(context, uri.c_str(), requestHandler, handler);
 }
 
-void CivetServer::removeHandler(const std::string &uri) {
+void CivetServer::removeHandler(const std::string &uri)
+{
 	mg_set_request_handler(context, uri.c_str(), NULL, NULL);
 }
 
-void CivetServer::close() {
+void CivetServer::close()
+{
 	if (context) {
 		mg_stop(context);
 		context = 0;
@@ -135,30 +145,37 @@ void CivetServer::close() {
 
 int CivetServer::getCookie(struct mg_connection *conn,
                            const std::string &cookieName,
-                           std::string &cookieValue) {
+                           std::string &cookieValue)
+{
 	// Maximum cookie length as per microsoft is 4096.
 	// http://msdn.microsoft.com/en-us/library/ms178194.aspx
 	char _cookieValue[4096];
 	const char *cookie = mg_get_header(conn, "Cookie");
-	int lRead = mg_get_cookie(cookie, cookieName.c_str(), _cookieValue,
-	                          sizeof(_cookieValue));
+	int lRead = mg_get_cookie(
+	    cookie, cookieName.c_str(), _cookieValue, sizeof(_cookieValue));
 	cookieValue.clear();
 	cookieValue.append(_cookieValue);
 	return lRead;
 }
 
 const char *CivetServer::getHeader(struct mg_connection *conn,
-                                   const std::string &headerName) {
+                                   const std::string &headerName)
+{
 	return mg_get_header(conn, headerName.c_str());
 }
 
-void CivetServer::urlDecode(const char *src, std::string &dst,
-                            bool is_form_url_encoded) {
+void CivetServer::urlDecode(const char *src,
+                            std::string &dst,
+                            bool is_form_url_encoded)
+{
 	urlDecode(src, strlen(src), dst, is_form_url_encoded);
 }
 
-void CivetServer::urlDecode(const char *src, size_t src_len, std::string &dst,
-                            bool is_form_url_encoded) {
+void CivetServer::urlDecode(const char *src,
+                            size_t src_len,
+                            std::string &dst,
+                            bool is_form_url_encoded)
+{
 	int i, j, a, b;
 #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
 
@@ -179,8 +196,11 @@ void CivetServer::urlDecode(const char *src, size_t src_len, std::string &dst,
 	}
 }
 
-bool CivetServer::getParam(struct mg_connection *conn, const char *name,
-                           std::string &dst, size_t occurrence) {
+bool CivetServer::getParam(struct mg_connection *conn,
+                           const char *name,
+                           std::string &dst,
+                           size_t occurrence)
+{
 	const char *formParams = NULL;
 	const struct mg_request_info *ri = mg_get_request_info(conn);
 	assert(ri != NULL);
@@ -227,8 +247,12 @@ bool CivetServer::getParam(struct mg_connection *conn, const char *name,
 	return false;
 }
 
-bool CivetServer::getParam(const char *data, size_t data_len, const char *name,
-                           std::string &dst, size_t occurrence) {
+bool CivetServer::getParam(const char *data,
+                           size_t data_len,
+                           const char *name,
+                           std::string &dst,
+                           size_t occurrence)
+{
 	const char *p, *e, *s;
 	size_t name_len;
 
@@ -262,12 +286,16 @@ bool CivetServer::getParam(const char *data, size_t data_len, const char *name,
 	return false;
 }
 
-void CivetServer::urlEncode(const char *src, std::string &dst, bool append) {
+void CivetServer::urlEncode(const char *src, std::string &dst, bool append)
+{
 	urlEncode(src, strlen(src), dst, append);
 }
 
-void CivetServer::urlEncode(const char *src, size_t src_len, std::string &dst,
-                            bool append) {
+void CivetServer::urlEncode(const char *src,
+                            size_t src_len,
+                            std::string &dst,
+                            bool append)
+{
 	static const char *dont_escape = "._-$,;~()";
 	static const char *hex = "0123456789abcdef";
 
@@ -286,7 +314,8 @@ void CivetServer::urlEncode(const char *src, size_t src_len, std::string &dst,
 	}
 }
 
-std::vector<int> CivetServer::getListeningPorts() {
+std::vector<int> CivetServer::getListeningPorts()
+{
 	std::vector<int> ports(10);
 	std::vector<int> ssl(10);
 	size_t size = mg_get_ports(context, ports.size(), &ports[0], &ssl[0]);
@@ -295,7 +324,8 @@ std::vector<int> CivetServer::getListeningPorts() {
 	return ports;
 }
 
-CivetServer::CivetConnection::CivetConnection() {
+CivetServer::CivetConnection::CivetConnection()
+{
 	postData = NULL;
 	postDataLen = 0;
 }

+ 77 - 41
src/civetweb.c

@@ -52,6 +52,10 @@
 #endif
 #endif
 
+#if defined(USE_LUA) && defined(USE_WEBSOCKET)
+#define USE_TIMERS
+#endif
+
 #if defined(_MSC_VER)
 /* 'type cast' : conversion from 'int' to 'HANDLE' of greater size */
 #pragma warning(disable : 4306)
@@ -292,10 +296,6 @@ typedef long off_t;
 #define sleep(x) (Sleep((x)*1000))
 #define rmdir(x) (_rmdir(x))
 
-#if defined(USE_LUA) && defined(USE_WEBSOCKET)
-#define USE_TIMERS
-#endif
-
 #if !defined(fileno)
 #define fileno(x) (_fileno(x))
 #endif /* !fileno MINGW #defines fileno */
@@ -1149,6 +1149,7 @@ typedef struct tagTHREADNAME_INFO {
 #pragma pack(pop)
 #elif defined(__linux__)
 #include <sys/prctl.h>
+#include <sys/sendfile.h>
 #endif
 
 #if ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12)))
@@ -1169,7 +1170,7 @@ static void mg_set_thread_name(const char *name)
 	threadName[sizeof(threadName) - 1] = 0;
 
 #if defined(_WIN32)
-	#if defined(_MSC_VER)
+#if defined(_MSC_VER)
 	/* Windows and Visual Studio Compiler */
 	__try
 	{
@@ -1185,34 +1186,34 @@ static void mg_set_thread_name(const char *name)
 		               (ULONG_PTR *)&info);
 	}
 	__except(EXCEPTION_EXECUTE_HANDLER) {}
-	#elif defined(__MINGW32__)
+#elif defined(__MINGW32__)
 	/* No option known to set thread name for MinGW */
 	;
-	#endif
+#endif
 #elif defined(__linux__)
-	/* Linux */
-	#if defined(GLIBC_CHK)
+/* Linux */
+#if defined(GLIBC_CHK)
 	(void)pthread_setname_np(pthread_self(), threadName);
-	#else
+#else
 	(void)prctl(PR_SET_NAME, threadName, 0, 0, 0);
-	#endif
+#endif
 #elif defined(__APPLE__) || defined(__MACH__)
-	/* OS X */
-	#if defined(GLIBC_CHK)
+/* OS X */
+#if defined(GLIBC_CHK)
 	(void)pthread_setname_np(threadName);
-	#endif
+#endif
 #elif defined(BSD) || defined(__FreeBSD__) || defined(__OpenBSD__)
-	/* BSD (TODO: test) */
-	#if defined(GLIBC_CHK)
+/* BSD (TODO: test) */
+#if defined(GLIBC_CHK)
 	pthread_set_name_np(pthread_self(), threadName);
-	#endif
+#endif
 #elif defined(__AIX__) || defined(_AIX) || defined(__hpux) || defined(__sun)
-	/* pthread_set_name_np seems to be missing on AIX, hpux, sun, ... */
+/* pthread_set_name_np seems to be missing on AIX, hpux, sun, ... */
 #else
-	/* POSIX */
-	#if defined(GLIBC_CHK)
+/* POSIX */
+#if defined(GLIBC_CHK)
 	(void)pthread_setname_np(pthread_self(), threadName);
-	#endif
+#endif
 #endif
 }
 #else /* !defined(NO_THREAD_NAME) */
@@ -5238,36 +5239,71 @@ static void send_file_data(struct mg_connection *conn,
 	offset = offset < 0 ? 0 : offset > size ? size : offset;
 
 	if (len > 0 && filep->membuf != NULL && size > 0) {
+		/* file stored in memory */
 		if (len > size - offset) {
 			len = size - offset;
 		}
 		mg_write(conn, filep->membuf + offset, (size_t)len);
 	} else if (len > 0 && filep->fp != NULL) {
+/* file stored on disk */
+#if defined(__linux__)
+		/* TODO (high): Test sendfile for Linux */
+		if (conn->throttle == 0 && conn->ssl == 0) {
+			off_t sf_offs = (off_t)offset;
+			ssize_t sf_sent;
+			int sf_file = fileno(filep->fp);
+
+			do {
+				/* 2147479552 (0x7FFFF000) is a limit found by experiment on 64
+				 * bit Linux (2^31 minus one memory page of 4k?). */
+				ssize_t sf_tosend =
+				    (size_t)((len < 0x7FFFF000) ? len : 0x7FFFF000);
+				sf_sent =
+				    sendfile(conn->client.sock, sf_file, &sf_offs, sf_tosend);
+				if (sf_sent > 0) {
+					conn->num_bytes_sent += sf_sent;
+					len -= sf_sent;
+					offset += sf_sent;
+				}
+
+			} while ((len > 0) && (sf_sent >= 0));
+
+			if (sf_sent > 0) {
+				return; /* OK */
+			}
+			/* sf_sent<0 means error, thus fall back to the classic way */
+			mg_cry(conn,
+			       "%s: sendfile() failed: %s (now trying read+write)",
+			       __func__,
+			       strerror(ERRNO));
+		}
+#endif
 		if (offset > 0 && fseeko(filep->fp, offset, SEEK_SET) != 0) {
 			mg_cry(conn, "%s: fseeko() failed: %s", __func__, strerror(ERRNO));
-		}
-		while (len > 0) {
-			/* Calculate how much to read from the file in the buffer */
-			to_read = sizeof(buf);
-			if ((int64_t)to_read > len) {
-				to_read = (int)len;
-			}
+		} else {
+			while (len > 0) {
+				/* Calculate how much to read from the file in the buffer */
+				to_read = sizeof(buf);
+				if ((int64_t)to_read > len) {
+					to_read = (int)len;
+				}
 
-			/* Read from file, exit the loop on error */
-			if ((num_read = (int)fread(buf, 1, (size_t)to_read, filep->fp)) <=
-			    0) {
-				break;
-			}
+				/* Read from file, exit the loop on error */
+				if ((num_read =
+				         (int)fread(buf, 1, (size_t)to_read, filep->fp)) <= 0) {
+					break;
+				}
 
-			/* Send read bytes to the client, exit the loop on error */
-			if ((num_written = mg_write(conn, buf, (size_t)num_read)) !=
-			    num_read) {
-				break;
-			}
+				/* Send read bytes to the client, exit the loop on error */
+				if ((num_written = mg_write(conn, buf, (size_t)num_read)) !=
+				    num_read) {
+					break;
+				}
 
-			/* Both read and were successful, adjust counters */
-			conn->num_bytes_sent += num_written;
-			len -= num_written;
+				/* Both read and were successful, adjust counters */
+				conn->num_bytes_sent += num_written;
+				len -= num_written;
+			}
 		}
 	}
 }

+ 2 - 1
src/lua_civet.h

@@ -1,4 +1,5 @@
 /* "lua_civet.h" */
-/* Project internal header to allow main.c to call a non-public function in mod_lua.inl */
+/* Project internal header to allow main.c to call a non-public function in
+ * mod_lua.inl */
 
 void lua_civet_open_all_libs(lua_State *L);

+ 7 - 7
src/main.c

@@ -127,7 +127,7 @@ static struct tuser_data
 #endif
 
 /* backup config file */
-#if !defined(CONFIG_FILE2) && defined(LINUX)
+#if !defined(CONFIG_FILE2) && defined(__linux__)
 #define CONFIG_FILE2 "/usr/local/etc/civetweb.conf"
 #endif
 
@@ -299,11 +299,11 @@ static const char *get_option(char **options, const char *option_name)
 	const char *opt_value = NULL;
 
 	/* TODO (low, api makeover): options should be an array of key-value-pairs,
-	 * like 
-     *     struct {const char * key, const char * value} options[]
+	 * like
+	 *     struct {const char * key, const char * value} options[]
 	 * but it currently is an array with
 	 *     options[2*i] = key, options[2*i + 1] = value
-     * (probably with a MG_LEGACY_INTERFACE definition)
+	 * (probably with a MG_LEGACY_INTERFACE definition)
 	 */
 	while (options[2 * i] != NULL) {
 		if (strcmp(options[2 * i], option_name) == 0) {
@@ -340,7 +340,7 @@ static int set_option(char **options, const char *name, const char *value)
 		return 0;
 	case CONFIG_TYPE_NUMBER:
 		/* integer number > 0, e.g. number of threads */
-		if (atol(value) < 1) {
+		if (atol(value) < 0) {
 			/* invalid number */
 			return 0;
 		}
@@ -1813,8 +1813,8 @@ static void change_password_file()
 static int manage_service(int action)
 {
 	static const char *service_name =
-	    "Civetweb"; /* TODO (mid): check using server_name instead of 
-                     * service_name */
+	    "Civetweb"; /* TODO (mid): check using server_name instead of
+	                 * service_name */
 	SC_HANDLE hSCM = NULL, hService = NULL;
 	SERVICE_DESCRIPTION descr;
 	char path[PATH_MAX + 20] = ""; /* Path to executable plus magic argument */

+ 11 - 9
src/mod_lua.inl

@@ -8,9 +8,9 @@ mmap(void *addr, int64_t len, int prot, int flags, int fd, int offset)
 {
 	/* TODO (low): This is an incomplete implementation of mmap for windows.
 	 * Currently it is sufficient, but there are a lot of unused parameters.
-     * Better use a function "mg_map" which only has the required parameters,
-     * and implement it using mmap in Linux and CreateFileMapping in Windows.
-     * Noone should expect a full mmap for Windows here.
+	 * Better use a function "mg_map" which only has the required parameters,
+	 * and implement it using mmap in Linux and CreateFileMapping in Windows.
+	 * Noone should expect a full mmap for Windows here.
 	 */
 	HANDLE fh = (HANDLE)_get_osfhandle(fd);
 	HANDLE mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0);
@@ -1109,14 +1109,14 @@ void lua_civet_open_all_libs(lua_State *L)
 	}
 #endif
 #ifdef USE_LUA_BINARY
-    {
-        /* TODO (low): Test if this could be used as a replacement for bit32.
-         * Check again with Lua 5.3 later. */
+	{
+		/* TODO (low): Test if this could be used as a replacement for bit32.
+		 * Check again with Lua 5.3 later. */
 		extern int luaopen_binary(lua_State *);
 
-        luaL_requiref(L, "binary", luaopen_binary, 1);
-        lua_pop(L, 1);
-    }
+		luaL_requiref(L, "binary", luaopen_binary, 1);
+		lua_pop(L, 1);
+	}
 #endif
 }
 
@@ -1572,6 +1572,8 @@ static void lua_websocket_close(struct mg_connection *conn, void *ws_arg)
 	/* TODO: Delete lua_websock_data and remove it from the websocket list.
 	   This must only be done, when all connections are closed, and all
 	   asynchronous operations and timers are completed/expired. */
+	(void)shared_websock_list; /* shared_websock_list unused (see open TODO) */
+
 	(void)pthread_mutex_unlock(&ws->ws_mutex);
 }
 #endif

+ 199 - 0
test/1000images.lua

@@ -0,0 +1,199 @@
+mg.write("HTTP/1.1 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")
+
+t = os.time()
+
+if not mg.request_info.query_string then
+  cnt = 1000
+else
+  cnt = tonumber(mg.get_var(mg.request_info.query_string, "cnt"))
+end
+
+cnt = 100*math.floor(cnt/100)
+
+mg.write([[
+<html>
+  <head>
+    <title>]] .. cnt .. [[ images</title>
+    <script type="text/javascript">
+      var startLoad = Date.now();
+      window.onload = function () {
+        var loadTime = (Date.now()-startLoad) + " ms";
+        document.getElementById('timing').innerHTML = loadTime;
+      }
+    </script>
+  </head>
+  <body>
+    <h1>A large gallery of small images:</h1>
+    <p>
+]])
+for s=0,(cnt/100)-1 do
+local ts = (tostring(t) .. tostring(s))
+mg.write([[
+      <h2>page ]]..s..[[</h2>
+      <table>
+        <tr>
+          <td><img src="imagetest/00.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/01.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/02.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/03.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/04.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/05.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/06.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/07.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/08.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/09.png?ts=]]..ts..[["></td>
+        </tr>
+]])
+mg.write([[
+        <tr>
+          <td><img src="imagetest/10.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/11.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/12.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/13.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/14.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/15.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/16.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/17.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/18.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/19.png?ts=]]..ts..[["></td>
+        </tr>
+]])
+mg.write([[
+        <tr>
+          <td><img src="imagetest/20.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/21.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/22.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/23.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/24.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/25.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/26.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/27.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/28.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/29.png?ts=]]..ts..[["></td>
+        </tr>
+]])
+mg.write([[
+        <tr>
+          <td><img src="imagetest/20.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/21.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/22.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/23.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/24.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/25.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/26.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/27.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/28.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/29.png?ts=]]..ts..[["></td>
+        </tr>
+]])
+mg.write([[
+        <tr>
+          <td><img src="imagetest/30.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/31.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/32.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/33.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/34.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/35.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/36.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/37.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/38.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/39.png?ts=]]..ts..[["></td>
+        </tr>
+]])
+mg.write([[
+        <tr>
+          <td><img src="imagetest/40.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/41.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/42.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/43.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/44.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/45.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/46.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/47.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/48.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/49.png?ts=]]..ts..[["></td>
+        </tr>
+]])
+mg.write([[
+        <tr>
+          <td><img src="imagetest/50.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/51.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/52.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/53.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/54.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/55.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/56.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/57.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/58.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/59.png?ts=]]..ts..[["></td>
+        </tr>
+]])
+mg.write([[
+        <tr>
+          <td><img src="imagetest/60.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/61.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/62.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/63.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/64.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/65.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/66.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/67.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/68.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/69.png?ts=]]..ts..[["></td>
+        </tr>
+]])
+mg.write([[
+        <tr>
+          <td><img src="imagetest/70.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/71.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/72.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/73.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/74.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/75.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/76.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/77.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/78.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/79.png?ts=]]..ts..[["></td>
+        </tr>
+]])
+mg.write([[
+        <tr>
+          <td><img src="imagetest/80.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/81.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/82.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/83.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/84.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/85.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/86.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/87.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/88.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/89.png?ts=]]..ts..[["></td>
+        </tr>
+]])
+mg.write([[
+        <tr>
+          <td><img src="imagetest/90.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/91.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/92.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/93.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/94.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/95.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/96.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/97.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/98.png?ts=]]..ts..[["></td>
+          <td><img src="imagetest/99.png?ts=]]..ts..[["></td>
+        </tr>
+      </table>
+]])
+end
+mg.write([[
+    </p>
+    <p id="timing">
+      Test case: all images are displayed.
+    </p>
+  </body>
+</html>
+]])

+ 168 - 160
test/100images.htm

@@ -1,160 +1,168 @@
-<html>
-
-  <!-- Test case description:                              -->
-  <!-- This test contains 100 small images in a table.     -->
-  <!-- Once a browser opens the html file, it will request -->
-  <!-- all these images from the server very quickly.      -->
-  <!-- Depending on the "keep-alive" settings, it will     -->
-  <!-- either open/close 100 connections quite rapidly     -->
-  <!-- if keep-alive=no, or otherwise establish only a few -->
-  <!-- connections, typically one or two, and reuse them.  -->
-  <!-- If the test succeeds, all 100 images are displayed. -->
-
-  <!-- Bug: I saw cases where more than 40 were missing.   -->
-
-  <head>
-    <title>100 images</title>
-  </head>
-  <body>
-    <h1>A gallery of small images:</h1>
-    <p>
-      <table>
-        <tr>
-          <td><img src="imagetest/00.png"></td>
-          <td><img src="imagetest/01.png"></td>
-          <td><img src="imagetest/02.png"></td>
-          <td><img src="imagetest/03.png"></td>
-          <td><img src="imagetest/04.png"></td>
-          <td><img src="imagetest/05.png"></td>
-          <td><img src="imagetest/06.png"></td>
-          <td><img src="imagetest/07.png"></td>
-          <td><img src="imagetest/08.png"></td>
-          <td><img src="imagetest/09.png"></td>
-        </tr>
-        <tr>
-          <td><img src="imagetest/10.png"></td>
-          <td><img src="imagetest/11.png"></td>
-          <td><img src="imagetest/12.png"></td>
-          <td><img src="imagetest/13.png"></td>
-          <td><img src="imagetest/14.png"></td>
-          <td><img src="imagetest/15.png"></td>
-          <td><img src="imagetest/16.png"></td>
-          <td><img src="imagetest/17.png"></td>
-          <td><img src="imagetest/18.png"></td>
-          <td><img src="imagetest/19.png"></td>
-        </tr>
-        <tr>
-          <td><img src="imagetest/20.png"></td>
-          <td><img src="imagetest/21.png"></td>
-          <td><img src="imagetest/22.png"></td>
-          <td><img src="imagetest/23.png"></td>
-          <td><img src="imagetest/24.png"></td>
-          <td><img src="imagetest/25.png"></td>
-          <td><img src="imagetest/26.png"></td>
-          <td><img src="imagetest/27.png"></td>
-          <td><img src="imagetest/28.png"></td>
-          <td><img src="imagetest/29.png"></td>
-        </tr>
-        <tr>
-          <td><img src="imagetest/20.png"></td>
-          <td><img src="imagetest/21.png"></td>
-          <td><img src="imagetest/22.png"></td>
-          <td><img src="imagetest/23.png"></td>
-          <td><img src="imagetest/24.png"></td>
-          <td><img src="imagetest/25.png"></td>
-          <td><img src="imagetest/26.png"></td>
-          <td><img src="imagetest/27.png"></td>
-          <td><img src="imagetest/28.png"></td>
-          <td><img src="imagetest/29.png"></td>
-        </tr>
-        <tr>
-          <td><img src="imagetest/30.png"></td>
-          <td><img src="imagetest/31.png"></td>
-          <td><img src="imagetest/32.png"></td>
-          <td><img src="imagetest/33.png"></td>
-          <td><img src="imagetest/34.png"></td>
-          <td><img src="imagetest/35.png"></td>
-          <td><img src="imagetest/36.png"></td>
-          <td><img src="imagetest/37.png"></td>
-          <td><img src="imagetest/38.png"></td>
-          <td><img src="imagetest/39.png"></td>
-        </tr>
-        <tr>
-          <td><img src="imagetest/40.png"></td>
-          <td><img src="imagetest/41.png"></td>
-          <td><img src="imagetest/42.png"></td>
-          <td><img src="imagetest/43.png"></td>
-          <td><img src="imagetest/44.png"></td>
-          <td><img src="imagetest/45.png"></td>
-          <td><img src="imagetest/46.png"></td>
-          <td><img src="imagetest/47.png"></td>
-          <td><img src="imagetest/48.png"></td>
-          <td><img src="imagetest/49.png"></td>
-        </tr>
-        <tr>
-          <td><img src="imagetest/50.png"></td>
-          <td><img src="imagetest/51.png"></td>
-          <td><img src="imagetest/52.png"></td>
-          <td><img src="imagetest/53.png"></td>
-          <td><img src="imagetest/54.png"></td>
-          <td><img src="imagetest/55.png"></td>
-          <td><img src="imagetest/56.png"></td>
-          <td><img src="imagetest/57.png"></td>
-          <td><img src="imagetest/58.png"></td>
-          <td><img src="imagetest/59.png"></td>
-        </tr>
-        <tr>
-          <td><img src="imagetest/60.png"></td>
-          <td><img src="imagetest/61.png"></td>
-          <td><img src="imagetest/62.png"></td>
-          <td><img src="imagetest/63.png"></td>
-          <td><img src="imagetest/64.png"></td>
-          <td><img src="imagetest/65.png"></td>
-          <td><img src="imagetest/66.png"></td>
-          <td><img src="imagetest/67.png"></td>
-          <td><img src="imagetest/68.png"></td>
-          <td><img src="imagetest/69.png"></td>
-        </tr>
-        <tr>
-          <td><img src="imagetest/70.png"></td>
-          <td><img src="imagetest/71.png"></td>
-          <td><img src="imagetest/72.png"></td>
-          <td><img src="imagetest/73.png"></td>
-          <td><img src="imagetest/74.png"></td>
-          <td><img src="imagetest/75.png"></td>
-          <td><img src="imagetest/76.png"></td>
-          <td><img src="imagetest/77.png"></td>
-          <td><img src="imagetest/78.png"></td>
-          <td><img src="imagetest/79.png"></td>
-        </tr>
-        <tr>
-          <td><img src="imagetest/80.png"></td>
-          <td><img src="imagetest/81.png"></td>
-          <td><img src="imagetest/82.png"></td>
-          <td><img src="imagetest/83.png"></td>
-          <td><img src="imagetest/84.png"></td>
-          <td><img src="imagetest/85.png"></td>
-          <td><img src="imagetest/86.png"></td>
-          <td><img src="imagetest/87.png"></td>
-          <td><img src="imagetest/88.png"></td>
-          <td><img src="imagetest/89.png"></td>
-        </tr>
-        <tr>
-          <td><img src="imagetest/90.png"></td>
-          <td><img src="imagetest/91.png"></td>
-          <td><img src="imagetest/92.png"></td>
-          <td><img src="imagetest/93.png"></td>
-          <td><img src="imagetest/94.png"></td>
-          <td><img src="imagetest/95.png"></td>
-          <td><img src="imagetest/96.png"></td>
-          <td><img src="imagetest/97.png"></td>
-          <td><img src="imagetest/98.png"></td>
-          <td><img src="imagetest/99.png"></td>
-        </tr>
-      </table>
-    </p>
-    <p>
-      Test case: all images are displayed.
-    </p>    
-  </body>
-</html>
+<html>
+
+  <!-- Test case description:                              -->
+  <!-- This test contains 100 small images in a table.     -->
+  <!-- Once a browser opens the html file, it will request -->
+  <!-- all these images from the server very quickly.      -->
+  <!-- Depending on the "keep-alive" settings, it will     -->
+  <!-- either open/close 100 connections quite rapidly     -->
+  <!-- if keep-alive=no, or otherwise establish only a few -->
+  <!-- connections, typically one or two, and reuse them.  -->
+  <!-- If the test succeeds, all 100 images are displayed. -->
+  <!-- The loading time is measured automatically in the   -->
+  <!-- browser using JavaScript. Note that the load times  -->
+  <!-- also differs between HTTP and HTTPS.                -->
+
+  <head>
+    <title>100 images</title>
+    <script type="text/javascript">
+      var startLoad = Date.now();
+      window.onload = function () {
+        var loadTime = (Date.now()-startLoad) + " ms";
+        document.getElementById('timing').innerHTML = loadTime;
+      }
+    </script>
+  </head>
+  <body>
+    <h1>A gallery of small images:</h1>
+    <p>
+      <table>
+        <tr>
+          <td><img src="imagetest/00.png"></td>
+          <td><img src="imagetest/01.png"></td>
+          <td><img src="imagetest/02.png"></td>
+          <td><img src="imagetest/03.png"></td>
+          <td><img src="imagetest/04.png"></td>
+          <td><img src="imagetest/05.png"></td>
+          <td><img src="imagetest/06.png"></td>
+          <td><img src="imagetest/07.png"></td>
+          <td><img src="imagetest/08.png"></td>
+          <td><img src="imagetest/09.png"></td>
+        </tr>
+        <tr>
+          <td><img src="imagetest/10.png"></td>
+          <td><img src="imagetest/11.png"></td>
+          <td><img src="imagetest/12.png"></td>
+          <td><img src="imagetest/13.png"></td>
+          <td><img src="imagetest/14.png"></td>
+          <td><img src="imagetest/15.png"></td>
+          <td><img src="imagetest/16.png"></td>
+          <td><img src="imagetest/17.png"></td>
+          <td><img src="imagetest/18.png"></td>
+          <td><img src="imagetest/19.png"></td>
+        </tr>
+        <tr>
+          <td><img src="imagetest/20.png"></td>
+          <td><img src="imagetest/21.png"></td>
+          <td><img src="imagetest/22.png"></td>
+          <td><img src="imagetest/23.png"></td>
+          <td><img src="imagetest/24.png"></td>
+          <td><img src="imagetest/25.png"></td>
+          <td><img src="imagetest/26.png"></td>
+          <td><img src="imagetest/27.png"></td>
+          <td><img src="imagetest/28.png"></td>
+          <td><img src="imagetest/29.png"></td>
+        </tr>
+        <tr>
+          <td><img src="imagetest/20.png"></td>
+          <td><img src="imagetest/21.png"></td>
+          <td><img src="imagetest/22.png"></td>
+          <td><img src="imagetest/23.png"></td>
+          <td><img src="imagetest/24.png"></td>
+          <td><img src="imagetest/25.png"></td>
+          <td><img src="imagetest/26.png"></td>
+          <td><img src="imagetest/27.png"></td>
+          <td><img src="imagetest/28.png"></td>
+          <td><img src="imagetest/29.png"></td>
+        </tr>
+        <tr>
+          <td><img src="imagetest/30.png"></td>
+          <td><img src="imagetest/31.png"></td>
+          <td><img src="imagetest/32.png"></td>
+          <td><img src="imagetest/33.png"></td>
+          <td><img src="imagetest/34.png"></td>
+          <td><img src="imagetest/35.png"></td>
+          <td><img src="imagetest/36.png"></td>
+          <td><img src="imagetest/37.png"></td>
+          <td><img src="imagetest/38.png"></td>
+          <td><img src="imagetest/39.png"></td>
+        </tr>
+        <tr>
+          <td><img src="imagetest/40.png"></td>
+          <td><img src="imagetest/41.png"></td>
+          <td><img src="imagetest/42.png"></td>
+          <td><img src="imagetest/43.png"></td>
+          <td><img src="imagetest/44.png"></td>
+          <td><img src="imagetest/45.png"></td>
+          <td><img src="imagetest/46.png"></td>
+          <td><img src="imagetest/47.png"></td>
+          <td><img src="imagetest/48.png"></td>
+          <td><img src="imagetest/49.png"></td>
+        </tr>
+        <tr>
+          <td><img src="imagetest/50.png"></td>
+          <td><img src="imagetest/51.png"></td>
+          <td><img src="imagetest/52.png"></td>
+          <td><img src="imagetest/53.png"></td>
+          <td><img src="imagetest/54.png"></td>
+          <td><img src="imagetest/55.png"></td>
+          <td><img src="imagetest/56.png"></td>
+          <td><img src="imagetest/57.png"></td>
+          <td><img src="imagetest/58.png"></td>
+          <td><img src="imagetest/59.png"></td>
+        </tr>
+        <tr>
+          <td><img src="imagetest/60.png"></td>
+          <td><img src="imagetest/61.png"></td>
+          <td><img src="imagetest/62.png"></td>
+          <td><img src="imagetest/63.png"></td>
+          <td><img src="imagetest/64.png"></td>
+          <td><img src="imagetest/65.png"></td>
+          <td><img src="imagetest/66.png"></td>
+          <td><img src="imagetest/67.png"></td>
+          <td><img src="imagetest/68.png"></td>
+          <td><img src="imagetest/69.png"></td>
+        </tr>
+        <tr>
+          <td><img src="imagetest/70.png"></td>
+          <td><img src="imagetest/71.png"></td>
+          <td><img src="imagetest/72.png"></td>
+          <td><img src="imagetest/73.png"></td>
+          <td><img src="imagetest/74.png"></td>
+          <td><img src="imagetest/75.png"></td>
+          <td><img src="imagetest/76.png"></td>
+          <td><img src="imagetest/77.png"></td>
+          <td><img src="imagetest/78.png"></td>
+          <td><img src="imagetest/79.png"></td>
+        </tr>
+        <tr>
+          <td><img src="imagetest/80.png"></td>
+          <td><img src="imagetest/81.png"></td>
+          <td><img src="imagetest/82.png"></td>
+          <td><img src="imagetest/83.png"></td>
+          <td><img src="imagetest/84.png"></td>
+          <td><img src="imagetest/85.png"></td>
+          <td><img src="imagetest/86.png"></td>
+          <td><img src="imagetest/87.png"></td>
+          <td><img src="imagetest/88.png"></td>
+          <td><img src="imagetest/89.png"></td>
+        </tr>
+        <tr>
+          <td><img src="imagetest/90.png"></td>
+          <td><img src="imagetest/91.png"></td>
+          <td><img src="imagetest/92.png"></td>
+          <td><img src="imagetest/93.png"></td>
+          <td><img src="imagetest/94.png"></td>
+          <td><img src="imagetest/95.png"></td>
+          <td><img src="imagetest/96.png"></td>
+          <td><img src="imagetest/97.png"></td>
+          <td><img src="imagetest/98.png"></td>
+          <td><img src="imagetest/99.png"></td>
+        </tr>
+      </table>
+    </p>
+    <p id="timing">
+      Test case: all images are displayed.
+    </p>
+  </body>
+</html>

+ 8 - 73
test/ajax/echo.cgi

@@ -1,73 +1,8 @@
-#!/usr/bin/lua5.1
-
--- Every CGI script that returns any valid JSON object will work in the test.
--- In case you do not have not yet used CGI, you may want to use this script which is written in Lua.
--- You may download an interpreter from http://luabinaries.sourceforge.net/download.html, extract it
--- to some folder in your search path (the path of the webserver or /usr/bin on Linux), and add the
--- following lines to your .conf file.
--- cgi_interpreter c:\somewhere\lua5.1.exe
--- enable_keep_alive yes
-
-resp = "{";
-
-method = os.getenv("REQUEST_METHOD")
-uri = os.getenv("REQUEST_URI");
-query = os.getenv("QUERY_STRING");
-datalen = os.getenv("CONTENT_LENGTH");
-
-if method then
-  resp = resp .. '"method" : "' .. method .. '", ';
-end
-if uri then
-  resp = resp .. '"uri" : "' .. uri .. '", ';
-end
-if query then
-  resp = resp .. '"query" : "' .. query .. '", ';
-end
-if datalen then
-  resp = resp .. '"datalen" : "' .. datalen .. '", ';
-end
-
-resp = resp .. '"time" : "' .. os.date() .. '" ';
-
-resp = resp .. "}";
-
-
-
-
-print "Status: 200 OK"
-print "Connection: close"
---print "Connection: keep-alive"
-print "Content-Type: text/html; charset=utf-8"
-print "Cache-Control: no-cache"
---print ("Content-Length: " .. resp:len())
-print ""
-
-print (resp)
-
-
-doLogging = false
-
-if (doLogging) then
-  -- Store the POST data to a file
-  if (method == "POST") then
-    myFile = io.open("data" .. query:sub(4) .. ".txt", "wb");
-    myFile:write(resp)
-    myFile:write("\r\n\r\n")  
-    if datalen then
-      datalen = tonumber(datalen)
-      myFile:write("<<< " .. datalen .. " bytes of data >>>\r\n")
-      
-      data = io.stdin:read(datalen)
-      myFile:write(data)
-      
-      myFile:write("\r\n<<< end >>>\r\n")
-    else
-      myFile:write("<<< no data >>>\r\n")
-    end  
-    myFile:close()
-  end
-end
-
-
-
+#!/bin/sh
+
+echo "Content-Type: text/plain; charset=utf-8"
+echo "Connection: close"
+echo "Cache-Control: no-cache"
+echo ""
+
+echo "{}"

+ 73 - 0
test/ajax/echo.cgi.old

@@ -0,0 +1,73 @@
+#!/usr/bin/lua5.1
+
+-- Every CGI script that returns any valid JSON object will work in the test.
+-- In case you do not have not yet used CGI, you may want to use this script which is written in Lua.
+-- You may download an interpreter from http://luabinaries.sourceforge.net/download.html, extract it
+-- to some folder in your search path (the path of the webserver or /usr/bin on Linux), and add the
+-- following lines to your .conf file.
+-- cgi_interpreter c:\somewhere\lua5.1.exe
+-- enable_keep_alive yes
+
+resp = "{";
+
+method = os.getenv("REQUEST_METHOD")
+uri = os.getenv("REQUEST_URI");
+query = os.getenv("QUERY_STRING");
+datalen = os.getenv("CONTENT_LENGTH");
+
+if method then
+  resp = resp .. '"method" : "' .. method .. '", ';
+end
+if uri then
+  resp = resp .. '"uri" : "' .. uri .. '", ';
+end
+if query then
+  resp = resp .. '"query" : "' .. query .. '", ';
+end
+if datalen then
+  resp = resp .. '"datalen" : "' .. datalen .. '", ';
+end
+
+resp = resp .. '"time" : "' .. os.date() .. '" ';
+
+resp = resp .. "}";
+
+
+
+
+print "Status: 200 OK"
+print "Connection: close"
+--print "Connection: keep-alive"
+print "Content-Type: text/html; charset=utf-8"
+print "Cache-Control: no-cache"
+--print ("Content-Length: " .. resp:len())
+print ""
+
+print (resp)
+
+
+doLogging = false
+
+if (doLogging) then
+  -- Store the POST data to a file
+  if (method == "POST") then
+    myFile = io.open("data" .. query:sub(4) .. ".txt", "wb");
+    myFile:write(resp)
+    myFile:write("\r\n\r\n")  
+    if datalen then
+      datalen = tonumber(datalen)
+      myFile:write("<<< " .. datalen .. " bytes of data >>>\r\n")
+      
+      data = io.stdin:read(datalen)
+      myFile:write(data)
+      
+      myFile:write("\r\n<<< end >>>\r\n")
+    else
+      myFile:write("<<< no data >>>\r\n")
+    end  
+    myFile:close()
+  end
+end
+
+
+

+ 2 - 2
test/cors.html

@@ -32,7 +32,7 @@ function getTitle(text) {
 
 // Make the actual CORS request.
 function makeCorsRequest(method, resource) {
-  var url = "http://localhost/cors.reply." + resource;
+  var url = "http://localhost:8080/cors.reply." + resource;
   var xhr = createCORSRequest(method, url);
   if (!xhr) {
     alert('ERROR: CORS not supported');
@@ -55,7 +55,7 @@ function makeCorsRequest(method, resource) {
 
 function start() {
   var el = document.getElementById("from");
-  el.innerHTML = "Test CORS from " + document.URL + " to http://localhost/cors.reply.*";
+  el.innerHTML = "Test CORS from " + document.URL + " to http://localhost:8080/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.");
   }

+ 0 - 0
test/imagetest/00.PNG → test/imagetest/00.png


+ 0 - 0
test/imagetest/01.PNG → test/imagetest/01.png


+ 0 - 0
test/imagetest/02.PNG → test/imagetest/02.png


+ 0 - 0
test/imagetest/03.PNG → test/imagetest/03.png


+ 0 - 0
test/imagetest/04.PNG → test/imagetest/04.png


+ 0 - 0
test/imagetest/05.PNG → test/imagetest/05.png


+ 0 - 0
test/imagetest/06.PNG → test/imagetest/06.png


+ 0 - 0
test/imagetest/07.PNG → test/imagetest/07.png


+ 0 - 0
test/imagetest/08.PNG → test/imagetest/08.png


+ 0 - 0
test/imagetest/09.PNG → test/imagetest/09.png


+ 0 - 0
test/imagetest/10.PNG → test/imagetest/10.png


+ 0 - 0
test/imagetest/11.PNG → test/imagetest/11.png


+ 0 - 0
test/imagetest/12.PNG → test/imagetest/12.png


+ 0 - 0
test/imagetest/13.PNG → test/imagetest/13.png


+ 0 - 0
test/imagetest/14.PNG → test/imagetest/14.png


+ 0 - 0
test/imagetest/15.PNG → test/imagetest/15.png


+ 0 - 0
test/imagetest/16.PNG → test/imagetest/16.png


+ 0 - 0
test/imagetest/17.PNG → test/imagetest/17.png


+ 0 - 0
test/imagetest/18.PNG → test/imagetest/18.png


+ 0 - 0
test/imagetest/19.PNG → test/imagetest/19.png


+ 0 - 0
test/imagetest/20.PNG → test/imagetest/20.png


+ 0 - 0
test/imagetest/21.PNG → test/imagetest/21.png


+ 0 - 0
test/imagetest/22.PNG → test/imagetest/22.png


+ 0 - 0
test/imagetest/23.PNG → test/imagetest/23.png


+ 0 - 0
test/imagetest/24.PNG → test/imagetest/24.png


+ 0 - 0
test/imagetest/25.PNG → test/imagetest/25.png


+ 0 - 0
test/imagetest/26.PNG → test/imagetest/26.png


+ 0 - 0
test/imagetest/27.PNG → test/imagetest/27.png


+ 0 - 0
test/imagetest/28.PNG → test/imagetest/28.png


+ 0 - 0
test/imagetest/29.PNG → test/imagetest/29.png


+ 0 - 0
test/imagetest/30.PNG → test/imagetest/30.png


+ 0 - 0
test/imagetest/31.PNG → test/imagetest/31.png


+ 0 - 0
test/imagetest/32.PNG → test/imagetest/32.png


+ 0 - 0
test/imagetest/33.PNG → test/imagetest/33.png


+ 0 - 0
test/imagetest/34.PNG → test/imagetest/34.png


+ 0 - 0
test/imagetest/35.PNG → test/imagetest/35.png


+ 0 - 0
test/imagetest/36.PNG → test/imagetest/36.png


+ 0 - 0
test/imagetest/37.PNG → test/imagetest/37.png


+ 0 - 0
test/imagetest/38.PNG → test/imagetest/38.png


+ 0 - 0
test/imagetest/39.PNG → test/imagetest/39.png


+ 0 - 0
test/imagetest/40.PNG → test/imagetest/40.png


+ 0 - 0
test/imagetest/41.PNG → test/imagetest/41.png


+ 0 - 0
test/imagetest/42.PNG → test/imagetest/42.png


+ 0 - 0
test/imagetest/43.PNG → test/imagetest/43.png


+ 0 - 0
test/imagetest/44.PNG → test/imagetest/44.png


+ 0 - 0
test/imagetest/45.PNG → test/imagetest/45.png


+ 0 - 0
test/imagetest/46.PNG → test/imagetest/46.png


+ 0 - 0
test/imagetest/47.PNG → test/imagetest/47.png


+ 0 - 0
test/imagetest/48.PNG → test/imagetest/48.png


+ 0 - 0
test/imagetest/49.PNG → test/imagetest/49.png


+ 0 - 0
test/imagetest/50.PNG → test/imagetest/50.png


+ 0 - 0
test/imagetest/51.PNG → test/imagetest/51.png


+ 0 - 0
test/imagetest/52.PNG → test/imagetest/52.png


+ 0 - 0
test/imagetest/53.PNG → test/imagetest/53.png


+ 0 - 0
test/imagetest/54.PNG → test/imagetest/54.png


+ 0 - 0
test/imagetest/55.PNG → test/imagetest/55.png


+ 0 - 0
test/imagetest/56.PNG → test/imagetest/56.png


+ 0 - 0
test/imagetest/57.PNG → test/imagetest/57.png


+ 0 - 0
test/imagetest/58.PNG → test/imagetest/58.png


+ 0 - 0
test/imagetest/59.PNG → test/imagetest/59.png


+ 0 - 0
test/imagetest/60.PNG → test/imagetest/60.png


+ 0 - 0
test/imagetest/61.PNG → test/imagetest/61.png


+ 0 - 0
test/imagetest/62.PNG → test/imagetest/62.png


+ 0 - 0
test/imagetest/63.PNG → test/imagetest/63.png


+ 0 - 0
test/imagetest/64.PNG → test/imagetest/64.png


+ 0 - 0
test/imagetest/65.PNG → test/imagetest/65.png


+ 0 - 0
test/imagetest/66.PNG → test/imagetest/66.png


+ 0 - 0
test/imagetest/67.PNG → test/imagetest/67.png


+ 0 - 0
test/imagetest/68.PNG → test/imagetest/68.png


+ 0 - 0
test/imagetest/69.PNG → test/imagetest/69.png


+ 0 - 0
test/imagetest/70.PNG → test/imagetest/70.png


+ 0 - 0
test/imagetest/71.PNG → test/imagetest/71.png


+ 0 - 0
test/imagetest/72.PNG → test/imagetest/72.png


+ 0 - 0
test/imagetest/73.PNG → test/imagetest/73.png


+ 0 - 0
test/imagetest/74.PNG → test/imagetest/74.png


+ 0 - 0
test/imagetest/75.PNG → test/imagetest/75.png


+ 0 - 0
test/imagetest/76.PNG → test/imagetest/76.png


+ 0 - 0
test/imagetest/77.PNG → test/imagetest/77.png


+ 0 - 0
test/imagetest/78.PNG → test/imagetest/78.png


+ 0 - 0
test/imagetest/79.PNG → test/imagetest/79.png


+ 0 - 0
test/imagetest/80.PNG → test/imagetest/80.png


+ 0 - 0
test/imagetest/81.PNG → test/imagetest/81.png


+ 0 - 0
test/imagetest/82.PNG → test/imagetest/82.png


+ 0 - 0
test/imagetest/83.PNG → test/imagetest/83.png


+ 0 - 0
test/imagetest/84.PNG → test/imagetest/84.png


+ 0 - 0
test/imagetest/85.PNG → test/imagetest/85.png


部分文件因为文件数量过多而无法显示