summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/browser/download/download_resource_handler.cc12
-rw-r--r--net/base/net_error_list.h3
-rw-r--r--net/http/http_network_transaction_unittest.cc2
-rw-r--r--net/http/http_stream_parser.cc38
-rw-r--r--net/url_request/url_request_http_job.cc28
-rw-r--r--net/url_request/url_request_http_job.h7
-rw-r--r--net/url_request/url_request_unittest.cc4
-rw-r--r--webkit/glue/weburlloader_impl.cc12
8 files changed, 51 insertions, 55 deletions
diff --git a/content/browser/download/download_resource_handler.cc b/content/browser/download/download_resource_handler.cc
index 47180b7..26f575c 100644
--- a/content/browser/download/download_resource_handler.cc
+++ b/content/browser/download/download_resource_handler.cc
@@ -232,12 +232,12 @@ bool DownloadResourceHandler::OnResponseCompleted(
net::Error error_code = net::OK;
if (status.status() == net::URLRequestStatus::FAILED)
error_code = static_cast<net::Error>(status.error()); // Normal case.
- // ERR_CONTENT_LENGTH_MISMATCH is allowed since a number of servers in the
- // wild advertise a larger Content-Length than the amount of bytes in the
- // message body, and then close the connection. Other browsers - IE8,
- // Firefox 4.0.1, and Safari 5.0.4 - treat the download as complete in this
- // case, so we follow their lead.
- if (error_code == net::ERR_CONTENT_LENGTH_MISMATCH)
+ // ERR_CONNECTION_CLOSED is allowed since a number of servers in the wild
+ // advertise a larger Content-Length than the amount of bytes in the message
+ // body, and then close the connection. Other browsers - IE8, Firefox 4.0.1,
+ // and Safari 5.0.4 - treat the download as complete in this case, so we
+ // follow their lead.
+ if (error_code == net::ERR_CONNECTION_CLOSED)
error_code = net::OK;
InterruptReason reason =
ConvertNetErrorToInterruptReason(error_code,
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h
index f9734e0..13fba2c 100644
--- a/net/base/net_error_list.h
+++ b/net/base/net_error_list.h
@@ -518,9 +518,6 @@ NET_ERROR(SPDY_SERVER_REFUSED_STREAM, -351)
// SPDY server didn't respond to the PING message.
NET_ERROR(SPDY_PING_FAILED, -352)
-// Content-Length does not match the number of bytes received.
-NET_ERROR(CONTENT_LENGTH_MISMATCH, -353)
-
// The cache does not have the requested entry.
NET_ERROR(CACHE_MISS, -400)
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index dbd7e2f..d6f966c 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -6491,7 +6491,7 @@ TEST_F(HttpNetworkTransactionTest, LargeContentLengthThenClose) {
std::string response_data;
rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(ERR_CONTENT_LENGTH_MISMATCH, rv);
+ EXPECT_EQ(ERR_CONNECTION_CLOSED, rv);
}
TEST_F(HttpNetworkTransactionTest, UploadFileSmallerThanLength) {
diff --git a/net/http/http_stream_parser.cc b/net/http/http_stream_parser.cc
index 5ee1f22..cd3c9fa 100644
--- a/net/http/http_stream_parser.cc
+++ b/net/http/http_stream_parser.cc
@@ -530,38 +530,12 @@ int HttpStreamParser::DoReadBody() {
}
int HttpStreamParser::DoReadBodyComplete(int result) {
- // When the connection is closed, there are numerous ways to interpret it.
- //
- // - If a Content-Length header is present and the body contains exactly that
- // number of bytes at connection close, the response is successful.
- //
- // - If a Content-Length header is present and the body contains fewer bytes
- // than promised by the header at connection close, it may indicate that
- // the connection was closed prematurely, or it may indicate that the
- // server sent an invalid Content-Length header. Unfortunately, the invalid
- // Content-Length header case does occur in practice and other browsers are
- // tolerant of it, so this is reported as an ERR_CONTENT_LENGTH_MISMATCH
- // rather than an ERR_CONNECTION_CLOSE.
- //
- // - If chunked encoding is used and the terminating chunk has been processed
- // when the connection is closed, the response is successful.
- //
- // - If chunked encoding is used and the terminating chunk has not been
- // processed when the connection is closed, it may indicate that the
- // connection was closed prematurely or it may indicate that the server
- // sent an invalid chunked encoding. We choose to treat it as
- // an invalid chunked encoding.
- //
- // - If a Content-Length is not present and chunked encoding is not used,
- // connection close is the only way to signal that the response is
- // complete. Unfortunately, this also means that there is no way to detect
- // early close of a connection. No error is returned.
- if (result == 0 && !IsResponseBodyComplete() && CanFindEndOfResponse()) {
- if (chunked_decoder_.get())
- result = ERR_INVALID_CHUNKED_ENCODING;
- else
- result = ERR_CONTENT_LENGTH_MISMATCH;
- }
+ // If we didn't get a Content-Length and aren't using a chunked encoding,
+ // the only way to signal the end of a stream is to close the connection,
+ // so we don't treat that as an error, though in some cases we may not
+ // have completely received the resource.
+ if (result == 0 && !IsResponseBodyComplete() && CanFindEndOfResponse())
+ result = ERR_CONNECTION_CLOSED;
// Filter incoming data if appropriate. FilterBuf may return an error.
if (result > 0 && chunked_decoder_.get()) {
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 335d5ed..2cf667a 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -765,6 +765,9 @@ void URLRequestHttpJob::OnHeadersReceivedCallback(int result) {
void URLRequestHttpJob::OnReadCompleted(int result) {
read_in_progress_ = false;
+ if (ShouldFixMismatchedContentLength(result))
+ result = 0;
+
if (result == 0) {
NotifyDone(URLRequestStatus());
} else if (result < 0) {
@@ -1100,6 +1103,28 @@ void URLRequestHttpJob::ContinueDespiteLastError() {
&URLRequestHttpJob::OnStartCompleted, rv));
}
+bool URLRequestHttpJob::ShouldFixMismatchedContentLength(int rv) const {
+ // Some servers send the body compressed, but specify the content length as
+ // the uncompressed size. Although this violates the HTTP spec we want to
+ // support it (as IE and FireFox do), but *only* for an exact match.
+ // See http://crbug.com/79694.
+ if (rv == net::ERR_CONNECTION_CLOSED) {
+ if (request_ && request_->response_headers()) {
+ int64 expected_length = request_->response_headers()->GetContentLength();
+ VLOG(1) << __FUNCTION__ << "() "
+ << "\"" << request_->url().spec() << "\""
+ << " content-length = " << expected_length
+ << " pre total = " << prefilter_bytes_read()
+ << " post total = " << postfilter_bytes_read();
+ if (postfilter_bytes_read() == expected_length) {
+ // Clear the error.
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
bool URLRequestHttpJob::ReadRawData(IOBuffer* buf, int buf_size,
int* bytes_read) {
DCHECK_NE(buf_size, 0);
@@ -1108,6 +1133,9 @@ bool URLRequestHttpJob::ReadRawData(IOBuffer* buf, int buf_size,
int rv = transaction_->Read(buf, buf_size, &read_callback_);
+ if (ShouldFixMismatchedContentLength(rv))
+ rv = 0;
+
if (rv >= 0) {
*bytes_read = rv;
if (!rv)
diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h
index b94b462..c924e1c 100644
--- a/net/url_request/url_request_http_job.h
+++ b/net/url_request/url_request_http_job.h
@@ -172,6 +172,13 @@ class URLRequestHttpJob : public URLRequestJob {
void OnCookieSaved(bool cookie_status);
void CookieHandled();
+ // Some servers send the body compressed, but specify the content length as
+ // the uncompressed size. If this is the case, we return true in order
+ // to request to work around this non-adherence to the HTTP standard.
+ // |rv| is the standard return value of a read function indicating the number
+ // of bytes read or, if negative, an error code.
+ bool ShouldFixMismatchedContentLength(int rv) const;
+
// Returns the effective response headers, considering that they may be
// overridden by |override_response_headers_|.
HttpResponseHeaders* GetResponseHeaders() const;
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index b4be49e..14aa8aa 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -881,7 +881,7 @@ TEST_F(URLRequestTestHTTP, GetZippedTest) {
// L & M are larger than the data sent, and show an error.
// S has too little data, but we seem to accept it.
const bool test_expect_success[num_tests] =
- { true, false, false, false, true };
+ { true, true, false, false, true };
for (int i = 0; i < num_tests ; i++) {
TestDelegate d;
@@ -913,7 +913,7 @@ TEST_F(URLRequestTestHTTP, GetZippedTest) {
<< " Parameter = \"" << test_file << "\"";
} else {
EXPECT_EQ(URLRequestStatus::FAILED, r.status().status());
- EXPECT_EQ(ERR_CONTENT_LENGTH_MISMATCH, r.status().error())
+ EXPECT_EQ(-100, r.status().error())
<< " Parameter = \"" << test_file << "\"";
}
}
diff --git a/webkit/glue/weburlloader_impl.cc b/webkit/glue/weburlloader_impl.cc
index de470c4..7df6ace 100644
--- a/webkit/glue/weburlloader_impl.cc
+++ b/webkit/glue/weburlloader_impl.cc
@@ -608,7 +608,7 @@ void WebURLLoaderImpl::Context::OnReceivedCachedMetadata(
}
void WebURLLoaderImpl::Context::OnCompletedRequest(
- const net::URLRequestStatus& original_status,
+ const net::URLRequestStatus& status,
const std::string& security_info,
const base::Time& completion_time) {
if (ftp_listing_delegate_.get()) {
@@ -619,16 +619,6 @@ void WebURLLoaderImpl::Context::OnCompletedRequest(
multipart_delegate_.reset(NULL);
}
- net::URLRequestStatus status = original_status;
-
- // Rewrite the Content-Length mismatch as a success.
- // See crbug.com/52847 for justification.
- if (status.status() != net::URLRequestStatus::SUCCESS &&
- status.error() == net::ERR_CONTENT_LENGTH_MISMATCH) {
- status.set_status(net::URLRequestStatus::SUCCESS);
- status.set_error(net::OK);
- }
-
// Prevent any further IPC to the browser now that we're complete, but
// don't delete it to keep any downloaded temp files alive.
DCHECK(!completed_bridge_.get());