From 9c876ea01ad806ae6e345c5dc0cf252c0ebe8864 Mon Sep 17 00:00:00 2001 From: Sascha Schumann Date: Wed, 3 Jul 2002 10:42:31 +0000 Subject: [PATCH] Add sapi_header_op interface which supersedes the sapi_add_header and _ex calls. Revert the change to the sapi_add_header_ex interface. Fix various bugs: 1. header("HTTP/1.0 306 foo"); header("Location: absolute-uri"); did not work in combination with several SAPI modules, because http_status_line was never properly reset. And thus, all SAPI modules which looked at http_status_line ignored the changed http_response_code. 2. The CGI SAPI did not send out the HTTP status line at all, if http_status_line had not been set explicitly by calling header("HTTP/1.0 200 foo"); --- ext/standard/head.c | 22 +++++----- main/SAPI.c | 88 +++++++++++++++++++++++++++++---------- main/SAPI.h | 34 +++++++++++++-- sapi/pi3web/pi3web_sapi.c | 12 ++++-- sapi/tux/php_tux.c | 8 ++-- sapi/webjames/webjames.c | 18 +------- 6 files changed, 124 insertions(+), 58 deletions(-) diff --git a/ext/standard/head.c b/ext/standard/head.c index 4e4e74c914..d8cc5345c0 100644 --- a/ext/standard/head.c +++ b/ext/standard/head.c @@ -39,16 +39,14 @@ Sends a raw HTTP header */ PHP_FUNCTION(header) { - char *header; - int header_len; - zend_bool replace = 1; - int http_code = 0; + zend_bool rep = 1; + sapi_header_line ctr = {0}; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bl", &header, - &header_len, &replace, &http_code) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bl", &ctr.line, + &ctr.line_len, &rep, &ctr.response_code) == FAILURE) return; - } - sapi_add_header_ex(header, header_len, 1, replace, http_code TSRMLS_CC); + + sapi_header_op(rep ? SAPI_HEADER_REPLACE:SAPI_HEADER_ADD, &ctr TSRMLS_CC); } /* }}} */ @@ -70,7 +68,8 @@ PHPAPI int php_setcookie(char *name, int name_len, char *value, int value_len, t int len=sizeof("Set-Cookie: "); time_t t; char *dt; - + sapi_header_line ctr = {0}; + len += name_len; if (value) { int encoded_value_len; @@ -122,7 +121,10 @@ PHPAPI int php_setcookie(char *name, int name_len, char *value, int value_len, t strcat(cookie, "; secure"); } - return sapi_add_header_ex(cookie, strlen(cookie), 0, 0, 0 TSRMLS_CC); + ctr.line = cookie; + ctr.line_len = strlen(cookie); + + return sapi_header_op(SAPI_HEADER_ADD, &ctr TSRMLS_CC); } diff --git a/main/SAPI.c b/main/SAPI.c index 0077e277fa..6ac801ebb7 100644 --- a/main/SAPI.c +++ b/main/SAPI.c @@ -385,41 +385,83 @@ static int sapi_extract_response_code(const char *header_line) return code; } + +static void sapi_update_response_code(int ncode TSRMLS_CC) +{ + if (SG(sapi_headers).http_status_line) { + efree(SG(sapi_headers).http_status_line); + SG(sapi_headers).http_status_line = NULL; + } + SG(sapi_headers).http_response_code = ncode; +} + static int sapi_find_matching_header(void *element1, void *element2) { return strncasecmp(((sapi_header_struct*)element1)->header, (char*)element2, strlen((char*)element2)) == 0; } -/* This function expects a *duplicated* string, that was previously emalloc()'d. - * Pointers sent to this functions will be automatically freed by the framework. - */ -SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bool duplicate, zend_bool replace, int http_response_code TSRMLS_DC) +SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bool duplicate, zend_bool replace TSRMLS_DC) +{ + sapi_header_line ctr = {0}; + int r; + + ctr.line = header_line; + ctr.line_len = header_line_len; + + r = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, + &ctr TSRMLS_CC); + + if (!duplicate) + efree(header_line); + + return r; +} + +SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC) { int retval; sapi_header_struct sapi_header; char *colon_offset; long myuid = 0L; - + char *header_line; + uint header_line_len; + zend_bool replace; + int http_response_code; + if (SG(headers_sent) && !SG(request_info).no_headers) { char *output_start_filename = php_get_output_start_filename(TSRMLS_C); int output_start_lineno = php_get_output_start_lineno(TSRMLS_C); if (output_start_filename) { - sapi_module.sapi_error(E_WARNING, "Cannot add header information - headers already sent by (output started at %s:%d)", + sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent by (output started at %s:%d)", output_start_filename, output_start_lineno); } else { - sapi_module.sapi_error(E_WARNING, "Cannot add header information - headers already sent"); - } - if (!duplicate) { - efree(header_line); + sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent"); } return FAILURE; } - if (duplicate) { - header_line = estrndup(header_line, header_line_len); + switch (op) { + case SAPI_HEADER_SET_STATUS: + sapi_update_response_code((int) arg TSRMLS_CC); + return SUCCESS; + + case SAPI_HEADER_REPLACE: + case SAPI_HEADER_ADD: { + sapi_header_line *p = arg; + header_line = p->line; + header_line_len = p->line_len; + http_response_code = p->response_code; + replace = (op == SAPI_HEADER_REPLACE); + break; + } + + default: + return FAILURE; } + header_line = estrndup(header_line, header_line_len); + /* cut of trailing spaces, linefeeds and carriage-returns */ while(isspace(header_line[header_line_len-1])) header_line[--header_line_len]='\0'; @@ -433,7 +475,7 @@ SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bo if (header_line_len>=5 && !strncasecmp(header_line, "HTTP/", 5)) { /* filter out the response code */ - SG(sapi_headers).http_response_code = sapi_extract_response_code(header_line); + sapi_update_response_code(sapi_extract_response_code(header_line) TSRMLS_CC); SG(sapi_headers).http_status_line = header_line; return SUCCESS; } else { @@ -465,7 +507,7 @@ SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bo if (SG(sapi_headers).http_response_code < 300 || SG(sapi_headers).http_response_code > 307) { /* Return a Found Redirect if one is not already specified */ - SG(sapi_headers).http_response_code = 302; + sapi_update_response_code(302 TSRMLS_CC); } } else if (!STRCASECMP(header_line, "WWW-Authenticate")) { /* HTTP Authentication */ int newlen; @@ -476,7 +518,7 @@ SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bo int ptr_len=0, result_len = 0; #endif - SG(sapi_headers).http_response_code = 401; /* authentication-required */ + sapi_update_response_code(401 TSRMLS_CC); /* authentication-required */ #if HAVE_PCRE || HAVE_BUNDLED_PCRE if(PG(safe_mode)) { myuid = php_getuid(); @@ -546,9 +588,8 @@ SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bo } } } - if (http_response_code) { - SG(sapi_headers).http_response_code = http_response_code; + sapi_update_response_code(http_response_code TSRMLS_CC); } if (sapi_module.header_handler) { retval = sapi_module.header_handler(&sapi_header, &SG(sapi_headers) TSRMLS_CC); @@ -602,12 +643,17 @@ SAPI_API int sapi_send_headers(TSRMLS_D) case SAPI_HEADER_SENT_SUCCESSFULLY: ret = SUCCESS; break; - case SAPI_HEADER_DO_SEND: - if (SG(sapi_headers).http_status_line) { + case SAPI_HEADER_DO_SEND: { sapi_header_struct http_status_line; + char buf[255]; - http_status_line.header = SG(sapi_headers).http_status_line; - http_status_line.header_len = strlen(SG(sapi_headers).http_status_line); + if (SG(sapi_headers).http_status_line) { + http_status_line.header = SG(sapi_headers).http_status_line; + http_status_line.header_len = strlen(SG(sapi_headers).http_status_line); + } else { + http_status_line.header = buf; + http_status_line.header_len = sprintf(buf, "HTTP/1.0 %d X", SG(sapi_headers).http_response_code); + } sapi_module.send_header(&http_status_line, SG(server_context) TSRMLS_CC); } zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) sapi_module.send_header, SG(server_context) TSRMLS_CC); diff --git a/main/SAPI.h b/main/SAPI.h index c335b32795..dd2753d9cd 100644 --- a/main/SAPI.h +++ b/main/SAPI.h @@ -133,9 +133,37 @@ SAPI_API void sapi_activate(TSRMLS_D); SAPI_API void sapi_deactivate(TSRMLS_D); SAPI_API void sapi_initialize_empty_request(TSRMLS_D); -SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bool duplicate, zend_bool replace, int http_response_code TSRMLS_DC); -#define sapi_add_header(header_line, header_line_len, duplicate) \ - sapi_add_header_ex((header_line), (header_line_len), (duplicate), 1, 0 TSRMLS_CC) +/* + * This is the preferred and maintained API for + * operating on HTTP headers. + */ + +/* + * Always specify a sapi_header_line this way: + * + * sapi_header_line ctr = {0}; + */ + +typedef struct { + char *line; /* If you allocated this, you need to free it yourself */ + uint line_len; + long response_code; /* long due to zend_parse_parameters compatibility */ +} sapi_header_line; + +typedef enum { /* Parameter: */ + SAPI_HEADER_REPLACE, /* sapi_header_line* */ + SAPI_HEADER_ADD, /* sapi_header_line* */ + SAPI_HEADER_SET_STATUS /* int */ +} sapi_header_op_enum; + +SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC); + + +/* Deprecated functions. Use sapi_header_op instead. */ +SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bool duplicate, zend_bool replace TSRMLS_DC); +#define sapi_add_header(a, b, c) sapi_add_header_ex((a),(b),(c),1 TSRMLS_CC) + + SAPI_API int sapi_send_headers(TSRMLS_D); SAPI_API void sapi_free_header(sapi_header_struct *sapi_header); SAPI_API void sapi_handle_post(void *arg TSRMLS_DC); diff --git a/sapi/pi3web/pi3web_sapi.c b/sapi/pi3web/pi3web_sapi.c index a7176a1b2a..83fe5fdef7 100644 --- a/sapi/pi3web/pi3web_sapi.c +++ b/sapi/pi3web/pi3web_sapi.c @@ -422,9 +422,14 @@ DWORD PHP4_wrapper(LPCONTROL_BLOCK lpCB) }; }; break; - case PHP_MODE_INDENT: - header_line = (char *)estrdup("Content-Type: text/plain"); - sapi_add_header_ex(header_line, strlen(header_line), 1, 1, 0 TSRMLS_CC); + case PHP_MODE_INDENT: { + sapi_header_line ctr = {0}; + + ctr.line = "Content-Type: text/plain"; + ctr.line_len = strlen(ctr.line); + + sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC); + } if ( open_file_for_scanning( &file_handle TSRMLS_CC ) == SUCCESS ) { zend_indent(); @@ -433,7 +438,6 @@ DWORD PHP4_wrapper(LPCONTROL_BLOCK lpCB) { iRet = PIAPI_ERROR; }; - efree(header_line); break; case PHP_MODE_LINT: iRet = (php_lint_script(&file_handle TSRMLS_CC) == SUCCESS) ? diff --git a/sapi/tux/php_tux.c b/sapi/tux/php_tux.c index d2da64882a..4f0b6e17db 100644 --- a/sapi/tux/php_tux.c +++ b/sapi/tux/php_tux.c @@ -192,10 +192,12 @@ static void sapi_tux_register_variables(zval *track_vars_array TSRMLS_DC) { char buf[BUF_SIZE + 1]; char *p; - + sapi_header_line ctr = {0}; + + ctr.line = buf; + ctr.line_len = sprintf(buf, "Server: %s", TUXAPI_version); + sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC); - sprintf(buf, "Server: %s", TUXAPI_version); - sapi_add_header_ex(buf, strlen(buf), 1, 0, 0 TSRMLS_CC); php_register_variable("PHP_SELF", SG(request_info).request_uri, track_vars_array TSRMLS_CC); php_register_variable("SERVER_SOFTWARE", TUXAPI_version, track_vars_array TSRMLS_CC); php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC); diff --git a/sapi/webjames/webjames.c b/sapi/webjames/webjames.c index 1aba413dee..3bea3457e4 100644 --- a/sapi/webjames/webjames.c +++ b/sapi/webjames/webjames.c @@ -54,22 +54,6 @@ static int sapi_webjames_ub_write(const char *str, uint str_length TSRMLS_DC) return bytes; } -static int sapi_webjames_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) -/*send the HTTP response line*/ -{ - char buf[256]; - - if (WG(conn)->flags.outputheaders) { - if (!SG(sapi_headers).http_status_line) { - int code=SG(sapi_headers).http_response_code; - snprintf(buf, 255, "HTTP/1.0 %d %s\r\n", code, code==200 ? "OK" : code==302 ? "Moved temporarily" : "Something"); - webjames_writestring(WG(conn), buf); - } - } - - return SAPI_HEADER_DO_SEND; -} - static void sapi_webjames_send_header(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC) /*send an HTTP header*/ { @@ -286,7 +270,7 @@ static sapi_module_struct sapi_module = { php_error, /* error handler */ NULL, /* header handler */ - sapi_webjames_send_headers, /* send headers handler */ + NULL, /* send headers handler */ sapi_webjames_send_header, /* send header handler */ sapi_webjames_read_post, /* read POST data */ sapi_webjames_read_cookies, /* read Cookies */ -- 2.50.1