OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 "net/cronet/android/org_chromium_net_UrlRequest.h" | |
6 | |
7 #include "base/android/jni_android.h" | |
8 #include "base/macros.h" | |
9 #include "jni/UrlRequest_jni.h" | |
10 #include "net/base/net_errors.h" | |
11 #include "net/base/request_priority.h" | |
12 #include "net/cronet/android/url_request_context_peer.h" | |
13 #include "net/cronet/android/url_request_peer.h" | |
14 | |
15 namespace net { | |
16 namespace { | |
17 | |
18 net::RequestPriority ConvertRequestPriority(jint request_priority) { | |
19 switch (request_priority) { | |
20 case REQUEST_PRIORITY_IDLE: | |
21 return net::IDLE; | |
22 case REQUEST_PRIORITY_LOWEST: | |
23 return net::LOWEST; | |
24 case REQUEST_PRIORITY_LOW: | |
25 return net::LOW; | |
26 case REQUEST_PRIORITY_MEDIUM: | |
27 return net::MEDIUM; | |
28 case REQUEST_PRIORITY_HIGHEST: | |
29 return net::HIGHEST; | |
30 default: | |
31 return net::LOWEST; | |
32 } | |
33 } | |
34 | |
35 void SetPostContentType(JNIEnv* env, | |
36 URLRequestPeer* request, | |
37 jstring content_type) { | |
38 DCHECK(request != NULL); | |
39 | |
40 std::string method_post("POST"); | |
41 request->SetMethod(method_post); | |
42 | |
43 std::string content_type_header("Content-Type"); | |
44 | |
45 const char* content_type_utf8 = env->GetStringUTFChars(content_type, NULL); | |
46 std::string content_type_string(content_type_utf8); | |
47 env->ReleaseStringUTFChars(content_type, content_type_utf8); | |
48 | |
49 request->AddHeader(content_type_header, content_type_string); | |
50 } | |
51 | |
52 // A delegate of URLRequestPeer that delivers callbacks to the Java layer. | |
53 class JniURLRequestPeerDelegate | |
54 : public URLRequestPeer::URLRequestPeerDelegate { | |
55 public: | |
56 JniURLRequestPeerDelegate(JNIEnv* env, jobject owner) { | |
57 owner_ = env->NewGlobalRef(owner); | |
58 } | |
59 | |
60 virtual void OnAppendChunkCompleted(URLRequestPeer* request) OVERRIDE { | |
61 JNIEnv* env = base::android::AttachCurrentThread(); | |
62 net::Java_UrlRequest_onAppendChunkCompleted(env, owner_); | |
63 } | |
64 | |
65 virtual void OnResponseStarted(URLRequestPeer* request) OVERRIDE { | |
66 JNIEnv* env = base::android::AttachCurrentThread(); | |
67 net::Java_UrlRequest_onResponseStarted(env, owner_); | |
68 } | |
69 | |
70 virtual void OnBytesRead(URLRequestPeer* request) OVERRIDE { | |
71 int bytes_read = request->bytes_read(); | |
72 if (bytes_read != 0) { | |
73 JNIEnv* env = base::android::AttachCurrentThread(); | |
74 jobject bytebuf = env->NewDirectByteBuffer(request->Data(), bytes_read); | |
75 net::Java_UrlRequest_onBytesRead(env, owner_, bytebuf); | |
76 env->DeleteLocalRef(bytebuf); | |
77 } | |
78 } | |
79 | |
80 virtual void OnRequestFinished(URLRequestPeer* request) OVERRIDE { | |
81 JNIEnv* env = base::android::AttachCurrentThread(); | |
82 net::Java_UrlRequest_finish(env, owner_); | |
83 } | |
84 | |
85 protected: | |
86 virtual ~JniURLRequestPeerDelegate() { | |
87 JNIEnv* env = base::android::AttachCurrentThread(); | |
88 env->DeleteGlobalRef(owner_); | |
89 } | |
90 | |
91 private: | |
92 jobject owner_; | |
93 | |
94 DISALLOW_COPY_AND_ASSIGN(JniURLRequestPeerDelegate); | |
95 }; | |
96 | |
97 } // namespace | |
98 | |
99 // Explicitly register static JNI functions. | |
100 bool UrlRequestRegisterJni(JNIEnv* env) { return RegisterNativesImpl(env); } | |
101 | |
102 static jlong CreateRequestPeer(JNIEnv* env, | |
103 jobject object, | |
104 jlong urlRequestContextPeer, | |
105 jstring url_string, | |
106 jint priority) { | |
107 URLRequestContextPeer* context = | |
108 reinterpret_cast<URLRequestContextPeer*>(urlRequestContextPeer); | |
109 DCHECK(context != NULL); | |
110 | |
111 const char* url_utf8 = env->GetStringUTFChars(url_string, NULL); | |
112 | |
113 DVLOG(context->logging_level()) | |
114 << "New chromium network request. URL:" << url_utf8; | |
115 | |
116 GURL url(url_utf8); | |
117 | |
118 env->ReleaseStringUTFChars(url_string, url_utf8); | |
119 | |
120 URLRequestPeer* peer = | |
121 new URLRequestPeer(context, | |
122 new JniURLRequestPeerDelegate(env, object), | |
123 url, | |
124 ConvertRequestPriority(priority)); | |
125 | |
126 return reinterpret_cast<jlong>(peer); | |
127 } | |
128 | |
129 // synchronized | |
130 static void AddHeader(JNIEnv* env, | |
131 jobject object, | |
132 jlong urlRequestPeer, | |
133 jstring name, | |
134 jstring value) { | |
135 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
136 DCHECK(request != NULL); | |
137 | |
138 const char* name_utf8 = env->GetStringUTFChars(name, NULL); | |
139 std::string name_string(name_utf8); | |
140 env->ReleaseStringUTFChars(name, name_utf8); | |
141 | |
142 const char* value_utf8 = env->GetStringUTFChars(value, NULL); | |
143 std::string value_string(value_utf8); | |
144 env->ReleaseStringUTFChars(value, value_utf8); | |
145 | |
146 request->AddHeader(name_string, value_string); | |
147 } | |
148 | |
149 static void SetPostData(JNIEnv* env, | |
150 jobject object, | |
151 jlong urlRequestPeer, | |
152 jstring content_type, | |
153 jbyteArray content) { | |
154 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
155 SetPostContentType(env, request, content_type); | |
156 | |
157 if (content != NULL) { | |
158 jsize size = env->GetArrayLength(content); | |
159 if (size > 0) { | |
160 jbyte* content_bytes = env->GetByteArrayElements(content, NULL); | |
161 request->SetPostContent(reinterpret_cast<const char*>(content_bytes), | |
162 size); | |
163 env->ReleaseByteArrayElements(content, content_bytes, 0); | |
164 } | |
165 } | |
166 } | |
167 | |
168 static void BeginChunkedUpload(JNIEnv* env, | |
169 jobject object, | |
170 jlong urlRequestPeer, | |
171 jstring content_type) { | |
172 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
173 SetPostContentType(env, request, content_type); | |
174 | |
175 request->EnableStreamingUpload(); | |
176 } | |
177 | |
178 static void AppendChunk(JNIEnv* env, | |
179 jobject object, | |
180 jlong urlRequestPeer, | |
181 jobject chunk_byte_buffer, | |
182 jint chunk_size, | |
183 jboolean is_last_chunk) { | |
184 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
185 CHECK(request != NULL); | |
186 | |
187 if (chunk_byte_buffer != NULL) { | |
188 void* chunk = env->GetDirectBufferAddress(chunk_byte_buffer); | |
189 request->AppendChunk( | |
190 reinterpret_cast<const char*>(chunk), chunk_size, is_last_chunk); | |
191 } | |
192 } | |
193 | |
194 /* synchronized */ | |
195 static void Start(JNIEnv* env, jobject object, jlong urlRequestPeer) { | |
196 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
197 if (request != NULL) { | |
198 request->Start(); | |
199 } | |
200 } | |
201 | |
202 /* synchronized */ | |
203 static void DestroyRequestPeer(JNIEnv* env, | |
204 jobject object, | |
205 jlong urlRequestPeer) { | |
206 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
207 if (request != NULL) { | |
208 request->Destroy(); | |
209 } | |
210 } | |
211 | |
212 /* synchronized */ | |
213 static void Cancel(JNIEnv* env, jobject object, jlong urlRequestPeer) { | |
214 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
215 if (request != NULL) { | |
216 request->Cancel(); | |
217 } | |
218 } | |
219 | |
220 static jint GetErrorCode(JNIEnv* env, jobject object, jlong urlRequestPeer) { | |
221 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
222 int error_code = request->error_code(); | |
223 switch (error_code) { | |
224 // TODO(mef): Investigate returning success on positive values, too, as | |
225 // they technically indicate success. | |
226 case net::OK: | |
227 return REQUEST_ERROR_SUCCESS; | |
228 | |
229 // TODO(mef): Investigate this. The fact is that Chrome does not do this, | |
230 // and this library is not just being used for downloads. | |
231 | |
232 // Comment from src/content/browser/download/download_resource_handler.cc: | |
233 // ERR_CONTENT_LENGTH_MISMATCH and ERR_INCOMPLETE_CHUNKED_ENCODING are | |
234 // allowed since a number of servers in the wild close the connection too | |
235 // early by mistake. Other browsers - IE9, Firefox 11.0, and Safari 5.1.4 - | |
236 // treat downloads as complete in both cases, so we follow their lead. | |
237 case net::ERR_CONTENT_LENGTH_MISMATCH: | |
238 case net::ERR_INCOMPLETE_CHUNKED_ENCODING: | |
239 return REQUEST_ERROR_SUCCESS; | |
240 | |
241 case net::ERR_INVALID_URL: | |
242 case net::ERR_DISALLOWED_URL_SCHEME: | |
243 case net::ERR_UNKNOWN_URL_SCHEME: | |
244 return REQUEST_ERROR_MALFORMED_URL; | |
245 | |
246 case net::ERR_CONNECTION_TIMED_OUT: | |
247 return REQUEST_ERROR_CONNECTION_TIMED_OUT; | |
248 | |
249 case net::ERR_NAME_NOT_RESOLVED: | |
250 return REQUEST_ERROR_UNKNOWN_HOST; | |
251 } | |
252 return REQUEST_ERROR_UNKNOWN; | |
253 } | |
254 | |
255 static jstring GetErrorString(JNIEnv* env, | |
256 jobject object, | |
257 jlong urlRequestPeer) { | |
258 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
259 int error_code = request->error_code(); | |
260 char buffer[200]; | |
261 snprintf(buffer, | |
262 sizeof(buffer), | |
263 "System error: %s(%d)", | |
264 net::ErrorToString(error_code), | |
265 error_code); | |
266 return env->NewStringUTF(buffer); | |
267 } | |
268 | |
269 static jint GetHttpStatusCode(JNIEnv* env, | |
270 jobject object, | |
271 jlong urlRequestPeer) { | |
272 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
273 return request->http_status_code(); | |
274 } | |
275 | |
276 static jstring GetContentType(JNIEnv* env, | |
277 jobject object, | |
278 jlong urlRequestPeer) { | |
279 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
280 if (request == NULL) { | |
281 return NULL; | |
282 } | |
283 std::string type = request->content_type(); | |
284 if (!type.empty()) { | |
285 return env->NewStringUTF(type.c_str()); | |
286 } else { | |
287 return NULL; | |
288 } | |
289 } | |
290 | |
291 static jlong GetContentLength(JNIEnv* env, | |
292 jobject object, | |
293 jlong urlRequestPeer) { | |
294 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
295 if (request == NULL) { | |
296 return 0; | |
297 } | |
298 return request->content_length(); | |
299 } | |
300 | |
301 } // namespace net | |
OLD | NEW |