Index: webkit/glue/multipart_response_delegate.cc |
diff --git a/webkit/glue/multipart_response_delegate.cc b/webkit/glue/multipart_response_delegate.cc |
deleted file mode 100644 |
index 325caf9103e0a50a6b88f6b66d3753b83c3d68b3..0000000000000000000000000000000000000000 |
--- a/webkit/glue/multipart_response_delegate.cc |
+++ /dev/null |
@@ -1,404 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "webkit/glue/multipart_response_delegate.h" |
- |
-#include "base/logging.h" |
-#include "base/strings/string_number_conversions.h" |
-#include "base/strings/string_util.h" |
-#include "net/base/net_util.h" |
-#include "net/http/http_util.h" |
-#include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h" |
-#include "third_party/WebKit/public/platform/WebString.h" |
-#include "third_party/WebKit/public/platform/WebURL.h" |
-#include "third_party/WebKit/public/platform/WebURLLoaderClient.h" |
- |
-using WebKit::WebHTTPHeaderVisitor; |
-using WebKit::WebString; |
-using WebKit::WebURLLoader; |
-using WebKit::WebURLLoaderClient; |
-using WebKit::WebURLResponse; |
- |
-namespace webkit_glue { |
- |
-namespace { |
- |
-// The list of response headers that we do not copy from the original |
-// response when generating a WebURLResponse for a MIME payload. |
-const char* kReplaceHeaders[] = { |
- "content-type", |
- "content-length", |
- "content-disposition", |
- "content-range", |
- "range", |
- "set-cookie" |
-}; |
- |
-class HeaderCopier : public WebHTTPHeaderVisitor { |
- public: |
- HeaderCopier(WebURLResponse* response) |
- : response_(response) { |
- } |
- virtual void visitHeader(const WebString& name, const WebString& value) { |
- const std::string& name_utf8 = name.utf8(); |
- for (size_t i = 0; i < arraysize(kReplaceHeaders); ++i) { |
- if (LowerCaseEqualsASCII(name_utf8, kReplaceHeaders[i])) |
- return; |
- } |
- response_->setHTTPHeaderField(name, value); |
- } |
- private: |
- WebURLResponse* response_; |
-}; |
- |
-} // namespace |
- |
-MultipartResponseDelegate::MultipartResponseDelegate( |
- WebURLLoaderClient* client, |
- WebURLLoader* loader, |
- const WebURLResponse& response, |
- const std::string& boundary) |
- : client_(client), |
- loader_(loader), |
- original_response_(response), |
- encoded_data_length_(0), |
- boundary_("--"), |
- first_received_data_(true), |
- processing_headers_(false), |
- stop_sending_(false), |
- has_sent_first_response_(false) { |
- // Some servers report a boundary prefixed with "--". See bug 5786. |
- if (StartsWithASCII(boundary, "--", true)) { |
- boundary_.assign(boundary); |
- } else { |
- boundary_.append(boundary); |
- } |
-} |
- |
-void MultipartResponseDelegate::OnReceivedData(const char* data, |
- int data_len, |
- int encoded_data_length) { |
- // stop_sending_ means that we've already received the final boundary token. |
- // The server should stop sending us data at this point, but if it does, we |
- // just throw it away. |
- if (stop_sending_) |
- return; |
- |
- data_.append(data, data_len); |
- encoded_data_length_ += encoded_data_length; |
- if (first_received_data_) { |
- // Some servers don't send a boundary token before the first chunk of |
- // data. We handle this case anyway (Gecko does too). |
- first_received_data_ = false; |
- |
- // Eat leading \r\n |
- int pos = PushOverLine(data_, 0); |
- if (pos) |
- data_ = data_.substr(pos); |
- |
- if (data_.length() < boundary_.length() + 2) { |
- // We don't have enough data yet to make a boundary token. Just wait |
- // until the next chunk of data arrives. |
- first_received_data_ = true; |
- return; |
- } |
- |
- if (0 != data_.compare(0, boundary_.length(), boundary_)) { |
- data_ = boundary_ + "\n" + data_; |
- } |
- } |
- DCHECK(!first_received_data_); |
- |
- // Headers |
- if (processing_headers_) { |
- // Eat leading \r\n |
- int pos = PushOverLine(data_, 0); |
- if (pos) |
- data_ = data_.substr(pos); |
- |
- if (ParseHeaders()) { |
- // Successfully parsed headers. |
- processing_headers_ = false; |
- } else { |
- // Get more data before trying again. |
- return; |
- } |
- } |
- DCHECK(!processing_headers_); |
- |
- size_t boundary_pos; |
- while ((boundary_pos = FindBoundary()) != std::string::npos) { |
- if (client_) { |
- // Strip out trailing \n\r characters in the buffer preceding the |
- // boundary on the same lines as Firefox. |
- size_t data_length = boundary_pos; |
- if (boundary_pos > 0 && data_[boundary_pos - 1] == '\n') { |
- data_length--; |
- if (boundary_pos > 1 && data_[boundary_pos - 2] == '\r') { |
- data_length--; |
- } |
- } |
- if (data_length > 0) { |
- // Send the last data chunk. |
- client_->didReceiveData(loader_, |
- data_.data(), |
- static_cast<int>(data_length), |
- encoded_data_length_); |
- encoded_data_length_ = 0; |
- } |
- } |
- size_t boundary_end_pos = boundary_pos + boundary_.length(); |
- if (boundary_end_pos < data_.length() && '-' == data_[boundary_end_pos]) { |
- // This was the last boundary so we can stop processing. |
- stop_sending_ = true; |
- data_.clear(); |
- return; |
- } |
- |
- // We can now throw out data up through the boundary |
- int offset = PushOverLine(data_, boundary_end_pos); |
- data_ = data_.substr(boundary_end_pos + offset); |
- |
- // Ok, back to parsing headers |
- if (!ParseHeaders()) { |
- processing_headers_ = true; |
- break; |
- } |
- } |
- |
- // At this point, we should send over any data we have, but keep enough data |
- // buffered to handle a boundary that may have been truncated. |
- if (!processing_headers_ && data_.length() > boundary_.length()) { |
- // If the last character is a new line character, go ahead and just send |
- // everything we have buffered. This matches an optimization in Gecko. |
- int send_length = data_.length() - boundary_.length(); |
- if (data_[data_.length() - 1] == '\n') |
- send_length = data_.length(); |
- if (client_) |
- client_->didReceiveData(loader_, |
- data_.data(), |
- send_length, |
- encoded_data_length_); |
- data_ = data_.substr(send_length); |
- encoded_data_length_ = 0; |
- } |
-} |
- |
-void MultipartResponseDelegate::OnCompletedRequest() { |
- // If we have any pending data and we're not in a header, go ahead and send |
- // it to WebCore. |
- if (!processing_headers_ && !data_.empty() && !stop_sending_ && client_) { |
- client_->didReceiveData(loader_, |
- data_.data(), |
- static_cast<int>(data_.length()), |
- encoded_data_length_); |
- encoded_data_length_ = 0; |
- } |
-} |
- |
-int MultipartResponseDelegate::PushOverLine(const std::string& data, |
- size_t pos) { |
- int offset = 0; |
- if (pos < data.length() && (data[pos] == '\r' || data[pos] == '\n')) { |
- ++offset; |
- if (pos + 1 < data.length() && data[pos + 1] == '\n') |
- ++offset; |
- } |
- return offset; |
-} |
- |
-bool MultipartResponseDelegate::ParseHeaders() { |
- int line_feed_increment = 1; |
- |
- // Grab the headers being liberal about line endings. |
- size_t line_start_pos = 0; |
- size_t line_end_pos = data_.find('\n'); |
- while (line_end_pos != std::string::npos) { |
- // Handle CRLF |
- if (line_end_pos > line_start_pos && data_[line_end_pos - 1] == '\r') { |
- line_feed_increment = 2; |
- --line_end_pos; |
- } else { |
- line_feed_increment = 1; |
- } |
- if (line_start_pos == line_end_pos) { |
- // A blank line, end of headers |
- line_end_pos += line_feed_increment; |
- break; |
- } |
- // Find the next header line. |
- line_start_pos = line_end_pos + line_feed_increment; |
- line_end_pos = data_.find('\n', line_start_pos); |
- } |
- // Truncated in the middle of a header, stop parsing. |
- if (line_end_pos == std::string::npos) |
- return false; |
- |
- // Eat headers |
- std::string headers("\n"); |
- headers.append(data_, 0, line_end_pos); |
- data_ = data_.substr(line_end_pos); |
- |
- // Create a WebURLResponse based on the original set of headers + the |
- // replacement headers. We only replace the same few headers that gecko |
- // does. See netwerk/streamconv/converters/nsMultiMixedConv.cpp. |
- std::string content_type = net::GetSpecificHeader(headers, "content-type"); |
- std::string mime_type; |
- std::string charset; |
- bool has_charset = false; |
- net::HttpUtil::ParseContentType(content_type, &mime_type, &charset, |
- &has_charset, NULL); |
- WebURLResponse response(original_response_.url()); |
- response.setMIMEType(WebString::fromUTF8(mime_type)); |
- response.setTextEncodingName(WebString::fromUTF8(charset)); |
- |
- HeaderCopier copier(&response); |
- original_response_.visitHTTPHeaderFields(&copier); |
- |
- for (size_t i = 0; i < arraysize(kReplaceHeaders); ++i) { |
- std::string name(kReplaceHeaders[i]); |
- std::string value = net::GetSpecificHeader(headers, name); |
- if (!value.empty()) { |
- response.setHTTPHeaderField(WebString::fromUTF8(name), |
- WebString::fromUTF8(value)); |
- } |
- } |
- // To avoid recording every multipart load as a separate visit in |
- // the history database, we want to keep track of whether the response |
- // is part of a multipart payload. We do want to record the first visit, |
- // so we only set isMultipartPayload to true after the first visit. |
- response.setIsMultipartPayload(has_sent_first_response_); |
- has_sent_first_response_ = true; |
- // Send the response! |
- if (client_) |
- client_->didReceiveResponse(loader_, response); |
- |
- return true; |
-} |
- |
-// Boundaries are supposed to be preceeded with --, but it looks like gecko |
-// doesn't require the dashes to exist. See nsMultiMixedConv::FindToken. |
-size_t MultipartResponseDelegate::FindBoundary() { |
- size_t boundary_pos = data_.find(boundary_); |
- if (boundary_pos != std::string::npos) { |
- // Back up over -- for backwards compat |
- // TODO(tc): Don't we only want to do this once? Gecko code doesn't seem |
- // to care. |
- if (boundary_pos >= 2) { |
- if ('-' == data_[boundary_pos - 1] && '-' == data_[boundary_pos - 2]) { |
- boundary_pos -= 2; |
- boundary_ = "--" + boundary_; |
- } |
- } |
- } |
- return boundary_pos; |
-} |
- |
-bool MultipartResponseDelegate::ReadMultipartBoundary( |
- const WebURLResponse& response, |
- std::string* multipart_boundary) { |
- std::string content_type = |
- response.httpHeaderField(WebString::fromUTF8("Content-Type")).utf8(); |
- |
- size_t boundary_start_offset = content_type.find("boundary="); |
- if (boundary_start_offset == std::string::npos) |
- return false; |
- |
- boundary_start_offset += strlen("boundary="); |
- |
- size_t boundary_end_offset = content_type.find(';', boundary_start_offset); |
- |
- if (boundary_end_offset == std::string::npos) |
- boundary_end_offset = content_type.length(); |
- |
- size_t boundary_length = boundary_end_offset - boundary_start_offset; |
- |
- *multipart_boundary = |
- content_type.substr(boundary_start_offset, boundary_length); |
- // The byte range response can have quoted boundary strings. This is legal |
- // as per MIME specifications. Individual data fragements however don't |
- // contain quoted boundary strings. |
- TrimString(*multipart_boundary, "\"", multipart_boundary); |
- return true; |
-} |
- |
-bool MultipartResponseDelegate::ReadContentRanges( |
- const WebURLResponse& response, |
- int64* content_range_lower_bound, |
- int64* content_range_upper_bound, |
- int64* content_range_instance_size) { |
- |
- std::string content_range = response.httpHeaderField("Content-Range").utf8(); |
- if (content_range.empty()) { |
- content_range = response.httpHeaderField("Range").utf8(); |
- } |
- |
- if (content_range.empty()) { |
- DLOG(WARNING) << "Failed to read content range from response."; |
- return false; |
- } |
- |
- size_t byte_range_lower_bound_start_offset = content_range.find(" "); |
- if (byte_range_lower_bound_start_offset == std::string::npos) { |
- return false; |
- } |
- |
- // Skip over the initial space. |
- byte_range_lower_bound_start_offset++; |
- |
- // Find the lower bound. |
- size_t byte_range_lower_bound_end_offset = |
- content_range.find("-", byte_range_lower_bound_start_offset); |
- if (byte_range_lower_bound_end_offset == std::string::npos) { |
- return false; |
- } |
- |
- size_t byte_range_lower_bound_characters = |
- byte_range_lower_bound_end_offset - byte_range_lower_bound_start_offset; |
- std::string byte_range_lower_bound = |
- content_range.substr(byte_range_lower_bound_start_offset, |
- byte_range_lower_bound_characters); |
- |
- // Find the upper bound. |
- size_t byte_range_upper_bound_start_offset = |
- byte_range_lower_bound_end_offset + 1; |
- |
- size_t byte_range_upper_bound_end_offset = |
- content_range.find("/", byte_range_upper_bound_start_offset); |
- if (byte_range_upper_bound_end_offset == std::string::npos) { |
- return false; |
- } |
- |
- size_t byte_range_upper_bound_characters = |
- byte_range_upper_bound_end_offset - byte_range_upper_bound_start_offset; |
- std::string byte_range_upper_bound = |
- content_range.substr(byte_range_upper_bound_start_offset, |
- byte_range_upper_bound_characters); |
- |
- // Find the instance size. |
- size_t byte_range_instance_size_start_offset = |
- byte_range_upper_bound_end_offset + 1; |
- |
- size_t byte_range_instance_size_end_offset = |
- content_range.length(); |
- |
- size_t byte_range_instance_size_characters = |
- byte_range_instance_size_end_offset - |
- byte_range_instance_size_start_offset; |
- std::string byte_range_instance_size = |
- content_range.substr(byte_range_instance_size_start_offset, |
- byte_range_instance_size_characters); |
- |
- if (!base::StringToInt64(byte_range_lower_bound, content_range_lower_bound)) |
- return false; |
- if (!base::StringToInt64(byte_range_upper_bound, content_range_upper_bound)) |
- return false; |
- if (!base::StringToInt64(byte_range_instance_size, |
- content_range_instance_size)) { |
- return false; |
- } |
- return true; |
-} |
- |
-} // namespace webkit_glue |