|
| 1 | +/* |
| 2 | + +----------------------------------------------------------------------+ |
| 3 | + | PHP version 4.0 | |
| 4 | + +----------------------------------------------------------------------+ |
| 5 | + | Copyright (c) 1997, 1998, 1999 The PHP Group | |
| 6 | + +----------------------------------------------------------------------+ |
| 7 | + | This source file is subject to version 2.0 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_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 | + | [email protected] so we can mail you a copy immediately. | |
| 14 | + +----------------------------------------------------------------------+ |
| 15 | + | Author: Sascha Schumann <[email protected]> | |
| 16 | + +----------------------------------------------------------------------+ |
| 17 | +*/ |
| 18 | + |
| 19 | + |
| 20 | +#include "php.h" |
| 21 | +#include "SAPI.h" |
| 22 | +#include "main.h" |
| 23 | +#include "php_thttpd.h" |
| 24 | +#include "version.h" |
| 25 | + |
| 26 | +typedef struct { |
| 27 | + httpd_conn *hc; |
| 28 | + int post_off; |
| 29 | +} php_thttpd_globals; |
| 30 | + |
| 31 | +static php_thttpd_globals thttpd_globals; |
| 32 | + |
| 33 | +#define TLS_D |
| 34 | +#define TLS_DC |
| 35 | +#define TLS_C |
| 36 | +#define TLS_CC |
| 37 | +#define TG(v) (thttpd_globals.v) |
| 38 | +#define TLS_FETCH() |
| 39 | + |
| 40 | +static int sapi_thttpd_ub_write(const char *str, uint str_length) |
| 41 | +{ |
| 42 | + TLS_FETCH(); |
| 43 | + |
| 44 | + return send(TG(hc)->conn_fd, str, str_length, 0); |
| 45 | +} |
| 46 | + |
| 47 | +static int sapi_thttpd_send_headers(sapi_headers_struct *sapi_headers SLS_DC) |
| 48 | +{ |
| 49 | + char buf[1024]; |
| 50 | + |
| 51 | + if (!SG(sapi_headers).http_status_line) { |
| 52 | + snprintf(buf, 1023, "HTTP/1.0 %d Something\r\n", SG(sapi_headers).http_response_code); |
| 53 | + send(TG(hc)->conn_fd, buf, strlen(buf), 0); |
| 54 | + } |
| 55 | + |
| 56 | + return SAPI_HEADER_DO_SEND; |
| 57 | +} |
| 58 | + |
| 59 | +static void sapi_thttpd_send_header(sapi_header_struct *sapi_header, void *server_context) |
| 60 | +{ |
| 61 | + TLS_FETCH(); |
| 62 | + |
| 63 | + if (sapi_header) |
| 64 | + send(TG(hc)->conn_fd, sapi_header->header, sapi_header->header_len, 0); |
| 65 | + send(TG(hc)->conn_fd, "\r\n", sizeof("\r\n") - 1, 0); |
| 66 | +} |
| 67 | + |
| 68 | +static int sapi_thttpd_read_post(char *buffer, uint count_bytes SLS_DC) |
| 69 | +{ |
| 70 | + size_t read_bytes = 0, tmp; |
| 71 | + int c; |
| 72 | + TLS_FETCH(); |
| 73 | + |
| 74 | + /* to understand this, read cgi_interpose_input() in libhttpd.c */ |
| 75 | + c = TG(hc)->read_idx - TG(hc)->checked_idx; |
| 76 | + if (c > 0) { |
| 77 | + read_bytes = MIN(c, count_bytes); |
| 78 | + memcpy(buffer, TG(hc)->read_buf + TG(hc)->checked_idx, read_bytes); |
| 79 | + TG(hc)->checked_idx += read_bytes; |
| 80 | + count_bytes -= read_bytes; |
| 81 | + } |
| 82 | + |
| 83 | + count_bytes = MIN(count_bytes, |
| 84 | + SG(request_info).content_length - SG(read_post_bytes) - TG(post_off)); |
| 85 | + |
| 86 | + while (read_bytes < count_bytes) { |
| 87 | + tmp = recv(TG(hc)->conn_fd, buffer + read_bytes, |
| 88 | + count_bytes - read_bytes, 0); |
| 89 | + if (tmp <= 0) |
| 90 | + break; |
| 91 | + read_bytes += tmp; |
| 92 | + } |
| 93 | + |
| 94 | + return read_bytes; |
| 95 | +} |
| 96 | + |
| 97 | +static char *sapi_thttpd_read_cookies(SLS_D) |
| 98 | +{ |
| 99 | + TLS_FETCH(); |
| 100 | + |
| 101 | + return TG(hc)->cookie; |
| 102 | +} |
| 103 | + |
| 104 | +static sapi_module_struct sapi_module = { |
| 105 | + "PHP Language", |
| 106 | + |
| 107 | + php_module_startup, |
| 108 | + php_module_shutdown_wrapper, |
| 109 | + |
| 110 | + sapi_thttpd_ub_write, |
| 111 | + php_error, |
| 112 | + |
| 113 | + NULL, |
| 114 | + sapi_thttpd_send_headers, |
| 115 | + sapi_thttpd_send_header, |
| 116 | + sapi_thttpd_read_post, |
| 117 | + sapi_thttpd_read_cookies, |
| 118 | + |
| 119 | + STANDARD_SAPI_MODULE_PROPERTIES |
| 120 | +}; |
| 121 | + |
| 122 | +#define BUF_SIZE 512 |
| 123 | +#define ADD_STRING(name) \ |
| 124 | + MAKE_STD_ZVAL(pval); \ |
| 125 | + pval->type = IS_STRING; \ |
| 126 | + pval->value.str.len = strlen(buf); \ |
| 127 | + pval->value.str.val = estrndup(buf, pval->value.str.len); \ |
| 128 | + zend_hash_update(&EG(symbol_table), name, sizeof(name), \ |
| 129 | + &pval, sizeof(zval *), NULL) |
| 130 | + |
| 131 | +static void thttpd_hash_environment(void) |
| 132 | +{ |
| 133 | + char buf[BUF_SIZE + 1]; |
| 134 | + zval *pval; |
| 135 | + |
| 136 | + buf[BUF_SIZE] = '\0'; |
| 137 | + |
| 138 | + strncpy(buf, SERVER_SOFTWARE, BUF_SIZE); |
| 139 | + ADD_STRING("SERVER_SOFTWARE"); |
| 140 | + |
| 141 | + strncpy(buf, "CGI/1.1", BUF_SIZE); |
| 142 | + ADD_STRING("GATEWAY_INTERFACE"); |
| 143 | + |
| 144 | + snprintf(buf, BUF_SIZE, "%d", TG(hc)->hs->port); |
| 145 | + ADD_STRING("SERVER_PORT"); |
| 146 | + |
| 147 | + strncpy(buf, SG(request_info).request_method, BUF_SIZE); |
| 148 | + ADD_STRING("REQUEST_METHOD"); |
| 149 | + |
| 150 | + strncpy(buf, SG(request_info).request_uri, BUF_SIZE); |
| 151 | + ADD_STRING("REQUEST_URI"); |
| 152 | + |
| 153 | + snprintf(buf, BUF_SIZE, "/%s", TG(hc)->pathinfo); |
| 154 | + ADD_STRING("PATH_INFO"); |
| 155 | + |
| 156 | + strncpy(buf, SG(request_info).path_translated, BUF_SIZE); |
| 157 | + ADD_STRING("PATH_TRANSLATED"); |
| 158 | + |
| 159 | + snprintf(buf, BUF_SIZE, "/%s", TG(hc)->origfilename); |
| 160 | + ADD_STRING("SCRIPT_NAME"); |
| 161 | + |
| 162 | + strncpy(buf, inet_ntoa(TG(hc)->client_addr), BUF_SIZE); |
| 163 | + ADD_STRING("REMOTE_ADDR"); |
| 164 | + ADD_STRING("REMOTE_HOST"); |
| 165 | + |
| 166 | +#define CONDADD(name, field) \ |
| 167 | + if (TG(hc)->field[0]) { \ |
| 168 | + strncpy(buf, TG(hc)->field, BUF_SIZE); \ |
| 169 | + ADD_STRING(#name); \ |
| 170 | + } |
| 171 | + |
| 172 | + CONDADD(HTTP_REFERER, referer); |
| 173 | + CONDADD(HTTP_USER_AGENT, useragent); |
| 174 | + CONDADD(HTTP_ACCEPT, accept); |
| 175 | + CONDADD(HTTP_ACCEPT_ENCODING, accepte); |
| 176 | + CONDADD(HTTP_COOKIE, cookie); |
| 177 | + CONDADD(CONTENT_TYPE, contenttype); |
| 178 | + CONDADD(REMOTE_USER, remoteuser); |
| 179 | + CONDADD(SERVER_PROTOCOL, protocol); |
| 180 | + |
| 181 | + if (TG(hc)->contentlength != -1) { |
| 182 | + sprintf(buf, "%ld", (long) TG(hc)->contentlength); |
| 183 | + ADD_STRING("CONTENT_LENGTH"); |
| 184 | + } |
| 185 | + |
| 186 | + if (TG(hc)->authorization[0]) { |
| 187 | + strcpy(buf, "Basic"); |
| 188 | + ADD_STRING("AUTH_TYPE"); |
| 189 | + } |
| 190 | +} |
| 191 | + |
| 192 | +static void thttpd_module_main(TLS_D SLS_DC) |
| 193 | +{ |
| 194 | + zend_file_handle file_handle; |
| 195 | + CLS_FETCH(); |
| 196 | + ELS_FETCH(); |
| 197 | + PLS_FETCH(); |
| 198 | + |
| 199 | + file_handle.type = ZEND_HANDLE_FILENAME; |
| 200 | + file_handle.filename = TG(hc)->expnfilename; |
| 201 | + file_handle.free_filename = 0; |
| 202 | + |
| 203 | + if (php_request_startup(CLS_C ELS_CC PLS_CC SLS_CC) == FAILURE) { |
| 204 | + return; |
| 205 | + } |
| 206 | + |
| 207 | + thttpd_hash_environment(); |
| 208 | + php_execute_script(&file_handle CLS_CC ELS_CC PLS_CC); |
| 209 | + php_request_shutdown(NULL); |
| 210 | +} |
| 211 | + |
| 212 | +static void thttpd_request_ctor(TLS_D SLS_DC) |
| 213 | +{ |
| 214 | + char *cp2; |
| 215 | + int l; |
| 216 | + char buf[1024]; |
| 217 | + int offset; |
| 218 | + size_t pathinfo_len; |
| 219 | + size_t cwd_len; |
| 220 | + |
| 221 | + pathinfo_len = strlen(TG(hc)->pathinfo); |
| 222 | + cwd_len = strlen(TG(hc)->hs->cwd); |
| 223 | + |
| 224 | + SG(request_info).query_string = TG(hc)->query; |
| 225 | + |
| 226 | + l = cwd_len + pathinfo_len + 1; |
| 227 | + cp2 = (char *) malloc(l); |
| 228 | + sprintf(cp2, "%s%s", TG(hc)->hs->cwd, TG(hc)->pathinfo); |
| 229 | + SG(request_info).path_translated = cp2; |
| 230 | + |
| 231 | + snprintf(buf, 1023, "/%s", TG(hc)->origfilename); |
| 232 | + SG(request_info).request_uri = strdup(buf); |
| 233 | + SG(request_info).request_method = httpd_method_str(TG(hc)->method); |
| 234 | + |
| 235 | + SG(request_info).content_type = TG(hc)->contenttype; |
| 236 | + SG(request_info).content_length = TG(hc)->contentlength; |
| 237 | + |
| 238 | + SG(request_info).auth_user = NULL; |
| 239 | + SG(request_info).auth_password = NULL; |
| 240 | + |
| 241 | + TG(post_off) = TG(hc)->read_idx - TG(hc)->checked_idx; |
| 242 | + |
| 243 | + /* avoid feeding \r\n from POST data to SAPI */ |
| 244 | + offset = TG(post_off) - SG(request_info).content_length; |
| 245 | + |
| 246 | + if (offset > 0) { |
| 247 | + TG(post_off) -= offset; |
| 248 | + TG(hc)->read_idx -= offset; |
| 249 | + } |
| 250 | +} |
| 251 | + |
| 252 | +static void thttpd_request_dtor(TLS_D SLS_DC) |
| 253 | +{ |
| 254 | + free(SG(request_info).request_uri); |
| 255 | + free(SG(request_info).path_translated); |
| 256 | +} |
| 257 | + |
| 258 | +off_t thttpd_php_request(httpd_conn *hc) |
| 259 | +{ |
| 260 | + SLS_FETCH(); |
| 261 | + TLS_FETCH(); |
| 262 | + |
| 263 | + TG(hc) = hc; |
| 264 | + |
| 265 | + thttpd_request_ctor(TLS_C SLS_CC); |
| 266 | + |
| 267 | + thttpd_module_main(TLS_C SLS_CC); |
| 268 | + |
| 269 | + thttpd_request_dtor(TLS_C SLS_CC); |
| 270 | + |
| 271 | + return 0; |
| 272 | +} |
| 273 | + |
| 274 | +void thttpd_php_init(void) |
| 275 | +{ |
| 276 | + sapi_startup(&sapi_module); |
| 277 | + sapi_module.startup(&sapi_module); |
| 278 | + SG(server_context) = (void *) 1; |
| 279 | +} |
| 280 | + |
| 281 | +void thttpd_php_shutdown(void) |
| 282 | +{ |
| 283 | + sapi_module.shutdown(&sapi_module); |
| 284 | + sapi_shutdown(); |
| 285 | +} |
0 commit comments