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