OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "android_webview/browser/net/android_stream_reader_url_request_job.h" | |
6 | |
7 #include "android_webview/browser/input_stream.h" | |
8 #include "android_webview/browser/net/input_stream_reader.h" | |
9 #include "base/android/jni_android.h" | |
10 #include "base/android/jni_string.h" | |
11 #include "base/bind.h" | |
12 #include "base/bind_helpers.h" | |
13 #include "base/lazy_instance.h" | |
14 #include "base/message_loop.h" | |
15 #include "base/task_runner.h" | |
16 #include "base/threading/sequenced_worker_pool.h" | |
17 #include "base/threading/thread.h" | |
18 #include "content/public/browser/browser_thread.h" | |
19 #include "net/base/io_buffer.h" | |
20 #include "net/base/mime_util.h" | |
21 #include "net/base/net_errors.h" | |
22 #include "net/base/net_util.h" | |
23 #include "net/http/http_util.h" | |
24 #include "net/url_request/url_request.h" | |
25 #include "net/url_request/url_request_job_manager.h" | |
26 | |
27 using android_webview::InputStream; | |
28 using android_webview::InputStreamReader; | |
29 using base::android::AttachCurrentThread; | |
30 using base::PostTaskAndReplyWithResult; | |
31 using content::BrowserThread; | |
32 | |
33 AndroidStreamReaderURLRequestJob::AndroidStreamReaderURLRequestJob( | |
34 net::URLRequest* request, | |
35 net::NetworkDelegate* network_delegate, | |
36 scoped_ptr<Delegate> delegate) | |
37 : URLRequestJob(request, network_delegate), | |
38 delegate_(delegate.Pass()), | |
39 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { | |
40 DCHECK(delegate_.get()); | |
41 } | |
42 | |
43 AndroidStreamReaderURLRequestJob::~AndroidStreamReaderURLRequestJob() { | |
44 } | |
45 | |
46 void AndroidStreamReaderURLRequestJob::Start() { | |
47 // Start reading asynchronously so that all error reporting and data | |
48 // callbacks happen as they would for network requests. | |
49 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); | |
50 MessageLoop::current()->PostTask( | |
51 FROM_HERE, | |
52 base::Bind( | |
53 &AndroidStreamReaderURLRequestJob::StartAsync, | |
54 weak_factory_.GetWeakPtr())); | |
55 } | |
56 | |
57 void AndroidStreamReaderURLRequestJob::Kill() { | |
58 weak_factory_.InvalidateWeakPtrs(); | |
59 URLRequestJob::Kill(); | |
60 } | |
61 | |
62 InputStreamReader* AndroidStreamReaderURLRequestJob::CreateStreamReader( | |
63 InputStream* stream) { | |
64 return new InputStreamReader(stream); | |
65 } | |
66 | |
67 void AndroidStreamReaderURLRequestJob::StartAsync() { | |
68 JNIEnv* env = AttachCurrentThread(); | |
69 DCHECK(env); | |
70 | |
71 // This could be done in the InputStreamReader but would force more | |
72 // complex synchronization in the delegate. | |
73 stream_ = delegate_->OpenInputStream(env, request()); | |
74 if (!stream_) { | |
75 NotifyDone( | |
76 net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED)); | |
77 return; | |
78 } | |
79 | |
80 DCHECK(!input_stream_reader_); | |
81 input_stream_reader_ = CreateStreamReader(stream_.get()); | |
82 CHECK(input_stream_reader_); | |
83 | |
84 PostTaskAndReplyWithResult( | |
85 GetWorkerThreadRunner(), | |
86 FROM_HERE, | |
87 base::Bind(&InputStreamReader::Seek, input_stream_reader_, byte_range_), | |
88 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted, | |
89 weak_factory_.GetWeakPtr())); | |
90 } | |
91 | |
92 void AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted( | |
93 int result) { | |
94 // Clear the IO_PENDING status set in Start(). | |
95 SetStatus(net::URLRequestStatus()); | |
96 if (result >= 0) { | |
97 set_expected_content_size(result); | |
98 NotifyHeadersComplete(); | |
99 } else { | |
100 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); | |
101 } | |
102 } | |
103 | |
104 void AndroidStreamReaderURLRequestJob::OnReaderReadCompleted( | |
105 int result) { | |
106 // The URLRequest API contract requires that: | |
107 // * NotifyDone be called once, to set the status code, indicate the job is | |
108 // finished (there will be no further IO), | |
109 // * NotifyReadComplete be called if false is returned from ReadRawData to | |
110 // indicate that the IOBuffer will not be used by the job anymore. | |
111 // There might be multiple calls to ReadRawData (and thus multiple calls to | |
112 // NotifyReadComplete), which is why NotifyDone is called only on errors | |
113 // (result < 0) and end of data (result == 0). | |
114 if (result == 0) { | |
115 NotifyDone(net::URLRequestStatus()); | |
116 } else if (result < 0) { | |
117 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); | |
118 } else { | |
119 // Clear the IO_PENDING status. | |
120 SetStatus(net::URLRequestStatus()); | |
121 } | |
122 NotifyReadComplete(result); | |
123 } | |
124 | |
125 base::TaskRunner* AndroidStreamReaderURLRequestJob::GetWorkerThreadRunner() { | |
126 return static_cast<base::TaskRunner*>(BrowserThread::GetBlockingPool()); | |
127 } | |
128 | |
129 bool AndroidStreamReaderURLRequestJob::ReadRawData(net::IOBuffer* dest, | |
130 int dest_size, | |
131 int *bytes_read) { | |
joth
2012/11/20 20:46:35
ubernit: put '*' next to the type
mkosiba (inactive)
2012/11/21 15:19:47
Done.
| |
132 DCHECK(input_stream_reader_); | |
133 | |
134 PostTaskAndReplyWithResult( | |
135 GetWorkerThreadRunner(), | |
136 FROM_HERE, | |
137 base::Bind(&InputStreamReader::ReadRawData, | |
138 input_stream_reader_, | |
139 base::Unretained(dest), | |
140 dest_size), | |
141 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderReadCompleted, | |
142 weak_factory_.GetWeakPtr())); | |
143 | |
144 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); | |
145 return false; | |
146 } | |
147 | |
148 bool AndroidStreamReaderURLRequestJob::GetMimeType( | |
149 std::string* mime_type) const { | |
150 JNIEnv* env = AttachCurrentThread(); | |
151 DCHECK(env); | |
152 | |
153 if (!stream_) | |
154 return false; | |
155 | |
156 return delegate_->GetMimeType(env, request(), *stream_, mime_type); | |
157 } | |
158 | |
159 bool AndroidStreamReaderURLRequestJob::GetCharset( | |
160 std::string* charset) { | |
161 JNIEnv* env = AttachCurrentThread(); | |
162 DCHECK(env); | |
163 | |
164 if (!stream_) | |
165 return false; | |
166 | |
167 return delegate_->GetCharset(env, request(), *stream_, charset); | |
168 } | |
169 | |
170 void AndroidStreamReaderURLRequestJob::SetExtraRequestHeaders( | |
171 const net::HttpRequestHeaders& headers) { | |
172 std::string range_header; | |
173 if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) { | |
174 // We only care about "Range" header here. | |
joth
2012/11/20 20:46:35
nit: maybe expand the comment a little about what
mkosiba (inactive)
2012/11/21 15:19:47
Done.
| |
175 std::vector<net::HttpByteRange> ranges; | |
176 if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) { | |
177 if (ranges.size() == 1) { | |
178 byte_range_ = ranges[0]; | |
179 } else { | |
180 // We don't support multiple range requests in one single URL request, | |
181 // because we need to do multipart encoding here. | |
182 NotifyDone(net::URLRequestStatus( | |
183 net::URLRequestStatus::FAILED, | |
184 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); | |
185 } | |
186 } | |
187 } | |
188 } | |
OLD | NEW |