- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / drive / drive_url_request_job.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/drive/drive_url_request_job.h"
6
7 #include <string>
8
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "chrome/browser/chromeos/drive/drive.pb.h"
13 #include "chrome/browser/chromeos/drive/drive_file_stream_reader.h"
14 #include "chrome/browser/chromeos/drive/file_system_interface.h"
15 #include "chrome/browser/chromeos/drive/file_system_util.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "net/base/net_errors.h"
18 #include "net/http/http_byte_range.h"
19 #include "net/http/http_request_headers.h"
20 #include "net/http/http_response_info.h"
21 #include "net/http/http_util.h"
22 #include "net/url_request/url_request.h"
23 #include "net/url_request/url_request_status.h"
24
25 using content::BrowserThread;
26
27 namespace drive {
28 namespace {
29
30 struct MimeTypeReplacement {
31   const char* original_type;
32   const char* new_type;
33 };
34
35 const MimeTypeReplacement kMimeTypeReplacements[] = {
36   {"message/rfc822", "multipart/related"}  // Fixes MHTML
37 };
38
39 std::string FixupMimeType(const std::string& type) {
40   for (size_t i = 0; i < arraysize(kMimeTypeReplacements); i++) {
41     if (type == kMimeTypeReplacements[i].original_type)
42       return kMimeTypeReplacements[i].new_type;
43   }
44   return type;
45 }
46
47 }  // namespace
48
49 DriveURLRequestJob::DriveURLRequestJob(
50     const FileSystemGetter& file_system_getter,
51     base::SequencedTaskRunner* file_task_runner,
52     net::URLRequest* request,
53     net::NetworkDelegate* network_delegate)
54     : net::URLRequestJob(request, network_delegate),
55       file_system_getter_(file_system_getter),
56       file_task_runner_(file_task_runner),
57       weak_ptr_factory_(this) {
58 }
59
60 void DriveURLRequestJob::SetExtraRequestHeaders(
61     const net::HttpRequestHeaders& headers) {
62   std::string range_header;
63   if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
64     // Note: We only support single range requests.
65     std::vector<net::HttpByteRange> ranges;
66     if (net::HttpUtil::ParseRangeHeader(range_header, &ranges) &&
67         ranges.size() == 1) {
68       byte_range_ = ranges[0];
69     } else {
70       // Failed to parse Range: header, so notify the error.
71       NotifyDone(
72           net::URLRequestStatus(net::URLRequestStatus::FAILED,
73                                 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
74     }
75   }
76 }
77
78 void DriveURLRequestJob::Start() {
79   DVLOG(1) << "Starting request";
80   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
81   DCHECK(!stream_reader_);
82
83   // We only support GET request.
84   if (request()->method() != "GET") {
85     LOG(WARNING) << "Failed to start request: "
86                  << request()->method() << " method is not supported";
87     NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
88                                            net::ERR_METHOD_NOT_SUPPORTED));
89     return;
90   }
91
92   base::FilePath drive_file_path(util::DriveURLToFilePath(request_->url()));
93   if (drive_file_path.empty()) {
94     // Not a valid url.
95     NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
96                                            net::ERR_INVALID_URL));
97     return;
98   }
99
100   // Initialize the stream reader.
101   stream_reader_.reset(
102       new DriveFileStreamReader(file_system_getter_, file_task_runner_.get()));
103   stream_reader_->Initialize(
104       drive_file_path,
105       byte_range_,
106       base::Bind(&DriveURLRequestJob::OnDriveFileStreamReaderInitialized,
107                  weak_ptr_factory_.GetWeakPtr()));
108 }
109
110 void DriveURLRequestJob::Kill() {
111   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
112
113   stream_reader_.reset();
114   net::URLRequestJob::Kill();
115   weak_ptr_factory_.InvalidateWeakPtrs();
116 }
117
118 bool DriveURLRequestJob::GetMimeType(std::string* mime_type) const {
119   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
120
121   if (!entry_) {
122     return false;
123   }
124
125   mime_type->assign(
126       FixupMimeType(entry_->file_specific_info().content_mime_type()));
127   return !mime_type->empty();
128 }
129
130 bool DriveURLRequestJob::IsRedirectResponse(
131     GURL* location, int* http_status_code) {
132   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
133
134   if (!entry_ || !entry_->file_specific_info().is_hosted_document()) {
135     return false;
136   }
137
138   // Redirect a hosted document.
139   *location = GURL(entry_->file_specific_info().alternate_url());
140   const int kHttpFound = 302;
141   *http_status_code = kHttpFound;
142   return true;
143 }
144
145 bool DriveURLRequestJob::ReadRawData(
146     net::IOBuffer* buf, int buf_size, int* bytes_read) {
147   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
148   DCHECK(stream_reader_ && stream_reader_->IsInitialized());
149
150   int result = stream_reader_->Read(
151       buf, buf_size,
152       base::Bind(&DriveURLRequestJob::OnReadCompleted,
153                  weak_ptr_factory_.GetWeakPtr()));
154
155   if (result == net::ERR_IO_PENDING) {
156     // The data is not yet available.
157     SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
158     return false;
159   }
160   if (result < 0) {
161     // An error occurs.
162     NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
163     return false;
164   }
165
166   // Reading has been finished immediately.
167   *bytes_read = result;
168   return true;
169 }
170
171 DriveURLRequestJob::~DriveURLRequestJob() {
172 }
173
174 void DriveURLRequestJob::OnDriveFileStreamReaderInitialized(
175     int error, scoped_ptr<ResourceEntry> entry) {
176   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
177   DCHECK(stream_reader_);
178
179   if (error != FILE_ERROR_OK) {
180     NotifyStartError(
181         net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
182     return;
183   }
184
185   DCHECK(entry && entry->has_file_specific_info());
186   entry_ = entry.Pass();
187
188   if (!entry_->file_specific_info().is_hosted_document()) {
189     // We don't need to set content size for hosted documents,
190     // because it will be redirected.
191     set_expected_content_size(entry_->file_info().size());
192   }
193
194   NotifyHeadersComplete();
195 }
196
197 void DriveURLRequestJob::OnReadCompleted(int read_result) {
198   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
199
200   if (read_result < 0) {
201     DCHECK_NE(read_result, net::ERR_IO_PENDING);
202     NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
203                                      read_result));
204   }
205
206   SetStatus(net::URLRequestStatus());  // Clear the IO_PENDING status.
207   NotifyReadComplete(read_result);
208 }
209
210 }  // namespace drive