drop dep on ext-propro (dysfunctional with PHP 8)
[m6w6/ext-http] / tests / helper / server.inc
1 <?php
2
3 ini_set("log_errors", true);
4 ini_set("error_log", __DIR__."/server.log");
5
6 function logger() {
7 if (!ini_get("date.timezone")) {
8 date_default_timezone_set(@date_default_timezone_get());
9 }
10 error_log(sprintf("%s(%s): %s",
11 basename(getenv("SCRIPT_FILENAME"), ".php"),
12 basename(current(get_included_files()), ".inc"),
13 call_user_func_array("sprintf", func_get_args())
14 ));
15 }
16
17 $php = getenv('TEST_PHP_EXECUTABLE');
18 if ($php) {
19 define('PHP_BIN', $php);
20 } else if (defined('PHP_BINARY')) {
21 define('PHP_BIN', PHP_BINARY);
22 } else {
23 // PHP-5.3
24 define("PHP_BIN", PHP_BINDIR.DIRECTORY_SEPARATOR."php");
25 }
26
27 foreach (array("raphf", "http") as $ext) {
28 if (!extension_loaded($ext)) {
29 dl(ext_lib_name($ext));
30 }
31 }
32
33 function get_extension_load_arg($bin, $args, $ext) {
34 $bin = escapeshellcmd($bin);
35 $args = implode(' ', array_map('escapeshellarg', $args));
36
37 // check if php will load the extension with the existing args
38 exec(sprintf('%s %s -m', $bin, $args), $output);
39
40 foreach ($output as $line ) {
41 if (trim($line) === $ext) {
42 return null;
43 }
44 }
45
46 // try to load the extension with an arg
47 $arg = '-dextension=' . ini_get('extension_dir') . '/' . ext_lib_name($ext);
48 exec(sprintf('%s %s %s -m', $bin, $args, escapeshellarg($arg)), $output);
49
50 foreach ($output as $line ) {
51 if (trim($line) === $ext) {
52 return $arg;
53 }
54 }
55
56 // check if the child will be able to dl() the extension
57 $success = shell_exec(sprintf('%s %s -r "echo (int)dl(%s);', $bin, $args, var_export(ext_lib_name($ext), true)));
58 if ($success) {
59 return null;
60 }
61
62 echo "Unable to load extension '{$ext}' in child process";
63 exit(1);
64 }
65
66 function ext_lib_name($ext) {
67 if (PHP_SHLIB_SUFFIX === 'dll') {
68 return "php_{$ext}.dll";
69 }
70
71 return $ext . "." . PHP_SHLIB_SUFFIX;
72 }
73
74 function serve($cb) {
75 /* stream_socket_server() automatically sets SO_REUSEADDR,
76 * which is, well, bad if the tests are run in parallel
77 */
78 $offset = rand(0,2000);
79 foreach (range(8000+$offset, 9000+$offset) as $port) {
80 logger("serve: Trying port %d", $port);
81 if (($server = @stream_socket_server("tcp://localhost:$port"))) {
82 fprintf(STDERR, "%s\n", $port);
83 logger("serve: Using port %d", $port);
84 do {
85 $R = array($server); $W = array(); $E = array();
86 $select = stream_select($R, $E, $E, 10, 0);
87 if ($select && ($client = stream_socket_accept($server, 1))) {
88 logger("serve: Accept client %d", (int) $client);
89 if (getenv("PHP_HTTP_TEST_SSL")) {
90 stream_socket_enable_crypto($client, true, STREAM_CRYPTO_METHOD_SSLv23_SERVER);
91 }
92 try {
93 $R = array($client);
94 while (!feof($client) && stream_select($R, $W, $E, 1, 0)) {
95 logger("serve: Handle client %d", (int) $client);
96 $cb($client);
97 }
98 logger("serve: EOF/timeout on client %d", (int) $client);
99 } catch (Exception $ex) {
100 logger("serve: Exception on client %d: %s", (int) $client, $ex->getMessage());
101 /* ignore disconnect */
102 if ($ex->getMessage() !== "Empty message received from stream") {
103 fprintf(STDERR, "%s\n", $ex);
104 }
105 break;
106 }
107 }
108 } while ($select);
109 return;
110 }
111 }
112 }
113
114 function server($handler, $cb) {
115 $args = [];
116 $argList = preg_split('#\s+#', getenv('TEST_PHP_ARGS'), -1, PREG_SPLIT_NO_EMPTY);
117 for ($i = 0; isset($argList[$i]); $i++) {
118 if ($argList[$i] === '-c') {
119 array_push($args, '-c', $argList[++$i]);
120 continue;
121 }
122 if ($argList[$i] === '-n') {
123 $args[] = '-n';
124 continue;
125 }
126 if ($argList[$i] === '-d') {
127 $args[] = '-d' . $argList[++$i];
128 continue;
129 }
130 if (substr($argList[$i], 0, 2) === '-d') {
131 $args[] = $argList[$i];
132 }
133 }
134 foreach (['raphf', 'http'] as $ext) {
135 if (null !== $arg = get_extension_load_arg(PHP_BIN, $args, $ext)) {
136 $args[] = $arg;
137 }
138 }
139 $args[] = __DIR__ . '/' . $handler;
140 proc(PHP_BIN, $args, $cb);
141 }
142
143 function nghttpd($cb) {
144 $spec = array(array("pipe","r"), array("pipe","w"), array("pipe","w"));
145 $offset = rand(0,2000);
146 foreach (range(8000+$offset, 9000+$offset) as $port) {
147 $comm = "exec nghttpd -d html $port http2.key http2.crt";
148 if (($proc = proc_open($comm, $spec, $pipes, __DIR__))) {
149 $stdin = $pipes[0];
150 $stdout = $pipes[1];
151 $stderr = $pipes[2];
152
153 sleep(1);
154 $status = proc_get_status($proc);
155 logger("nghttpd: %s", new http\Params($status));
156 if (!$status["running"]) {
157 continue;
158 }
159
160 try {
161 $cb($port, $stdin, $stdout, $stderr);
162 } catch (Exception $e) {
163 echo $e,"\n";
164 }
165
166 proc_terminate($proc);
167
168 fpassthru($stderr);
169 fpassthru($stdout);
170 return;
171 }
172 }
173
174 }
175
176 function proc($bin, $args, $cb) {
177 $spec = array(array("pipe","r"), array("pipe","w"), array("pipe","w"));
178 $comm = escapeshellcmd($bin) . " ". implode(" ", array_map("escapeshellarg", $args));
179 logger("proc: %s %s", $bin, implode(" ", $args));
180 if (($proc = proc_open($comm, $spec, $pipes, __DIR__))) {
181 $stdin = $pipes[0];
182 $stdout = $pipes[1];
183 $stderr = $pipes[2];
184
185 do {
186 $port = trim(fgets($stderr));
187 $R = array($stderr); $W = array(); $E = array();
188 } while (is_numeric($port) && stream_select($R, $W, $E, 0, 10000));
189
190 if (is_numeric($port)) {
191 try {
192 $cb($port, $stdin, $stdout, $stderr);
193 } catch (Exception $e) {
194 echo $e,"\n";
195 }
196 }
197
198 proc_terminate($proc);
199
200 fpassthru($stderr);
201 fpassthru($stdout);
202 }
203 }