Browse Source

Fixing Content-Length calculation when there is buffered output that will be sent before the response body. fixes #2208

Jose Lorenzo Rodriguez 14 years ago
parent
commit
2711178b4b
2 changed files with 35 additions and 7 deletions
  1. 18 7
      lib/Cake/Network/CakeResponse.php
  2. 17 0
      lib/Cake/Test/Case/Network/CakeResponseTest.php

+ 18 - 7
lib/Cake/Network/CakeResponse.php

@@ -349,19 +349,30 @@ class CakeResponse {
 		$codeMessage = $this->_statusCodes[$this->_status];
 		$this->_sendHeader("{$this->_protocol} {$this->_status} {$codeMessage}");
 		$this->_sendHeader('Content-Type', "{$this->_contentType}; charset={$this->_charset}");
+		$this->_setContentLength();
+		foreach ($this->_headers as $header => $value) {
+			$this->_sendHeader($header, $value);
+		}
+		$this->_sendContent($this->_body);
+	}
+
+/**
+ * Calculates the correct Content-Length and sets it as a header in the response
+ * Will not set the value if already set or if the output is compressed.
+ *
+ * @return void
+ */
+	protected function _setContentLength() {
 		$shouldSetLength = empty($this->_headers['Content-Length']) && !in_array($this->_status, range(301, 307));
 		if ($shouldSetLength && !$this->outputCompressed()) {
+			$offset = ob_get_level() ? ob_get_length() : 0;
 			if (ini_get('mbstring.func_overload') & 2 && function_exists('mb_strlen')) {
-				$this->_headers['Content-Length'] = mb_strlen($this->_body, '8bit');
+				$this->_headers['Content-Length'] = $offset + mb_strlen($this->_body, '8bit');
 			} else {
-				$this->_headers['Content-Length'] = strlen($this->_body);
+				$this->_headers['Content-Length'] = $offset + strlen($this->_body);
 			}
 		}
-		foreach ($this->_headers as $header => $value) {
-			$this->_sendHeader($header, $value);
-		}
-		$this->_sendContent($this->_body);
-	}
+    }
 
 /**
  * Sends a header to the client.

+ 17 - 0
lib/Cake/Test/Case/Network/CakeResponseTest.php

@@ -424,5 +424,22 @@ class CakeResponseTest extends CakeTestCase {
 		$response->expects($this->once())->method('_sendContent')->with($body);
 		$response->expects($this->exactly(2))->method('_sendHeader');
 		$response->send();
+
+		ob_start();
+		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
+		$goofyOutput = 'I am goofily sending output in the controller';
+		echo $goofyOutput;
+		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
+		$body = '長い長い長いSubjectの場合はfoldingするのが正しいんだけどいったいどうなるんだろう?';
+		$response->body($body);
+		$response->expects($this->once())->method('_sendContent')->with($body);
+		$response->expects($this->at(0))
+			->method('_sendHeader')->with('HTTP/1.1 200 OK');
+		$response->expects($this->at(1))
+			->method('_sendHeader')->with('Content-Type', 'text/html; charset=UTF-8');
+		$response->expects($this->at(2))
+			->method('_sendHeader')->with('Content-Length', strlen($goofyOutput) + 116);
+		$response->send();
+		ob_end_clean();
 	}
 }