From d3e6ade96f0f5ac9bb73c3d4d134727a83404496 Mon Sep 17 00:00:00 2001 From: Paul Tarjan Date: Wed, 5 Jun 2013 13:51:48 -0700 Subject: [PATCH] fix all the $_SERVER urls - take 2 I needed to `m_origPathInfo.reset()` in `RequestURI::clear` --- hphp/runtime/base/server/http_protocol.cpp | 7 ++- hphp/runtime/base/server/request_uri.cpp | 58 ++++++++++++++-------- hphp/runtime/base/server/request_uri.h | 4 +- hphp/util/util.cpp | 25 ++++++---- hphp/util/util.h | 3 +- 5 files changed, 58 insertions(+), 39 deletions(-) diff --git a/hphp/runtime/base/server/http_protocol.cpp b/hphp/runtime/base/server/http_protocol.cpp index 2c93d67e7..b2f19fa88 100644 --- a/hphp/runtime/base/server/http_protocol.cpp +++ b/hphp/runtime/base/server/http_protocol.cpp @@ -362,11 +362,10 @@ void HttpProtocol::PrepareSystemVariables(Transport *transport, } else { server.set(s_SCRIPT_NAME, r.resolvedURL()); } - if (!r.rewritten() && r.pathInfo().empty()) { - server.set(s_PHP_SELF, r.resolvedURL()); - } else { - // when URL is rewritten, or pathinfo is not empty, use original URL + if (r.rewritten()) { server.set(s_PHP_SELF, r.originalURL()); + } else { + server.set(s_PHP_SELF, r.resolvedURL() + r.origPathInfo()); } server.set(s_SCRIPT_FILENAME, r.absolutePath()); diff --git a/hphp/runtime/base/server/request_uri.cpp b/hphp/runtime/base/server/request_uri.cpp index a841efaa1..254a9d543 100644 --- a/hphp/runtime/base/server/request_uri.cpp +++ b/hphp/runtime/base/server/request_uri.cpp @@ -68,13 +68,11 @@ bool RequestURI::process(const VirtualHost *vhost, Transport *transport, m_originalURL = StringUtil::UrlDecode(m_originalURL, false); // Fast path for files that exist - String canon = Util::canonicalize(string(m_originalURL.c_str(), - m_originalURL.size())); - String relUrl(canon.charAt(0) == '/' ? canon.substr(1) : canon); - if (virtualFileExists(vhost, sourceRoot, pathTranslation, relUrl)) { - m_rewrittenURL = relUrl; - m_resolvedURL = std::move(relUrl); - PrependSlash(m_resolvedURL); + String canon(Util::canonicalize(m_originalURL.c_str(), m_originalURL.size()), + AttachString); + if (virtualFileExists(vhost, sourceRoot, pathTranslation, canon)) { + m_rewrittenURL = canon; + m_resolvedURL = canon; return true; } @@ -142,8 +140,9 @@ bool RequestURI::rewriteURL(const VirtualHost *vhost, Transport *transport, } splitURL(m_rewrittenURL, m_rewrittenURL, m_queryString); } - m_rewrittenURL = Util::canonicalize(string(m_rewrittenURL.c_str(), - m_rewrittenURL.size())); + m_rewrittenURL = String( + Util::canonicalize(m_rewrittenURL.c_str(), m_rewrittenURL.size()), + AttachString); if (!m_rewritten && m_rewrittenURL.charAt(0) == '/') { // A un-rewritten URL is always relative, so remove prepending / m_rewrittenURL = m_rewrittenURL.substr(1); @@ -184,31 +183,43 @@ bool RequestURI::rewriteURL(const VirtualHost *vhost, Transport *transport, bool RequestURI::resolveURL(const VirtualHost *vhost, const string &pathTranslation, const string &sourceRoot) { - m_resolvedURL = m_rewrittenURL; + + String startURL; + if (m_rewritten) { + startURL = m_rewrittenURL; + } else { + startURL = m_originalURL; + } + startURL = String( + Util::canonicalize(startURL.c_str(), startURL.size(), false), + AttachString); + m_resolvedURL = startURL; + while (!virtualFileExists(vhost, sourceRoot, pathTranslation, m_resolvedURL)) { int pos = m_resolvedURL.rfind('/'); if (pos <= 0) { // when none of the exists, we give up, and try default doc - m_resolvedURL = m_rewrittenURL; + m_resolvedURL = startURL; if (!m_resolvedURL.empty() && m_resolvedURL.charAt(m_resolvedURL.length() - 1) != '/') { m_resolvedURL += "/"; } m_resolvedURL += String(RuntimeOption::DefaultDocument); - m_pathInfo.reset(); + m_origPathInfo.reset(); if (virtualFileExists(vhost, sourceRoot, pathTranslation, m_resolvedURL)) { m_defaultDoc = true; - PrependSlash(m_resolvedURL); return true; } return false; } - m_resolvedURL = m_rewrittenURL.substr(0, pos); - m_pathInfo = m_rewrittenURL.substr(pos); + m_resolvedURL = startURL.substr(0, pos); + m_origPathInfo = startURL.substr(pos); } - PrependSlash(m_resolvedURL); + m_pathInfo = String( + Util::canonicalize(m_origPathInfo.c_str(), m_origPathInfo.size()), + AttachString); return true; } @@ -219,13 +230,14 @@ bool RequestURI::virtualFileExists(const VirtualHost *vhost, if (filename.empty() || filename.charAt(filename.length() - 1) == '/') { return false; } + String canon(Util::canonicalize(filename.c_str(), filename.size()), + AttachString); if (!vhost->getDocumentRoot().empty()) { - string fullname = filename.data(); - if (fullname[0] == '/') { + string fullname = canon.data(); + while (fullname[0] == '/') { fullname = fullname.substr(1); - } else { - fullname = pathTranslation + fullname; } + fullname = pathTranslation + fullname; m_path = fullname; m_absolutePath = String(sourceRoot) + m_path; processExt(); @@ -241,8 +253,8 @@ bool RequestURI::virtualFileExists(const VirtualHost *vhost, (stat(m_absolutePath.c_str(), &st) == 0 && (st.st_mode & S_IFMT) == S_IFREG); } - m_path = filename; - m_absolutePath = String(sourceRoot) + filename; + m_path = canon; + m_absolutePath = String(sourceRoot) + canon; processExt(); return true; } @@ -327,6 +339,7 @@ void RequestURI::dump() { m_rewrittenURL.dump(); m_resolvedURL.dump(); m_pathInfo.dump(); + m_origPathInfo.dump(); m_absolutePath.dump(); m_path.dump(); } @@ -337,6 +350,7 @@ void RequestURI::clear() { m_rewrittenURL.reset(); m_resolvedURL.reset(); m_pathInfo.reset(); + m_origPathInfo.reset(); m_absolutePath.reset(); m_path.reset(); } diff --git a/hphp/runtime/base/server/request_uri.h b/hphp/runtime/base/server/request_uri.h index 8c069fc68..648d79a92 100644 --- a/hphp/runtime/base/server/request_uri.h +++ b/hphp/runtime/base/server/request_uri.h @@ -31,7 +31,7 @@ public: RequestURI(const VirtualHost *vhost, Transport *transport, const std::string &pathTranslation, const std::string &sourceRoot); - RequestURI(const std::string & rpcFunc); + explicit RequestURI(const std::string & rpcFunc); CStrRef originalURL() const { return m_originalURL; } CStrRef resolvedURL() const { return m_resolvedURL; } @@ -41,6 +41,7 @@ public: const char *ext() const { return m_ext; } CStrRef absolutePath() const { return m_absolutePath; } CStrRef pathInfo() const { return m_pathInfo; } + CStrRef origPathInfo() const { return m_origPathInfo; } bool rewritten() const { return m_rewritten; } bool defaultDoc() const { return m_defaultDoc; } @@ -59,6 +60,7 @@ private: // without pathinfo String m_pathInfo; + String m_origPathInfo; String m_absolutePath; String m_path; // path relative to SourceRoot diff --git a/hphp/util/util.cpp b/hphp/util/util.cpp index 006d63334..fc7bb12ce 100644 --- a/hphp/util/util.cpp +++ b/hphp/util/util.cpp @@ -552,7 +552,9 @@ std::string Util::canonicalize(const std::string &path) { * limitations under the License. */ -const char *Util::canonicalize(const char *addpath, size_t addlen) { +const char *Util::canonicalize(const char *addpath, size_t addlen, + bool collapse_slashes /* = true */) { + assert(strlen(addpath) == addlen); // 4 for slashes at start, after root, and at end, plus trailing // null size_t maxlen = addlen + 4; @@ -566,7 +568,7 @@ const char *Util::canonicalize(const char *addpath, size_t addlen) { char *path = (char *)malloc(maxlen); - if (addpath[0] == '/') { + if (addpath[0] == '/' && collapse_slashes) { /* Ignore the given root path, strip off leading * '/'s to a single leading '/' from the addpath, * and leave addpath at the first non-'/' character. @@ -586,9 +588,13 @@ const char *Util::canonicalize(const char *addpath, size_t addlen) { } seglen = next - addpath; - if (seglen == 0 || (seglen == 1 && addpath[0] == '.')) { - /* noop segment (/ or ./) so skip it - */ + if (seglen == 0) { + /* / */ + if (!collapse_slashes) { + path[pathlen++] = '/'; + } + } else if (seglen == 1 && addpath[0] == '.') { + /* ./ */ } else if (seglen == 2 && addpath[0] == '.' && addpath[1] == '.') { /* backpath (../) */ if (pathlen == 1 && path[0] == '/') { @@ -603,15 +609,13 @@ const char *Util::canonicalize(const char *addpath, size_t addlen) { memcpy(path + pathlen, "../", *next ? 3 : 2); pathlen += *next ? 3 : 2; } else { - /* otherwise crop the prior segment - */ + /* otherwise crop the prior segment */ do { --pathlen; } while (pathlen && path[pathlen - 1] != '/'); } } else { - /* An actual segment, append it to the destination path - */ + /* An actual segment, append it to the destination path */ if (*next) { seglen++; } @@ -619,8 +623,7 @@ const char *Util::canonicalize(const char *addpath, size_t addlen) { pathlen += seglen; } - /* Skip over trailing slash to the next segment - */ + /* Skip over trailing slash to the next segment */ if (*next) { ++next; } diff --git a/hphp/util/util.h b/hphp/util/util.h index a40133790..9f451698c 100644 --- a/hphp/util/util.h +++ b/hphp/util/util.h @@ -174,7 +174,8 @@ std::string relativePath(const std::string fromDir, const std::string toFile); * Canonicalize path to remove "..", "." and "\/", etc.. */ std::string canonicalize(const std::string &path); -const char *canonicalize(const char *path, size_t len); +const char *canonicalize(const char *path, size_t len, + bool collapse_slashes = true); /** * Makes sure there is ending slash by changing "path/name" to "path/name/".