Stan Vassilev | FM wrote:
I suggest header_remove('*') or simply header_remove() /no param/
removes all headers (including the one PHP sets by default), so we can
start with a clear state.
I added header_remove('Foo'). header_remove() without arguments removes
all headers (though Apache still adds some headers that you cannot remove).
I have tested with apache2handler and cgi. I had to change the signature
of SAPI header_handler function and sapi_header_struct, so the other
SAPIs should be updated for this. I am not sure how to test all these?
Creating a testing environment for all those webservers seems like a
huge task.
I am not comfortable with the size of this patch, given my understanding
of the PHP source code and my general C skills, so I am posting this
patch hoping that somebody will pick it up or help me get it into shape.
Christian
Index: ext/standard/basic_functions.c
===================================================================
RCS file: /repository/php-src/ext/standard/basic_functions.c,v
retrieving revision 1.725.2.31.2.64.2.69
diff -u -8 -p -r1.725.2.31.2.64.2.69 basic_functions.c
--- ext/standard/basic_functions.c 5 Nov 2008 21:35:02 -0000
1.725.2.31.2.64.2.69
+++ ext/standard/basic_functions.c 9 Nov 2008 18:37:09 -0000
@@ -1687,16 +1687,21 @@ ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO_EX(arginfo_header, 0, 0, 1)
ZEND_ARG_INFO(0, header)
ZEND_ARG_INFO(0, replace)
ZEND_ARG_INFO(0, http_response_code)
ZEND_END_ARG_INFO()
static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_header_remove, 0, 0, 0)
+ ZEND_ARG_INFO(0, name)
+ZEND_END_ARG_INFO()
+
+static
ZEND_BEGIN_ARG_INFO_EX(arginfo_setcookie, 0, 0, 1)
ZEND_ARG_INFO(0, name)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expires)
ZEND_ARG_INFO(0, path)
ZEND_ARG_INFO(0, domain)
ZEND_ARG_INFO(0, secure)
ZEND_END_ARG_INFO()
@@ -3445,16 +3450,17 @@ const zend_function_entry basic_function
PHP_FE(ini_restore,
arginfo_ini_restore)
PHP_FE(get_include_path,
arginfo_get_include_path)
PHP_FE(set_include_path,
arginfo_set_include_path)
PHP_FE(restore_include_path,
arginfo_restore_include_path)
PHP_FE(setcookie,
arginfo_setcookie)
PHP_FE(setrawcookie,
arginfo_setrawcookie)
PHP_FE(header,
arginfo_header)
+ PHP_FE(header_remove,
arginfo_header_remove)
PHP_FE(headers_sent,
arginfo_headers_sent)
PHP_FE(headers_list,
arginfo_headers_list)
PHP_FE(connection_aborted,
arginfo_connection_aborted)
PHP_FE(connection_status,
arginfo_connection_status)
PHP_FE(ignore_user_abort,
arginfo_ignore_user_abort)
PHP_FE(parse_ini_file,
arginfo_parse_ini_file)
PHP_FE(parse_ini_string,
arginfo_parse_ini_string)
Index: ext/standard/head.c
===================================================================
RCS file: /repository/php-src/ext/standard/head.c,v
retrieving revision 1.84.2.1.2.7.2.5
diff -u -8 -p -r1.84.2.1.2.7.2.5 head.c
--- ext/standard/head.c 21 Oct 2008 22:08:37 -0000 1.84.2.1.2.7.2.5
+++ ext/standard/head.c 9 Nov 2008 18:37:09 -0000
@@ -45,16 +45,30 @@ PHP_FUNCTION(header)
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bl", &ctr.line,
&ctr.line_len, &rep, &ctr.response_code) ==
FAILURE)
return;
sapi_header_op(rep ? SAPI_HEADER_REPLACE:SAPI_HEADER_ADD, &ctr
TSRMLS_CC);
}
/* }}} */
+/* {{{ proto void header_remove([string name])
+ Removes an HTTP header previously set using header() */
+PHP_FUNCTION(header_remove)
+{
+ sapi_header_line ctr = {0};
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &ctr.line,
+ &ctr.line_len) == FAILURE)
+ return;
+
+ sapi_header_op(ZEND_NUM_ARGS() == 0 ? SAPI_HEADER_DELETE_ALL :
SAPI_HEADER_DELETE, &ctr TSRMLS_CC);
+}
+/* }}} */
+
PHPAPI int php_header(TSRMLS_D)
{
if (sapi_send_headers(TSRMLS_C)==FAILURE ||
SG(request_info).headers_only) {
return 0; /* don't allow output */
} else {
return 1; /* allow output */
}
}
Index: ext/standard/head.h
===================================================================
RCS file: /repository/php-src/ext/standard/head.h,v
retrieving revision 1.28.2.1.2.2.2.1
diff -u -8 -p -r1.28.2.1.2.2.2.1 head.h
--- ext/standard/head.h 31 Dec 2007 07:17:15 -0000 1.28.2.1.2.2.2.1
+++ ext/standard/head.h 9 Nov 2008 18:37:09 -0000
@@ -18,16 +18,17 @@
/* $Id: head.h,v 1.28.2.1.2.2.2.1 2007/12/31 07:17:15 sebastian Exp $ */
#ifndef HEAD_H
#define HEAD_H
extern PHP_RINIT_FUNCTION(head);
PHP_FUNCTION(header);
+PHP_FUNCTION(header_remove);
PHP_FUNCTION(setcookie);
PHP_FUNCTION(setrawcookie);
PHP_FUNCTION(headers_sent);
PHP_FUNCTION(headers_list);
PHPAPI int php_header(TSRMLS_D);
PHPAPI int php_setcookie(char *name, int name_len, char *value, int value_len,
time_t expires, char *path, int path_len, char *domain, int domain_len, int
secure, int url_encode, int httponly TSRMLS_DC);
Index: main/SAPI.c
===================================================================
RCS file: /repository/php-src/main/SAPI.c,v
retrieving revision 1.202.2.7.2.15.2.4
diff -u -8 -p -r1.202.2.7.2.15.2.4 SAPI.c
--- main/SAPI.c 18 Mar 2008 21:42:50 -0000 1.202.2.7.2.15.2.4
+++ main/SAPI.c 9 Nov 2008 18:37:09 -0000
@@ -492,17 +492,18 @@ static void sapi_update_response_code(in
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;
+ int len = strlen((char*)element2);
+ return strncasecmp(((sapi_header_struct*)element1)->header,
(char*)element2, len) == 0 && ((sapi_header_struct*)element1)->header[len] ==
':';
}
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;
@@ -520,17 +521,16 @@ SAPI_API int sapi_add_header_ex(char *he
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 modify header
information - headers already sent by (output started at %s:%d)",
@@ -541,57 +541,78 @@ SAPI_API int sapi_header_op(sapi_header_
return FAILURE;
}
switch (op) {
case SAPI_HEADER_SET_STATUS:
sapi_update_response_code((int)(zend_intptr_t) arg
TSRMLS_CC);
return SUCCESS;
+ case SAPI_HEADER_ADD:
case SAPI_HEADER_REPLACE:
- case SAPI_HEADER_ADD: {
+ case SAPI_HEADER_DELETE: {
sapi_header_line *p = arg;
if (!p->line || !p->line_len) {
return FAILURE;
}
header_line = p->line;
header_line_len = p->line_len;
http_response_code = p->response_code;
- replace = (op == SAPI_HEADER_REPLACE);
break;
}
+ case SAPI_HEADER_DELETE_ALL:
+ if (sapi_module.header_handler) {
+ sapi_module.header_handler(&sapi_header, op,
&SG(sapi_headers) TSRMLS_CC);
+ }
+ zend_llist_clean(&SG(sapi_headers).headers);
+ return SUCCESS;
+
default:
return FAILURE;
}
header_line = estrndup(header_line, header_line_len);
/* cut of trailing spaces, linefeeds and carriage-returns */
while(header_line_len && isspace(header_line[header_line_len-1]))
header_line[--header_line_len]='\0';
- /* new line safety check */
- {
+ if (op == SAPI_HEADER_DELETE) {
+ if (strchr(header_line, ':')) {
+ efree(header_line);
+ sapi_module.sapi_error(E_WARNING, "Header to delete may
not contain colon.");
+ return FAILURE;
+ }
+ } else {
+ /* new line safety check */
char *s = header_line, *e = header_line + header_line_len, *p;
while (s < e && (p = memchr(s, '\n', (e - s)))) {
if (*(p + 1) == ' ' || *(p + 1) == '\t') {
s = p + 1;
continue;
}
efree(header_line);
sapi_module.sapi_error(E_WARNING, "Header may not
contain more than a single header, new line detected.");
return FAILURE;
}
}
sapi_header.header = header_line;
sapi_header.header_len = header_line_len;
- sapi_header.replace = replace;
+
+ if (op == SAPI_HEADER_DELETE) {
+ if (sapi_module.header_handler) {
+ sapi_module.header_handler(&sapi_header, op,
&SG(sapi_headers) TSRMLS_CC);
+ }
+ zend_llist_del_element(&SG(sapi_headers).headers,
sapi_header.header, (int(*)(void*, void*))sapi_find_matching_header);
+ sapi_free_header(&sapi_header);
+ return SUCCESS;
+ }
/* Check the header for a few cases that we have special support for in
SAPI */
if (header_line_len>=5
&& !strncasecmp(header_line, "HTTP/", 5)) {
/* filter out the response code */
sapi_update_response_code(sapi_extract_response_code(header_line) TSRMLS_CC);
/* sapi_update_response_code doesn't free the status line if
the code didn't change */
if (SG(sapi_headers).http_status_line) {
@@ -723,30 +744,26 @@ SAPI_API int sapi_header_op(sapi_header_
*colon_offset = ':';
}
}
}
if (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);
+ retval = sapi_module.header_handler(&sapi_header, op,
&SG(sapi_headers) TSRMLS_CC);
} else {
retval = SAPI_HEADER_ADD;
}
- if (retval & SAPI_HEADER_DELETE_ALL) {
- zend_llist_clean(&SG(sapi_headers).headers);
- }
if (retval & SAPI_HEADER_ADD) {
/* in replace mode first remove the header if it already exists
in the headers llist */
- if (replace) {
+ if (op == SAPI_HEADER_REPLACE) {
colon_offset = strchr(sapi_header.header, ':');
if (colon_offset) {
char sav;
- colon_offset++;
sav = *colon_offset;
*colon_offset = 0;
zend_llist_del_element(&SG(sapi_headers).headers, sapi_header.header,
(int(*)(void*, void*))sapi_find_matching_header);
*colon_offset = sav;
}
}
zend_llist_add_element(&SG(sapi_headers).headers, (void *)
&sapi_header);
Index: main/SAPI.h
===================================================================
RCS file: /repository/php-src/main/SAPI.h,v
retrieving revision 1.114.2.1.2.3.2.3
diff -u -8 -p -r1.114.2.1.2.3.2.3 SAPI.h
--- main/SAPI.h 18 Mar 2008 21:42:50 -0000 1.114.2.1.2.3.2.3
+++ main/SAPI.h 9 Nov 2008 18:37:09 -0000
@@ -45,17 +45,16 @@
# define SAPI_API
#endif
#undef shutdown
typedef struct {
char *header;
uint header_len;
- zend_bool replace;
} sapi_header_struct;
typedef struct {
zend_llist headers;
int http_response_code;
unsigned char send_default_content_type;
char *mimetype;
@@ -165,16 +164,18 @@ 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_DELETE, /* sapi_header_line* */
+ SAPI_HEADER_DELETE_ALL, /* void
*/
SAPI_HEADER_SET_STATUS /* int
*/
} sapi_header_op_enum;
BEGIN_EXTERN_C()
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);
@@ -222,17 +223,17 @@ struct _sapi_module_struct {
int (*ub_write)(const char *str, unsigned int str_length TSRMLS_DC);
void (*flush)(void *server_context);
struct stat *(*get_stat)(TSRMLS_D);
char *(*getenv)(char *name, size_t name_len TSRMLS_DC);
void (*sapi_error)(int type, const char *error_msg, ...);
- int (*header_handler)(sapi_header_struct *sapi_header,
sapi_headers_struct *sapi_headers TSRMLS_DC);
+ int (*header_handler)(sapi_header_struct *sapi_header,
sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC);
int (*send_headers)(sapi_headers_struct *sapi_headers TSRMLS_DC);
void (*send_header)(sapi_header_struct *sapi_header, void
*server_context TSRMLS_DC);
int (*read_post)(char *buffer, uint count_bytes TSRMLS_DC);
char *(*read_cookies)(TSRMLS_D);
void (*register_server_variables)(zval *track_vars_array TSRMLS_DC);
void (*log_message)(char *message);
@@ -270,18 +271,16 @@ struct _sapi_post_entry {
char *content_type;
uint content_type_len;
void (*post_reader)(TSRMLS_D);
void (*post_handler)(char *content_type_dup, void *arg TSRMLS_DC);
};
/* header_handler() constants */
#define SAPI_HEADER_ADD (1<<0)
-#define SAPI_HEADER_DELETE_ALL (1<<1)
-#define SAPI_HEADER_SEND_NOW (1<<2)
#define SAPI_HEADER_SENT_SUCCESSFULLY 1
#define SAPI_HEADER_DO_SEND 2
#define SAPI_HEADER_SEND_FAILED 3
#define SAPI_DEFAULT_MIMETYPE "text/html"
#define SAPI_DEFAULT_CHARSET ""
Index: sapi/apache2handler/sapi_apache2.c
===================================================================
RCS file: /repository/php-src/sapi/apache2handler/sapi_apache2.c,v
retrieving revision 1.57.2.10.2.15.2.3
diff -u -8 -p -r1.57.2.10.2.15.2.3 sapi_apache2.c
--- sapi/apache2handler/sapi_apache2.c 18 Mar 2008 22:23:20 -0000
1.57.2.10.2.15.2.3
+++ sapi/apache2handler/sapi_apache2.c 9 Nov 2008 18:37:09 -0000
@@ -78,50 +78,60 @@ php_apache_sapi_ub_write(const char *str
if (ap_rwrite(str, str_length, r) < 0) {
php_handle_aborted_connection();
}
return str_length; /* we always consume all the data passed to us. */
}
static int
-php_apache_sapi_header_handler(sapi_header_struct
*sapi_header,sapi_headers_struct *sapi_headers TSRMLS_DC)
+php_apache_sapi_header_handler(sapi_header_struct *sapi_header,
sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC)
{
php_struct *ctx;
char *val, *ptr;
ctx = SG(server_context);
- val = strchr(sapi_header->header, ':');
-
- if (!val) {
- sapi_free_header(sapi_header);
- return 0;
- }
- ptr = val;
+ switch (op) {
+ case SAPI_HEADER_DELETE:
+ apr_table_unset(ctx->r->headers_out,
sapi_header->header);
+ return 0;
+
+ case SAPI_HEADER_DELETE_ALL:
+ apr_table_clear(ctx->r->headers_out);
+ return 0;
+
+ case SAPI_HEADER_ADD:
+ case SAPI_HEADER_REPLACE:
+ val = strchr(sapi_header->header, ':');
+
+ if (!val) {
+ sapi_free_header(sapi_header);
+ return 0;
+ }
+ ptr = val;
- *val = '\0';
+ *val = '\0';
- do {
- val++;
- } while (*val == ' ');
-
- if (!strcasecmp(sapi_header->header, "content-type")) {
- if (ctx->content_type) {
- efree(ctx->content_type);
- }
- ctx->content_type = estrdup(val);
- } else if (sapi_header->replace) {
- apr_table_set(ctx->r->headers_out, sapi_header->header, val);
- } else {
- apr_table_add(ctx->r->headers_out, sapi_header->header, val);
+ do {
+ val++;
+ } while (*val == ' ');
+
+ if (!strcasecmp(sapi_header->header, "content-type")) {
+ if (ctx->content_type) {
+ efree(ctx->content_type);
+ }
+ ctx->content_type = estrdup(val);
+ } else if (op == SAPI_HEADER_REPLACE) {
+ apr_table_set(ctx->r->headers_out,
sapi_header->header, val);
+ } else {
+ apr_table_add(ctx->r->headers_out,
sapi_header->header, val);
+ }
+ return SAPI_HEADER_ADD;
}
- *ptr = ':';
-
- return SAPI_HEADER_ADD;
}
static int
php_apache_sapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
{
php_struct *ctx = SG(server_context);
const char *sline = SG(sapi_headers).http_status_line;
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php