1 |
/* |
2 |
+----------------------------------------------------------------------+ |
3 |
| PHP Version 4 | |
4 |
+----------------------------------------------------------------------+ |
5 |
| Copyright (c) 1997-2002 The PHP Group | |
6 |
+----------------------------------------------------------------------+ |
7 |
| This source file is subject to version 2.02 of the PHP license, | |
8 |
| that is bundled with this package in the file LICENSE, and is | |
9 |
| available at through the world-wide-web at | |
10 |
| http://www.php.net/license/2_02.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 |
+----------------------------------------------------------------------+ |
15 |
| Author: Nikos Mavroyanopoulos <nmav@gnutls.org> | |
16 |
+----------------------------------------------------------------------+ |
17 |
*/ |
18 |
|
19 |
/* $Id: hydra.c,v 1.11.2.2 2003/01/19 10:15:22 nmav Exp $ */ |
20 |
|
21 |
#include "php.h" |
22 |
#include "SAPI.h" |
23 |
#include "php_main.h" |
24 |
#include "php_variables.h" |
25 |
#include "php_ini.h" |
26 |
|
27 |
#include "ext/standard/php_smart_str.h" |
28 |
|
29 |
#include <sys/time.h> |
30 |
#include <sys/types.h> |
31 |
#include <sys/uio.h> |
32 |
#include <stdlib.h> |
33 |
#include <unistd.h> |
34 |
|
35 |
#include <hic.h> /* for hic_stuff structure */ |
36 |
|
37 |
typedef struct { |
38 |
hic_stuff *hc; |
39 |
int read_post_data; |
40 |
void (*on_close)(int); |
41 |
long async_send; |
42 |
} php_hydra_globals; |
43 |
|
44 |
|
45 |
#ifdef ZTS |
46 |
static int hydra_globals_id; |
47 |
#define TG(v) TSRMG(hydra_globals_id, php_hydra_globals *, v) |
48 |
#else |
49 |
static php_hydra_globals hydra_globals; |
50 |
#define TG(v) (hydra_globals.v) |
51 |
#endif |
52 |
|
53 |
PHP_INI_BEGIN() |
54 |
STD_PHP_INI_ENTRY("async_send", "0", PHP_INI_ALL, OnUpdateInt, async_send, php_hydra_globals, hydra_globals) |
55 |
PHP_INI_END() |
56 |
|
57 |
static int sapi_hydra_ub_write(const char *str, uint str_length TSRMLS_DC) |
58 |
{ |
59 |
int n; |
60 |
uint sent = 0; |
61 |
|
62 |
while (str_length > 0) { |
63 |
n = write(TG(hc)->out_fd, str, str_length); |
64 |
|
65 |
if (n == -1 && errno == EPIPE) |
66 |
php_handle_aborted_connection(); |
67 |
if (n == -1 && errno == EINTR) |
68 |
continue; |
69 |
|
70 |
if (n <= 0) |
71 |
return n; |
72 |
|
73 |
TG(hc)->bytes_sent += n; |
74 |
str += n; |
75 |
sent += n; |
76 |
str_length -= n; |
77 |
} |
78 |
|
79 |
return sent; |
80 |
} |
81 |
|
82 |
#define COMBINE_HEADERS 30 |
83 |
|
84 |
static int sapi_hydra_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) |
85 |
{ |
86 |
char buf[1024]; |
87 |
struct iovec vec[COMBINE_HEADERS]; |
88 |
int n = 0; |
89 |
zend_llist_position pos; |
90 |
sapi_header_struct *h; |
91 |
size_t len; |
92 |
|
93 |
if (!SG(sapi_headers).http_status_line) { |
94 |
char* desc; |
95 |
|
96 |
if (SG(sapi_headers).http_response_code == 200) |
97 |
desc = "OK"; |
98 |
else |
99 |
desc = "Something"; |
100 |
|
101 |
snprintf(buf, sizeof(buf)-1, "Status: %d %s\r\n", SG(sapi_headers).http_response_code, |
102 |
desc); |
103 |
len = strlen(buf); |
104 |
vec[n].iov_base = buf; |
105 |
vec[n].iov_len = len; |
106 |
|
107 |
} else { |
108 |
vec[n].iov_base = SG(sapi_headers).http_status_line; |
109 |
len = strlen(vec[n].iov_base); |
110 |
vec[n].iov_len = len; |
111 |
vec[++n].iov_base = "\r\n"; |
112 |
vec[n].iov_len = 2; |
113 |
len += 2; |
114 |
} |
115 |
TG(hc)->status = SG(sapi_headers).http_response_code; |
116 |
TG(hc)->bytes_sent += len; |
117 |
n++; |
118 |
|
119 |
#define DEF_CONTENT_TYPE_LINE "Content-Type: text/html\r\n" |
120 |
if (SG(sapi_headers).send_default_content_type) { |
121 |
vec[n].iov_base = DEF_CONTENT_TYPE_LINE; |
122 |
vec[n].iov_len = sizeof(DEF_CONTENT_TYPE_LINE) - 1; |
123 |
n++; |
124 |
} |
125 |
|
126 |
h = zend_llist_get_first_ex(&sapi_headers->headers, &pos); |
127 |
while (h) { |
128 |
vec[n].iov_base = h->header; |
129 |
vec[n++].iov_len = h->header_len; |
130 |
if (n >= COMBINE_HEADERS - 1) { |
131 |
/* XXX: partial writevs are not handled */ |
132 |
if (writev(TG(hc)->out_fd, vec, n) == -1 && errno == EPIPE) |
133 |
php_handle_aborted_connection(); |
134 |
n = 0; |
135 |
} |
136 |
vec[n].iov_base = "\r\n"; |
137 |
vec[n++].iov_len = 2; |
138 |
|
139 |
h = zend_llist_get_next_ex(&sapi_headers->headers, &pos); |
140 |
} |
141 |
|
142 |
vec[n].iov_base = "\r\n"; |
143 |
vec[n++].iov_len = 2; |
144 |
|
145 |
if (n) { |
146 |
/* XXX: partial writevs are not handled */ |
147 |
if (writev(TG(hc)->out_fd, vec, n) == -1 && errno == EPIPE) |
148 |
php_handle_aborted_connection(); |
149 |
} |
150 |
|
151 |
return SAPI_HEADER_SENT_SUCCESSFULLY; |
152 |
} |
153 |
|
154 |
static int sapi_hydra_read_post(char *buffer, uint count_bytes TSRMLS_DC) |
155 |
{ |
156 |
size_t read_bytes = 0, tmp; |
157 |
int c; |
158 |
int n; |
159 |
|
160 |
/* In hydra, post data are written to a file, and an fd of the file is sent here |
161 |
*/ |
162 |
|
163 |
while (read_bytes < count_bytes) { |
164 |
tmp = read(TG(hc)->post_data_fd, buffer + read_bytes, |
165 |
count_bytes - read_bytes); |
166 |
|
167 |
if (tmp == 0 || (tmp == -1 && errno != EINTR)) |
168 |
break; |
169 |
/* A simple "tmp > 0" produced broken code on Solaris/GCC */ |
170 |
if (tmp != 0 && tmp != -1) |
171 |
read_bytes += tmp; |
172 |
|
173 |
} |
174 |
|
175 |
TG(read_post_data) += read_bytes; |
176 |
|
177 |
return read_bytes; |
178 |
} |
179 |
|
180 |
#define COOKIE "HTTP_COOKIE=" |
181 |
#define COOKIE_SIZE sizeof("HTTP_COOKIE=")-1 |
182 |
static char *sapi_hydra_read_cookies(TSRMLS_D) |
183 |
{ |
184 |
int i; |
185 |
char *p = NULL; |
186 |
/* register_variables should have been called before this. |
187 |
*/ |
188 |
i = 0; |
189 |
while( TG(hc)->cgi_env[i] != NULL) { |
190 |
if (strncmp( TG(hc)->cgi_env[i], COOKIE, COOKIE_SIZE)==0) { |
191 |
p = strchr( TG(hc)->cgi_env[i], '='); |
192 |
if (p) p++; |
193 |
break; |
194 |
} |
195 |
i++; |
196 |
} |
197 |
|
198 |
return p; |
199 |
} |
200 |
|
201 |
#define BUF_SIZE 512 |
202 |
|
203 |
static void sapi_hydra_register_variables(zval *track_vars_array TSRMLS_DC) |
204 |
{ |
205 |
char buf[BUF_SIZE]; |
206 |
char *p; |
207 |
int i; |
208 |
|
209 |
php_register_variable("PHP_SELF", SG(request_info).request_uri, track_vars_array TSRMLS_CC); |
210 |
|
211 |
buf[BUF_SIZE] = 0; |
212 |
|
213 |
/* Register all variables in cgi_env |
214 |
* cgi_env has variables in the form XXX=YYY |
215 |
*/ |
216 |
i = 0; |
217 |
while( TG(hc)->cgi_env[i] != NULL) { |
218 |
if (TG(hc)->cgi_env[i] == NULL) continue; |
219 |
|
220 |
strncpy( buf, TG(hc)->cgi_env[i], BUF_SIZE - 1); |
221 |
p = strchr( buf, '='); |
222 |
if (p!=NULL) { /* replace '=' with '\0' */ |
223 |
*p=0; |
224 |
php_register_variable( buf, p+1, track_vars_array TSRMLS_CC); |
225 |
} |
226 |
i++; |
227 |
} |
228 |
|
229 |
} |
230 |
|
231 |
static PHP_MINIT_FUNCTION(hydra) |
232 |
{ |
233 |
REGISTER_INI_ENTRIES(); |
234 |
return SUCCESS; |
235 |
} |
236 |
|
237 |
static zend_module_entry php_hydra_module = { |
238 |
STANDARD_MODULE_HEADER, |
239 |
"hydra", |
240 |
NULL, |
241 |
PHP_MINIT(hydra), |
242 |
NULL, |
243 |
NULL, |
244 |
NULL, |
245 |
NULL, /* info */ |
246 |
NULL, |
247 |
STANDARD_MODULE_PROPERTIES |
248 |
}; |
249 |
|
250 |
static int php_hydra_startup(sapi_module_struct *sapi_module) |
251 |
{ |
252 |
if (php_module_startup(sapi_module) == FAILURE |
253 |
|| zend_startup_module(&php_hydra_module) == FAILURE) { |
254 |
return FAILURE; |
255 |
} |
256 |
return SUCCESS; |
257 |
} |
258 |
|
259 |
static sapi_module_struct hydra_sapi_module = { |
260 |
"hydra", |
261 |
"hydra", |
262 |
|
263 |
php_hydra_startup, |
264 |
php_module_shutdown_wrapper, |
265 |
|
266 |
NULL, /* activate */ |
267 |
NULL, /* deactivate */ |
268 |
|
269 |
sapi_hydra_ub_write, |
270 |
NULL, |
271 |
NULL, /* get uid */ |
272 |
NULL, /* getenv */ |
273 |
|
274 |
php_error, |
275 |
|
276 |
NULL, |
277 |
sapi_hydra_send_headers, |
278 |
NULL, |
279 |
sapi_hydra_read_post, |
280 |
sapi_hydra_read_cookies, |
281 |
|
282 |
sapi_hydra_register_variables, |
283 |
NULL, /* Log message */ |
284 |
|
285 |
NULL, /* Block interruptions */ |
286 |
NULL, /* Unblock interruptions */ |
287 |
|
288 |
STANDARD_SAPI_MODULE_PROPERTIES |
289 |
}; |
290 |
|
291 |
static void hydra_module_main(TSRMLS_D) |
292 |
{ |
293 |
zend_file_handle file_handle; |
294 |
|
295 |
file_handle.type = ZEND_HANDLE_FILENAME; |
296 |
file_handle.filename = SG(request_info).path_translated; |
297 |
file_handle.free_filename = 0; |
298 |
file_handle.opened_path = NULL; |
299 |
|
300 |
if (php_request_startup(TSRMLS_C) == FAILURE) { |
301 |
return; |
302 |
} |
303 |
|
304 |
php_execute_script(&file_handle TSRMLS_CC); |
305 |
php_request_shutdown(NULL); |
306 |
} |
307 |
|
308 |
static int hydra_request_ctor(TSRMLS_D) |
309 |
{ |
310 |
int offset, i; |
311 |
char* query_string; |
312 |
char* content_length; |
313 |
char* auth = NULL; |
314 |
char* request_method; |
315 |
char *p = NULL; |
316 |
|
317 |
i = 0; |
318 |
while( TG(hc)->cgi_env[i] != NULL) { |
319 |
if (TG(hc)->cgi_env[i] == NULL) continue; |
320 |
|
321 |
if (strncmp( TG(hc)->cgi_env[i], "REQUEST_METHOD=", 15)==0) { |
322 |
p = strchr( TG(hc)->cgi_env[i], '='); |
323 |
if (p) p++; |
324 |
SG(request_info).request_method = p; |
325 |
} else if (strncmp( TG(hc)->cgi_env[i], "HTTP_AUTHORIZATION=", 19)==0) { |
326 |
p = strchr( TG(hc)->cgi_env[i], '='); |
327 |
if (p) p++; |
328 |
auth = p; |
329 |
} else if (strncmp( TG(hc)->cgi_env[i], "CONTENT_TYPE=", 13)==0) { |
330 |
p = strchr( TG(hc)->cgi_env[i], '='); |
331 |
if (p) p++; |
332 |
SG(request_info).content_type = p; |
333 |
} else if (strncmp( TG(hc)->cgi_env[i], "CONTENT_LENGTH=", 15)==0) { |
334 |
p = strchr( TG(hc)->cgi_env[i], '='); |
335 |
if (p) { |
336 |
p++; |
337 |
SG(request_info).content_length = atoi(p); |
338 |
} |
339 |
} else if (strncmp( TG(hc)->cgi_env[i], "QUERY_STRING=", 13)==0) { |
340 |
p = strchr( TG(hc)->cgi_env[i], '='); |
341 |
if (p) { |
342 |
p++; |
343 |
SG(request_info).query_string = p; |
344 |
} |
345 |
} else if (strncmp( TG(hc)->cgi_env[i], "REQUEST_URI=", 12)==0) { |
346 |
p = strchr( TG(hc)->cgi_env[i], '='); |
347 |
if (p) { |
348 |
p++; |
349 |
SG(request_info).request_uri = p; |
350 |
} |
351 |
} else if (strncmp( TG(hc)->cgi_env[i], "PATH_TRANSLATED=", 14)==0) { |
352 |
p = strchr( TG(hc)->cgi_env[i], '='); |
353 |
if (p) { |
354 |
p++; |
355 |
SG(request_info).path_translated = p; |
356 |
} |
357 |
} |
358 |
i++; |
359 |
} |
360 |
if ( SG(request_info).path_translated == NULL || |
361 |
SG(request_info).request_uri == NULL) return -1; |
362 |
|
363 |
SG(sapi_headers).http_response_code = 200; |
364 |
|
365 |
php_handle_auth_data(auth TSRMLS_CC); |
366 |
|
367 |
SG(server_context) = (void *) 1; |
368 |
|
369 |
return 0; |
370 |
} |
371 |
|
372 |
static void hydra_request_dtor(TSRMLS_D) |
373 |
{ |
374 |
return; |
375 |
} |
376 |
|
377 |
|
378 |
|
379 |
static off_t hydra_php_request(hic_stuff *hc TSRMLS_DC) |
380 |
{ |
381 |
TG(hc) = hc; |
382 |
hc->bytes_sent = 0; |
383 |
hc->status = 200; |
384 |
|
385 |
TG(read_post_data) = 0; |
386 |
|
387 |
if (hydra_request_ctor(TSRMLS_C) == -1) |
388 |
return 0; |
389 |
|
390 |
hydra_module_main(TSRMLS_C); |
391 |
|
392 |
hydra_request_dtor(TSRMLS_C); |
393 |
|
394 |
return 0; |
395 |
} |
396 |
|
397 |
off_t _php_hic_request( hic_stuff *hc) |
398 |
{ |
399 |
TSRMLS_FETCH(); |
400 |
return hydra_php_request(hc TSRMLS_CC); |
401 |
} |
402 |
|
403 |
void _php_hic_init(void) |
404 |
{ |
405 |
char *ini; |
406 |
|
407 |
#ifdef ZTS |
408 |
tsrm_startup(1, 1, 0, NULL); |
409 |
ts_allocate_id(&hydra_globals_id, sizeof(php_hydra_globals), NULL, NULL); |
410 |
{ |
411 |
TSRMLS_FETCH(); |
412 |
TG(on_close) = NULL; |
413 |
} |
414 |
#endif |
415 |
|
416 |
if ((ini = getenv("PHP_INI_PATH"))) { |
417 |
hydra_sapi_module.php_ini_path_override = ini; |
418 |
} |
419 |
|
420 |
sapi_startup(&hydra_sapi_module); |
421 |
hydra_sapi_module.startup(&hydra_sapi_module); |
422 |
|
423 |
{ |
424 |
TSRMLS_FETCH(); |
425 |
} |
426 |
|
427 |
} |
428 |
|
429 |
void _php_hic_shutdown(void) |
430 |
{ |
431 |
TSRMLS_FETCH(); |
432 |
|
433 |
if (SG(server_context) != NULL) { |
434 |
hydra_sapi_module.shutdown(&hydra_sapi_module); |
435 |
sapi_shutdown(); |
436 |
#ifdef ZTS |
437 |
tsrm_shutdown(); |
438 |
#endif |
439 |
} |
440 |
} |