]> granicus.if.org Git - php/commitdiff
MFB: Added header_remove() (chsc at peytz dotdk, Arnaud)
authorArnaud Le Blanc <lbarnaud@php.net>
Thu, 13 Nov 2008 10:33:08 +0000 (10:33 +0000)
committerArnaud Le Blanc <lbarnaud@php.net>
Thu, 13 Nov 2008 10:33:08 +0000 (10:33 +0000)
ext/standard/basic_functions.c
ext/standard/head.c
ext/standard/head.h
main/SAPI.c
main/SAPI.h
sapi/apache/mod_php.c
sapi/apache2handler/sapi_apache2.c
sapi/cgi/tests/011.phpt [new file with mode: 0644]
sapi/cli/php_cli.c

index 071c624dd33dbbac04ee569333d6beeb204b4161..6b9370245987bee655717a9c2d34caa43bfe4540 100644 (file)
@@ -1678,6 +1678,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_header, 0, 0, 1)
        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)
@@ -3479,6 +3484,7 @@ const zend_function_entry basic_functions[] = { /* {{{ */
        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)
 
index eca60369ed6b4d5e903ad75a48330c15700c99b7..1b10266894bb231e4925cca8fb4e8bbc9ae501a0 100644 (file)
@@ -50,6 +50,20 @@ PHP_FUNCTION(header)
 }
 /* }}} */
 
+/* {{{ proto void header_remove([string name]) U
+   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, UG(ascii_conv)) == 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) {
index 81abf7094f5bc1cee2085769e6b1e9eff50e785b..54dce2685b7c2dbddce0a3590ea555efb5489b07 100644 (file)
@@ -23,6 +23,7 @@
 
 extern PHP_RINIT_FUNCTION(head);
 PHP_FUNCTION(header);
+PHP_FUNCTION(header_remove);
 PHP_FUNCTION(setcookie);
 PHP_FUNCTION(setrawcookie);
 PHP_FUNCTION(headers_sent);
index 1ee7971903f7fc8b8b2843a337b457a33ee0c903..1810a1451db01f99fda44f50a90642fa7c861fef 100644 (file)
@@ -520,7 +520,8 @@ static void sapi_update_response_code(int ncode TSRMLS_DC)
 
 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)
@@ -548,7 +549,6 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
        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) {
@@ -569,8 +569,9 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
                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) {
@@ -579,9 +580,15 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
                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;
@@ -593,8 +600,14 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
        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') {
@@ -609,7 +622,15 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
 
        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 
@@ -688,20 +709,16 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
                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);
@@ -710,6 +727,8 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
                }
 
                zend_llist_add_element(&SG(sapi_headers).headers, (void *) &sapi_header);
+       } else {
+               sapi_free_header(&sapi_header);
        }
        return SUCCESS;
 }
index ff89c31a0cad8c6a60719e906b128a35b2bd7916..5adc7e9419cc65a9cf90e347932bd1a5d9365059 100644 (file)
@@ -50,7 +50,6 @@
 typedef struct {
        char *header;
        uint header_len;
-       zend_bool replace;
 } sapi_header_struct;
 
 
@@ -170,6 +169,8 @@ typedef struct {
 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;
 
@@ -228,7 +229,7 @@ struct _sapi_module_struct {
 
        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);
 
@@ -277,8 +278,6 @@ struct _sapi_post_entry {
 
 /* 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
index 8f4d93da935a89dbd406b25e9884c4059a099df9..9766b10e0a52c082b1cc1330eb5d7f8345f0011a 100644 (file)
@@ -35,7 +35,7 @@ static void php_save_umask(void);
 static void php_restore_umask(void);
 static int sapi_apache_read_post(char *buffer, uint count_bytes TSRMLS_DC);
 static char *sapi_apache_read_cookies(TSRMLS_D);
-static int sapi_apache_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC);
+static int sapi_apache_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC);
 static int sapi_apache_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC);
 static int send_php(request_rec *r, int display_source_mode, char *filename);
 static int send_parsed_php(request_rec * r);
@@ -163,41 +163,54 @@ static char *sapi_apache_read_cookies(TSRMLS_D)
 
 /* {{{ sapi_apache_header_handler
  */
-static int sapi_apache_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC)
+static int sapi_apache_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC)
 {
        char *header_name, *header_content, *p;
        request_rec *r = (request_rec *) SG(server_context);
        if(!r) {
-               efree(sapi_header->header);
                return 0;
        }
-      
-       header_name = sapi_header->header;
 
-       header_content = p = strchr(header_name, ':');
-       if (!p) {
-               efree(sapi_header->header);
-               return 0;
-       }
+       switch(op) {
+               case SAPI_HEADER_DELETE_ALL:
+                       clear_table(r->headers_out);
+                       return 0;
 
-       *p = 0;
-       do {
-               header_content++;
-       } while (*header_content==' ');
-
-       if (!strcasecmp(header_name, "Content-Type")) {
-               r->content_type = pstrdup(r->pool, header_content);
-       } else if (!strcasecmp(header_name, "Set-Cookie")) {
-               table_add(r->headers_out, header_name, header_content);
-       } else if (sapi_header->replace) {
-               table_set(r->headers_out, header_name, header_content);
-       } else {
-               table_add(r->headers_out, header_name, header_content);
-       }
+               case SAPI_HEADER_DELETE:
+                       table_unset(r->headers_out, sapi_header->header);
+                       return 0;
+
+               case SAPI_HEADER_ADD:
+               case SAPI_HEADER_REPLACE:
+                       header_name = sapi_header->header;
 
-       *p = ':';  /* a well behaved header handler shouldn't change its original arguments */
+                       header_content = p = strchr(header_name, ':');
+                       if (!p) {
+                               return 0;
+                       }
 
-       return SAPI_HEADER_ADD;
+                       *p = 0;
+                       do {
+                               header_content++;
+                       } while (*header_content==' ');
+
+                       if (!strcasecmp(header_name, "Content-Type")) {
+                               r->content_type = pstrdup(r->pool, header_content);
+                       } else if (!strcasecmp(header_name, "Set-Cookie")) {
+                               table_add(r->headers_out, header_name, header_content);
+                       } else if (op == SAPI_HEADER_REPLACE) {
+                               table_set(r->headers_out, header_name, header_content);
+                       } else {
+                               table_add(r->headers_out, header_name, header_content);
+                       }
+
+                       *p = ':';  /* a well behaved header handler shouldn't change its original arguments */
+
+                       return SAPI_HEADER_ADD;
+
+               default:
+                       return 0;
+       }
 }
 /* }}} */
 
index 9773c581f300802699d941f67315b5662cf24516..d410b788231f7e641759074446d25eac37dc4022 100644 (file)
@@ -83,40 +83,55 @@ php_apache_sapi_ub_write(const char *str, uint str_length TSRMLS_DC)
 }
 
 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, ':');
+       switch (op) {
+               case SAPI_HEADER_DELETE:
+                       apr_table_unset(ctx->r->headers_out, sapi_header->header);
+                       return 0;
 
-       if (!val) {
-               sapi_free_header(sapi_header);
-               return 0;
-       }
-       ptr = val;
+               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, ':');
 
-       *val = '\0';
+                       if (!val) {
+                               return 0;
+                       }
+                       ptr = val;
+
+                       *val = '\0';
        
-       do {
-               val++;
-       } while (*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);
+                       }
 
-       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);
+                       *ptr = ':';
+
+                       return SAPI_HEADER_ADD;
+
+               default:
+                       return 0;
        }
-       *ptr = ':';
-       
-       return SAPI_HEADER_ADD;
 }
 
 static int
diff --git a/sapi/cgi/tests/011.phpt b/sapi/cgi/tests/011.phpt
new file mode 100644 (file)
index 0000000..569024e
--- /dev/null
@@ -0,0 +1,165 @@
+--TEST--
+header_remove()
+--SKIPIF--
+<?php include "skipif.inc"; ?>
+--FILE--
+<?php
+
+include "include.inc";
+
+$php = get_cgi_path();
+reset_env_vars();
+
+$f = tempnam(sys_get_temp_dir(), 'cgitest');
+
+function test($script) {
+       file_put_contents($GLOBALS['f'], $script);
+       $cmd = escapeshellcmd($GLOBALS['php']);
+       $cmd .= ' -n -dreport_zend_debug=0 -dhtml_errors=0 ' . escapeshellarg($GLOBALS['f']);
+       echo "----------\n";
+       echo rtrim($script) . "\n";
+       echo "----------\n";
+       passthru($cmd);
+}
+
+test('<?php ?>');
+test('<?php header_remove(); ?>');
+test('<?php header_remove("X-Foo"); ?>');
+test('<?php
+header("X-Foo: Bar");
+?>');
+test('<?php
+header("X-Foo: Bar");
+header("X-Bar: Baz");
+header_remove("X-Foo");
+?>');
+test('<?php
+header("X-Foo: Bar");
+header_remove("X-Foo: Bar");
+?>');
+test('<?php
+header("X-Foo: Bar");
+header_remove("X-Foo:");
+?>');
+test('<?php
+header("X-Foo: Bar");
+header_remove();
+?>');
+test('<?php
+header_remove("");
+?>');
+test('<?php
+header_remove(":");
+?>');
+test('<?php
+header("X-Foo: Bar");
+echo "flush\n";
+flush();
+header_remove("X-Foo");
+?>');
+
+@unlink($f);
+?>
+--EXPECTF--
+----------
+<?php ?>
+----------
+X-Powered-By: PHP/%s
+Content-type: %s
+
+----------
+<?php header_remove(); ?>
+----------
+Content-type: %s
+
+----------
+<?php header_remove("X-Foo"); ?>
+----------
+X-Powered-By: PHP/%s
+Content-type: %s
+
+----------
+<?php
+header("X-Foo: Bar");
+?>
+----------
+X-Powered-By: PHP/%s
+X-Foo: Bar
+Content-type: %s
+
+----------
+<?php
+header("X-Foo: Bar");
+header("X-Bar: Baz");
+header_remove("X-Foo");
+?>
+----------
+X-Powered-By: PHP/%s
+X-Bar: Baz
+Content-type: %s
+
+----------
+<?php
+header("X-Foo: Bar");
+header_remove("X-Foo: Bar");
+?>
+----------
+X-Powered-By: PHP/%s
+X-Foo: Bar
+Content-type: %s
+
+
+Warning: Header to delete may not contain colon. in %s on line 3
+----------
+<?php
+header("X-Foo: Bar");
+header_remove("X-Foo:");
+?>
+----------
+X-Powered-By: PHP/%s
+X-Foo: Bar
+Content-type: %s
+
+
+Warning: Header to delete may not contain colon. in %s on line 3
+----------
+<?php
+header("X-Foo: Bar");
+header_remove();
+?>
+----------
+Content-type: %s
+
+----------
+<?php
+header_remove("");
+?>
+----------
+X-Powered-By: PHP/%s
+Content-type: %s
+
+----------
+<?php
+header_remove(":");
+?>
+----------
+X-Powered-By: PHP/%s
+Content-type: %s
+
+
+Warning: Header to delete may not contain colon. in %s on line 2
+----------
+<?php
+header("X-Foo: Bar");
+echo "flush\n";
+flush();
+header_remove("X-Foo");
+?>
+----------
+X-Powered-By: PHP/%s
+X-Foo: Bar
+Content-type: %s
+
+flush
+
+Warning: Cannot modify header information - headers already sent by (output started at %s:3) in %s on line 5
index a825fa16bb5274ac0bd34e4841bc679b01af06c3..ae88464e337639119bbe45bbbfbc7d14c7fa0ebe 100644 (file)
@@ -351,11 +351,8 @@ static char* sapi_cli_read_cookies(TSRMLS_D) /* {{{ */
 }
 /* }}} */
 
-static int sapi_cli_header_handler(sapi_header_struct *h, sapi_headers_struct *s TSRMLS_DC) /* {{{ */
+static int sapi_cli_header_handler(sapi_header_struct *h, sapi_header_op_enum op, sapi_headers_struct *s TSRMLS_DC) /* {{{ */
 {
-       /* free allocated header line */
-       efree(h->header);
-       /* avoid pushing headers into SAPI headers list */
        return 0;
 }
 /* }}} */