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

Reply via email to