Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(45)

Side by Side Diff: chrome/browser/android/android_stream_reader_url_request_job.cc

Issue 10832034: Upstreaming AndroidProtocolAdapter. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 "chrome/browser/android/android_stream_reader_url_request_job.h"
6
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_string.h"
9 #include "net/base/io_buffer.h"
10 #include "net/base/mime_util.h"
11 #include "net/base/net_errors.h"
12 #include "net/base/net_util.h"
13 #include "net/http/http_util.h"
14 #include "net/url_request/url_request.h"
15 #include "net/url_request/url_request_context.h"
16 #include "net/url_request/url_request_error_job.h"
17 #include "net/url_request/url_request_file_job.h"
18 #include "net/url_request/url_request_job_manager.h"
19 // Disable "Warnings treated as errors" for input_stream_jni as it's a Java
20 // system class and we have to generate C++ hooks for all methods in the class
21 // even if they're unused.
22 #pragma GCC diagnostic ignored "-Wunused-function"
23 #include "jni/InputStream_jni.h"
24
25 using base::android::AttachCurrentThread;
26 using base::android::ClearException;
27 using base::android::ConvertUTF8ToJavaString;
28 using base::android::ScopedJavaGlobalRef;
29 using base::android::ScopedJavaLocalRef;
30 using JNI_InputStream::Java_InputStream_available;
31 using JNI_InputStream::Java_InputStream_skip;
32 using JNI_InputStream::Java_InputStream_read;
33
34
35 namespace {
36
37 // Maximum number of bytes to be read in a single read.
38 const int kBufferSize = 4096;
39
40 } // namespace
41
42 AndroidStreamReaderURLRequestJob::AndroidStreamReaderURLRequestJob(
43 net::URLRequest* request,
44 scoped_ptr<Delegate> delegate)
45 : URLRequestJob(request, request->context()->network_delegate()),
46 delegate_(delegate.Pass()) {
47 DCHECK(delegate_.get());
48 }
49
50 AndroidStreamReaderURLRequestJob::~AndroidStreamReaderURLRequestJob() {
51 }
52
53 bool AndroidStreamReaderURLRequestJob::InitJNIBindings(JNIEnv* env) {
54 return JNI_InputStream::RegisterNativesImpl(env);
55 }
56
57 void AndroidStreamReaderURLRequestJob::Start() {
58 JNIEnv* env = AttachCurrentThread();
59 DCHECK(env);
60
61 stream_.Reset(env, delegate_->OpenInputStream(env, request()).obj());
62 if (!stream_.obj()) {
63 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
64 net::ERR_FAILED));
65 return;
66 }
67
68 if (VerifyRequestedRange(env) && SkipToRequestedRange(env))
69 NotifyHeadersComplete();
70 }
71
72 bool AndroidStreamReaderURLRequestJob::VerifyRequestedRange(JNIEnv* env) {
73 int32_t size = Java_InputStream_available(env, stream_.obj());
74 if (ClearException(env)) {
75 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
76 net::ERR_FAILED));
77 return false;
78 }
79
80 if (size <= 0)
81 return true;
82
83 // Check that the requested range was valid.
84 if (!byte_range_.ComputeBounds(size)) {
85 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
86 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
87 return false;
88 }
89
90 size = byte_range_.last_byte_position() -
91 byte_range_.first_byte_position() + 1;
92 DCHECK_GE(size, 0);
93 set_expected_content_size(size);
94
95 return true;
96 }
97
98 bool AndroidStreamReaderURLRequestJob::SkipToRequestedRange(JNIEnv* env) {
99 // Skip to the start of the requested data. This has to be done in a loop
100 // because the underlying InputStream is not guaranteed to skip the requested
101 // number of bytes.
102 if (byte_range_.first_byte_position() != 0) {
103 int64_t skipped, bytes_to_skip = byte_range_.first_byte_position();
104 do {
105 skipped = Java_InputStream_skip(env, stream_.obj(), bytes_to_skip);
106 if (ClearException(env)) {
107 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
108 net::ERR_FAILED));
109 return false;
110 }
111 if (skipped <= 0) {
112 NotifyDone(
113 net::URLRequestStatus(net::URLRequestStatus::FAILED,
114 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
115 return false;
116 }
117 } while ((bytes_to_skip -= skipped) > 0);
118 }
119 return true;
120 }
121
122 bool AndroidStreamReaderURLRequestJob::ReadRawData(net::IOBuffer* dest,
123 int dest_size,
124 int *bytes_read) {
125 DCHECK_NE(dest_size, 0);
126 DCHECK(bytes_read);
127 DCHECK(stream_.obj());
128
129 JNIEnv* env = AttachCurrentThread();
130 DCHECK(env);
131
132 if (!buffer_.obj()) {
133 // Allocate transfer buffer.
134 buffer_.Reset(env, env->NewByteArray(kBufferSize));
135 if (ClearException(env)) {
136 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
137 net::ERR_FAILED));
138 return false;
139 }
140 }
141
142 jbyteArray buffer = buffer_.obj();
143 *bytes_read = 0;
144 if (!dest_size)
145 return true;
146
147 // Read data in multiples of the buffer size.
148 while (dest_size > 0) {
149 int read_size = std::min(dest_size, kBufferSize);
150 // TODO(skyostil): Make this non-blocking
151 int32_t byte_count =
152 Java_InputStream_read(env, stream_.obj(), buffer, 0, read_size);
153 if (byte_count <= 0) {
154 // net::URLRequestJob will call NotifyDone for us after the end of the
155 // file is reached.
156 break;
157 }
158
159 if (ClearException(env)) {
160 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
161 net::ERR_FAILED));
162 return false;
163 }
164
165 #ifndef NDEBUG
166 int32_t buffer_length = env->GetArrayLength(buffer);
167 DCHECK_GE(read_size, byte_count);
168 DCHECK_GE(buffer_length, byte_count);
169 #endif // NDEBUG
170
171 // Copy the data over to the provided C++ side buffer.
172 DCHECK_GE(dest_size, byte_count);
173 env->GetByteArrayRegion(buffer, 0, byte_count,
174 reinterpret_cast<jbyte*>(dest->data() + *bytes_read));
175
176 if (ClearException(env)) {
177 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
178 net::ERR_FAILED));
179 return false;
180 }
181
182 *bytes_read += byte_count;
183 dest_size -= byte_count;
184 }
185 return true;
186 }
187
188 bool AndroidStreamReaderURLRequestJob::GetMimeType(
189 std::string* mime_type) const {
190 JNIEnv* env = AttachCurrentThread();
191 DCHECK(env);
192
193 return delegate_->GetMimeType(env,
194 request(),
195 stream_.obj(),
196 mime_type);
197 }
198
199 bool AndroidStreamReaderURLRequestJob::GetCharset(
200 std::string* charset) {
201 JNIEnv* env = AttachCurrentThread();
202 DCHECK(env);
203
204 return delegate_->GetCharset(env,
205 request(),
206 stream_.obj(),
207 charset);
208 }
209
210 void AndroidStreamReaderURLRequestJob::SetExtraRequestHeaders(
211 const net::HttpRequestHeaders& headers) {
212 std::string range_header;
213 if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
214 // We only care about "Range" header here.
215 std::vector<net::HttpByteRange> ranges;
216 if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
217 if (ranges.size() == 1) {
218 byte_range_ = ranges[0];
219 } else {
220 // We don't support multiple range requests in one single URL request,
221 // because we need to do multipart encoding here.
222 NotifyDone(net::URLRequestStatus(
223 net::URLRequestStatus::FAILED,
224 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
225 }
226 }
227 }
228 }
OLDNEW
« no previous file with comments | « chrome/browser/android/android_stream_reader_url_request_job.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698