Return to php_tux.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / sapi / tux |
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
1.1.1.2 ! misho 5: | Copyright (c) 1997-2013 The PHP Group |
1.1 misho 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: +----------------------------------------------------------------------+
15: | Author: Sascha Schumann <sascha@schumann.cx> |
16: +----------------------------------------------------------------------+
17: */
18:
19: #include "php.h"
20: #include "SAPI.h"
21: #include "php_main.h"
22: #include "php_variables.h"
23:
24: #include "ext/standard/php_smart_str.h"
25:
26: #include "tuxmodule.h"
27:
28: #include <sys/uio.h>
29:
30: #if 0
31: #include <pthread.h>
32: #endif
33:
34: void tux_closed_conn(int fd);
35:
36: enum {
37: PHP_TUX_BACKGROUND_CONN = 1
38: };
39:
40: typedef struct {
41: user_req_t *req;
42: void (*on_close)(int);
43: int tux_action;
44: struct iovec *header_vec;
45: int number_vec;
46: } php_tux_globals;
47:
48: static php_tux_globals tux_globals;
49:
50: #define TG(v) (tux_globals.v)
51:
52: static int sapi_tux_ub_write(const char *str, uint str_length TSRMLS_DC)
53: {
54: int n;
55: int m;
56: const char *estr;
57:
58: /* combine headers and body */
59: if (TG(number_vec)) {
60: struct iovec *vec = TG(header_vec);
61:
62: n = TG(number_vec);
63: vec[n].iov_base = (void *) str;
64: vec[n++].iov_len = str_length;
65:
66: /* XXX: this might need more complete error handling */
67: if ((m = writev(TG(req)->sock, vec, n)) == -1 && errno == EPIPE)
68: php_handle_aborted_connection();
69:
70: if (m > 0)
71: TG(req)->bytes_sent += str_length;
72:
73: TG(number_vec) = 0;
74: return str_length;
75: }
76:
77: estr = str + str_length;
78:
79: while (str < estr) {
80: n = send(TG(req)->sock, str, estr - str, 0);
81:
82: if (n == -1 && errno == EPIPE)
83: php_handle_aborted_connection();
84: if (n == -1 && errno == EAGAIN)
85: continue;
86: if (n <= 0)
87: return n;
88:
89: str += n;
90: }
91:
92: n = str_length - (estr - str);
93:
94: TG(req)->bytes_sent += n;
95:
96: return n;
97: }
98:
99: static int sapi_tux_send_headers(sapi_headers_struct *sapi_headers)
100: {
101: char buf[1024];
102: struct iovec *vec;
103: int n;
104: int max_headers;
105: zend_llist_position pos;
106: sapi_header_struct *h;
107: size_t len;
108: char *status_line;
109: int locate_cl;
110: TSRMLS_FETCH();
111:
112: max_headers = 30;
113: n = 1;
114:
115: vec = malloc(sizeof(struct iovec) * max_headers);
116: status_line = malloc(30);
117:
118: /* safe sprintf use */
119: len = slprintf(status_line, 30, "HTTP/1.1 %d NA\r\n", SG(sapi_headers).http_response_code);
120:
121: vec[0].iov_base = status_line;
122: vec[0].iov_len = len;
123:
124: TG(req)->http_status = SG(sapi_headers).http_response_code;
125:
126: if (TG(tux_action) == TUX_ACTION_FINISH_CLOSE_REQ && TG(req)->http_version == HTTP_1_1)
127: locate_cl = 1;
128: else
129: locate_cl = 0;
130:
131: h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
132: while (h) {
133: if (locate_cl
134: && strncasecmp(h->header, "Content-length:", sizeof("Content-length:")-1) == 0) {
135: TG(tux_action) = TUX_ACTION_FINISH_REQ;
136: locate_cl = 0;
137: }
138:
139: vec[n].iov_base = h->header;
140: vec[n++].iov_len = h->header_len;
141: if (n >= max_headers - 3) {
142: max_headers *= 2;
143: vec = realloc(vec, sizeof(struct iovec) * max_headers);
144: }
145: vec[n].iov_base = "\r\n";
146: vec[n++].iov_len = 2;
147:
148: h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);
149: }
150:
151: vec[n].iov_base = "\r\n";
152: vec[n++].iov_len = 2;
153:
154: TG(number_vec) = n;
155: TG(header_vec) = vec;
156:
157:
158: return SAPI_HEADER_SENT_SUCCESSFULLY;
159: }
160:
161: static int sapi_tux_read_post(char *buffer, uint count_bytes)
162: {
163: #if 0
164: int amount = 0;
165: TSRMLS_FETCH();
166:
167: TG(req)->objectlen = count_bytes;
168: TG(req)->object_addr = buffer;
169: if (tux(TUX_ACTION_READ_POST_DATA, TG(req)))
170: return 0;
171:
172: TG(read_post_data) = 1;
173:
174: return TG(req)->objectlen;
175: #else
176: return 0;
177: #endif
178: }
179:
180: static char *sapi_tux_read_cookies(void)
181: {
182: TSRMLS_FETCH();
183:
184: return TG(req)->cookies;
185: }
186:
187: #define BUF_SIZE 512
188: #define ADD_STRING(name) \
189: php_register_variable(name, buf, track_vars_array TSRMLS_CC)
190:
191: static void sapi_tux_register_variables(zval *track_vars_array TSRMLS_DC)
192: {
193: char buf[BUF_SIZE + 1];
194: char *p;
195: sapi_header_line ctr = {0};
196:
197: ctr.line = buf;
198: ctr.line_len = slprintf(buf, sizeof(buf), "Server: %s", TUXAPI_version);
199: sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
200:
201: php_register_variable("PHP_SELF", SG(request_info).request_uri, track_vars_array TSRMLS_CC);
202: php_register_variable("SERVER_SOFTWARE", TUXAPI_version, track_vars_array TSRMLS_CC);
203: php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC);
204: php_register_variable("REQUEST_METHOD", (char *) SG(request_info).request_method, track_vars_array TSRMLS_CC);
205: php_register_variable("DOCUMENT_ROOT", TUXAPI_docroot, track_vars_array TSRMLS_CC);
206: php_register_variable("SERVER_NAME", TUXAPI_servername, track_vars_array TSRMLS_CC);
207: php_register_variable("REQUEST_URI", SG(request_info).request_uri, track_vars_array TSRMLS_CC);
208: php_register_variable("PATH_TRANSLATED", SG(request_info).path_translated, track_vars_array TSRMLS_CC);
209:
210: p = inet_ntoa(TG(req)->client_host);
211: /* string representation of IPs are never larger than 512 bytes */
212: if (p) {
213: memcpy(buf, p, strlen(p) + 1);
214: ADD_STRING("REMOTE_ADDR");
215: ADD_STRING("REMOTE_HOST");
216: }
217:
218: snprintf(buf, sizeof(buf), "%d", CGI_SERVER_PORT(TG(req)));
219: ADD_STRING("SERVER_PORT");
220:
221: #if 0
222: snprintf(buf, BUF_SIZE, "/%s", TG(hc)->pathinfo);
223: ADD_STRING("PATH_INFO");
224:
225: snprintf(buf, BUF_SIZE, "/%s", TG(hc)->origfilename);
226: ADD_STRING("SCRIPT_NAME");
227: #endif
228:
229: #define CONDADD(name, field) \
230: if (TG(req)->field[0]) { \
231: php_register_variable(#name, TG(req)->field, track_vars_array TSRMLS_CC); \
232: }
233:
234: CONDADD(HTTP_REFERER, referer);
235: CONDADD(HTTP_USER_AGENT, user_agent);
236: CONDADD(HTTP_ACCEPT, accept);
237: CONDADD(HTTP_ACCEPT_ENCODING, accept_encoding);
238: CONDADD(HTTP_ACCEPT_LANGUAGE, accept_language);
239: CONDADD(HTTP_COOKIE, cookies);
240: CONDADD(CONTENT_TYPE, content_type);
241:
242: #if 0
243: if (TG(hc)->contentlength != -1) {
244: snprintf(buf, sizeof(buf), "%ld", (long) TG(hc)->contentlength);
245: ADD_STRING("CONTENT_LENGTH");
246: }
247: #endif
248:
249: #if 0
250: if (TG(hc)->authorization[0])
251: php_register_variable("AUTH_TYPE", "Basic", track_vars_array TSRMLS_CC);
252: #endif
253: }
254:
255:
256: static int php_tux_startup(sapi_module_struct *sapi_module)
257: {
258: if (php_module_startup(sapi_module, NULL, 0)==FAILURE) {
259: return FAILURE;
260: } else {
261: return SUCCESS;
262: }
263: }
264:
265: static sapi_module_struct tux_sapi_module = {
266: "tux",
267: "tux",
268:
269: php_tux_startup,
270: php_module_shutdown_wrapper,
271:
272: NULL, /* activate */
273: NULL, /* deactivate */
274:
275: sapi_tux_ub_write,
276: NULL,
277: NULL, /* get uid */
278: NULL, /* getenv */
279:
280: php_error,
281:
282: NULL,
283: sapi_tux_send_headers,
284: NULL,
285: sapi_tux_read_post,
286: sapi_tux_read_cookies,
287:
288: sapi_tux_register_variables,
289: NULL, /* Log message */
290: NULL, /* Get request time */
291: NULL, /* Child terminate */
292:
293: STANDARD_SAPI_MODULE_PROPERTIES
294: };
295:
296: static void tux_module_main(TSRMLS_D)
297: {
298: zend_file_handle file_handle;
299:
300: file_handle.type = ZEND_HANDLE_FILENAME;
301: file_handle.filename = SG(request_info).path_translated;
302: file_handle.free_filename = 0;
303: file_handle.opened_path = NULL;
304:
305: if (php_request_startup(TSRMLS_C) == FAILURE) {
306: return;
307: }
308:
309: php_execute_script(&file_handle TSRMLS_CC);
310: php_request_shutdown(NULL);
311: }
312:
313: static void tux_request_ctor(TSRMLS_D)
314: {
315: char buf[1024];
316: int offset;
317: size_t filename_len;
318: size_t cwd_len;
319: smart_str s = {0};
320: char *p;
321:
322: TG(number_vec) = 0;
323: TG(header_vec) = NULL;
324: SG(request_info).query_string = strdup(TG(req)->query);
325:
326: smart_str_appends_ex(&s, "/", 1);
327: smart_str_appends_ex(&s, TG(req)->query, 1);
328: smart_str_0(&s);
329: p = strchr(s.c, '&');
330: if (p)
331: *p = '\0';
332: SG(request_info).path_translated = s.c;
333:
334: s.c = NULL;
335: smart_str_appendc_ex(&s, '/', 1);
336: smart_str_appends_ex(&s, TG(req)->objectname, 1);
337: smart_str_0(&s);
338: SG(request_info).request_uri = s.c;
339: SG(request_info).request_method = CGI_REQUEST_METHOD(TG(req));
340: if(TG(req)->http_version == HTTP_1_1) SG(request_info).proto_num = 1001;
341: else SG(request_info).proto_num = 1000;
342: SG(sapi_headers).http_response_code = 200;
343: SG(request_info).content_type = TG(req)->content_type;
344: SG(request_info).content_length = 0; /* TG(req)->contentlength; */
345:
346: #if 0
347: php_handle_auth_data(TG(hc)->authorization TSRMLS_CC);
348: #endif
349: }
350:
351: static void tux_request_dtor(TSRMLS_D)
352: {
353: if (TG(header_vec)) {
354: /* free status_line */
355: free(TG(header_vec)[0].iov_base);
356: free(TG(header_vec));
357: }
358: if (SG(request_info).query_string)
359: free(SG(request_info).query_string);
360: free(SG(request_info).request_uri);
361: free(SG(request_info).path_translated);
362: }
363:
364: #if 0
365: static void *separate_thread(void *bla)
366: {
367: int fd;
368: int i = 0;
369:
370: fd = (int) bla;
371:
372: while (i++ < 5) {
373: send(fd, "test<br />\n", 9, 0);
374: sleep(1);
375: }
376:
377: tux(TUX_ACTION_CONTINUE_REQ, (user_req_t *) fd);
378: /* We HAVE to trigger some event on the fd. Otherwise
379: fast_thread won't wake up, so that the eventloop
380: won't be entered -> TUX hangs */
381: shutdown(fd, 2);
382: pthread_exit(NULL);
383: }
384: #endif
385:
386: int TUXAPI_handle_events(user_req_t *req)
387: {
388: TSRMLS_FETCH();
389:
390: if (req->event == PHP_TUX_BACKGROUND_CONN) {
391: tux_closed_conn(req->sock);
392: return tux(TUX_ACTION_FINISH_CLOSE_REQ, req);
393: }
394:
395: TG(req) = req;
396: TG(tux_action) = TUX_ACTION_FINISH_CLOSE_REQ;
397:
398: tux_request_ctor(TSRMLS_C);
399:
400: tux_module_main(TSRMLS_C);
401:
402: tux_request_dtor(TSRMLS_C);
403:
404: return tux(TG(tux_action), req);
405: }
406:
407: void tux_register_on_close(void (*arg)(int))
408: {
409: TG(on_close) = arg;
410: }
411:
412: void tux_closed_conn(int fd)
413: {
414: TSRMLS_FETCH();
415:
416: if (TG(on_close)) TG(on_close)(fd);
417: }
418:
419: int tux_get_fd(void)
420: {
421: TSRMLS_FETCH();
422:
423: return TG(req)->sock;
424: }
425:
426: void tux_set_dont_close(void)
427: {
428: TSRMLS_FETCH();
429:
430: TG(req)->event = PHP_TUX_BACKGROUND_CONN;
431: tux(TUX_ACTION_POSTPONE_REQ, TG(req));
432: TG(tux_action) = TUX_ACTION_EVENTLOOP;
433: }
434:
435: void TUXAPI_init(void)
436: {
437: sapi_startup(&tux_sapi_module);
438: tux_sapi_module.startup(&tux_sapi_module);
439: SG(server_context) = (void *) 1;
440: }
441:
442: void doesnotmatter_fini(void)
443: {
444: if (SG(server_context) != NULL) {
445: tux_sapi_module.shutdown(&tux_sapi_module);
446: sapi_shutdown();
447: }
448: }
449:
450: /*
451: * Local variables:
452: * tab-width: 4
453: * c-basic-offset: 4
454: * End:
455: * vim600: sw=4 ts=4 fdm=marker
456: * vim<600: sw=4 ts=4
457: */