Skip to content

Commit c59a087

Browse files
Will Shackletonfacebook-github-bot
authored andcommitted
Add new GlobalDocument request routing mode
Summary: I added a new config option, "GlobalDocument", designed to better suit applications that use a request routing framework and have a single Hack entry point that handles every URI. Previously the following config and file structure were required: ``` # config.hdf Server { ErrorDocument404 = index.php } VirtualHost { default { PathTranslation = html } } # file structure lib: utils.php ... html: index.php ``` With this new option the following is possible: ``` # config.hdf Server { GlobalDocument = lib/__entrypoint.php } # file structure lib: utils.php __entrypoint.php ... ``` This removes the need for a document folder entirely and ensures that every request must go through the single entrypoint. Further, this entrypoint can now be placed in the same folder / module as the rest of the routing framework's core code. Reviewed By: billf Differential Revision: D17131684 fbshipit-source-id: 15a2e22ec13f21df31bfd25fee77d129e074f174
1 parent 11df233 commit c59a087

11 files changed

Lines changed: 165 additions & 8 deletions

hphp/runtime/base/runtime-option.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,7 @@ bool RuntimeOption::AutoloadEnabled;
694694
std::string RuntimeOption::AutoloadDBPath;
695695
std::string RuntimeOption::FileCache;
696696
std::string RuntimeOption::DefaultDocument;
697+
std::string RuntimeOption::GlobalDocument;
697698
std::string RuntimeOption::ErrorDocument404;
698699
bool RuntimeOption::ForbiddenAs404 = false;
699700
std::string RuntimeOption::ErrorDocument500;
@@ -2245,6 +2246,7 @@ void RuntimeOption::Load(
22452246
Config::Bind(FileCache, ini, config, "Server.FileCache");
22462247
Config::Bind(DefaultDocument, ini, config, "Server.DefaultDocument",
22472248
"index.php");
2249+
Config::Bind(GlobalDocument, ini, config, "Server.GlobalDocument");
22482250
Config::Bind(ErrorDocument404, ini, config, "Server.ErrorDocument404");
22492251
normalizePath(ErrorDocument404);
22502252
Config::Bind(ForbiddenAs404, ini, config, "Server.ForbiddenAs404");

hphp/runtime/base/runtime-option.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@ struct RuntimeOption {
416416

417417
static std::string FileCache;
418418
static std::string DefaultDocument;
419+
static std::string GlobalDocument;
419420
static std::string ErrorDocument404;
420421
static bool ForbiddenAs404;
421422
static std::string ErrorDocument500;

hphp/runtime/server/http-protocol.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,9 @@ static void CopyPathInfo(Array& server,
666666
name = name.substr(0, pos);
667667
}
668668
}
669+
if (r.globalDoc()) {
670+
name = String(RuntimeOption::GlobalDocument);
671+
}
669672
if (r.defaultDoc()) {
670673
if (!name.empty() && name[name.length() - 1] != '/') {
671674
name += "/";

hphp/runtime/server/request-uri.cpp

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,13 @@ namespace HPHP {
3434
RequestURI::RequestURI(const VirtualHost *vhost, Transport *transport,
3535
const std::string &pathTranslation,
3636
const std::string &sourceRoot)
37-
: m_rewritten(false), m_defaultDoc(false), m_done(false),
38-
m_forbidden(false), m_ext(nullptr) {
37+
: m_rewritten(false)
38+
, m_defaultDoc(false)
39+
, m_globalDoc(false)
40+
, m_done(false)
41+
, m_forbidden(false)
42+
, m_ext(nullptr)
43+
{
3944
if (!process(vhost, transport, sourceRoot, pathTranslation,
4045
transport->getServerObject()) ||
4146
(m_forbidden && RuntimeOption::ForbiddenAs404)) {
@@ -64,7 +69,11 @@ RequestURI::RequestURI(const VirtualHost *vhost, Transport *transport,
6469
}
6570

6671
RequestURI::RequestURI(const std::string & rpcFunc)
67-
: m_rewritten(false), m_defaultDoc(false), m_done(false) {
72+
: m_rewritten(false)
73+
, m_defaultDoc(false)
74+
, m_globalDoc(false)
75+
, m_done(false)
76+
{
6877
m_originalURL = m_rewrittenURL = m_resolvedURL = String(rpcFunc);
6978
}
7079

@@ -99,6 +108,25 @@ bool RequestURI::process(const VirtualHost *vhost, Transport *transport,
99108
return true;
100109
}
101110

111+
if (!RuntimeOption::GlobalDocument.empty()) {
112+
// GlobalDocument option in use - never resolveURL and 404 if GlobalDocument
113+
// does not exist. Still check for rewrites.
114+
115+
if (!rewriteURL(vhost, transport, pathTranslation, sourceRoot)) {
116+
// Redirection
117+
m_done = true;
118+
return true;
119+
}
120+
121+
m_resolvedURL = String(RuntimeOption::GlobalDocument);
122+
if (virtualFileExists(vhost, sourceRoot, pathTranslation,
123+
m_resolvedURL)) {
124+
m_globalDoc = true;
125+
return true;
126+
}
127+
return false;
128+
}
129+
102130
// Fast path for files that exist
103131
if (vhost->checkExistenceBeforeRewrite()) {
104132
String canon = FileUtil::canonicalize(m_originalURL);

hphp/runtime/server/request-uri.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ struct RequestURI {
4343

4444
bool rewritten() const { return m_rewritten; }
4545
bool defaultDoc() const { return m_defaultDoc; }
46+
bool globalDoc() const { return m_globalDoc; }
4647
bool done() const { return m_done; }
4748
bool forbidden() const { return m_forbidden; }
4849

@@ -64,6 +65,7 @@ struct RequestURI {
6465

6566
bool m_rewritten; // whether rewrite rules have applied
6667
bool m_defaultDoc; // whether DefaultDocument was appended
68+
bool m_globalDoc; // whether GlobalDocument was used
6769
bool m_done;
6870
bool m_forbidden;
6971
const char *m_ext; // file extension
@@ -74,6 +76,9 @@ struct RequestURI {
7476
bool rewriteURL(const VirtualHost *vhost, Transport *transport,
7577
const std::string &pathTranslation,
7678
const std::string &sourceRoot);
79+
bool resolveGlobalURL(const VirtualHost *vhost,
80+
const std::string &pathTranslation,
81+
const std::string &sourceRoot);
7782
bool resolveURL(const VirtualHost *vhost,
7883
const std::string &pathTranslation,
7984
const std::string &sourceRoot);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?hh
2+
3+
<<__EntryPoint>>
4+
function main_global_document() {
5+
// Make the test runner happy. It expects this endpoint to exist.
6+
if ($_SERVER['REQUEST_URI'] == '/hello.php') {
7+
$testid = getenv('TESTID');
8+
echo "Hello, World!{$testid}";
9+
return;
10+
}
11+
12+
echo "Hit global document\n";
13+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?hh
2+
3+
<<__EntryPoint>>
4+
function main_global_document() {
5+
echo "Should not hit this!\n";
6+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?hh
2+
3+
require_once('test_base.inc');
4+
require_once('globalDocumentTestUtils.inc');
5+
6+
echo "No global doc\n";
7+
8+
requestAll(
9+
varray[
10+
"global_document_should_not_be_hit.php",
11+
],
12+
"",
13+
);
14+
15+
echo "Global doc, existing file\n";
16+
17+
requestAll(
18+
varray[
19+
"global_document_should_not_be_hit.php",
20+
],
21+
"-vServer.GlobalDocument=/global_document.php",
22+
);
23+
24+
echo "Global doc, nonexistent file\n";
25+
26+
requestAll(
27+
varray[
28+
"this_file_does_not_exist.php",
29+
"foo/this_file_does_not_exist.php",
30+
"foo/bar/this_file_does_not_exist.php",
31+
],
32+
"-vServer.GlobalDocument=/global_document.php",
33+
);
34+
35+
echo "Nonexistent global doc\n";
36+
37+
runTestWith404HealthCheck(
38+
function($serverPort) {
39+
$nonexistent_requests = varray[
40+
"some_file.php",
41+
"this_file_does_not_exist.php",
42+
"index.php",
43+
];
44+
45+
foreach ($nonexistent_requests as $request) {
46+
echo "Requesting '$request'\n";
47+
var_dump(request('localhost', $serverPort, $request));
48+
}
49+
},
50+
"-vServer.GlobalDocument=/this_file_does_not_exist.php",
51+
);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
No global doc
2+
Requesting 'global_document_should_not_be_hit.php'
3+
string(20) "Should not hit this!"
4+
Global doc, existing file
5+
Requesting 'global_document_should_not_be_hit.php'
6+
string(19) "Hit global document"
7+
Global doc, nonexistent file
8+
Requesting 'this_file_does_not_exist.php'
9+
string(19) "Hit global document"
10+
Requesting 'foo/this_file_does_not_exist.php'
11+
string(19) "Hit global document"
12+
Requesting 'foo/bar/this_file_does_not_exist.php'
13+
string(19) "Hit global document"
14+
Nonexistent global doc
15+
Requesting 'some_file.php'
16+
string(18) "404 File Not Found"
17+
Requesting 'this_file_does_not_exist.php'
18+
string(18) "404 File Not Found"
19+
Requesting 'index.php'
20+
string(18) "404 File Not Found"
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?hh
2+
3+
function runTestWith404HealthCheck($testController, $customArgs = '', $repoArgs = '',
4+
$expect404 = false) {
5+
$pid = posix_getpid();
6+
try {
7+
$serverProc = $serverPort = $adminPort = null;
8+
$debugPort = false;
9+
$serverProc = startServer(&$serverPort, &$adminPort, &$debugPort,
10+
__DIR__.'/..', __DIR__.'/../server_root',
11+
$customArgs, null, $repoArgs, true);
12+
$testController($serverPort);
13+
stopServer($adminPort, $serverProc);
14+
} catch (Exception $e) {
15+
error_log("Caught exception, test failed, pid=$pid, exn=".$e->getMessage());
16+
killChildren($pid);
17+
if ($serverProc) proc_close($serverProc);
18+
error_log('test failed');
19+
}
20+
}

0 commit comments

Comments
 (0)