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