remove _bin directory reference from test_server config file
[hiphop-php.git] / hphp / test / ext / test_server.cpp
blobac4e8b373faa7695a1c4fa7fdceb97560c1c2d47
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 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"
18 #include "hphp/compiler/parser/parser.h"
19 #include "hphp/compiler/builtin_symbols.h"
20 #include "hphp/compiler/code_generator.h"
21 #include "hphp/compiler/analysis/analysis_result.h"
22 #include "hphp/util/util.h"
23 #include "hphp/util/process.h"
24 #include "hphp/compiler/option.h"
25 #include "hphp/util/async-func.h"
26 #include "hphp/runtime/ext/curl/ext_curl.h"
27 #include "hphp/runtime/ext/ext_options.h"
28 #include "hphp/runtime/server/http-request-handler.h"
29 #include "hphp/runtime/base/http-client.h"
30 #include "hphp/runtime/base/runtime-option.h"
31 #include "hphp/runtime/server/server.h"
33 #include <memory>
35 using namespace HPHP;
37 #define PORT_MIN 1024
38 #define PORT_MAX 65535
40 ///////////////////////////////////////////////////////////////////////////////
42 TestServer::TestServer(const std::string serverType)
43 : m_serverType(serverType) { }
45 static int s_server_port = 0;
46 static int s_admin_port = 0;
47 static int s_rpc_port = 0;
48 static int inherit_fd = -1;
49 static std::unique_ptr<AsyncFunc<TestServer>> s_func;
50 static char s_pidfile[MAXPATHLEN];
51 static char s_repoFile[MAXPATHLEN];
52 static char s_filename[MAXPATHLEN];
53 static int k_timeout = 30;
55 bool TestServer::VerifyServerResponse(const char *input, const char **outputs,
56 const char **urls, int nUrls,
57 const char *method,
58 const char *header, const char *postdata,
59 bool responseHeader,
60 const char *file /* = "" */,
61 int line /* = 0 */,
62 int port /* = 0 */) {
63 assert(input);
64 if (port == 0) port = s_server_port;
66 if (!CleanUp()) return false;
67 string fullPath = "runtime/tmp/string";
68 std::ofstream f(fullPath.c_str());
69 if (!f) {
70 printf("Unable to open %s for write. Run this test from hphp/.\n",
71 fullPath.c_str());
72 return false;
75 f << input;
76 f.close();
78 AsyncFunc<TestServer> func(this, &TestServer::RunServer);
79 func.start();
81 if (s_func) {
82 s_func->waitForEnd(k_timeout);
83 s_func.reset();
85 bool passed = true;
87 string actual;
89 int url = 0;
90 for (url = 0; url < nUrls; url++) {
91 String server = "http://";
92 server += f_php_uname("n");
93 server += ":" + lexical_cast<string>(port) + "/";
94 server += urls[url];
95 actual = "<No response from server>";
96 string err;
97 for (int i = 0; i < 10; i++) {
98 Variant c = HHVM_FN(curl_init)();
99 HHVM_FN(curl_setopt)(c.toResource(), k_CURLOPT_URL, server);
100 HHVM_FN(curl_setopt)(c.toResource(), k_CURLOPT_RETURNTRANSFER, true);
101 if (postdata) {
102 HHVM_FN(curl_setopt)(c.toResource(), k_CURLOPT_POSTFIELDS, postdata);
103 HHVM_FN(curl_setopt)(c.toResource(), k_CURLOPT_POST, true);
105 if (header) {
106 HHVM_FN(curl_setopt)(c.toResource(), k_CURLOPT_HTTPHEADER,
107 make_packed_array(header));
109 if (responseHeader) {
110 HHVM_FN(curl_setopt)(c.toResource(), k_CURLOPT_HEADER, 1);
113 Variant res = HHVM_FN(curl_exec)(c.toResource());
114 if (!same(res, false)) {
115 actual = (std::string) res.toString();
116 break;
118 sleep(1); // wait until HTTP server is up and running
120 if (actual != outputs[url]) {
121 if (!responseHeader ||
122 actual.find(outputs[url]) == string::npos) {
123 passed = false;
124 break;
129 AsyncFunc<TestServer>(this, &TestServer::StopServer).run();
130 func.waitForEnd();
132 if (!passed) {
133 printf("%s:%d\nParsing: [%s] (req %d)\nBet %d:\n"
134 "--------------------------------------\n"
135 "%s"
136 "--------------------------------------\n"
137 "Got %d:\n"
138 "--------------------------------------\n"
139 "%s"
140 "--------------------------------------\n",
141 file, line, input, url + 1, (int)strlen(outputs[url]), outputs[url],
142 (int)actual.length(), actual.c_str());
143 return false;
145 return true;
148 void TestServer::RunServer() {
149 string out, err;
150 string portConfig = "-vServer.Port=" + lexical_cast<string>(s_server_port);
151 string adminConfig = "-vAdminServer.Port=" +
152 lexical_cast<string>(s_admin_port);
153 string rpcConfig = "-vSatellites.rpc.Port=" +
154 lexical_cast<string>(s_rpc_port);
155 string fd = lexical_cast<string>(inherit_fd);
156 string option = (inherit_fd >= 0) ? (string("--port-fd=") + fd) :
157 (string("-vServer.TakeoverFilename=") + string(s_filename));
158 string serverType = string("-vServer.Type=") + m_serverType;
159 string pidFile = string("-vPidFile=") + string(s_pidfile);
160 string repoFile = string("-vRepo.Central.Path=") + string(s_repoFile);
162 const char *argv[] = {
163 "__HHVM__", "--mode=server", "--config=test/ext/config-server.hdf",
164 portConfig.c_str(), adminConfig.c_str(), rpcConfig.c_str(),
165 option.c_str(), serverType.c_str(), pidFile.c_str(),
166 nullptr
169 // replace __HHVM__
170 if (Option::EnableEval < Option::FullEval) {
171 argv[0] = "runtime/tmp/TestServer/test";
172 } else {
173 argv[0] = HHVM_PATH;
176 Process::Exec(argv[0], argv, nullptr, out, &err);
179 void TestServer::StopServer() {
180 for (int i = 0; i < 10; i++) {
181 Variant c = HHVM_FN(curl_init)();
182 String url = "http://";
183 url += f_php_uname("n");
184 url += ":" + lexical_cast<string>(s_admin_port) + "/stop";
185 HHVM_FN(curl_setopt)(c.toResource(), k_CURLOPT_URL, url);
186 HHVM_FN(curl_setopt)(c.toResource(), k_CURLOPT_RETURNTRANSFER, true);
187 HHVM_FN(curl_setopt)(c.toResource(), k_CURLOPT_TIMEOUT, 1);
188 HHVM_FN(curl_setopt)(c.toResource(), k_CURLOPT_CONNECTTIMEOUT, 1);
189 Variant res = HHVM_FN(curl_exec)(c.toResource());
190 if (!same(res, false)) {
191 return;
193 sleep(1); // wait until HTTP server is up and running
196 // Getting more aggresive
197 char buf[1024];
198 int fd = open(s_pidfile, O_RDONLY);
199 int ret = read(fd, buf, sizeof(buf) - 1);
200 if (ret <= 0) {
201 printf("Can't read pid from pid file %s\n", s_pidfile);
202 return;
204 buf[ret] = 0;
205 string out, err;
206 const char *argv[] = {"kill", buf, nullptr};
207 for (int i = 0; i < 10; i++) {
208 auto ret = Process::Exec(argv[0], argv, nullptr, out, &err);
209 if (ret) {
210 return;
214 // Last resort
215 const char *argv9[] = {"kill", "-9", buf, nullptr};
216 for (int i = 0; i < 10; i++) {
217 auto ret = Process::Exec(argv9[0], argv9, nullptr, out, &err);
218 if (ret) {
219 return;
223 printf("Can't kill pid %s read from pid file %s\n", buf, s_pidfile);
226 ///////////////////////////////////////////////////////////////////////////////
228 class TestServerRequestHandler : public RequestHandler {
229 public:
230 explicit TestServerRequestHandler(int timeout) : RequestHandler(timeout) {}
231 // implementing RequestHandler
232 virtual void handleRequest(Transport *transport) {
233 // do nothing
235 virtual void abortRequest(Transport *transport) {
236 // do nothing
240 static int find_server_port(const std::string &serverType) {
241 for (int tries = 0; true; tries++) {
242 auto port = (rand() % (PORT_MAX - PORT_MIN)) + PORT_MIN;
243 try {
244 ServerPtr server = ServerFactoryRegistry::createServer(
245 serverType, "127.0.0.1", port, 50);
246 server->setRequestHandlerFactory<TestServerRequestHandler>(k_timeout);
247 server->start();
248 server->stop();
249 server->waitForEnd();
250 return port;
251 } catch (const FailedToListenException& e) {
252 if (tries >= 100) throw;
257 bool TestServer::RunTests(const std::string &which) {
258 bool ret = true;
260 srand(time(0));
261 s_server_port = find_server_port(m_serverType);
262 s_admin_port = find_server_port(m_serverType);
263 s_rpc_port = find_server_port(m_serverType);
264 snprintf(s_pidfile, MAXPATHLEN, "/tmp/pid_XXXXXX");
265 int tmpfd = mkstemp(s_pidfile);
266 close(tmpfd);
267 snprintf(s_repoFile, MAXPATHLEN, "/tmp/test_server.hhvm.hhbc_XXXXXX");
268 tmpfd = mkstemp(s_repoFile);
269 close(tmpfd);
271 RUN_TEST(TestInheritFdServer);
272 RUN_TEST(TestTakeoverServer);
273 RUN_TEST(TestSanity);
274 RUN_TEST(TestServerVariables);
275 RUN_TEST(TestInteraction);
276 RUN_TEST(TestGet);
277 RUN_TEST(TestPost);
278 RUN_TEST(TestCookie);
279 RUN_TEST(TestResponseHeader);
280 RUN_TEST(TestSetCookie);
281 //RUN_TEST(TestRequestHandling);
282 RUN_TEST(TestHttpClient);
283 RUN_TEST(TestRPCServer);
284 RUN_TEST(TestXboxServer);
285 RUN_TEST(TestPageletServer);
287 return ret;
290 ///////////////////////////////////////////////////////////////////////////////
292 bool TestServer::TestSanity() {
293 VSR("<?php print 'Hello, World!';",
294 "Hello, World!");
295 return true;
298 bool TestServer::TestServerVariables() {
299 VSR("<?php var_dump($_POST, $_GET);",
300 "array(0) {\n}\narray(0) {\n}\n");
302 VSR("<?php print $_SERVER['REQUEST_URI'];",
303 "/string");
305 VSGET("<?php "
306 "var_dump($_SERVER['PATH_INFO']);"
307 "var_dump(clean($_SERVER['PATH_TRANSLATED']));"
308 "var_dump($_SERVER['SCRIPT_NAME']);"
309 "var_dump($_SERVER['REQUEST_URI']);"
310 "var_dump(clean($_SERVER['SCRIPT_FILENAME']));"
311 "var_dump($_SERVER['QUERY_STRING']);"
312 "function clean($x) { return str_replace(getcwd(),'',$x); }",
314 "string(13) \"/path/subpath\"\n"
315 "string(20) \"/string/path/subpath\"\n"
316 "string(7) \"/string\"\n"
317 "string(28) \"/string/path/subpath?a=1&b=2\"\n"
318 "string(7) \"/string\"\n"
319 "string(7) \"a=1&b=2\"\n",
321 "string/path/subpath?a=1&b=2");
323 VSGET("<?php "
324 "var_dump($_SERVER['PATH_INFO']);"
325 "var_dump(clean($_SERVER['PATH_TRANSLATED']));"
326 "var_dump($_SERVER['SCRIPT_NAME']);"
327 "var_dump($_SERVER['REQUEST_URI']);"
328 "var_dump(clean($_SERVER['SCRIPT_FILENAME']));"
329 "var_dump($_SERVER['QUERY_STRING']);"
330 "var_dump(isset($_ENV['HPHP_RPC']));"
331 "function clean($x) { return str_replace(getcwd(),'',$x); }",
333 "NULL\n"
334 "string(7) \"/string\"\n"
335 "string(7) \"/string\"\n"
336 "string(15) \"/string?a=1&b=2\"\n"
337 "string(7) \"/string\"\n"
338 "string(7) \"a=1&b=2\"\n"
339 "bool(false)\n",
341 "string?a=1&b=2");
343 return true;
346 bool TestServer::TestInteraction() {
347 // run this twice to test lvalBlackHole
348 VSR2("<?php "
349 "$a[] = new stdclass;"
350 "var_dump(count(array_combine($a, $a)));",
351 "");
353 return true;
356 bool TestServer::TestGet() {
357 VSGET("<?php var_dump($_GET['name']);",
358 "string(0) \"\"\n", "string?name");
360 VSGET("<?php var_dump($_GET['name'], $_GET['id']);",
361 "string(0) \"\"\nstring(1) \"1\"\n", "string?name&id=1");
363 VSGET("<?php print $_GET['name'];",
364 "value", "string?name=value");
366 VSGET("<?php var_dump($_GET['names']);",
367 "array(2) {\n"
368 " [1]=>\n"
369 " string(3) \"foo\"\n"
370 " [2]=>\n"
371 " string(3) \"bar\"\n"
372 "}\n",
373 "string?names[1]=foo&names[2]=bar");
375 VSGET("<?php var_dump($_GET['names']);",
376 "array(2) {\n"
377 " [0]=>\n"
378 " string(3) \"foo\"\n"
379 " [1]=>\n"
380 " string(3) \"bar\"\n"
381 "}\n",
382 "string?names[]=foo&names[]=bar");
384 VSGET("<?php print $_REQUEST['name'];",
385 "value", "string?name=value");
387 return true;
390 bool TestServer::TestPost() {
391 const char *params = "name=value";
393 VSPOST("<?php print $_POST['name'];",
394 "value", "string", params);
396 VSPOST("<?php print $_REQUEST['name'];",
397 "value", "string", params);
399 VSPOST("<?php print $HTTP_RAW_POST_DATA;",
400 "name=value", "string", params);
402 return true;
405 bool TestServer::TestCookie() {
406 VSRX("<?php print $_COOKIE['name'];",
407 "value", "string", "GET", "Cookie: name=value;", nullptr);
409 VSRX("<?php print $_COOKIE['name2'];",
410 "value2", "string", "GET", "Cookie: n=v;name2=value2;n3=v3", nullptr);
412 return true;
415 bool TestServer::TestResponseHeader() {
416 VSR("<?php header('Set-Cookie: name=value'); var_dump(headers_list());",
417 "array(1) {\n"
418 " [0]=>\n"
419 " string(22) \"Set-Cookie: name=value\"\n"
420 "}\n");
422 VSRES("<?php header('Set-Cookie: name=value');",
423 "Set-Cookie: name=value");
425 VSRES("<?php header('Location: new/url');",
426 "302");
428 VSRES("<?php header(\"Test-Header: x\ry\"); echo 'done';",
429 "done");
431 return true;
434 bool TestServer::TestSetCookie() {
435 VSR("<?php setcookie('name', 'value'); var_dump(headers_list());",
436 "array(1) {\n"
437 " [0]=>\n"
438 " string(22) \"Set-Cookie: name=value\"\n"
439 "}\n");
440 return true;
442 VSRES("<?php setcookie('name', 'value');",
443 "Set-Cookie: name=value");
445 return true;
448 ///////////////////////////////////////////////////////////////////////////////
450 class TestTransport : public Transport {
451 public:
452 TestTransport() : m_code(0) {}
454 int m_code;
455 std::string m_response;
458 * Implementing HttpTransport...
460 virtual const char *getUrl() { return "/string";}
461 virtual const char *getRemoteHost() { return "remote";}
462 virtual const void *getPostData(int &size) { size = 0; return nullptr;}
463 virtual uint16_t getRemotePort() { return 0; }
464 virtual Method getMethod() { return Transport::Method::GET;}
465 virtual std::string getHeader(const char *name) { return "";}
466 virtual void getHeaders(HeaderMap &headers) {}
467 virtual void addHeaderImpl(const char *name, const char *value) {}
468 virtual void removeHeaderImpl(const char *name) {}
470 virtual void sendImpl(const void *data, int size, int code, bool chunked) {
471 m_response.clear();
472 m_response.append((const char *)data, size);
473 m_code = code;
476 void process() {
477 HttpRequestHandler handler(0);
478 for (unsigned int i = 0; i < 100; i++) {
479 handler.handleRequest(this);
484 typedef std::shared_ptr<TestTransport> TestTransportPtr;
485 typedef std::vector<TestTransportPtr> TestTransportPtrVec;
486 typedef AsyncFunc<TestTransport> TestTransportAsyncFunc;
487 typedef std::shared_ptr<TestTransportAsyncFunc> TestTransportAsyncFuncPtr;
488 typedef std::vector<TestTransportAsyncFuncPtr> TestTransportAsyncFuncPtrVec;
490 #define TEST_SIZE 100
493 * Start processing TEST_SIZE number of requests at the same time with
494 * that many threads. This is mainly testing global variables to make sure
495 * all handling are thread-safe.
497 bool TestServer::TestRequestHandling() {
498 RuntimeOption::AllowedFiles.insert("/string");
499 TestTransportPtrVec transports(TEST_SIZE);
500 TestTransportAsyncFuncPtrVec funcs(TEST_SIZE);
501 for (unsigned int i = 0; i < TEST_SIZE; i++) {
502 TestTransport *transport = new TestTransport();
503 transports[i] = TestTransportPtr(transport);
504 funcs[i] = TestTransportAsyncFuncPtr
505 (new TestTransportAsyncFunc(transport, &TestTransport::process));
508 for (unsigned int i = 0; i < TEST_SIZE; i++) {
509 funcs[i]->start();
511 for (unsigned int i = 0; i < TEST_SIZE; i++) {
512 funcs[i]->waitForEnd();
514 for (unsigned int i = 0; i < TEST_SIZE; i++) {
515 VS(transports[i]->m_code, 200);
516 VS(String(transports[i]->m_response), "Hello, world!");
518 return Count(true);
521 static bool PreBindSocketHelper(struct addrinfo *info) {
522 if (info->ai_family != AF_INET && info->ai_family != AF_INET6) {
523 printf("No IPV4/6 interface found.\n");
524 return false;
527 int fd = socket(info->ai_family, SOCK_STREAM, IPPROTO_TCP);
528 if (fd < 0) {
529 printf("Error creating socket: %s\n", strerror(errno));
530 return false;
533 int ret = ::bind(fd, info->ai_addr, info->ai_addrlen);
534 if (ret < 0) {
535 printf("Error binding socket to port %d: %s\n", s_server_port,
536 strerror(errno));
537 return false;
540 inherit_fd = fd;
541 return true;
544 bool TestServer::PreBindSocket() {
545 struct addrinfo hints, *res, *res0;
546 std::memset(&hints, 0, sizeof(hints));
547 hints.ai_family = AF_UNSPEC;
548 hints.ai_socktype = SOCK_STREAM;
549 hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
551 if (getaddrinfo(nullptr, lexical_cast<string>(s_server_port).c_str(),
552 &hints, &res0) < 0) {
553 printf("Error in getaddrinfo(): %s\n", strerror(errno));
554 return false;
557 for (res = res0; res; res = res->ai_next) {
558 if (res->ai_family == AF_INET6 || res->ai_next == nullptr) {
559 break;
563 bool ret = PreBindSocketHelper(res);
564 freeaddrinfo(res0);
565 return ret;
568 void TestServer::CleanupPreBoundSocket() {
569 close(inherit_fd);
570 inherit_fd = -1;
573 bool TestServer::TestInheritFdServer() {
574 WITH_PREBOUND_SOCKET(VSR("<?php print 'Hello, World!';",
575 "Hello, World!"));
576 return true;
579 bool TestServer::TestTakeoverServer() {
580 // start a server
581 snprintf(s_filename, MAXPATHLEN, "/tmp/hphp_takeover_XXXXXX");
582 int tmpfd = mkstemp(s_filename);
583 close(tmpfd);
585 s_func.reset(new AsyncFunc<TestServer>(this, &TestServer::RunServer));
586 s_func->start();
588 // Wait for the server to actually start
589 HttpClient http;
590 StringBuffer response;
591 vector<String> responseHeaders;
592 string url = "http://127.0.0.1:" + lexical_cast<string>(s_server_port) +
593 "/status.php";
594 HeaderMap headers;
595 for (int i = 0; i < 10; i++) {
596 int code = http.get(url.c_str(), response, &headers, &responseHeaders);
597 if (code > 0) {
598 break;
600 sleep(1);
603 // will start a second server, which should takeover
604 VSR("<?php print 'Hello, World!';",
605 "Hello, World!");
606 unlink(s_filename);
607 s_filename[0] = 0;
608 return true;
611 ///////////////////////////////////////////////////////////////////////////////
613 class EchoHandler : public RequestHandler {
614 public:
615 explicit EchoHandler(int timeout) : RequestHandler(timeout) {}
616 // implementing RequestHandler
617 virtual void handleRequest(Transport *transport) {
618 HeaderMap headers;
619 transport->getHeaders(headers);
621 string response;
622 response = "\nGET param: name = ";
623 response += transport->getParam("name");
625 if (transport->getMethod() == Transport::Method::POST) {
626 int size = 0;
627 const char *data = (const char *)transport->getPostData(size);
628 response += "\nPOST data: ";
629 response += string(data, size);
632 for (HeaderMap::const_iterator iter = headers.begin();
633 iter != headers.end(); ++iter) {
634 response += "\nHeader: ";
635 response += iter->first;
636 for (unsigned int i = 0; i < iter->second.size(); i++) {
637 response += "\n";
638 response += lexical_cast<string>(i);
639 response += ": ";
640 response += iter->second[i];
644 transport->addHeader("Custom", "blah");
645 transport->sendString(response);
647 virtual void abortRequest(Transport *transport) {
648 transport->sendString("Service Unavailable", 503);
652 bool TestServer::TestHttpClient() {
653 ServerPtr server;
654 for (s_server_port = PORT_MIN; s_server_port <= PORT_MAX; s_server_port++) {
655 try {
656 server = ServerFactoryRegistry::createServer(
657 m_serverType, "127.0.0.1", s_server_port, 50);
658 server->setRequestHandlerFactory<EchoHandler>(0);
659 server->start();
660 break;
661 } catch (const FailedToListenException& e) {
662 if (s_server_port == PORT_MAX) throw;
666 HeaderMap headers;
667 headers["Cookie"].push_back("c1=v1;c2=v2;");
668 headers["Cookie"].push_back("c3=v3;c4=v4;");
669 string url = "http://127.0.0.1:" + lexical_cast<string>(s_server_port) +
670 "/echo?name=value";
672 static const StaticString s_Custom_colon_blah("Custom: blah");
674 for (int i = 0; i < 10; i++) {
675 HttpClient http;
676 StringBuffer response;
677 vector<String> responseHeaders;
678 int code = http.get(url.c_str(), response, &headers, &responseHeaders);
679 VS(code, 200);
680 VS(response.data(),
681 ("\nGET param: name = value"
682 "\nHeader: Cookie"
683 "\n0: c1=v1;c2=v2;"
684 "\n1: c3=v3;c4=v4;"
685 "\nHeader: Accept"
686 "\n0: */*"
687 "\nHeader: Host"
688 "\n0: 127.0.0.1:" + lexical_cast<string>(s_server_port)).c_str());
690 bool found = false;
691 for (unsigned int i = 0; i < responseHeaders.size(); i++) {
692 if (responseHeaders[i] == s_Custom_colon_blah) {
693 found = true;
696 VERIFY(found);
698 for (int i = 0; i < 10; i++) {
699 HttpClient http;
700 StringBuffer response;
701 vector<String> responseHeaders;
702 int code = http.post(url.c_str(), "postdata", 8, response, &headers,
703 &responseHeaders);
704 VS(code, 200);
705 VS(response.data(),
706 ("\nGET param: name = value"
707 "\nPOST data: postdata"
708 "\nHeader: Content-Type"
709 "\n0: application/x-www-form-urlencoded"
710 "\nHeader: Content-Length"
711 "\n0: 8"
712 "\nHeader: Cookie"
713 "\n0: c1=v1;c2=v2;"
714 "\n1: c3=v3;c4=v4;"
715 "\nHeader: Accept"
716 "\n0: */*"
717 "\nHeader: Host"
718 "\n0: 127.0.0.1:" + lexical_cast<string>(s_server_port)).c_str());
720 bool found = false;
721 for (unsigned int i = 0; i < responseHeaders.size(); i++) {
722 if (responseHeaders[i] == s_Custom_colon_blah) {
723 found = true;
726 VERIFY(found);
729 server->stop();
730 server->waitForEnd();
731 return Count(true);
734 bool TestServer::TestRPCServer() {
735 // the simplest case
736 VSGETP("<?php\n"
737 "function f() { return 100; }\n",
738 "100",
739 "f?auth=test",
740 s_rpc_port);
742 // array output
743 VSGETP("<?php\n"
744 "function f($a) { return array(1, 2, 3, $a); }\n",
745 "[1,2,3,\"hello\"]",
746 "f?auth=test&p=\"hello\"",
747 s_rpc_port);
749 // associate arrays
750 VSGETP("<?php\n"
751 "function f($a, $b) { return array_merge($a, $b); }\n",
752 "{\"a\":1,\"0\":2,\"1\":1,\"2\":2}",
753 "f?auth=test&p={\"a\":1,\"1\":2}&p=[1,2]",
754 s_rpc_port);
756 // builtin function and static method
757 VSGETP("<?php\n"
758 "class A { static function f($a) { return $a; } }\n",
759 "100",
760 "call_user_func?auth=test&p=\"A::f\"&p=100",
761 s_rpc_port);
763 // invoking a file, with NO json encoding
764 // "int(100)" is printed twice, one from warmup, and the other from include
765 VSGETP("<?php\n"
766 "var_dump(100);\n",
767 "int(100)\n"
768 "int(100)\n",
769 "?include=string&output=1&auth=test",
770 s_rpc_port);
772 VSGETP("<?php\n"
773 "var_dump(isset($_ENV['HPHP_RPC']));\n",
774 "bool(true)\n"
775 "bool(true)\n",
776 "?include=string&output=1&auth=test",
777 s_rpc_port);
779 return true;
782 bool TestServer::TestXboxServer() {
783 VSGET("<?php\n"
784 "if (array_key_exists('main', $_GET)) {\n"
785 " $t = xbox_task_start('1');\n"
786 " xbox_task_result($t, 0, $r);\n"
787 " var_dump($r);\n"
788 " $t = xbox_task_start('2');\n"
789 " xbox_task_result($t, 0, $r);\n"
790 " $t = xbox_task_start('1');\n"
791 " xbox_task_result($t, 0, $r);\n"
792 " var_dump($r);\n"
793 " sleep(7);\n"
794 " $t = xbox_task_start('3');\n"
795 " xbox_task_result($t, 0, $r);\n"
796 " var_dump($r);\n"
797 " sleep(2);\n"
798 " $t = xbox_task_start('4');\n"
799 " xbox_task_result($t, 0, $r);\n"
800 " $t = xbox_task_start('3');\n"
801 " xbox_task_result($t, 0, $r);\n"
802 " var_dump($r);\n"
803 " sleep(2);\n"
804 " $t = xbox_task_start('3');\n"
805 " xbox_task_result($t, 0, $r);\n"
806 " var_dump($r);\n"
807 "} else {\n"
808 " function xbox_process_message($msg) {\n"
809 " if ($msg == '1') return xbox_get_thread_timeout();\n"
810 " else if ($msg == '2') xbox_set_thread_timeout(5);\n"
811 " else if ($msg == '3') return xbox_get_thread_time();\n"
812 " else xbox_schedule_thread_reset();\n"
813 " }\n"
814 "}\n",
815 "int(10)\n"
816 "int(5)\n"
817 "int(0)\n"
818 "int(0)\n"
819 "int(0)\n",
820 "string?main=1");
822 return true;
825 bool TestServer::TestPageletServer() {
826 VSGET("<?php\n"
827 "if (array_key_exists('pagelet', $_GET)) {\n"
828 " echo 'Hello from the pagelet!';\n"
829 "} else {\n"
830 " $h = array('Host: ' . $_SERVER['HTTP_HOST']);\n"
831 " $t = pagelet_server_task_start('/string?pagelet=1', $h, '');\n"
832 " echo 'First! ';\n"
833 " $r = pagelet_server_task_result($t, $h, $c);\n"
834 " echo $r;\n"
835 "}\n",
836 "First! Hello from the pagelet!",
837 "string");
839 // POST vs GET
840 VSGET("<?php\n"
841 "if (array_key_exists('pagelet', $_GET)) {\n"
842 " echo $_SERVER['REQUEST_METHOD'];\n"
843 "} else {\n"
844 " $h = array('Host: ' . $_SERVER['HTTP_HOST']);\n"
845 " $t = pagelet_server_task_start('/string?pagelet=1', $h, '');\n"
846 " echo 'First! ';\n"
847 " $r = pagelet_server_task_result($t, $h, $c);\n"
848 " echo $r;\n"
849 "}\n",
850 "First! GET",
851 "string");
853 VSGET("<?php\n"
854 "if ($_SERVER['THREAD_TYPE'] == 'Pagelet Thread') {\n"
855 " echo 'hello';\n"
856 " pagelet_server_flush();\n"
857 " ob_start();\n"
858 " echo 'world';\n"
859 " pagelet_server_flush();\n"
860 " echo 'what';\n"
861 "} else {\n"
862 " $h = array('Host: ' . $_SERVER['HTTP_HOST']);\n"
863 " $t = pagelet_server_task_start('/string', $h, '');\n"
864 " for ($i = 0; ; $i++) {\n"
865 " while (($s = pagelet_server_task_status($t)) == \n"
866 " PAGELET_NOT_READY) { sleep(1); }\n"
867 " echo \"Step $i:\\n\";\n"
868 " $r = pagelet_server_task_result($t, $h, $c);\n"
869 " echo $r . \"\\n\";\n"
870 " if ($s == PAGELET_DONE) break;\n"
871 " }\n"
872 "}\n",
873 "Step 0:\n"
874 "hello\n"
875 "Step 1:\n"
876 "world\n"
877 "Step 2:\n"
878 "what\n",
879 "string");
881 return true;