summaryrefslogtreecommitdiffstats
path: root/content/browser/streams/stream_url_request_job.cc
diff options
context:
space:
mode:
authorzork@chromium.org <zork@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-14 15:06:15 +0000
committerzork@chromium.org <zork@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-14 15:06:15 +0000
commit2f67b439d86916fad3abd6dc6d4a55a32d2596f6 (patch)
tree33a0f7b10c8113a6f04eadddffb08a118bb58e55 /content/browser/streams/stream_url_request_job.cc
parent61fdcbf4572ca0c6a80109f4c9437a58caded5ac (diff)
downloadchromium_src-2f67b439d86916fad3abd6dc6d4a55a32d2596f6.zip
chromium_src-2f67b439d86916fad3abd6dc6d4a55a32d2596f6.tar.gz
chromium_src-2f67b439d86916fad3abd6dc6d4a55a32d2596f6.tar.bz2
Add URL request handling for Streams.
BUG=181495 Review URL: https://chromiumcodereview.appspot.com/12734003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@188075 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/streams/stream_url_request_job.cc')
-rw-r--r--content/browser/streams/stream_url_request_job.cc243
1 files changed, 243 insertions, 0 deletions
diff --git a/content/browser/streams/stream_url_request_job.cc b/content/browser/streams/stream_url_request_job.cc
new file mode 100644
index 0000000..da2e9ce
--- /dev/null
+++ b/content/browser/streams/stream_url_request_job.cc
@@ -0,0 +1,243 @@
+// Copyright (c) 2013 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 "content/browser/streams/stream_url_request_job.h"
+
+#include "base/string_number_conversions.h"
+#include "content/browser/streams/stream.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_byte_range.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_response_info.h"
+#include "net/http/http_util.h"
+#include "net/url_request/url_request.h"
+
+namespace content {
+
+namespace {
+
+const int kHTTPOk = 200;
+const int kHTTPNotAllowed = 403;
+const int kHTTPNotFound = 404;
+const int kHTTPMethodNotAllow = 405;
+const int kHTTPInternalError = 500;
+
+const char kHTTPOKText[] = "OK";
+const char kHTTPNotAllowedText[] = "Not Allowed";
+const char kHTTPNotFoundText[] = "Not Found";
+const char kHTTPMethodNotAllowText[] = "Method Not Allowed";
+const char kHTTPInternalErrorText[] = "Internal Server Error";
+
+} // namespace
+
+StreamURLRequestJob::StreamURLRequestJob(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ scoped_refptr<Stream> stream)
+ : net::URLRequestJob(request, network_delegate),
+ ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
+ stream_(stream),
+ headers_set_(false),
+ pending_buffer_size_(0),
+ total_bytes_read_(0),
+ max_range_(0),
+ request_failed_(false) {
+ DCHECK(stream_);
+ stream_->SetReadObserver(this);
+}
+
+StreamURLRequestJob::~StreamURLRequestJob() {
+ ClearStream();
+}
+
+void StreamURLRequestJob::OnDataAvailable(Stream* stream) {
+ // Clear the IO_PENDING status.
+ SetStatus(net::URLRequestStatus());
+ if (pending_buffer_) {
+ int bytes_read;
+ stream_->ReadRawData(pending_buffer_, pending_buffer_size_, &bytes_read);
+
+ // Clear the buffers before notifying the read is complete, so that it is
+ // safe for the observer to read.
+ pending_buffer_ = NULL;
+ pending_buffer_size_ = 0;
+
+ total_bytes_read_ += bytes_read;
+ NotifyReadComplete(bytes_read);
+ }
+}
+
+// net::URLRequestJob methods.
+void StreamURLRequestJob::Start() {
+ // Continue asynchronously.
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&StreamURLRequestJob::DidStart, weak_factory_.GetWeakPtr()));
+}
+
+void StreamURLRequestJob::Kill() {
+ net::URLRequestJob::Kill();
+ weak_factory_.InvalidateWeakPtrs();
+ ClearStream();
+}
+
+bool StreamURLRequestJob::ReadRawData(net::IOBuffer* buf,
+ int buf_size,
+ int* bytes_read) {
+ if (request_failed_)
+ return true;
+
+ DCHECK(bytes_read);
+ int to_read = buf_size;
+ if (max_range_ && to_read) {
+ if (to_read + total_bytes_read_ > max_range_)
+ to_read = max_range_ - total_bytes_read_;
+
+ if (to_read <= 0) {
+ *bytes_read = 0;
+ return true;
+ }
+ }
+
+ switch (stream_->ReadRawData(buf, to_read, bytes_read)) {
+ case Stream::STREAM_HAS_DATA:
+ case Stream::STREAM_COMPLETE:
+ total_bytes_read_ += *bytes_read;
+ return true;
+ case Stream::STREAM_EMPTY:
+ pending_buffer_ = buf;
+ pending_buffer_size_ = to_read;
+ SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
+ return false;
+ }
+ NOTREACHED();
+ return false;
+}
+
+bool StreamURLRequestJob::GetMimeType(std::string* mime_type) const {
+ if (!response_info_.get())
+ return false;
+
+ // TODO(zork): Support registered MIME types if needed.
+ return response_info_->headers->GetMimeType(mime_type);
+}
+
+void StreamURLRequestJob::GetResponseInfo(net::HttpResponseInfo* info) {
+ if (response_info_.get())
+ *info = *response_info_;
+}
+
+int StreamURLRequestJob::GetResponseCode() const {
+ if (!response_info_.get())
+ return -1;
+
+ return response_info_->headers->response_code();
+}
+
+void StreamURLRequestJob::SetExtraRequestHeaders(
+ const net::HttpRequestHeaders& headers) {
+ std::string range_header;
+ if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
+ std::vector<net::HttpByteRange> ranges;
+ if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
+ if (ranges.size() == 1) {
+ // Streams don't support seeking, so a non-zero starting position
+ // doesn't make sense.
+ if (ranges[0].first_byte_position() == 0) {
+ max_range_ = ranges[0].last_byte_position() + 1;
+ } else {
+ NotifyFailure(net::ERR_METHOD_NOT_SUPPORTED);
+ return;
+ }
+ } else {
+ NotifyFailure(net::ERR_METHOD_NOT_SUPPORTED);
+ return;
+ }
+ }
+ }
+}
+
+void StreamURLRequestJob::DidStart() {
+ // We only support GET request.
+ if (request()->method() != "GET") {
+ NotifyFailure(net::ERR_METHOD_NOT_SUPPORTED);
+ return;
+ }
+
+ HeadersCompleted(kHTTPOk, kHTTPOKText);
+}
+
+void StreamURLRequestJob::NotifyFailure(int error_code) {
+ request_failed_ = true;
+
+ // If we already return the headers on success, we can't change the headers
+ // now. Instead, we just error out.
+ if (headers_set_) {
+ NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+ error_code));
+ return;
+ }
+
+ // TODO(zork): Share these with BlobURLRequestJob.
+ int status_code = 0;
+ std::string status_txt;
+ switch (error_code) {
+ case net::ERR_ACCESS_DENIED:
+ status_code = kHTTPNotAllowed;
+ status_txt = kHTTPNotAllowedText;
+ break;
+ case net::ERR_FILE_NOT_FOUND:
+ status_code = kHTTPNotFound;
+ status_txt = kHTTPNotFoundText;
+ break;
+ case net::ERR_METHOD_NOT_SUPPORTED:
+ status_code = kHTTPMethodNotAllow;
+ status_txt = kHTTPMethodNotAllowText;
+ break;
+ case net::ERR_FAILED:
+ status_code = kHTTPInternalError;
+ status_txt = kHTTPInternalErrorText;
+ break;
+ default:
+ DCHECK(false);
+ status_code = kHTTPInternalError;
+ status_txt = kHTTPInternalErrorText;
+ break;
+ }
+ HeadersCompleted(status_code, status_txt);
+}
+
+void StreamURLRequestJob::HeadersCompleted(int status_code,
+ const std::string& status_text) {
+ std::string status("HTTP/1.1 ");
+ status.append(base::IntToString(status_code));
+ status.append(" ");
+ status.append(status_text);
+ status.append("\0\0", 2);
+ net::HttpResponseHeaders* headers = new net::HttpResponseHeaders(status);
+
+ if (status_code == kHTTPOk) {
+ std::string content_type_header(net::HttpRequestHeaders::kContentType);
+ content_type_header.append(": ");
+ content_type_header.append("plain/text");
+ headers->AddHeader(content_type_header);
+ }
+
+ response_info_.reset(new net::HttpResponseInfo());
+ response_info_->headers = headers;
+
+ headers_set_ = true;
+
+ NotifyHeadersComplete();
+}
+
+void StreamURLRequestJob::ClearStream() {
+ if (stream_) {
+ stream_->RemoveReadObserver(this);
+ stream_ = NULL;
+ }
+}
+
+} // namespace content