2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/test/ext/test_server.h"
19 #include "hphp/compiler/option.h"
21 #include "hphp/util/async-func.h"
22 #include "hphp/util/process-exec.h"
24 #include "hphp/runtime/ext/curl/ext_curl.h"
25 #include "hphp/runtime/ext/std/ext_std_options.h"
26 #include "hphp/runtime/server/http-request-handler.h"
27 #include "hphp/runtime/base/array-init.h"
28 #include "hphp/runtime/base/comparisons.h"
29 #include "hphp/runtime/base/http-client.h"
30 #include "hphp/runtime/base/program-functions.h"
31 #include "hphp/runtime/base/runtime-option.h"
32 #include "hphp/runtime/server/server.h"
34 #include <sys/types.h>
38 #include <sys/param.h>
41 #include <folly/Conv.h>
42 #include <folly/portability/Sockets.h>
47 #define PORT_MAX 65535
49 ///////////////////////////////////////////////////////////////////////////////
51 TestServer::TestServer(const std::string serverType
)
52 : m_serverType(serverType
) { }
54 static int s_server_port
= 0;
55 static int s_admin_port
= 0;
56 static int s_rpc_port
= 0;
57 static int inherit_fd
= -1;
58 static std::unique_ptr
<AsyncFunc
<TestServer
>> s_func
;
59 static char s_pidfile
[PATH_MAX
];
60 static char s_repoFile
[PATH_MAX
];
61 static char s_logFile
[PATH_MAX
];
62 static char s_filename
[PATH_MAX
];
63 static int k_timeout
= 30;
65 bool TestServer::VerifyServerResponse(const char* input
, const char** outputs
,
66 const char** urls
, int nUrls
,
67 const char* /*method*/,
68 const char* header
, const char* postdata
,
70 const char* file
/* = "" */,
71 int line
/* = 0 */, int port
/* = 0 */) {
73 if (port
== 0) port
= s_server_port
;
75 std::string fullPath
= "runtime/tmp/string";
76 std::ofstream
f(fullPath
.c_str());
78 printf("Unable to open %s for write. Run this test from hphp/.\n",
86 AsyncFunc
<TestServer
> func(this, &TestServer::RunServer
);
91 if (!s_func
->waitForEnd(k_timeout
)) {
92 // Takeover didn't complete in 30s, stop the old server
93 fprintf(stderr
, "stopping HHVM\n");
94 AsyncFunc
<TestServer
> stopFunc(this, &TestServer::KillServer
);
96 fprintf(stderr
, "Waiting for stop\n");
97 stopFunc
.waitForEnd();
98 fprintf(stderr
, "Waiting for old HHVM\n");
100 // Mark this test a failure
101 fprintf(stderr
, "Proceeding to test\n");
110 for (url
= 0; url
< nUrls
; url
++) {
111 String server
= "http://";
112 server
+= HHVM_FN(php_uname
)("n").toString();
113 server
+= ":" + folly::to
<std::string
>(port
) + "/";
115 actual
= "<No response from server>";
117 for (int i
= 0; i
< 50; i
++) {
118 Variant c
= HHVM_FN(curl_init
)();
119 HHVM_FN(curl_setopt
)(c
.toResource(), CURLOPT_URL
, server
);
120 HHVM_FN(curl_setopt
)(c
.toResource(), CURLOPT_RETURNTRANSFER
, true);
122 HHVM_FN(curl_setopt
)(c
.toResource(), CURLOPT_POSTFIELDS
, postdata
);
123 HHVM_FN(curl_setopt
)(c
.toResource(), CURLOPT_POST
, true);
126 HHVM_FN(curl_setopt
)(c
.toResource(), CURLOPT_HTTPHEADER
,
127 make_varray(header
));
129 if (responseHeader
) {
130 HHVM_FN(curl_setopt
)(c
.toResource(), CURLOPT_HEADER
, 1);
133 Variant res
= HHVM_FN(curl_exec
)(c
.toResource());
134 if (!same(res
, false)) {
135 actual
= res
.toString().toCppString();
138 sleep(1); // wait until HTTP server is up and running
140 if (actual
!= outputs
[url
]) {
141 if (!responseHeader
||
142 actual
.find(outputs
[url
]) == std::string::npos
) {
149 AsyncFunc
<TestServer
>(this, &TestServer::StopServer
).run();
153 printf("%s:%d\nParsing: [%s] (req %d)\nBet %d:\n"
154 "--------------------------------------\n"
156 "--------------------------------------\n"
158 "--------------------------------------\n"
160 "--------------------------------------\n",
161 file
, line
, input
, url
+ 1, (int)strlen(outputs
[url
]), outputs
[url
],
162 (int)actual
.length(), actual
.c_str());
168 void TestServer::RunServer() {
169 std::string out
, err
;
170 auto const portConfig
= "-vServer.Port=" +
171 folly::to
<std::string
>(s_server_port
);
172 auto const adminConfig
= "-vAdminServer.Port=" +
173 folly::to
<std::string
>(s_admin_port
);
174 auto const rpcConfig
= "-vSatellites.rpc.Port=" +
175 folly::to
<std::string
>(s_rpc_port
);
176 auto const fd
= folly::to
<std::string
>(inherit_fd
);
177 auto option
= inherit_fd
>= 0
179 : "-vServer.TakeoverFilename=" + std::string(s_filename
);
180 auto serverType
= std::string("-vServer.Type=") + m_serverType
;
181 auto pidFile
= std::string("-vPidFile=") + s_pidfile
;
182 auto repoFile
= std::string("-vRepo.Central.Path=") + s_repoFile
;
183 auto logFile
= std::string("-vLog.File=") + s_logFile
;
185 const char *argv
[] = {
186 "__HHVM__", "--mode=server", "--config=test/ext/config-server.hdf",
187 portConfig
.c_str(), adminConfig
.c_str(), rpcConfig
.c_str(),
188 option
.c_str(), serverType
.c_str(), pidFile
.c_str(), repoFile
.c_str(),
198 proc::exec(argv
[0], argv
, nullptr, out
, &err
);
201 void TestServer::StopServer() {
202 for (int i
= 0; i
< 10; i
++) {
203 Variant c
= HHVM_FN(curl_init
)();
204 String url
= "http://";
205 url
+= HHVM_FN(php_uname
)("n").toString();
206 url
+= ":" + folly::to
<std::string
>(s_admin_port
) + "/stop";
207 HHVM_FN(curl_setopt
)(c
.toResource(), CURLOPT_URL
, url
);
208 HHVM_FN(curl_setopt
)(c
.toResource(), CURLOPT_RETURNTRANSFER
, true);
209 HHVM_FN(curl_setopt
)(c
.toResource(), CURLOPT_TIMEOUT
, 1);
210 HHVM_FN(curl_setopt
)(c
.toResource(), CURLOPT_CONNECTTIMEOUT
, 1);
211 Variant res
= HHVM_FN(curl_exec
)(c
.toResource());
212 if (!same(res
, false)) {
215 sleep(1); // wait until HTTP server is up and running
220 void TestServer::KillServer() {
221 fprintf(stderr
, "Have to kill HHVM\n");
222 // Getting more aggresive
224 int fd
= open(s_pidfile
, O_RDONLY
);
225 int ret
= read(fd
, buf
, sizeof(buf
) - 1);
227 printf("Can't read pid from pid file %s\n", s_pidfile
);
231 std::string out
, err
;
232 const char *argv
[] = {"kill", buf
, nullptr};
233 for (int i
= 0; i
< 10; i
++) {
234 auto ret
= proc::exec(argv
[0], argv
, nullptr, out
, &err
);
241 const char *argv9
[] = {"kill", "-9", buf
, nullptr};
242 for (int i
= 0; i
< 10; i
++) {
243 auto ret
= proc::exec(argv9
[0], argv9
, nullptr, out
, &err
);
249 printf("Can't kill pid %s read from pid file %s\n", buf
, s_pidfile
);
252 ///////////////////////////////////////////////////////////////////////////////
254 struct TestServerRequestHandler
: RequestHandler
{
255 explicit TestServerRequestHandler(int timeout
) : RequestHandler(timeout
) {}
256 // implementing RequestHandler
257 void handleRequest(Transport
* /*transport*/) override
{
260 void abortRequest(Transport
* /*transport*/) override
{
265 static int find_server_port(const std::string
&serverType
) {
266 for (int tries
= 0; true; tries
++) {
267 auto port
= (rand() % (PORT_MAX
- PORT_MIN
)) + PORT_MIN
;
269 ServerPtr server
= ServerFactoryRegistry::createServer(
270 serverType
, "127.0.0.1", port
, 50);
271 server
->setRequestHandlerFactory
<TestServerRequestHandler
>(k_timeout
);
274 server
->waitForEnd();
276 } catch (const FailedToListenException
& e
) {
277 if (tries
>= 100) throw;
282 bool TestServer::RunTests(const std::string
&which
) {
286 s_server_port
= find_server_port(m_serverType
);
287 s_admin_port
= find_server_port(m_serverType
);
288 s_rpc_port
= find_server_port(m_serverType
);
289 snprintf(s_pidfile
, MAXPATHLEN
, "/tmp/test_server.hhvm.pid_XXXXXX");
290 int tmpfd
= mkstemp(s_pidfile
);
292 snprintf(s_repoFile
, MAXPATHLEN
, "/tmp/test_server.hhvm.hhbc_XXXXXX");
293 tmpfd
= mkstemp(s_repoFile
);
295 snprintf(s_logFile
, MAXPATHLEN
, "/tmp/test_server.hhvm.log_XXXXXX");
296 tmpfd
= mkstemp(s_logFile
);
299 RUN_TEST(TestInheritFdServer
);
300 RUN_TEST(TestTakeoverServer
);
301 RUN_TEST(TestSanity
);
302 RUN_TEST(TestServerVariables
);
303 RUN_TEST(TestInteraction
);
306 RUN_TEST(TestExpectContinue
);
307 RUN_TEST(TestCookie
);
308 RUN_TEST(TestResponseHeader
);
309 RUN_TEST(TestSetCookie
);
310 //RUN_TEST(TestRequestHandling);
311 RUN_TEST(TestHttpClient
);
312 RUN_TEST(TestRPCServer
);
313 RUN_TEST(TestXboxServer
);
314 RUN_TEST(TestPageletServer
);
319 ///////////////////////////////////////////////////////////////////////////////
321 bool TestServer::TestSanity() {
322 VSR("<?php print 'Hello, World!';",
327 bool TestServer::TestServerVariables() {
328 VSR("<?php var_dump($_POST, $_GET);",
329 "array(0) {\n}\narray(0) {\n}\n");
331 VSR("<?php print $_SERVER['REQUEST_URI'];",
335 "var_dump($_SERVER['PATH_INFO']);"
336 "var_dump(clean($_SERVER['PATH_TRANSLATED']));"
337 "var_dump($_SERVER['SCRIPT_NAME']);"
338 "var_dump($_SERVER['REQUEST_URI']);"
339 "var_dump(clean($_SERVER['SCRIPT_FILENAME']));"
340 "var_dump($_SERVER['QUERY_STRING']);"
341 "function clean($x) { return str_replace(getcwd(),'',$x); }",
343 "string(13) \"/path/subpath\"\n"
344 "string(20) \"/string/path/subpath\"\n"
345 "string(7) \"/string\"\n"
346 "string(28) \"/string/path/subpath?a=1&b=2\"\n"
347 "string(7) \"/string\"\n"
348 "string(7) \"a=1&b=2\"\n",
350 "string/path/subpath?a=1&b=2");
353 "var_dump($_SERVER['PATH_INFO']);"
354 "var_dump(clean($_SERVER['PATH_TRANSLATED']));"
355 "var_dump($_SERVER['SCRIPT_NAME']);"
356 "var_dump($_SERVER['REQUEST_URI']);"
357 "var_dump(clean($_SERVER['SCRIPT_FILENAME']));"
358 "var_dump($_SERVER['QUERY_STRING']);"
359 "var_dump(isset($_ENV['HPHP_RPC']));"
360 "function clean($x) { return str_replace(getcwd(),'',$x); }",
363 "string(7) \"/string\"\n"
364 "string(7) \"/string\"\n"
365 "string(15) \"/string?a=1&b=2\"\n"
366 "string(7) \"/string\"\n"
367 "string(7) \"a=1&b=2\"\n"
375 bool TestServer::TestInteraction() {
376 // run this twice to test lvalBlackHole
378 "$a[] = new stdclass;"
379 "var_dump(count(array_combine($a, $a)));",
385 bool TestServer::TestGet() {
386 VSGET("<?php var_dump($_GET['name']);",
387 "string(0) \"\"\n", "string?name");
389 VSGET("<?php var_dump($_GET['name'], $_GET['id']);",
390 "string(0) \"\"\nstring(1) \"1\"\n", "string?name&id=1");
392 VSGET("<?php print $_GET['name'];",
393 "value", "string?name=value");
395 VSGET("<?php var_dump($_GET['names']);",
398 " string(3) \"foo\"\n"
400 " string(3) \"bar\"\n"
402 "string?names[1]=foo&names[2]=bar");
404 VSGET("<?php var_dump($_GET['names']);",
407 " string(3) \"foo\"\n"
409 " string(3) \"bar\"\n"
411 "string?names[]=foo&names[]=bar");
413 VSGET("<?php print $_REQUEST['name'];",
414 "value", "string?name=value");
419 bool TestServer::TestPost() {
420 const char *params
= "name=value";
422 VSPOST("<?php print $_POST['name'];",
423 "value", "string", params
);
425 VSPOST("<?php print $_REQUEST['name'];",
426 "value", "string", params
);
428 VSPOST("<?php print $HTTP_RAW_POST_DATA;",
429 "name=value", "string", params
);
434 bool TestServer::TestExpectContinue() {
435 const char *params
= "name=value";
437 VSRX("<?php print $_POST['name'];",
438 "value", "string", "POST", "Expect: 100-continue", params
);
443 bool TestServer::TestCookie() {
444 VSRX("<?php print $_COOKIE['name'];",
445 "value", "string", "GET", "Cookie: name=value;", nullptr);
447 VSRX("<?php print $_COOKIE['name2'];",
448 "value2", "string", "GET", "Cookie: n=v;name2=value2;n3=v3", nullptr);
453 bool TestServer::TestResponseHeader() {
454 VSR("<?php header('Set-Cookie: name=value'); var_dump(headers_list());",
457 " string(22) \"Set-Cookie: name=value\"\n"
460 VSRES("<?php header('Set-Cookie: name=value');",
461 "Set-Cookie: name=value");
463 VSRES("<?php header('Location: new/url');",
466 VSRES("<?php header(\"Test-Header: x\ry\"); echo 'done';",
472 bool TestServer::TestSetCookie() {
473 VSR("<?php setcookie('name', 'value'); var_dump(headers_list());",
476 " string(22) \"Set-Cookie: name=value\"\n"
480 VSRES("<?php setcookie('name', 'value');",
481 "Set-Cookie: name=value");
486 ///////////////////////////////////////////////////////////////////////////////
488 const StaticString
s_test("test");
490 struct TestTransport final
: Transport
{
491 TestTransport() : m_code(0) {}
494 std::string m_response
;
497 * Implementing HttpTransport...
499 const char *getUrl() override
{ return "/string"; }
500 const char *getRemoteHost() override
{ return "remote"; }
501 const void *getPostData(size_t &size
) override
{ size
= 0; return nullptr; }
502 uint16_t getRemotePort() override
{ return 0; }
503 Method
getMethod() override
{ return Transport::Method::GET
; }
504 std::string
getHeader(const char* /*name*/) override
{ return ""; }
505 const HeaderMap
& getHeaders() override
{
506 static const HeaderMap emptyMap
{};
509 void addHeaderImpl(const char* /*name*/, const char* /*value*/) override
{}
510 void removeHeaderImpl(const char* /*name*/) override
{}
513 * Get a description of the type of transport.
515 String
describe() const override
{
519 void sendImpl(const void* data
, int size
, int code
, bool /*chunked*/,
520 bool /*eom*/) override
{
522 m_response
.append((const char *)data
, size
);
527 HttpRequestHandler
handler(0);
528 for (unsigned int i
= 0; i
< 100; i
++) {
534 typedef std::shared_ptr
<TestTransport
> TestTransportPtr
;
535 typedef std::vector
<TestTransportPtr
> TestTransportPtrVec
;
536 typedef AsyncFunc
<TestTransport
> TestTransportAsyncFunc
;
537 typedef std::shared_ptr
<TestTransportAsyncFunc
> TestTransportAsyncFuncPtr
;
538 typedef std::vector
<TestTransportAsyncFuncPtr
> TestTransportAsyncFuncPtrVec
;
540 #define TEST_SIZE 100
543 * Start processing TEST_SIZE number of requests at the same time with
544 * that many threads. This is mainly testing global variables to make sure
545 * all handling are thread-safe.
547 bool TestServer::TestRequestHandling() {
548 RuntimeOption::AllowedFiles
.insert("/string");
549 TestTransportPtrVec
transports(TEST_SIZE
);
550 TestTransportAsyncFuncPtrVec
funcs(TEST_SIZE
);
551 for (unsigned int i
= 0; i
< TEST_SIZE
; i
++) {
552 TestTransport
*transport
= new TestTransport();
553 transports
[i
] = TestTransportPtr(transport
);
554 funcs
[i
] = TestTransportAsyncFuncPtr
555 (new TestTransportAsyncFunc(transport
, &TestTransport::process
));
558 for (unsigned int i
= 0; i
< TEST_SIZE
; i
++) {
561 for (unsigned int i
= 0; i
< TEST_SIZE
; i
++) {
562 funcs
[i
]->waitForEnd();
564 for (unsigned int i
= 0; i
< TEST_SIZE
; i
++) {
565 VS(transports
[i
]->m_code
, 200);
566 VS(String(transports
[i
]->m_response
), "Hello, world!");
571 static bool PreBindSocketHelper(struct addrinfo
*info
) {
572 if (info
->ai_family
!= AF_INET
&& info
->ai_family
!= AF_INET6
) {
573 printf("No IPV4/6 interface found.\n");
577 int fd
= socket(info
->ai_family
, SOCK_STREAM
, IPPROTO_TCP
);
579 printf("Error creating socket: %s\n", strerror(errno
));
583 int ret
= ::bind(fd
, info
->ai_addr
, info
->ai_addrlen
);
585 printf("Error binding socket to port %d: %s\n", s_server_port
,
594 bool TestServer::PreBindSocket() {
595 struct addrinfo hints
, *res
, *res0
;
596 std::memset(&hints
, 0, sizeof(hints
));
597 hints
.ai_family
= AF_UNSPEC
;
598 hints
.ai_socktype
= SOCK_STREAM
;
599 hints
.ai_flags
= AI_PASSIVE
| AI_ADDRCONFIG
;
601 if (getaddrinfo(nullptr, folly::to
<std::string
>(s_server_port
).c_str(),
602 &hints
, &res0
) < 0) {
603 printf("Error in getaddrinfo(): %s\n", strerror(errno
));
607 for (res
= res0
; res
; res
= res
->ai_next
) {
608 if (res
->ai_family
== AF_INET6
|| res
->ai_next
== nullptr) {
613 bool ret
= PreBindSocketHelper(res
);
618 void TestServer::CleanupPreBoundSocket() {
623 bool TestServer::TestInheritFdServer() {
624 WITH_PREBOUND_SOCKET(VSR("<?php print 'Hello, World!';",
629 bool TestServer::TestTakeoverServer() {
631 snprintf(s_filename
, MAXPATHLEN
, "/tmp/hphp_takeover_XXXXXX");
632 auto const tmpfd
= mkstemp(s_filename
);
635 s_func
.reset(new AsyncFunc
<TestServer
>(this, &TestServer::RunServer
));
638 // Wait for the server to actually start
640 StringBuffer response
;
641 req::vector
<String
> responseHeaders
;
642 auto url
= "http://127.0.0.1:" + folly::to
<std::string
>(s_server_port
) +
645 for (int i
= 0; i
< 10; i
++) {
646 int code
= http
.get(url
.c_str(), response
, &headers
, &responseHeaders
);
653 // will start a second server, which should takeover
654 VSR("<?php print 'Hello, World!';",
661 ///////////////////////////////////////////////////////////////////////////////
663 struct EchoHandler final
: RequestHandler
{
664 explicit EchoHandler(int timeout
) : RequestHandler(timeout
) {}
665 // implementing RequestHandler
666 void handleRequest(Transport
*transport
) override
{
667 g_context
.getCheck();
668 const HeaderMap
& headers
= transport
->getHeaders();
670 std::string response
;
671 response
= "\nGET param: name = ";
672 response
+= transport
->getParam("name");
674 if (transport
->getMethod() == Transport::Method::POST
) {
676 auto const data
= (const char *)transport
->getPostData(size
);
677 response
+= "\nPOST data: ";
678 response
+= std::string(data
, size
);
681 for (HeaderMap::const_iterator iter
= headers
.begin();
682 iter
!= headers
.end(); ++iter
) {
683 response
+= "\nHeader: ";
684 response
+= iter
->first
;
685 for (unsigned int i
= 0; i
< iter
->second
.size(); i
++) {
687 response
+= folly::to
<std::string
>(i
);
689 response
+= iter
->second
[i
];
693 transport
->addHeader("Custom", "blah");
694 transport
->sendString(response
);
695 hphp_memory_cleanup();
697 void abortRequest(Transport
*transport
) override
{
698 transport
->sendString("Service Unavailable", 503);
702 bool TestServer::TestHttpClient() {
704 for (s_server_port
= PORT_MIN
; s_server_port
<= PORT_MAX
; s_server_port
++) {
706 server
= ServerFactoryRegistry::createServer(
707 m_serverType
, "127.0.0.1", s_server_port
, 50);
708 server
->setRequestHandlerFactory
<EchoHandler
>(0);
711 } catch (const FailedToListenException
& e
) {
712 if (s_server_port
== PORT_MAX
) throw;
717 headers
["Cookie"].push_back("c1=v1;c2=v2;");
718 headers
["Cookie"].push_back("c3=v3;c4=v4;");
719 auto url
= "http://127.0.0.1:" + folly::to
<std::string
>(s_server_port
) +
722 static const StaticString
s_Custom_colon_blah("Custom: blah");
724 for (int i
= 0; i
< 10; i
++) {
726 StringBuffer response
;
727 req::vector
<String
> responseHeaders
;
728 int code
= http
.get(url
.c_str(), response
, &headers
, &responseHeaders
);
731 ("\nGET param: name = value"
738 "\n0: 127.0.0.1:" + folly::to
<std::string
>(s_server_port
)).c_str());
741 for (unsigned int i2
= 0; i2
< responseHeaders
.size(); i2
++) {
742 if (responseHeaders
[i2
] == s_Custom_colon_blah
) {
748 for (int i
= 0; i
< 10; i
++) {
750 StringBuffer response
;
751 req::vector
<String
> responseHeaders
;
752 int code
= http
.post(url
.c_str(), "postdata", 8, response
, &headers
,
756 ("\nGET param: name = value"
757 "\nPOST data: postdata"
758 "\nHeader: Content-Type"
759 "\n0: application/x-www-form-urlencoded"
765 "\nHeader: Content-Length"
768 "\n0: 127.0.0.1:" + folly::to
<std::string
>(s_server_port
)).c_str());
771 for (unsigned int i2
= 0; i2
< responseHeaders
.size(); i2
++) {
772 if (responseHeaders
[i2
] == s_Custom_colon_blah
) {
780 server
->waitForEnd();
784 bool TestServer::TestRPCServer() {
787 "function f() { return 100; }\n",
794 "function f($a) { return array(1, 2, 3, $a); }\n",
796 "f?auth=test&p=\"hello\"",
801 "function f($a, $b) { return array_merge($a, $b); }\n",
802 "{\"a\":1,\"0\":2,\"1\":1,\"2\":2}",
803 "f?auth=test&p={\"a\":1,\"1\":2}&p=[1,2]",
806 // builtin function and static method
808 "class A { static function f($a) { return $a; } }\n",
810 "call_user_func?auth=test&p=\"A::f\"&p=100",
813 // invoking a file, with NO json encoding
814 // "int(100)" is printed twice, one from warmup, and the other from include
819 "?include=string&output=1&auth=test",
823 "var_dump(isset($_ENV['HPHP_RPC']));\n",
826 "?include=string&output=1&auth=test",
832 bool TestServer::TestXboxServer() {
834 "if (array_key_exists('main', $_GET)) {\n"
835 " $t = xbox_task_start('1');\n"
836 " xbox_task_result($t, 0, $r);\n"
838 " $t = xbox_task_start('2');\n"
839 " xbox_task_result($t, 0, $r);\n"
840 " $t = xbox_task_start('1');\n"
841 " xbox_task_result($t, 0, $r);\n"
844 " $t = xbox_task_start('3');\n"
845 " xbox_task_result($t, 0, $r);\n"
848 " $t = xbox_task_start('4');\n"
849 " xbox_task_result($t, 0, $r);\n"
850 " $t = xbox_task_start('3');\n"
851 " xbox_task_result($t, 0, $r);\n"
854 " $t = xbox_task_start('3');\n"
855 " xbox_task_result($t, 0, $r);\n"
858 " function xbox_process_message($msg) {\n"
859 " if ($msg == '1') return xbox_get_thread_timeout();\n"
860 " else if ($msg == '2') xbox_set_thread_timeout(5);\n"
861 " else if ($msg == '3') return xbox_get_thread_time();\n"
862 " else xbox_schedule_thread_reset();\n"
875 bool TestServer::TestPageletServer() {
877 "if (array_key_exists('pagelet', $_GET)) {\n"
878 " echo 'Hello from the pagelet!';\n"
880 " $h = array('Host: ' . $_SERVER['HTTP_HOST']);\n"
881 " $t = pagelet_server_task_start('/string?pagelet=1', $h, '');\n"
883 " $r = pagelet_server_task_result($t, $h, $c);\n"
886 "First! Hello from the pagelet!",
891 "if (array_key_exists('pagelet', $_GET)) {\n"
892 " echo $_SERVER['REQUEST_METHOD'];\n"
894 " $h = array('Host: ' . $_SERVER['HTTP_HOST']);\n"
895 " $t = pagelet_server_task_start('/string?pagelet=1', $h, '');\n"
897 " $r = pagelet_server_task_result($t, $h, $c);\n"
904 "if ($_SERVER['THREAD_TYPE'] == 'Pagelet Thread') {\n"
906 " pagelet_server_flush();\n"
909 " pagelet_server_flush();\n"
912 " $h = array('Host: ' . $_SERVER['HTTP_HOST']);\n"
913 " $t = pagelet_server_task_start('/string', $h, '');\n"
914 " for ($i = 0; ; $i++) {\n"
915 " while (($s = pagelet_server_task_status($t)) == \n"
916 " PAGELET_NOT_READY) { sleep(1); }\n"
917 " echo \"Step $i:\\n\";\n"
918 " $r = pagelet_server_task_result($t, $h, $c);\n"
919 " echo $r . \"\\n\";\n"
920 " if ($s == PAGELET_DONE) break;\n"