diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 329a72aa..76acddef 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -5,6 +5,7 @@ Release Notes v1.6 (Under Development)
Changes
-------
+- Support user defined error pages (bel)
- Method to get POST request parameters via C++ interface (bel)
- Re-Add unit tests for Linux and Windows (jmc-, bel)
- Allow to specify title and tray icon for the Windows standalone server (bel)
diff --git a/VS2012/civetweb/civetweb.vcxproj b/VS2012/civetweb/civetweb.vcxproj
index f2a2d8fc..91d81533 100644
--- a/VS2012/civetweb/civetweb.vcxproj
+++ b/VS2012/civetweb/civetweb.vcxproj
@@ -27,7 +27,7 @@
Application
true
- v110_xp
+ v100
MultiByte
diff --git a/VS2012/civetweb_lua/civetweb_lua.vcxproj b/VS2012/civetweb_lua/civetweb_lua.vcxproj
index c8a1f6b4..b1844e8b 100644
--- a/VS2012/civetweb_lua/civetweb_lua.vcxproj
+++ b/VS2012/civetweb_lua/civetweb_lua.vcxproj
@@ -28,7 +28,7 @@
Application
true
MultiByte
- v110_xp
+ v100
Application
diff --git a/VS2012/ex_embed_cpp/ex_embed_cpp.vcxproj b/VS2012/ex_embed_cpp/ex_embed_cpp.vcxproj
index 3b7115ec..ba4fa520 100644
--- a/VS2012/ex_embed_cpp/ex_embed_cpp.vcxproj
+++ b/VS2012/ex_embed_cpp/ex_embed_cpp.vcxproj
@@ -27,7 +27,7 @@
Application
true
- v110_xp
+ v100
Unicode
diff --git a/VS2012/ex_embedded_c/ex_embedded_c.vcxproj b/VS2012/ex_embedded_c/ex_embedded_c.vcxproj
index e2ca4ddb..3c1f407f 100644
--- a/VS2012/ex_embedded_c/ex_embedded_c.vcxproj
+++ b/VS2012/ex_embedded_c/ex_embedded_c.vcxproj
@@ -34,7 +34,7 @@
Application
true
- v110_xp
+ v100
Unicode
diff --git a/docs/UserManual.md b/docs/UserManual.md
index 3e188e41..5e68c068 100644
--- a/docs/UserManual.md
+++ b/docs/UserManual.md
@@ -342,6 +342,18 @@ be used for websockets as well. Since websockets use a different URL scheme
websockets may also be served from a different directory. By default,
the document_root is used as websocket_root as well.
+## access_control_allow_origin
+Access-Control-Allow-Origin header field used for cross-origin resource
+sharing (CORS).
+
+## error_pages
+This option may be used to specify a directory for user defined error pages.
+The error pages may be specified for an individual http status code (e.g.,
+404 - page requested by the client not found), a group of http status codes
+(e.g., 4xx - all client errors) or all errors. The corresponding error pages
+must be called error404.ext, error4xx.ext or error.ext, whereas the file
+extention may be one of the extentions specified for the index_files option.
+
# Lua Scripts and Lua Server Pages
Pre-built Windows and Mac civetweb binaries have built-in Lua scripting
diff --git a/src/civetweb.c b/src/civetweb.c
index 40c18bdc..9bd7fa56 100644
--- a/src/civetweb.c
+++ b/src/civetweb.c
@@ -678,7 +678,7 @@ enum {
#if defined(USE_LUA) && defined(USE_WEBSOCKET)
LUA_WEBSOCKET_EXTENSIONS,
#endif
- ACCESS_CONTROL_ALLOW_ORIGIN,
+ ACCESS_CONTROL_ALLOW_ORIGIN, ERROR_PAGES,
NUM_OPTIONS
};
@@ -699,9 +699,9 @@ static struct mg_option config_options[] = {
{"global_auth_file", CONFIG_TYPE_FILE, NULL},
{"index_files", 12345,
#ifdef USE_LUA
- "index.html,index.htm,index.lp,index.lsp,index.lua,index.cgi,index.shtml,index.php"},
+ "index.xhtml,index.html,index.htm,index.lp,index.lsp,index.lua,index.cgi,index.shtml,index.php"},
#else
- "index.html,index.htm,index.cgi,index.shtml,index.php"},
+ "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"},
#endif
{"enable_keep_alive", CONFIG_TYPE_BOOLEAN, "no"},
{"access_control_list", 12345, NULL},
@@ -727,6 +727,7 @@ static struct mg_option config_options[] = {
{"lua_websocket_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lua$"},
#endif
{"access_control_allow_origin", CONFIG_TYPE_STRING, "*"},
+ {"error_pages", CONFIG_TYPE_DIRECTORY, NULL},
{NULL, CONFIG_TYPE_UNKNOWN, NULL}
};
@@ -1303,6 +1304,7 @@ static const char *suggest_connection_header(const struct mg_connection *conn)
}
static void handle_file_based_request(struct mg_connection *conn, const char *path, struct file *filep);
+static int mg_stat(struct mg_connection *conn, const char *path, struct file *filep);
static void send_http_error(struct mg_connection *, int, const char *,
PRINTF_FORMAT_STRING(const char *fmt), ...)
@@ -1314,11 +1316,12 @@ static void send_http_error(struct mg_connection *conn, int status,
{
char buf[MG_BUF_LEN];
va_list ap;
- int len = 0;
+ int len = 0, i, page_handler_found, scope;
char date[64];
time_t curtime = time(NULL);
- const char * error_handler = NULL;
+ const char *error_handler = NULL;
struct file error_page_file = STRUCT_FILE_INITIALIZER;
+ const char *error_page_file_ext, *tstr;
conn->status_code = status;
if (conn->in_error_handler ||
@@ -1326,10 +1329,39 @@ static void send_http_error(struct mg_connection *conn, int status,
conn->ctx->callbacks.http_error(conn, status)) {
if (!conn->in_error_handler) {
- /* TODO: allow user defined error page */
- if ((error_handler!=NULL) && mg_stat(conn, error_handler, &error_page_file)) {
+ /* Send user defined error pages, if defined */
+ error_handler = conn->ctx->config[ERROR_PAGES];
+ error_page_file_ext = conn->ctx->config[INDEX_FILES];
+ page_handler_found = 0;
+ if (error_handler != NULL) {
+ for (scope=1; (scope<=3) && !page_handler_found; scope++) {
+ switch (scope) {
+ case 1:
+ len = mg_snprintf(conn, buf, sizeof(buf)-32, "%serror%03u.", error_handler, status);
+ break;
+ case 2:
+ len = mg_snprintf(conn, buf, sizeof(buf)-32, "%serror%01uxx.", error_handler, status/100);
+ break;
+ default:
+ len = mg_snprintf(conn, buf, sizeof(buf)-32, "%serror.", error_handler);
+ break;
+ }
+ tstr = strchr(error_page_file_ext, '.');
+ while (tstr) {
+ for (i=1; i<32 && tstr[i]!=0 && tstr[i]!=','; i++) buf[len+i-1]=tstr[i];
+ buf[len+i-1]=0;
+ if (mg_stat(conn, buf, &error_page_file)) {
+ page_handler_found = 1;
+ break;
+ }
+ tstr = strchr(tstr+i, '.');
+ }
+ }
+ }
+
+ if (page_handler_found) {
conn->in_error_handler = 1;
- handle_file_based_request(conn, error_handler, &error_page_file);
+ handle_file_based_request(conn, buf, &error_page_file);
conn->in_error_handler = 0;
return;
}
@@ -1621,8 +1653,7 @@ static int path_cannot_disclose_cgi(const char *path)
return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
}
-static int mg_stat(struct mg_connection *conn, const char *path,
- struct file *filep)
+static int mg_stat(struct mg_connection *conn, const char *path, struct file *filep)
{
wchar_t wbuf[PATH_MAX];
WIN32_FILE_ATTRIBUTE_DATA info;
diff --git a/test/error4xx.htm b/test/error4xx.htm
new file mode 100644
index 00000000..357db2ce
--- /dev/null
+++ b/test/error4xx.htm
@@ -0,0 +1,10 @@
+
+
+
+Error
+
+
+Custom error page
+
+
\ No newline at end of file