]> granicus.if.org Git - php/commitdiff
Fixed bug #61548
authorMichael Wallner <mike@php.net>
Tue, 1 Oct 2013 09:07:55 +0000 (11:07 +0200)
committerMichael Wallner <mike@php.net>
Tue, 1 Oct 2013 09:07:55 +0000 (11:07 +0200)
NEWS
ext/standard/http_fopen_wrapper.c
ext/standard/tests/http/bug61548.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 4dc7ef7c18e9daef087e0cb69e06e7de92f7f5aa..9bb60327fa9dd2cff9f3c1bac5e22a5b75b37fe4 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -26,6 +26,10 @@ PHP                                                                        NEWS
   . Fixed bug #65721 (configure script broken in 5.5.4 and 5.4.20 when enabling
     imap). (ryotakatsuki at gmail dot com)
 
+- Standard:
+  . Fixed bug #61548 (content-type must appear at the end of headers for 201 
+    Location to work in http). (Mike)
+
 19 Sep 2013, PHP 5.4.20
 
 - Core:
index b8676bbba4df642ff3ef827a46ddfdaac0d96686..4605e7494fa3de7673f40c0aabd4c8d644f49b79 100644 (file)
 #define HTTP_WRAPPER_HEADER_INIT    1
 #define HTTP_WRAPPER_REDIRECTED     2
 
+static inline void strip_header(char *header_bag, char *lc_header_bag,
+               const char *lc_header_name)
+{
+       char *lc_header_start = strstr(lc_header_bag, lc_header_name);
+       char *header_start = header_bag + (lc_header_start - lc_header_bag);
+
+       if (lc_header_start
+       && (lc_header_start == lc_header_bag || *(lc_header_start-1) == '\n')
+       ) {
+               char *lc_eol = strchr(lc_header_start, '\n');
+               char *eol = header_start + (lc_eol - lc_header_start);
+
+               if (lc_eol) {
+                       size_t eollen = strlen(lc_eol);
+
+                       memmove(lc_header_start, lc_eol+1, eollen);
+                       memmove(header_start, eol+1, eollen);
+               } else {
+                       *lc_header_start = '\0';
+                       *header_start = '\0';
+               }
+       }
+}
+
 php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context, int redirect_max, int flags STREAMS_DC TSRMLS_DC) /* {{{ */
 {
        php_stream *stream = NULL;
@@ -425,40 +449,17 @@ finish:
                if (tmp && strlen(tmp) > 0) {
                        char *s;
 
-                       if (!header_init) { /* Remove post headers for redirects */
-                               int l = strlen(tmp);
-                               char *s2, *tmp_c = estrdup(tmp);
-                               
-                               php_strtolower(tmp_c, l);
-                               if ((s = strstr(tmp_c, "content-length:"))) {
-                                       if ((s2 = memchr(s, '\n', tmp_c + l - s))) {
-                                               int b = tmp_c + l - 1 - s2;
-                                               memmove(tmp, tmp + (s2 + 1 - tmp_c), b);
-                                               memmove(tmp_c, s2 + 1, b);
-                                               
-                                       } else {
-                                               tmp[s - tmp_c] = *s = '\0';
-                                       }
-                                       l = strlen(tmp_c);
-                               }
-                               if ((s = strstr(tmp_c, "content-type:"))) {
-                                       if ((s2 = memchr(s, '\n', tmp_c + l - s))) {
-                                               memmove(tmp, tmp + (s2 + 1 - tmp_c), tmp_c + l - 1 - s2);
-                                       } else {
-                                               tmp[s - tmp_c] = '\0';
-                                       }
-                               }
-
-                               efree(tmp_c);
-                               tmp_c = php_trim(tmp, strlen(tmp), NULL, 0, NULL, 3 TSRMLS_CC);
-                               efree(tmp);
-                               tmp = tmp_c;
-                       }
-
                        user_headers = estrdup(tmp);
 
                        /* Make lowercase for easy comparison against 'standard' headers */
                        php_strtolower(tmp, strlen(tmp));
+
+                       if (!header_init) {
+                               /* strip POST headers on redirect */
+                               strip_header(user_headers, tmp, "content-length:");
+                               strip_header(user_headers, tmp, "content-type:");
+                       }
+
                        if ((s = strstr(tmp, "user-agent:")) && 
                            (s == tmp || *(s-1) == '\r' || *(s-1) == '\n' || 
                                         *(s-1) == '\t' || *(s-1) == ' ')) {
diff --git a/ext/standard/tests/http/bug61548.phpt b/ext/standard/tests/http/bug61548.phpt
new file mode 100644 (file)
index 0000000..138b15a
--- /dev/null
@@ -0,0 +1,118 @@
+--TEST--
+Bug #61548 (content-type must appear at the end of headers)
+--INI--
+allow_url_fopen=1
+--SKIPIF--
+<?php require 'server.inc'; http_server_skipif('tcp://127.0.0.1:12342'); ?>
+--FILE--
+<?php
+require 'server.inc';
+
+function do_test($header) {
+    $options = [
+        'http' => [
+                       'method' => 'POST',
+                       'header' => $header,
+            'follow_location' => true,
+        ],
+    ];
+
+    $ctx = stream_context_create($options);
+
+    $responses = [
+               "data://text/plain,HTTP/1.1 201\r\nLocation: /foo\r\n\r\n",
+               "data://text/plain,HTTP/1.1 200\r\nConnection: close\r\n\r\n",
+       ];
+    $pid = http_server('tcp://127.0.0.1:12342', $responses, $output);
+
+    $fd = fopen('http://127.0.0.1:12342/', 'rb', false, $ctx);
+    fseek($output, 0, SEEK_SET);
+    echo stream_get_contents($output);
+
+    http_server_kill($pid);
+}
+
+do_test("First:1\nSecond:2\nContent-type: text/plain");
+do_test("First:1\nSecond:2\nContent-type: text/plain\n");
+do_test("First:1\nSecond:2\nContent-type: text/plain\nThird:");
+do_test("First:1\nContent-type:text/plain\nSecond:2");
+do_test("First:1\nContent-type:text/plain\nSecond:2\n");
+do_test("First:1\nContent-type:text/plain\nSecond:2\nThird:");
+
+?>
+Done
+--EXPECT--
+POST / HTTP/1.0
+Host: 127.0.0.1:12342
+First:1
+Second:2
+Content-type: text/plain
+
+GET /foo HTTP/1.0
+Host: 127.0.0.1:12342
+First:1
+Second:2
+
+
+POST / HTTP/1.0
+Host: 127.0.0.1:12342
+First:1
+Second:2
+Content-type: text/plain
+
+GET /foo HTTP/1.0
+Host: 127.0.0.1:12342
+First:1
+Second:2
+
+
+POST / HTTP/1.0
+Host: 127.0.0.1:12342
+First:1
+Second:2
+Content-type: text/plain
+Third:
+
+GET /foo HTTP/1.0
+Host: 127.0.0.1:12342
+First:1
+Second:2
+Third:
+
+POST / HTTP/1.0
+Host: 127.0.0.1:12342
+First:1
+Content-type:text/plain
+Second:2
+
+GET /foo HTTP/1.0
+Host: 127.0.0.1:12342
+First:1
+Second:2
+
+POST / HTTP/1.0
+Host: 127.0.0.1:12342
+First:1
+Content-type:text/plain
+Second:2
+
+GET /foo HTTP/1.0
+Host: 127.0.0.1:12342
+First:1
+Second:2
+
+POST / HTTP/1.0
+Host: 127.0.0.1:12342
+First:1
+Content-type:text/plain
+Second:2
+Third:
+
+GET /foo HTTP/1.0
+Host: 127.0.0.1:12342
+First:1
+Second:2
+Third:
+
+Done
+