1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "webkit/glue/multipart_response_delegate.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h" 83345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h" 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_util.h" 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/http/http_util.h" 1272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "third_party/WebKit/Source/WebKit/chromium/public/WebHTTPHeaderVisitor.h" 1372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" 1472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "third_party/WebKit/Source/WebKit/chromium/public/WebURL.h" 1572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "third_party/WebKit/Source/WebKit/chromium/public/WebURLLoaderClient.h" 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebHTTPHeaderVisitor; 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebString; 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebURLLoader; 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebURLLoaderClient; 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebURLResponse; 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace webkit_glue { 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The list of response headers that we do not copy from the original 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// response when generating a WebURLResponse for a MIME payload. 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char* kReplaceHeaders[] = { 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "content-type", 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "content-length", 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "content-disposition", 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "content-range", 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "range", 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "set-cookie" 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass HeaderCopier : public WebHTTPHeaderVisitor { 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch HeaderCopier(WebURLResponse* response) 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : response_(response) { 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void visitHeader(const WebString& name, const WebString& value) { 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& name_utf8 = name.utf8(); 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < arraysize(kReplaceHeaders); ++i) { 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (LowerCaseEqualsASCII(name_utf8, kReplaceHeaders[i])) 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch response_->setHTTPHeaderField(name, value); 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WebURLResponse* response_; 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochMultipartResponseDelegate::MultipartResponseDelegate( 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WebURLLoaderClient* client, 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WebURLLoader* loader, 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const WebURLResponse& response, 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& boundary) 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : client_(client), 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch loader_(loader), 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch original_response_(response), 65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen encoded_data_length_(0), 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch boundary_("--"), 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch first_received_data_(true), 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch processing_headers_(false), 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch stop_sending_(false), 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_sent_first_response_(false) { 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Some servers report a boundary prefixed with "--". See bug 5786. 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (StartsWithASCII(boundary, "--", true)) { 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch boundary_.assign(boundary); 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch boundary_.append(boundary); 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid MultipartResponseDelegate::OnReceivedData(const char* data, 80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen int data_len, 81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen int encoded_data_length) { 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // stop_sending_ means that we've already received the final boundary token. 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The server should stop sending us data at this point, but if it does, we 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // just throw it away. 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (stop_sending_) 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data_.append(data, data_len); 89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen encoded_data_length_ += encoded_data_length; 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (first_received_data_) { 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Some servers don't send a boundary token before the first chunk of 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // data. We handle this case anyway (Gecko does too). 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch first_received_data_ = false; 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Eat leading \r\n 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int pos = PushOverLine(data_, 0); 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (pos) 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data_ = data_.substr(pos); 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (data_.length() < boundary_.length() + 2) { 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We don't have enough data yet to make a boundary token. Just wait 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // until the next chunk of data arrives. 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch first_received_data_ = true; 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (0 != data_.compare(0, boundary_.length(), boundary_)) { 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data_ = boundary_ + "\n" + data_; 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!first_received_data_); 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Headers 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (processing_headers_) { 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Eat leading \r\n 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int pos = PushOverLine(data_, 0); 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (pos) 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data_ = data_.substr(pos); 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (ParseHeaders()) { 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Successfully parsed headers. 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch processing_headers_ = false; 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get more data before trying again. 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!processing_headers_); 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t boundary_pos; 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while ((boundary_pos = FindBoundary()) != std::string::npos) { 1323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (client_) { 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Strip out trailing \n\r characters in the buffer preceding the 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // boundary on the same lines as Firefox. 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t data_length = boundary_pos; 1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (boundary_pos > 0 && data_[boundary_pos - 1] == '\n') { 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data_length--; 1383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (boundary_pos > 1 && data_[boundary_pos - 2] == '\r') { 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data_length--; 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (data_length > 0) { 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Send the last data chunk. 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch client_->didReceiveData(loader_, 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data_.data(), 146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen static_cast<int>(data_length), 147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen encoded_data_length_); 148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen encoded_data_length_ = 0; 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t boundary_end_pos = boundary_pos + boundary_.length(); 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (boundary_end_pos < data_.length() && '-' == data_[boundary_end_pos]) { 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This was the last boundary so we can stop processing. 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch stop_sending_ = true; 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data_.clear(); 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We can now throw out data up through the boundary 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int offset = PushOverLine(data_, boundary_end_pos); 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data_ = data_.substr(boundary_end_pos + offset); 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Ok, back to parsing headers 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!ParseHeaders()) { 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch processing_headers_ = true; 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // At this point, we should send over any data we have, but keep enough data 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // buffered to handle a boundary that may have been truncated. 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!processing_headers_ && data_.length() > boundary_.length()) { 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the last character is a new line character, go ahead and just send 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // everything we have buffered. This matches an optimization in Gecko. 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int send_length = data_.length() - boundary_.length(); 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (data_[data_.length() - 1] == '\n') 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch send_length = data_.length(); 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (client_) 179ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen client_->didReceiveData(loader_, 180ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen data_.data(), 181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen send_length, 182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen encoded_data_length_); 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data_ = data_.substr(send_length); 184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen encoded_data_length_ = 0; 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid MultipartResponseDelegate::OnCompletedRequest() { 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we have any pending data and we're not in a header, go ahead and send 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // it to WebCore. 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!processing_headers_ && !data_.empty() && !stop_sending_ && client_) { 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch client_->didReceiveData(loader_, 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data_.data(), 194ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen static_cast<int>(data_.length()), 195ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen encoded_data_length_); 196ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen encoded_data_length_ = 0; 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint MultipartResponseDelegate::PushOverLine(const std::string& data, 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t pos) { 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int offset = 0; 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (pos < data.length() && (data[pos] == '\r' || data[pos] == '\n')) { 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++offset; 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (pos + 1 < data.length() && data[pos + 1] == '\n') 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++offset; 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return offset; 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool MultipartResponseDelegate::ParseHeaders() { 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int line_feed_increment = 1; 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Grab the headers being liberal about line endings. 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t line_start_pos = 0; 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t line_end_pos = data_.find('\n'); 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (line_end_pos != std::string::npos) { 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Handle CRLF 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (line_end_pos > line_start_pos && data_[line_end_pos - 1] == '\r') { 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch line_feed_increment = 2; 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch --line_end_pos; 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch line_feed_increment = 1; 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (line_start_pos == line_end_pos) { 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // A blank line, end of headers 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch line_end_pos += line_feed_increment; 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Find the next header line. 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch line_start_pos = line_end_pos + line_feed_increment; 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch line_end_pos = data_.find('\n', line_start_pos); 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Truncated in the middle of a header, stop parsing. 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (line_end_pos == std::string::npos) 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Eat headers 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string headers("\n"); 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch headers.append(data_, 0, line_end_pos); 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data_ = data_.substr(line_end_pos); 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create a WebURLResponse based on the original set of headers + the 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // replacement headers. We only replace the same few headers that gecko 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // does. See netwerk/streamconv/converters/nsMultiMixedConv.cpp. 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string content_type = net::GetSpecificHeader(headers, "content-type"); 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string mime_type; 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string charset; 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool has_charset = false; 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch net::HttpUtil::ParseContentType(content_type, &mime_type, &charset, 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &has_charset); 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WebURLResponse response(original_response_.url()); 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch response.setMIMEType(WebString::fromUTF8(mime_type)); 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch response.setTextEncodingName(WebString::fromUTF8(charset)); 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch HeaderCopier copier(&response); 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch original_response_.visitHTTPHeaderFields(&copier); 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < arraysize(kReplaceHeaders); ++i) { 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string name(kReplaceHeaders[i]); 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string value = net::GetSpecificHeader(headers, name); 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!value.empty()) { 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch response.setHTTPHeaderField(WebString::fromUTF8(name), 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WebString::fromUTF8(value)); 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // To avoid recording every multipart load as a separate visit in 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the history database, we want to keep track of whether the response 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // is part of a multipart payload. We do want to record the first visit, 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // so we only set isMultipartPayload to true after the first visit. 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch response.setIsMultipartPayload(has_sent_first_response_); 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_sent_first_response_ = true; 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Send the response! 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (client_) 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch client_->didReceiveResponse(loader_, response); 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Boundaries are supposed to be preceeded with --, but it looks like gecko 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// doesn't require the dashes to exist. See nsMultiMixedConv::FindToken. 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochsize_t MultipartResponseDelegate::FindBoundary() { 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t boundary_pos = data_.find(boundary_); 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (boundary_pos != std::string::npos) { 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Back up over -- for backwards compat 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(tc): Don't we only want to do this once? Gecko code doesn't seem 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to care. 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (boundary_pos >= 2) { 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ('-' == data_[boundary_pos - 1] && '-' == data_[boundary_pos - 2]) { 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch boundary_pos -= 2; 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch boundary_ = "--" + boundary_; 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return boundary_pos; 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool MultipartResponseDelegate::ReadMultipartBoundary( 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const WebURLResponse& response, 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string* multipart_boundary) { 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string content_type = 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch response.httpHeaderField(WebString::fromUTF8("Content-Type")).utf8(); 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t boundary_start_offset = content_type.find("boundary="); 30572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (boundary_start_offset == std::string::npos) 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch boundary_start_offset += strlen("boundary="); 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t boundary_end_offset = content_type.find(';', boundary_start_offset); 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (boundary_end_offset == std::string::npos) 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch boundary_end_offset = content_type.length(); 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t boundary_length = boundary_end_offset - boundary_start_offset; 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *multipart_boundary = 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch content_type.substr(boundary_start_offset, boundary_length); 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The byte range response can have quoted boundary strings. This is legal 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // as per MIME specifications. Individual data fragements however don't 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // contain quoted boundary strings. 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TrimString(*multipart_boundary, "\"", multipart_boundary); 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool MultipartResponseDelegate::ReadContentRanges( 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const WebURLResponse& response, 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int* content_range_lower_bound, 32921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen int* content_range_upper_bound, 33021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen int* content_range_instance_size) { 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string content_range = response.httpHeaderField("Content-Range").utf8(); 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (content_range.empty()) { 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch content_range = response.httpHeaderField("Range").utf8(); 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (content_range.empty()) { 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DLOG(WARNING) << "Failed to read content range from response."; 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t byte_range_lower_bound_start_offset = content_range.find(" "); 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (byte_range_lower_bound_start_offset == std::string::npos) { 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Skip over the initial space. 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch byte_range_lower_bound_start_offset++; 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 35021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Find the lower bound. 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t byte_range_lower_bound_end_offset = 352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch content_range.find("-", byte_range_lower_bound_start_offset); 353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (byte_range_lower_bound_end_offset == std::string::npos) { 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 35721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen size_t byte_range_lower_bound_characters = 35821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen byte_range_lower_bound_end_offset - byte_range_lower_bound_start_offset; 35921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen std::string byte_range_lower_bound = 36021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen content_range.substr(byte_range_lower_bound_start_offset, 36121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen byte_range_lower_bound_characters); 36221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 36321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Find the upper bound. 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t byte_range_upper_bound_start_offset = 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch byte_range_lower_bound_end_offset + 1; 366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t byte_range_upper_bound_end_offset = 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch content_range.find("/", byte_range_upper_bound_start_offset); 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (byte_range_upper_bound_end_offset == std::string::npos) { 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 37321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen size_t byte_range_upper_bound_characters = 37421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen byte_range_upper_bound_end_offset - byte_range_upper_bound_start_offset; 37521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen std::string byte_range_upper_bound = 37621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen content_range.substr(byte_range_upper_bound_start_offset, 37721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen byte_range_upper_bound_characters); 37821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 37921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Find the instance size. 38021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen size_t byte_range_instance_size_start_offset = 38121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen byte_range_upper_bound_end_offset + 1; 38221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 38321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen size_t byte_range_instance_size_end_offset = 38421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen content_range.length(); 385513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 38621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen size_t byte_range_instance_size_characters = 38721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen byte_range_instance_size_end_offset - 38821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen byte_range_instance_size_start_offset; 38921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen std::string byte_range_instance_size = 39021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen content_range.substr(byte_range_instance_size_start_offset, 39121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen byte_range_instance_size_characters); 39221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 39321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (!base::StringToInt(byte_range_lower_bound, content_range_lower_bound)) 39421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return false; 39521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (!base::StringToInt(byte_range_upper_bound, content_range_upper_bound)) 39621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return false; 39721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (!base::StringToInt(byte_range_instance_size, content_range_instance_size)) 398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace webkit_glue 403