OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "storage/browser/blob/blob_url_request_job.h" | 5 #include "storage/browser/blob/blob_url_request_job.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <limits> | 10 #include <limits> |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 } else { | 136 } else { |
137 // We don't support multiple range requests in one single URL request, | 137 // We don't support multiple range requests in one single URL request, |
138 // because we need to do multipart encoding here. | 138 // because we need to do multipart encoding here. |
139 // TODO(jianli): Support multipart byte range requests. | 139 // TODO(jianli): Support multipart byte range requests. |
140 NotifyFailure(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE); | 140 NotifyFailure(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE); |
141 } | 141 } |
142 } | 142 } |
143 } | 143 } |
144 } | 144 } |
145 | 145 |
| 146 scoped_refptr<net::HttpResponseHeaders> BlobURLRequestJob::GenerateHeaders( |
| 147 net::HttpStatusCode status_code, |
| 148 BlobDataHandle* blob_handle, |
| 149 BlobReader* blob_reader, |
| 150 net::HttpByteRange* byte_range, |
| 151 int64_t* content_size) { |
| 152 std::string status("HTTP/1.1 "); |
| 153 status.append(base::IntToString(status_code)); |
| 154 status.append(" "); |
| 155 status.append(net::GetHttpReasonPhrase(status_code)); |
| 156 status.append("\0\0", 2); |
| 157 scoped_refptr<net::HttpResponseHeaders> headers = |
| 158 new net::HttpResponseHeaders(status); |
| 159 |
| 160 if (status_code == net::HTTP_OK || status_code == net::HTTP_PARTIAL_CONTENT) { |
| 161 *content_size = blob_reader->remaining_bytes(); |
| 162 std::string content_length_header(net::HttpRequestHeaders::kContentLength); |
| 163 content_length_header.append(": "); |
| 164 content_length_header.append(base::Int64ToString(*content_size)); |
| 165 headers->AddHeader(content_length_header); |
| 166 if (status_code == net::HTTP_PARTIAL_CONTENT) { |
| 167 DCHECK(byte_range->IsValid()); |
| 168 std::string content_range_header(net::HttpResponseHeaders::kContentRange); |
| 169 content_range_header.append(": bytes "); |
| 170 content_range_header.append(base::StringPrintf( |
| 171 "%" PRId64 "-%" PRId64, byte_range->first_byte_position(), |
| 172 byte_range->last_byte_position())); |
| 173 content_range_header.append("/"); |
| 174 content_range_header.append( |
| 175 base::StringPrintf("%" PRId64, blob_reader->total_size())); |
| 176 headers->AddHeader(content_range_header); |
| 177 } |
| 178 if (!blob_handle->content_type().empty()) { |
| 179 std::string content_type_header(net::HttpRequestHeaders::kContentType); |
| 180 content_type_header.append(": "); |
| 181 content_type_header.append(blob_handle->content_type()); |
| 182 headers->AddHeader(content_type_header); |
| 183 } |
| 184 if (!blob_handle->content_disposition().empty()) { |
| 185 std::string content_disposition_header("Content-Disposition: "); |
| 186 content_disposition_header.append(blob_handle->content_disposition()); |
| 187 headers->AddHeader(content_disposition_header); |
| 188 } |
| 189 } |
| 190 |
| 191 return headers; |
| 192 } |
| 193 |
| 194 net::HttpStatusCode BlobURLRequestJob::NetErrorToHttpStatusCode( |
| 195 int error_code) { |
| 196 net::HttpStatusCode status_code = net::HTTP_INTERNAL_SERVER_ERROR; |
| 197 switch (error_code) { |
| 198 case net::ERR_ACCESS_DENIED: |
| 199 status_code = net::HTTP_FORBIDDEN; |
| 200 break; |
| 201 case net::ERR_FILE_NOT_FOUND: |
| 202 status_code = net::HTTP_NOT_FOUND; |
| 203 break; |
| 204 case net::ERR_METHOD_NOT_SUPPORTED: |
| 205 status_code = net::HTTP_METHOD_NOT_ALLOWED; |
| 206 break; |
| 207 case net::ERR_REQUEST_RANGE_NOT_SATISFIABLE: |
| 208 status_code = net::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE; |
| 209 break; |
| 210 case net::ERR_INVALID_ARGUMENT: |
| 211 status_code = net::HTTP_BAD_REQUEST; |
| 212 break; |
| 213 case net::ERR_CACHE_READ_FAILURE: |
| 214 case net::ERR_CACHE_CHECKSUM_READ_FAILURE: |
| 215 case net::ERR_UNEXPECTED: |
| 216 case net::ERR_FAILED: |
| 217 break; |
| 218 default: |
| 219 DCHECK(false) << "Error code not supported: " << error_code; |
| 220 break; |
| 221 } |
| 222 return status_code; |
| 223 } |
| 224 |
146 BlobURLRequestJob::~BlobURLRequestJob() { | 225 BlobURLRequestJob::~BlobURLRequestJob() { |
147 TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest", this, "uuid", | 226 TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest", this, "uuid", |
148 blob_handle_ ? blob_handle_->uuid() : "NotFound"); | 227 blob_handle_ ? blob_handle_->uuid() : "NotFound"); |
149 } | 228 } |
150 | 229 |
151 void BlobURLRequestJob::DidStart() { | 230 void BlobURLRequestJob::DidStart() { |
152 error_ = false; | 231 error_ = false; |
153 | 232 |
154 // We only support GET request per the spec. | 233 // We only support GET request per the spec. |
155 if (request()->method() != "GET") { | 234 if (request()->method() != "GET") { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
237 ReadRawDataComplete(result); | 316 ReadRawDataComplete(result); |
238 } | 317 } |
239 | 318 |
240 void BlobURLRequestJob::NotifyFailure(int error_code) { | 319 void BlobURLRequestJob::NotifyFailure(int error_code) { |
241 error_ = true; | 320 error_ = true; |
242 | 321 |
243 // If we already return the headers on success, we can't change the headers | 322 // If we already return the headers on success, we can't change the headers |
244 // now. Instead, we just error out. | 323 // now. Instead, we just error out. |
245 DCHECK(!response_info_) << "Cannot NotifyFailure after headers."; | 324 DCHECK(!response_info_) << "Cannot NotifyFailure after headers."; |
246 | 325 |
247 net::HttpStatusCode status_code = net::HTTP_INTERNAL_SERVER_ERROR; | 326 HeadersCompleted(NetErrorToHttpStatusCode(error_code)); |
248 switch (error_code) { | |
249 case net::ERR_ACCESS_DENIED: | |
250 status_code = net::HTTP_FORBIDDEN; | |
251 break; | |
252 case net::ERR_FILE_NOT_FOUND: | |
253 status_code = net::HTTP_NOT_FOUND; | |
254 break; | |
255 case net::ERR_METHOD_NOT_SUPPORTED: | |
256 status_code = net::HTTP_METHOD_NOT_ALLOWED; | |
257 break; | |
258 case net::ERR_REQUEST_RANGE_NOT_SATISFIABLE: | |
259 status_code = net::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE; | |
260 break; | |
261 case net::ERR_INVALID_ARGUMENT: | |
262 status_code = net::HTTP_BAD_REQUEST; | |
263 break; | |
264 case net::ERR_CACHE_READ_FAILURE: | |
265 case net::ERR_CACHE_CHECKSUM_READ_FAILURE: | |
266 case net::ERR_UNEXPECTED: | |
267 case net::ERR_FAILED: | |
268 break; | |
269 default: | |
270 DCHECK(false) << "Error code not supported: " << error_code; | |
271 break; | |
272 } | |
273 HeadersCompleted(status_code); | |
274 } | 327 } |
275 | 328 |
276 void BlobURLRequestJob::HeadersCompleted(net::HttpStatusCode status_code) { | 329 void BlobURLRequestJob::HeadersCompleted(net::HttpStatusCode status_code) { |
277 std::string status("HTTP/1.1 "); | 330 int64_t content_size = 0; |
278 status.append(base::IntToString(status_code)); | |
279 status.append(" "); | |
280 status.append(net::GetHttpReasonPhrase(status_code)); | |
281 status.append("\0\0", 2); | |
282 net::HttpResponseHeaders* headers = new net::HttpResponseHeaders(status); | |
283 | |
284 set_expected_content_size(0); | |
285 | |
286 if (status_code == net::HTTP_OK || status_code == net::HTTP_PARTIAL_CONTENT) { | |
287 set_expected_content_size(blob_reader_->remaining_bytes()); | |
288 std::string content_length_header(net::HttpRequestHeaders::kContentLength); | |
289 content_length_header.append(": "); | |
290 content_length_header.append( | |
291 base::Int64ToString(blob_reader_->remaining_bytes())); | |
292 headers->AddHeader(content_length_header); | |
293 if (status_code == net::HTTP_PARTIAL_CONTENT) { | |
294 DCHECK(byte_range_set_); | |
295 DCHECK(byte_range_.IsValid()); | |
296 std::string content_range_header(net::HttpResponseHeaders::kContentRange); | |
297 content_range_header.append(": bytes "); | |
298 content_range_header.append(base::StringPrintf( | |
299 "%" PRId64 "-%" PRId64, byte_range_.first_byte_position(), | |
300 byte_range_.last_byte_position())); | |
301 content_range_header.append("/"); | |
302 content_range_header.append( | |
303 base::StringPrintf("%" PRId64, blob_reader_->total_size())); | |
304 headers->AddHeader(content_range_header); | |
305 } | |
306 if (!blob_handle_->content_type().empty()) { | |
307 std::string content_type_header(net::HttpRequestHeaders::kContentType); | |
308 content_type_header.append(": "); | |
309 content_type_header.append(blob_handle_->content_type()); | |
310 headers->AddHeader(content_type_header); | |
311 } | |
312 if (!blob_handle_->content_disposition().empty()) { | |
313 std::string content_disposition_header("Content-Disposition: "); | |
314 content_disposition_header.append(blob_handle_->content_disposition()); | |
315 headers->AddHeader(content_disposition_header); | |
316 } | |
317 } | |
318 | |
319 response_info_.reset(new net::HttpResponseInfo()); | 331 response_info_.reset(new net::HttpResponseInfo()); |
320 response_info_->headers = headers; | 332 response_info_->headers = |
| 333 GenerateHeaders(status_code, blob_handle_.get(), blob_reader_.get(), |
| 334 &byte_range_, &content_size); |
| 335 set_expected_content_size(content_size); |
321 if (blob_reader_) | 336 if (blob_reader_) |
322 response_info_->metadata = blob_reader_->side_data(); | 337 response_info_->metadata = blob_reader_->side_data(); |
323 | 338 |
324 NotifyHeadersComplete(); | 339 NotifyHeadersComplete(); |
325 } | 340 } |
326 | 341 |
327 } // namespace storage | 342 } // namespace storage |
OLD | NEW |