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: -

    + Test POST request to + +
    @@ -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):

      @@ -70,7 +63,7 @@

    -

    $_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();
    -?>
    -