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

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 int64 size = static_cast<int64>(Java_InputStream_available(env,
74 stream_.obj()));
75 if (ClearException(env)) {
76 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
77 net::ERR_FAILED));
78 return false;
79 }
80
81 if (size <= 0)
82 return true;
83
84 // Check that the requested range was valid.
85 if (!byte_range_.ComputeBounds(size)) {
86 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
87 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
88 return false;
89 }
90
91 size = byte_range_.last_byte_position() -
92 byte_range_.first_byte_position() + 1;
93 DCHECK_GE(size, 0);
94 set_expected_content_size(size);
95
96 return true;
97 }
98
99 bool AndroidStreamReaderURLRequestJob::SkipToRequestedRange(JNIEnv* env) {
100 // Skip to the start of the requested data. This has to be done in a loop
101 // because the underlying InputStream is not guaranteed to skip the requested
102 // number of bytes.
103 if (byte_range_.first_byte_position() != 0) {
104 int64 skipped, bytes_to_skip = byte_range_.first_byte_position();
105 do {
106 skipped = static_cast<int64>(Java_InputStream_skip(env, stream_.obj(),
107 bytes_to_skip));
108 if (ClearException(env)) {
109 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
110 net::ERR_FAILED));
111 return false;
112 }
113 if (skipped <= 0) {
114 NotifyDone(
115 net::URLRequestStatus(net::URLRequestStatus::FAILED,
116 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
117 return false;
118 }
119 } while ((bytes_to_skip -= skipped) > 0);
120 }
121 return true;
122 }
123
124 bool AndroidStreamReaderURLRequestJob::ReadRawData(net::IOBuffer* dest,
125 int dest_size,
126 int *bytes_read) {
127 DCHECK_NE(dest_size, 0);
128 DCHECK(bytes_read);
129 DCHECK(stream_.obj());
130
131 JNIEnv* env = AttachCurrentThread();
132 DCHECK(env);
133
134 if (!buffer_.obj()) {
135 // Allocate transfer buffer.
136 buffer_.Reset(env, env->NewByteArray(kBufferSize));
137 if (ClearException(env)) {
138 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
139 net::ERR_FAILED));
140 return false;
141 }
142 }
143
144 jbyteArray buffer = static_cast<jbyteArray>(buffer_.obj());
Nico 2012/07/27 15:23:45 You shouldn't need the static_cast
felipeg 2012/07/30 16:48:54 Done.
145
146 *bytes_read = 0;
147 if (!dest_size)
148 return true;
149
150 // Read data in multiples of the buffer size.
151 while (dest_size > 0) {
152 int read_size = std::min(dest_size, kBufferSize);
153 // TODO(skyostil): Make this non-blocking
154 int byte_count = static_cast<int>(
Nico 2012/07/27 15:23:45 nit: Why not using the corresponding stdint.h type
felipeg 2012/07/30 16:48:54 Done.
155 Java_InputStream_read(env, stream_.obj(), buffer, 0, read_size));
156 if (byte_count <= 0) {
157 // net::URLRequestJob will call NotifyDone for us after the end of the
158 // file is reached.
159 break;
160 }
161
162 if (ClearException(env)) {
163 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
164 net::ERR_FAILED));
165 return false;
166 }
167
168 #ifndef NDEBUG
169 int buffer_length = static_cast<int>(env->GetArrayLength(buffer));
170 DCHECK_GE(read_size, byte_count);
171 DCHECK_GE(buffer_length, byte_count);
172 #endif // NDEBUG
173
174 // Copy the data over to the provided C++ side buffer.
175 DCHECK_GE(dest_size, byte_count);
176 env->GetByteArrayRegion(buffer, 0, byte_count,
177 reinterpret_cast<jbyte*>(dest->data() + *bytes_read));
178
179 if (ClearException(env)) {
180 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
181 net::ERR_FAILED));
182 return false;
183 }
184
185 *bytes_read += byte_count;
186 dest_size -= byte_count;
187 }
188 return true;
189 }
190
191 bool AndroidStreamReaderURLRequestJob::GetMimeType(
192 std::string* mime_type) const {
193 JNIEnv* env = AttachCurrentThread();
194 DCHECK(env);
195
196 return delegate_->GetMimeType(env,
197 request(),
198 stream_.obj(),
199 mime_type);
200 }
201
202 bool AndroidStreamReaderURLRequestJob::GetCharset(
203 std::string* charset) {
204 JNIEnv* env = AttachCurrentThread();
205 DCHECK(env);
206
207 return delegate_->GetCharset(env,
208 request(),
209 stream_.obj(),
210 charset);
211 }
212
213 void AndroidStreamReaderURLRequestJob::SetExtraRequestHeaders(
214 const net::HttpRequestHeaders& headers) {
215 std::string range_header;
216 if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
217 // We only care about "Range" header here.
218 std::vector<net::HttpByteRange> ranges;
219 if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
220 if (ranges.size() == 1) {
221 byte_range_ = ranges[0];
222 } else {
223 // We don't support multiple range requests in one single URL request,
224 // because we need to do multipart encoding here.
225 NotifyDone(net::URLRequestStatus(
226 net::URLRequestStatus::FAILED,
227 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
228 }
229 }
230 }
231 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698