~ubuntu-branches/ubuntu/hardy/php5/hardy-updates

« back to all changes in this revision

Viewing changes to sapi/thttpd/thttpd.c

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-10-09 03:14:32 UTC
  • Revision ID: james.westby@ubuntu.com-20051009031432-kspik3lobxstafv9
Tags: upstream-5.0.5
ImportĀ upstreamĀ versionĀ 5.0.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   +----------------------------------------------------------------------+
 
3
   | PHP Version 5                                                        |
 
4
   +----------------------------------------------------------------------+
 
5
   | Copyright (c) 1997-2004 The PHP Group                                |
 
6
   +----------------------------------------------------------------------+
 
7
   | This source file is subject to version 3.0 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_0.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
/* $Id: thttpd.c,v 1.92 2004/01/08 08:18:18 andi Exp $ */
 
20
 
 
21
#include "php.h"
 
22
#include "SAPI.h"
 
23
#include "php_main.h"
 
24
#include "php_thttpd.h"
 
25
#include "php_variables.h"
 
26
#include "version.h"
 
27
#include "php_ini.h"
 
28
#include "zend_highlight.h"
 
29
 
 
30
#include "ext/standard/php_smart_str.h"
 
31
 
 
32
#include <sys/time.h>
 
33
#include <sys/types.h>
 
34
#include <sys/uio.h>
 
35
#include <stdlib.h>
 
36
#include <unistd.h>
 
37
 
 
38
#ifdef HAVE_GETNAMEINFO
 
39
#include <sys/socket.h>
 
40
#include <netdb.h>
 
41
#endif
 
42
 
 
43
typedef struct {
 
44
        httpd_conn *hc;
 
45
        void (*on_close)(int);
 
46
 
 
47
        size_t unconsumed_length;
 
48
        smart_str sbuf;
 
49
        int seen_cl;
 
50
        int seen_cn;
 
51
} php_thttpd_globals;
 
52
 
 
53
#define PHP_SYS_CALL(x) do { x } while (n == -1 && errno == EINTR)
 
54
 
 
55
#ifdef PREMIUM_THTTPD
 
56
# define do_keep_alive persistent
 
57
#endif
 
58
 
 
59
#ifdef ZTS
 
60
static int thttpd_globals_id;
 
61
#define TG(v) TSRMG(thttpd_globals_id, php_thttpd_globals *, v)
 
62
#else
 
63
static php_thttpd_globals thttpd_globals;
 
64
#define TG(v) (thttpd_globals.v)
 
65
#endif
 
66
 
 
67
static int sapi_thttpd_ub_write(const char *str, uint str_length TSRMLS_DC)
 
68
{
 
69
        int n;
 
70
        uint sent = 0;
 
71
        
 
72
        if (TG(sbuf).c != 0) {
 
73
                smart_str_appendl_ex(&TG(sbuf), str, str_length, 1);
 
74
                return str_length;
 
75
        }
 
76
        
 
77
        while (str_length > 0) {
 
78
                PHP_SYS_CALL(n = send(TG(hc)->conn_fd, str, str_length, 0););
 
79
 
 
80
                if (n == -1) {
 
81
                        if (errno == EAGAIN) {
 
82
                                smart_str_appendl_ex(&TG(sbuf), str, str_length, 1);
 
83
 
 
84
                                return sent + str_length;
 
85
                        } else
 
86
                                php_handle_aborted_connection();
 
87
                }
 
88
 
 
89
                TG(hc)->bytes_sent += n;
 
90
                str += n;
 
91
                sent += n;
 
92
                str_length -= n;
 
93
        }
 
94
 
 
95
        return sent;
 
96
}
 
97
 
 
98
#define COMBINE_HEADERS 64
 
99
 
 
100
#if defined(IOV_MAX)
 
101
# if IOV_MAX - 64 <= 0
 
102
#  define SERIALIZE_HEADERS
 
103
# endif
 
104
#endif
 
105
 
 
106
static int do_writev(struct iovec *vec, int nvec, int len TSRMLS_DC)
 
107
{
 
108
        int n;
 
109
 
 
110
        assert(nvec <= IOV_MAX);
 
111
 
 
112
        if (TG(sbuf).c == 0) {
 
113
                PHP_SYS_CALL(n = writev(TG(hc)->conn_fd, vec, nvec););
 
114
 
 
115
                if (n == -1) {
 
116
                        if (errno == EAGAIN) {
 
117
                                n = 0;
 
118
                        } else {
 
119
                                php_handle_aborted_connection();
 
120
                        }
 
121
                }
 
122
 
 
123
 
 
124
                TG(hc)->bytes_sent += n;
 
125
        } else {
 
126
                n = 0;
 
127
        }
 
128
 
 
129
        if (n < len) {
 
130
                int i;
 
131
 
 
132
                /* merge all unwritten data into sbuf */
 
133
                for (i = 0; i < nvec; vec++, i++) {
 
134
                        /* has this vector been written completely? */
 
135
                        if (n >= vec->iov_len) {
 
136
                                /* yes, proceed */
 
137
                                n -= vec->iov_len;
 
138
                                continue;
 
139
                        }
 
140
 
 
141
                        if (n > 0) {
 
142
                                /* adjust vector */
 
143
                                vec->iov_base = (char *) vec->iov_base + n;
 
144
                                vec->iov_len -= n;
 
145
                                n = 0;
 
146
                        }
 
147
 
 
148
                        smart_str_appendl_ex(&TG(sbuf), vec->iov_base, vec->iov_len, 1);
 
149
                }
 
150
        }
 
151
        
 
152
        return 0;
 
153
}
 
154
 
 
155
#ifdef SERIALIZE_HEADERS
 
156
# define ADD_VEC(str,l) smart_str_appendl(&vec_str, (str), (l))
 
157
# define VEC_BASE() smart_str vec_str = {0}
 
158
# define VEC_FREE() smart_str_free(&vec_str)
 
159
#else
 
160
# define ADD_VEC(str,l) vec[n].iov_base=str;len += (vec[n].iov_len=l); n++
 
161
# define VEC_BASE() struct iovec vec[COMBINE_HEADERS]
 
162
# define VEC_FREE() do {} while (0)
 
163
#endif
 
164
 
 
165
#define ADD_VEC_S(str) ADD_VEC((str), sizeof(str)-1)
 
166
 
 
167
#define CL_TOKEN "Content-length: "
 
168
#define CN_TOKEN "Connection: "
 
169
#define KA_DO "Connection: keep-alive\r\n"
 
170
#define KA_NO "Connection: close\r\n"
 
171
#define DEF_CT "Content-Type: text/html\r\n"
 
172
 
 
173
static int sapi_thttpd_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
 
174
{
 
175
        char buf[1024], *p;
 
176
        VEC_BASE();
 
177
        int n = 0;
 
178
        zend_llist_position pos;
 
179
        sapi_header_struct *h;
 
180
        size_t len = 0;
 
181
        
 
182
        if (!SG(sapi_headers).http_status_line) {
 
183
                ADD_VEC_S("HTTP/1.1 ");
 
184
                p = smart_str_print_long(buf+sizeof(buf)-1, 
 
185
                                SG(sapi_headers).http_response_code);
 
186
                ADD_VEC(p, strlen(p));
 
187
                ADD_VEC_S(" HTTP\r\n");
 
188
        } else {
 
189
                ADD_VEC(SG(sapi_headers).http_status_line, 
 
190
                                strlen(SG(sapi_headers).http_status_line));
 
191
                ADD_VEC("\r\n", 2);
 
192
        }
 
193
        TG(hc)->status = SG(sapi_headers).http_response_code;
 
194
 
 
195
        if (SG(sapi_headers).send_default_content_type) {
 
196
                ADD_VEC(DEF_CT, strlen(DEF_CT));
 
197
        }
 
198
 
 
199
        h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
 
200
        while (h) {
 
201
                
 
202
                switch (h->header[0]) {
 
203
                        case 'c': case 'C':
 
204
                                if (!TG(seen_cl) && strncasecmp(h->header, CL_TOKEN, sizeof(CL_TOKEN)-1) == 0) {
 
205
                                        TG(seen_cl) = 1;
 
206
                                } else if (!TG(seen_cn) && strncasecmp(h->header, CN_TOKEN, sizeof(CN_TOKEN)-1) == 0) {
 
207
                                        TG(seen_cn) = 1;
 
208
                                }
 
209
                }
 
210
 
 
211
                ADD_VEC(h->header, h->header_len);
 
212
#ifndef SERIALIZE_HEADERS
 
213
                if (n >= COMBINE_HEADERS - 1) {
 
214
                        len = do_writev(vec, n, len TSRMLS_CC);
 
215
                        n = 0;
 
216
                }
 
217
#endif
 
218
                ADD_VEC("\r\n", 2);
 
219
                
 
220
                h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);
 
221
        }
 
222
 
 
223
        if (TG(seen_cl) && !TG(seen_cn) && TG(hc)->do_keep_alive) {
 
224
                ADD_VEC(KA_DO, sizeof(KA_DO)-1);
 
225
        } else {
 
226
                TG(hc)->do_keep_alive = 0;
 
227
                ADD_VEC(KA_NO, sizeof(KA_NO)-1);
 
228
        }
 
229
                
 
230
        ADD_VEC("\r\n", 2);
 
231
 
 
232
#ifdef SERIALIZE_HEADERS
 
233
        sapi_thttpd_ub_write(vec_str.c, vec_str.len TSRMLS_CC);
 
234
#else                   
 
235
        do_writev(vec, n, len TSRMLS_CC);
 
236
#endif
 
237
 
 
238
        VEC_FREE();
 
239
 
 
240
        return SAPI_HEADER_SENT_SUCCESSFULLY;
 
241
}
 
242
 
 
243
/* to understand this, read cgi_interpose_input() in libhttpd.c */
 
244
#define SIZEOF_UNCONSUMED_BYTES() (TG(hc)->read_idx - TG(hc)->checked_idx)
 
245
#define CONSUME_BYTES(n) do { TG(hc)->checked_idx += (n); } while (0)
 
246
 
 
247
 
 
248
static int sapi_thttpd_read_post(char *buffer, uint count_bytes TSRMLS_DC)
 
249
{
 
250
        size_t read_bytes = 0;
 
251
 
 
252
        if (TG(unconsumed_length) > 0) {
 
253
                read_bytes = MIN(TG(unconsumed_length), count_bytes);
 
254
                memcpy(buffer, TG(hc)->read_buf + TG(hc)->checked_idx, read_bytes);
 
255
                TG(unconsumed_length) -= read_bytes;
 
256
                CONSUME_BYTES(read_bytes);
 
257
        }
 
258
        
 
259
        return read_bytes;
 
260
}
 
261
 
 
262
static char *sapi_thttpd_read_cookies(TSRMLS_D)
 
263
{
 
264
        return TG(hc)->cookie;
 
265
}
 
266
 
 
267
#define BUF_SIZE 512
 
268
#define ADD_STRING_EX(name,buf)                                                                 \
 
269
        php_register_variable(name, buf, track_vars_array TSRMLS_CC)
 
270
#define ADD_STRING(name) ADD_STRING_EX((name), buf)
 
271
 
 
272
static void sapi_thttpd_register_variables(zval *track_vars_array TSRMLS_DC)
 
273
{
 
274
        char buf[BUF_SIZE + 1];
 
275
        char *p;
 
276
 
 
277
        php_register_variable("PHP_SELF", SG(request_info).request_uri, track_vars_array TSRMLS_CC);
 
278
        php_register_variable("SERVER_SOFTWARE", SERVER_SOFTWARE, track_vars_array TSRMLS_CC);
 
279
        php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC);
 
280
        php_register_variable("REQUEST_METHOD", (char *) SG(request_info).request_method, track_vars_array TSRMLS_CC);
 
281
        php_register_variable("REQUEST_URI", SG(request_info).request_uri, track_vars_array TSRMLS_CC);
 
282
        php_register_variable("PATH_TRANSLATED", SG(request_info).path_translated, track_vars_array TSRMLS_CC);
 
283
 
 
284
        if (TG(hc)->one_one) {
 
285
                php_register_variable("SERVER_PROTOCOL", "HTTP/1.1", track_vars_array TSRMLS_CC);
 
286
        } else {
 
287
                php_register_variable("SERVER_PROTOCOL", "HTTP/1.0", track_vars_array TSRMLS_CC);
 
288
        }
 
289
 
 
290
        p = httpd_ntoa(&TG(hc)->client_addr);   
 
291
        
 
292
        ADD_STRING_EX("REMOTE_ADDR", p);
 
293
        ADD_STRING_EX("REMOTE_HOST", p);
 
294
 
 
295
        ADD_STRING_EX("SERVER_PORT",
 
296
                        smart_str_print_long(buf + sizeof(buf) - 1,
 
297
                                TG(hc)->hs->port));
 
298
 
 
299
        buf[0] = '/';
 
300
        memcpy(buf + 1, TG(hc)->pathinfo, strlen(TG(hc)->pathinfo) + 1);
 
301
        ADD_STRING("PATH_INFO");
 
302
 
 
303
        buf[0] = '/';
 
304
        memcpy(buf + 1, TG(hc)->origfilename, strlen(TG(hc)->origfilename) + 1);
 
305
        ADD_STRING("SCRIPT_NAME");
 
306
 
 
307
#define CONDADD(name, field)                                                    \
 
308
        if (TG(hc)->field[0]) {                                                         \
 
309
                php_register_variable(#name, TG(hc)->field, track_vars_array TSRMLS_CC); \
 
310
        }
 
311
 
 
312
        CONDADD(QUERY_STRING, query);
 
313
        CONDADD(HTTP_HOST, hdrhost);
 
314
        CONDADD(HTTP_REFERER, referer);
 
315
        CONDADD(HTTP_USER_AGENT, useragent);
 
316
        CONDADD(HTTP_ACCEPT, accept);
 
317
        CONDADD(HTTP_ACCEPT_LANGUAGE, acceptl);
 
318
        CONDADD(HTTP_ACCEPT_ENCODING, accepte);
 
319
        CONDADD(HTTP_COOKIE, cookie);
 
320
        CONDADD(CONTENT_TYPE, contenttype);
 
321
        CONDADD(REMOTE_USER, remoteuser);
 
322
        CONDADD(SERVER_PROTOCOL, protocol);
 
323
 
 
324
        if (TG(hc)->contentlength != -1) {
 
325
                ADD_STRING_EX("CONTENT_LENGTH",
 
326
                                smart_str_print_long(buf + sizeof(buf) - 1, 
 
327
                                        TG(hc)->contentlength));
 
328
        }
 
329
 
 
330
        if (TG(hc)->authorization[0])
 
331
                php_register_variable("AUTH_TYPE", "Basic", track_vars_array TSRMLS_CC);
 
332
}
 
333
 
 
334
static PHP_MINIT_FUNCTION(thttpd)
 
335
{
 
336
        return SUCCESS;
 
337
}
 
338
 
 
339
static zend_module_entry php_thttpd_module = {
 
340
        STANDARD_MODULE_HEADER,
 
341
        "thttpd",
 
342
        NULL,
 
343
        PHP_MINIT(thttpd),
 
344
        NULL,
 
345
        NULL,
 
346
        NULL,
 
347
        NULL, /* info */
 
348
        NULL,
 
349
        STANDARD_MODULE_PROPERTIES
 
350
};
 
351
 
 
352
static int php_thttpd_startup(sapi_module_struct *sapi_module)
 
353
{
 
354
#if PHP_API_VERSION >= 20020918
 
355
        if (php_module_startup(sapi_module, &php_thttpd_module, 1) == FAILURE) {
 
356
#else
 
357
        if (php_module_startup(sapi_module) == FAILURE
 
358
                        || zend_startup_module(&php_thttpd_module) == FAILURE) {
 
359
#endif
 
360
                return FAILURE;
 
361
        }
 
362
        return SUCCESS;
 
363
}
 
364
 
 
365
static int sapi_thttpd_get_fd(int *nfd TSRMLS_DC)
 
366
{
 
367
        if (nfd) *nfd = TG(hc)->conn_fd;
 
368
        return SUCCESS;
 
369
}
 
370
 
 
371
static sapi_module_struct thttpd_sapi_module = {
 
372
        "thttpd",
 
373
        "thttpd",
 
374
        
 
375
        php_thttpd_startup,
 
376
        php_module_shutdown_wrapper,
 
377
        
 
378
        NULL,                                                                   /* activate */
 
379
        NULL,                                                                   /* deactivate */
 
380
 
 
381
        sapi_thttpd_ub_write,
 
382
        NULL,
 
383
        NULL,                                                                   /* get uid */
 
384
        NULL,                                                                   /* getenv */
 
385
 
 
386
        php_error,
 
387
        
 
388
        NULL,
 
389
        sapi_thttpd_send_headers,
 
390
        NULL,
 
391
        sapi_thttpd_read_post,
 
392
        sapi_thttpd_read_cookies,
 
393
 
 
394
        sapi_thttpd_register_variables,
 
395
        NULL,                                                                   /* Log message */
 
396
 
 
397
        NULL,                                                                   /* php.ini path override */
 
398
        NULL,                                                                   /* Block interruptions */
 
399
        NULL,                                                                   /* Unblock interruptions */
 
400
 
 
401
        NULL,
 
402
        NULL,
 
403
        NULL,
 
404
        0,
 
405
        sapi_thttpd_get_fd
 
406
};
 
407
 
 
408
static void thttpd_module_main(int show_source TSRMLS_DC)
 
409
{
 
410
        zend_file_handle file_handle;
 
411
 
 
412
        if (php_request_startup(TSRMLS_C) == FAILURE) {
 
413
                return;
 
414
        }
 
415
        
 
416
        if (show_source) {
 
417
                zend_syntax_highlighter_ini syntax_highlighter_ini;
 
418
 
 
419
                php_get_highlight_struct(&syntax_highlighter_ini);
 
420
                highlight_file(SG(request_info).path_translated, &syntax_highlighter_ini TSRMLS_CC);
 
421
        } else {
 
422
                file_handle.type = ZEND_HANDLE_FILENAME;
 
423
                file_handle.filename = SG(request_info).path_translated;
 
424
                file_handle.free_filename = 0;
 
425
                file_handle.opened_path = NULL;
 
426
 
 
427
                php_execute_script(&file_handle TSRMLS_CC);
 
428
        }
 
429
        
 
430
        php_request_shutdown(NULL);
 
431
}
 
432
 
 
433
static void thttpd_request_ctor(TSRMLS_D)
 
434
{
 
435
        smart_str s = {0};
 
436
 
 
437
        TG(seen_cl) = 0;
 
438
        TG(seen_cn) = 0;
 
439
        TG(sbuf).c = 0;
 
440
        SG(request_info).query_string = TG(hc)->query?strdup(TG(hc)->query):NULL;
 
441
 
 
442
        smart_str_appends_ex(&s, TG(hc)->hs->cwd, 1);
 
443
        smart_str_appends_ex(&s, TG(hc)->expnfilename, 1);
 
444
        smart_str_0(&s);
 
445
        SG(request_info).path_translated = s.c;
 
446
        
 
447
        s.c = NULL;
 
448
        smart_str_appendc_ex(&s, '/', 1);
 
449
        smart_str_appends_ex(&s, TG(hc)->origfilename, 1);
 
450
        smart_str_0(&s);
 
451
        SG(request_info).request_uri = s.c;
 
452
        SG(request_info).request_method = httpd_method_str(TG(hc)->method);
 
453
        SG(sapi_headers).http_response_code = 200;
 
454
        if (TG(hc)->contenttype)
 
455
                SG(request_info).content_type = strdup(TG(hc)->contenttype);
 
456
        SG(request_info).content_length = TG(hc)->contentlength == -1 ? 0
 
457
                : TG(hc)->contentlength;
 
458
 
 
459
        TG(unconsumed_length) = SG(request_info).content_length;
 
460
        
 
461
        php_handle_auth_data(TG(hc)->authorization TSRMLS_CC);
 
462
}
 
463
 
 
464
static void thttpd_request_dtor(TSRMLS_D)
 
465
{
 
466
        smart_str_free_ex(&TG(sbuf), 1);
 
467
        if (SG(request_info).query_string)
 
468
                free(SG(request_info).query_string);
 
469
        free(SG(request_info).request_uri);
 
470
        free(SG(request_info).path_translated);
 
471
        if (SG(request_info).content_type)
 
472
                free(SG(request_info).content_type);
 
473
}
 
474
 
 
475
#ifdef ZTS
 
476
 
 
477
#ifdef TSRM_ST
 
478
#define thread_create_simple_detached(n) st_thread_create(n, NULL, 0, 0)
 
479
#define thread_usleep(n) st_usleep(n)
 
480
#define thread_exit() st_thread_exit(NULL)
 
481
/* No preemption, simple operations are safe */
 
482
#define thread_atomic_inc(n) (++n)
 
483
#define thread_atomic_dec(n) (--n)
 
484
#else
 
485
#error No thread primitives available
 
486
#endif
 
487
 
 
488
/* We might want to replace this with a STAILQ */
 
489
typedef struct qreq {
 
490
        httpd_conn *hc;
 
491
        struct qreq *next;
 
492
} qreq_t;
 
493
 
 
494
static MUTEX_T qr_lock;
 
495
static qreq_t *queued_requests;
 
496
static qreq_t *last_qr;
 
497
static int nr_free_threads;
 
498
static int nr_threads;
 
499
static int max_threads = 50;
 
500
 
 
501
#define HANDLE_STRINGS() { \
 
502
        HANDLE_STR(encodedurl); \
 
503
        HANDLE_STR(decodedurl); \
 
504
        HANDLE_STR(origfilename); \
 
505
        HANDLE_STR(expnfilename); \
 
506
        HANDLE_STR(pathinfo); \
 
507
        HANDLE_STR(query); \
 
508
        HANDLE_STR(referer); \
 
509
        HANDLE_STR(useragent); \
 
510
        HANDLE_STR(accept); \
 
511
        HANDLE_STR(accepte); \
 
512
        HANDLE_STR(acceptl); \
 
513
        HANDLE_STR(cookie); \
 
514
        HANDLE_STR(contenttype); \
 
515
        HANDLE_STR(authorization); \
 
516
        HANDLE_STR(remoteuser); \
 
517
        }
 
518
 
 
519
static httpd_conn *duplicate_conn(httpd_conn *hc, httpd_conn *nhc)
 
520
{
 
521
        memcpy(nhc, hc, sizeof(*nhc));
 
522
 
 
523
#define HANDLE_STR(m) nhc->m = nhc->m ? strdup(nhc->m) : NULL
 
524
        HANDLE_STRINGS();
 
525
#undef HANDLE_STR
 
526
        
 
527
        return nhc;
 
528
}
 
529
 
 
530
static void destroy_conn(httpd_conn *hc)
 
531
{
 
532
#define HANDLE_STR(m) if (hc->m) free(hc->m)
 
533
        HANDLE_STRINGS();
 
534
#undef HANDLE_STR
 
535
}
 
536
 
 
537
static httpd_conn *dequeue_request(void)
 
538
{
 
539
        httpd_conn *ret = NULL;
 
540
        qreq_t *m;
 
541
        
 
542
        tsrm_mutex_lock(qr_lock);
 
543
        if (queued_requests) {
 
544
                m = queued_requests;
 
545
                ret = m->hc;
 
546
                if (!(queued_requests = m->next))
 
547
                        last_qr = NULL;
 
548
                free(m);
 
549
        }
 
550
        tsrm_mutex_unlock(qr_lock);
 
551
        
 
552
        return ret;
 
553
}
 
554
 
 
555
static void *worker_thread(void *);
 
556
 
 
557
static void queue_request(httpd_conn *hc)
 
558
{
 
559
        qreq_t *m;
 
560
        httpd_conn *nhc;
 
561
        
 
562
        /* Mark as long-running request */
 
563
        hc->file_address = (char *) 1;
 
564
 
 
565
        /*
 
566
     * We cannot synchronously revoke accesses to hc in the worker
 
567
         * thread, so we need to pass a copy of hc to the worker thread.
 
568
         */
 
569
        nhc = malloc(sizeof *nhc);
 
570
        duplicate_conn(hc, nhc);
 
571
        
 
572
        /* Allocate request queue container */
 
573
        m = malloc(sizeof *m);
 
574
        m->hc = nhc;
 
575
        m->next = NULL;
 
576
        
 
577
        tsrm_mutex_lock(qr_lock);
 
578
        /* Create new threads when reaching a certain threshhold */
 
579
        if (nr_threads < max_threads && nr_free_threads < 2) {
 
580
                nr_threads++; /* protected by qr_lock */
 
581
                
 
582
                thread_atomic_inc(nr_free_threads);
 
583
                thread_create_simple_detached(worker_thread);
 
584
        }
 
585
        /* Insert container into request queue */
 
586
        if (queued_requests)
 
587
                last_qr->next = m;
 
588
        else
 
589
                queued_requests = m;
 
590
        last_qr = m;
 
591
        tsrm_mutex_unlock(qr_lock);
 
592
}
 
593
 
 
594
static off_t thttpd_real_php_request(httpd_conn *hc, int TSRMLS_DC);
 
595
 
 
596
static void *worker_thread(void *dummy)
 
597
{
 
598
        int do_work = 50;
 
599
        httpd_conn *hc;
 
600
 
 
601
        while (do_work) {
 
602
                hc = dequeue_request();
 
603
 
 
604
                if (!hc) {
 
605
/*                      do_work--; */
 
606
                        thread_usleep(500000);
 
607
                        continue;
 
608
                }
 
609
/*              do_work = 50; */
 
610
 
 
611
                thread_atomic_dec(nr_free_threads);
 
612
 
 
613
                thttpd_real_php_request(hc, 0 TSRMLS_CC);
 
614
                shutdown(hc->conn_fd, 0);
 
615
                destroy_conn(hc);
 
616
                free(hc);
 
617
 
 
618
                thread_atomic_inc(nr_free_threads);
 
619
        }
 
620
        thread_atomic_dec(nr_free_threads);
 
621
        thread_atomic_dec(nr_threads);
 
622
        thread_exit();
 
623
}
 
624
 
 
625
static void remove_dead_conn(int fd)
 
626
{
 
627
        qreq_t *m, *prev = NULL;
 
628
 
 
629
        tsrm_mutex_lock(qr_lock);
 
630
        m = queued_requests;
 
631
        while (m) {
 
632
                if (m->hc->conn_fd == fd) {
 
633
                        if (prev)
 
634
                                if (!(prev->next = m->next))
 
635
                                        last_qr = prev;
 
636
                        else
 
637
                                if (!(queued_requests = m->next))
 
638
                                        last_qr = NULL;
 
639
                        destroy_conn(m->hc);
 
640
                        free(m->hc);
 
641
                        free(m);
 
642
                        break;
 
643
                }
 
644
                prev = m;
 
645
                m = m->next;
 
646
        }
 
647
        tsrm_mutex_unlock(qr_lock);
 
648
}
 
649
 
 
650
#endif
 
651
 
 
652
static off_t thttpd_real_php_request(httpd_conn *hc, int show_source TSRMLS_DC)
 
653
{
 
654
        TG(hc) = hc;
 
655
        hc->bytes_sent = 0;
 
656
 
 
657
        if (hc->contentlength != -1) {
 
658
                hc->should_linger = 1;
 
659
                hc->do_keep_alive = 0;
 
660
        }
 
661
        
 
662
        if (hc->contentlength != -1
 
663
                        && SIZEOF_UNCONSUMED_BYTES() < hc->contentlength) {
 
664
                hc->read_body_into_mem = 1;
 
665
                return 0;
 
666
        }
 
667
        
 
668
        thttpd_request_ctor(TSRMLS_C);
 
669
 
 
670
        thttpd_module_main(show_source TSRMLS_CC);
 
671
 
 
672
        /* disable kl, if no content-length was seen or Connection: was set */
 
673
        if (TG(seen_cl) == 0 || TG(seen_cn) == 1) {
 
674
                TG(hc)->do_keep_alive = 0;
 
675
        }
 
676
        
 
677
        if (TG(sbuf).c != 0) {
 
678
                if (TG(hc)->response)
 
679
                        free(TG(hc)->response);
 
680
                
 
681
                TG(hc)->response = TG(sbuf).c;
 
682
                TG(hc)->responselen = TG(sbuf).len;
 
683
                TG(hc)->maxresponse = TG(sbuf).a;
 
684
 
 
685
                TG(sbuf).c = 0;
 
686
                TG(sbuf).len = 0;
 
687
                TG(sbuf).a = 0;
 
688
        }
 
689
 
 
690
        thttpd_request_dtor(TSRMLS_C);
 
691
 
 
692
        return 0;
 
693
}
 
694
 
 
695
off_t thttpd_php_request(httpd_conn *hc, int show_source)
 
696
{
 
697
#ifdef ZTS
 
698
        queue_request(hc);
 
699
#else
 
700
        TSRMLS_FETCH();
 
701
        return thttpd_real_php_request(hc, show_source TSRMLS_CC);
 
702
#endif
 
703
}
 
704
 
 
705
void thttpd_register_on_close(void (*arg)(int)) 
 
706
{
 
707
        TSRMLS_FETCH();
 
708
        TG(on_close) = arg;
 
709
}
 
710
 
 
711
void thttpd_closed_conn(int fd)
 
712
{
 
713
        TSRMLS_FETCH();
 
714
        if (TG(on_close)) TG(on_close)(fd);
 
715
}
 
716
 
 
717
int thttpd_get_fd(void)
 
718
{
 
719
        TSRMLS_FETCH();
 
720
        return TG(hc)->conn_fd;
 
721
}
 
722
 
 
723
void thttpd_set_dont_close(void)
 
724
{
 
725
        TSRMLS_FETCH();
 
726
#ifndef PREMIUM_THTTPD
 
727
        TG(hc)->file_address = (char *) 1;
 
728
#endif
 
729
}
 
730
 
 
731
 
 
732
void thttpd_php_init(void)
 
733
{
 
734
        char *ini;
 
735
 
 
736
#ifdef ZTS
 
737
        tsrm_startup(1, 1, 0, NULL);
 
738
        ts_allocate_id(&thttpd_globals_id, sizeof(php_thttpd_globals), NULL, NULL);
 
739
        qr_lock = tsrm_mutex_alloc();
 
740
        thttpd_register_on_close(remove_dead_conn);
 
741
#endif
 
742
 
 
743
        if ((ini = getenv("PHP_INI_PATH"))) {
 
744
                thttpd_sapi_module.php_ini_path_override = ini;
 
745
        }
 
746
 
 
747
        sapi_startup(&thttpd_sapi_module);
 
748
        thttpd_sapi_module.startup(&thttpd_sapi_module);
 
749
        
 
750
        {
 
751
                TSRMLS_FETCH();
 
752
 
 
753
                SG(server_context) = (void *) 1;
 
754
        }
 
755
}
 
756
 
 
757
void thttpd_php_shutdown(void)
 
758
{
 
759
        TSRMLS_FETCH();
 
760
 
 
761
        if (SG(server_context) != NULL) {
 
762
                thttpd_sapi_module.shutdown(&thttpd_sapi_module);
 
763
                sapi_shutdown();
 
764
#ifdef ZTS
 
765
                tsrm_shutdown();
 
766
#endif
 
767
        }
 
768
}