diff --git a/phpdesktop-chrome/cef/client_handler.cpp b/phpdesktop-chrome/cef/client_handler.cpp
index b97f17f..9cdbd5c 100644
--- a/phpdesktop-chrome/cef/client_handler.cpp
+++ b/phpdesktop-chrome/cef/client_handler.cpp
@@ -310,7 +310,8 @@ void ClientHandler::OnLoadingStateChange(CefRefPtr cefBrowser,
bool isLoading,
bool canGoBack,
bool canGoForward) {
- LOG_DEBUG << "OnLoadingStateChange: loading = " << isLoading;
+ LOG_DEBUG << "OnLoadingStateChange: loading=" << isLoading << ", url="
+ << cefBrowser->GetMainFrame()->GetURL().ToString().c_str();
static int calls = 0;
calls++;
if (calls > 1) {
@@ -336,7 +337,8 @@ void ClientHandler::OnLoadError(CefRefPtr browser,
const CefString& errorText,
const CefString& failedUrl) {
REQUIRE_UI_THREAD();
- LOG_DEBUG << "OnLoadError, errorCode=" << errorCode;
+ LOG_DEBUG << "OnLoadError, errorCode=" << errorCode
+ << ", failedUrl=" << failedUrl.ToString().c_str();
// Don't display an error for downloaded files.
if (errorCode == ERR_ABORTED)
diff --git a/phpdesktop-chrome/mongoose.c b/phpdesktop-chrome/mongoose.c
index e48a52a..49a0bcd 100644
--- a/phpdesktop-chrome/mongoose.c
+++ b/phpdesktop-chrome/mongoose.c
@@ -455,7 +455,7 @@ enum {
ACCESS_LOG_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE,
GLOBAL_PASSWORDS_FILE, INDEX_FILES, ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST,
EXTRA_MIME_TYPES, LISTENING_PORTS, DOCUMENT_ROOT, SSL_CERTIFICATE,
- NUM_THREADS, RUN_AS_USER, REWRITE, HIDE_FILES, REQUEST_TIMEOUT,
+ NUM_THREADS, RUN_AS_USER, REWRITE, HIDE_FILES, REQUEST_TIMEOUT, _404_HANDLER,
NUM_OPTIONS
};
@@ -485,6 +485,7 @@ static const char *config_options[] = {
"url_rewrite_patterns", NULL,
"hide_files_patterns", NULL,
"request_timeout_ms", "30000",
+ "404_handler", NULL,
NULL
};
@@ -1827,12 +1828,39 @@ int mg_get_cookie(const char *cookie_header, const char *var_name,
return len;
}
+static void support_path_info_for_cgi_scripts(
+ struct mg_connection *conn, char *buf,
+ size_t buf_len, struct file *filep) {
+ char *p;
+ // Support PATH_INFO for CGI scripts.
+ for (p = buf + strlen(buf); p > buf + 1; p--) {
+ if (*p == '/') {
+ *p = '\0';
+ if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
+ strlen(conn->ctx->config[CGI_EXTENSIONS]), buf) > 0 &&
+ mg_stat(conn, buf, filep)) {
+ // Shift PATH_INFO block one character right, e.g.
+ // "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
+ // conn->path_info is pointing to the local variable "path" declared
+ // in handle_request(), so PATH_INFO is not valid after
+ // handle_request returns.
+ conn->path_info = p + 1;
+ memmove(p + 2, p + 1, strlen(p + 1) + 1); // +1 is for trailing \0
+ p[1] = '/';
+ break;
+ } else {
+ *p = '/';
+ }
+ }
+ }
+}
+
static void convert_uri_to_file_name(struct mg_connection *conn, char *buf,
size_t buf_len, struct file *filep) {
struct vec a, b;
const char *rewrite, *uri = conn->request_info.uri,
- *root = conn->ctx->config[DOCUMENT_ROOT];
- char *p;
+ *root = conn->ctx->config[DOCUMENT_ROOT],
+ *_404_handler = conn->ctx->config[_404_HANDLER];
int match_len;
char gz_path[PATH_MAX];
char const* accept_encoding;
@@ -1852,7 +1880,7 @@ static void convert_uri_to_file_name(struct mg_connection *conn, char *buf,
break;
}
}
-
+
if (mg_stat(conn, buf, filep)) return;
// if we can't find the actual file, look for the file
@@ -1871,27 +1899,33 @@ static void convert_uri_to_file_name(struct mg_connection *conn, char *buf,
}
}
- // Support PATH_INFO for CGI scripts.
- for (p = buf + strlen(buf); p > buf + 1; p--) {
- if (*p == '/') {
- *p = '\0';
- if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
- strlen(conn->ctx->config[CGI_EXTENSIONS]), buf) > 0 &&
- mg_stat(conn, buf, filep)) {
- // Shift PATH_INFO block one character right, e.g.
- // "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
- // conn->path_info is pointing to the local variable "path" declared
- // in handle_request(), so PATH_INFO is not valid after
- // handle_request returns.
- conn->path_info = p + 1;
- memmove(p + 2, p + 1, strlen(p + 1) + 1); // +1 is for trailing \0
- p[1] = '/';
- break;
- } else {
- *p = '/';
- }
- }
+ support_path_info_for_cgi_scripts(conn, buf, buf_len, filep);
+
+ // --------------------------------------------------------------------------
+ // PHP Desktop 404_handler.
+ // Condition that checks if file exists (filep->membuf == NULL),
+ // must run after support_path_info_for_cgi_scripts(). Otherwise
+ // it will evaluate to false when checking uri "/foo.php/bar/5".
+ if (
+ (
+ !strcmp(conn->request_info.request_method, "GET")
+ || !strcmp(conn->request_info.request_method, "HEAD")
+ || !strcmp(conn->request_info.request_method, "POST")
+ )
+ && (filep->membuf == NULL && filep->modification_time == (time_t) 0)
+ && (root != NULL)
+ && (strlen(_404_handler) > 0)
+ ) {
+ mg_snprintf(conn, buf, buf_len - 1,
+ "%s%s%s",
+ root, _404_handler, uri
+ );
+ support_path_info_for_cgi_scripts(conn, buf, buf_len, filep);
+ // cry(conn, "%s%s", "!!! 404_handler=TRUE, buf=", buf);
+ } else {
+ // cry(conn, "%s%s", "!!! 404_handler=FALSE, buf=", buf);
}
+ // --------------------------------------------------------------------------
}
// Check whether full request is buffered. Return:
@@ -3295,10 +3329,13 @@ static char *addenv(struct cgi_env_block *block, const char *fmt, ...) {
static void prepare_cgi_environment(struct mg_connection *conn,
const char *prog,
struct cgi_env_block *blk) {
- const char *s, *slash;
+ const char *s;
struct vec var_vec;
char *p, src_addr[IP_ADDR_STR_LEN];
int i;
+ char prog2[PATH_MAX] = "";
+ char script_name[PATH_MAX] = "";
+ int root_len = strlen(conn->ctx->config[DOCUMENT_ROOT]);
blk->len = blk->nvars = 0;
blk->conn = conn;
@@ -3320,18 +3357,36 @@ static void prepare_cgi_environment(struct mg_connection *conn,
addenv(blk, "REQUEST_METHOD=%s", conn->request_info.request_method);
addenv(blk, "REMOTE_ADDR=%s", src_addr);
addenv(blk, "REMOTE_PORT=%d", conn->request_info.remote_port);
- addenv(blk, "REQUEST_URI=%s", conn->request_info.uri);
+ if (conn->request_info.query_string == NULL) {
+ addenv(blk, "REQUEST_URI=%s", conn->request_info.uri);
+ } else {
+ addenv(blk, "REQUEST_URI=%s?%s", conn->request_info.uri,
+ conn->request_info.query_string);
+ }
- // SCRIPT_NAME
+ // SCRIPT_NAME - original code was buggy and was removed.
assert(conn->request_info.uri[0] == '/');
- slash = strrchr(conn->request_info.uri, '/');
- if ((s = strrchr(prog, '/')) == NULL)
- s = prog;
- addenv(blk, "SCRIPT_NAME=%.*s%s", (int) (slash - conn->request_info.uri),
- conn->request_info.uri, s);
-
- addenv(blk, "SCRIPT_FILENAME=%s", prog);
- addenv(blk, "PATH_TRANSLATED=%s", prog);
+ // Detect SCRIPT_NAME using "prog" and document root.
+ if ((int)strlen(prog) > root_len) {
+ for (i = root_len; i < (int)strlen(prog); i++) {
+ assert(i-root_len >= 0);
+ script_name[i-root_len] = prog[i];
+ }
+ }
+ addenv(blk, "SCRIPT_NAME=%s", script_name);
+
+ // Fix "prog", replace forward slashes with backslashes on Windows.
+ strcpy(prog2, prog);
+#if defined(_WIN32)
+ for (i = 0; i < (int)strlen(prog2); i++) {
+ if (prog2[i] == '/') {
+ prog2[i] = '\\';
+ }
+#endif
+ }
+
+ addenv(blk, "SCRIPT_FILENAME=%s", prog2);
+ addenv(blk, "PATH_TRANSLATED=%s", prog2);
addenv(blk, "HTTPS=%s", conn->ssl == NULL ? "off" : "on");
if ((s = mg_get_header(conn, "Content-Type")) != NULL)
@@ -4455,7 +4510,7 @@ static void handle_request(struct mg_connection *conn) {
convert_uri_to_file_name(conn, path, sizeof(path), &file);
conn->throttle = set_throttle(conn->ctx->config[THROTTLE],
get_remote_ip(conn), ri->uri);
-
+
DEBUG_TRACE(("%s", ri->uri));
// Perform redirect and auth checks before calling begin_request() handler.
// Otherwise, begin_request() would need to perform auth checks and redirects.
diff --git a/phpdesktop-chrome/web_server.cpp b/phpdesktop-chrome/web_server.cpp
index 74ac33d..de54102 100644
--- a/phpdesktop-chrome/web_server.cpp
+++ b/phpdesktop-chrome/web_server.cpp
@@ -49,38 +49,13 @@ static void end_request(const struct mg_connection* conn, int reply_status_code)
LOG_INFO << message;
}
-// Called when mongoose is about to send HTTP error to the client.
-// Implementing this callback allows to create custom error pages.
-// Parameters:
-// status: HTTP error status code.
-static int http_error(struct mg_connection* conn, int status) {
- mg_request_info* request = mg_get_request_info(
- const_cast(conn));
- std::string request_uri;
- request_uri.append(request->uri);
- if (request->query_string != NULL) {
- request_uri.append("?").append(request->query_string);
- }
- LOG_INFO << "http_error(), status=" << status
- << ", uri=" << request_uri.c_str();
- json_value* appSettings = GetApplicationSettings();
- std::string _404_handler = (*appSettings)["web_server"]["404_handler"];
- if (status == 404 && !_404_handler.empty()) {
- mg_printf(conn,
- "HTTP/1.1 302 Found\r\n"
- "Location: %s%s\r\n\r\n",
- _404_handler.c_str(),
- request_uri.c_str()
- );
- return 0;
- }
- return 1;
-}
-
bool StartWebServer() {
LOG_INFO << "Starting Mongoose " << mg_version() << " web server";
json_value* appSettings = GetApplicationSettings();
+ // 404_handler
+ std::string _404_handler = (*appSettings)["web_server"]["404_handler"];
+
// Ip address and port. If port was set to 0, then real port
// will be known only after the webserver was started.
std::string ipAddress = (*appSettings)["web_server"]["listen_on"][0];
@@ -178,6 +153,7 @@ bool StartWebServer() {
"cgi_interpreter", cgiInterpreter.c_str(),
"cgi_pattern", cgiPattern.c_str(),
"cgi_environment", cgiEnvironment.c_str(),
+ "404_handler", _404_handler.c_str(),
NULL
};
@@ -188,7 +164,6 @@ bool StartWebServer() {
mg_callbacks callbacks = {0};
callbacks.log_message = &log_message;
callbacks.end_request = &end_request;
- callbacks.http_error = &http_error;
g_mongooseContext = mg_start(&callbacks, NULL, options);
if (g_mongooseContext == NULL)
return false;
diff --git a/phpdesktop-chrome/www/pretty-urls.php b/phpdesktop-chrome/www/pretty-urls.php
index 39a5367..29e1987 100644
--- a/phpdesktop-chrome/www/pretty-urls.php
+++ b/phpdesktop-chrome/www/pretty-urls.php
@@ -14,10 +14,6 @@
and makes a redirect to "/pretty-urls.php/company/5".
To know what the pretty url that was accessed check
the PATH_INFO or REQUEST_URI environment variables.
- Additionally it is required to fix some of the Mongoose
- environment variables by calling __fix_mongoose_env_variables()
- php function at the beginning of your php script. See the code
- further down this page.
@@ -29,16 +25,18 @@
- Test POST request to "/company.html" url:
-
-
-
-
- Test POST request to "/pretty-urls.php/company.html" url:
-
@@ -51,11 +49,6 @@
-
- Urls like "index.php/company/5" will work correctly only after applying
- a fix to mongoose $_SERVER/$_ENV variables. See the
- __fix_mongoose_env_variables() php function further down the page.
-
Other tests (these urls do not require 404_handler to be set):
-$_SERVER before fix
+$_SERVER
-
-> [PHP_SELF] => /index.php/company/index.php/company/5
- $php_self = $_SERVER["PHP_SELF"];
- if (strrpos($php_self, "/") !== 0) {
- // When PHP_SELF contains more than one slash. Remove
- // path info from both PHP_SELF and SCRIPT_NAME.
- $php_self = preg_replace('#^(/+[^/\\\]+)[\s\S]+#',
- '\\1', $php_self);
- $_SERVER["PHP_SELF"] = $php_self;
- $_SERVER["SCRIPT_NAME"] = $php_self;
- }
- // Append QUERY_STRING to REQUEST_URI env variable.
- if (isset($_SERVER["QUERY_STRING"]) && $_SERVER["QUERY_STRING"]) {
- $_SERVER["REQUEST_URI"] = $_SERVER["REQUEST_URI"]."?".(
- $_SERVER["QUERY_STRING"]);
- }
- }
- // Fix forward slash in SCRIPT_FILENAME and PATH_TRANSLATED:
- // >> C:\phpdesktop\phpdesktop-chrome\www/pretty-urls.php
- // should become:
- // >> C:\phpdesktop\phpdesktop-chrome\www\pretty-urls.php
- $_SERVER["SCRIPT_FILENAME"] = str_replace("/", "\\",
- $_SERVER["SCRIPT_FILENAME"]);
- $_SERVER["PATH_TRANSLATED"] = str_replace("/", "\\",
- $_SERVER["PATH_TRANSLATED"]);
- // Fixes were applied to $_SERVER only. Apply them to $_ENV as well.
- $keys_to_fix = ["REQUEST_URI", "SCRIPT_NAME", "PHP_SELF",
- "SCRIPT_FILENAME", "PATH_TRANSLATED"];
- foreach ($keys_to_fix as $env_key) {
- putenv("$env_key={$_SERVER[$env_key]}");
- $_ENV[$env_key] = $_SERVER[$env_key];
- }
-}
-__fix_mongoose_env_variables();
-?>
-
-
-$_SERVER after fix
-The following fixes are applied:
-
- - REQUEST_URI does not contain QUERY_STRING
-
- Pretty urls like "/index.php/company/5" have invalid values
- for SCRIPT_NAME and PHP_SELF keys
-
- SCRIPT_FILENAME and PATH_TRANSLATED contain forward slash
- before script name
-
-
-
-
-To fix env variables use the code below
-Put this code at the very beginning of php script.
-
-<?php
-function __fix_mongoose_env_variables()
-{
- // REQUEST_URI does not contain QUERY_STRING. See Issue 112
- // in the tracker. The condition below will be always executed.
- if (strpos($_SERVER["REQUEST_URI"], "?") === false) {
- // Fix PHP_SELF and SCRIPT_NAME env variables which may be
- // broken for pretty urls like "/index.php/company/5":
- // >> [PHP_SELF] => /index.php/company/index.php/company/5
- $php_self = $_SERVER["PHP_SELF"];
- if (strrpos($php_self, "/") !== 0) {
- // When PHP_SELF contains more than one slash. Remove
- // path info from both PHP_SELF and SCRIPT_NAME.
- $php_self = preg_replace('#^(/+[^/\\\]+)[\s\S]+#',
- '\\1', $php_self);
- $_SERVER["PHP_SELF"] = $php_self;
- $_SERVER["SCRIPT_NAME"] = $php_self;
- }
- // Append QUERY_STRING to REQUEST_URI env variable.
- if (isset($_SERVER["QUERY_STRING"]) && $_SERVER["QUERY_STRING"]) {
- $_SERVER["REQUEST_URI"] = $_SERVER["REQUEST_URI"]."?".(
- $_SERVER["QUERY_STRING"]);
- }
- }
- // Fix forward slash in SCRIPT_FILENAME and PATH_TRANSLATED:
- // >> C:\phpdesktop\phpdesktop-chrome\www/pretty-urls.php
- // should become:
- // >> C:\phpdesktop\phpdesktop-chrome\www\pretty-urls.php
- $_SERVER["SCRIPT_FILENAME"] = str_replace("/", "\\",
- $_SERVER["SCRIPT_FILENAME"]);
- $_SERVER["PATH_TRANSLATED"] = str_replace("/", "\\",
- $_SERVER["PATH_TRANSLATED"]);
- // Fixes were applied to $_SERVER only. Apply them to $_ENV as well.
- $keys_to_fix = ["REQUEST_URI", "SCRIPT_NAME", "PHP_SELF",
- "SCRIPT_FILENAME", "PATH_TRANSLATED"];
- foreach ($keys_to_fix as $env_key) {
- putenv("$env_key={$_SERVER[$env_key]}");
- $_ENV[$env_key] = $_SERVER[$env_key];
- }
-}
-__fix_mongoose_env_variables();
-?>
-