blob: 7ac56e8674b606d47ddc0c49874459cf8bc52491 [file] [log] [blame]
Andreas Huber5f5719e2011-03-08 15:59:28 -08001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "ChromiumHTTPDataSourceSupport"
19#include <utils/Log.h>
20
21#include <media/stagefright/foundation/AString.h>
22
23#include "support.h"
24
25#include "android/net/android_network_library_impl.h"
26#include "base/thread.h"
27#include "net/base/host_resolver.h"
28#include "net/base/ssl_config_service.h"
Andreas Huber20660ee2011-03-09 14:41:28 -080029#include "net/http/http_auth_handler_factory.h"
Andreas Huber5f5719e2011-03-08 15:59:28 -080030#include "net/http/http_cache.h"
Andreas Huberdb7dc9c2011-03-09 13:36:15 -080031#include "net/proxy/proxy_config_service_android.h"
Andreas Huber5f5719e2011-03-08 15:59:28 -080032
33#include "include/ChromiumHTTPDataSource.h"
34
35#include <cutils/properties.h>
36#include <media/stagefright/MediaErrors.h>
37
38namespace android {
39
40static Mutex gNetworkThreadLock;
41static base::Thread *gNetworkThread = NULL;
42static scoped_refptr<URLRequestContext> gReqContext;
43
44static void InitializeNetworkThreadIfNecessary() {
45 Mutex::Autolock autoLock(gNetworkThreadLock);
46 if (gNetworkThread == NULL) {
47 gNetworkThread = new base::Thread("network");
48 base::Thread::Options options;
49 options.message_loop_type = MessageLoop::TYPE_IO;
50 CHECK(gNetworkThread->StartWithOptions(options));
51
52 gReqContext = new SfRequestContext;
53
54 net::AndroidNetworkLibrary::RegisterSharedInstance(
55 new SfNetworkLibrary);
56 }
57}
58
59static void MY_LOGI(const char *s) {
60 LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "%s", s);
61}
62
63static void MY_LOGV(const char *s) {
64#if !defined(LOG_NDEBUG) || LOG_NDEBUG == 0
65 LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, "%s", s);
66#endif
67}
68
69SfNetLog::SfNetLog()
70 : mNextID(1) {
71}
72
73void SfNetLog::AddEntry(
74 EventType type,
75 const base::TimeTicks &time,
76 const Source &source,
77 EventPhase phase,
78 EventParameters *params) {
79#if 0
80 MY_LOGI(StringPrintf(
81 "AddEntry time=%s type=%s source=%s phase=%s\n",
82 TickCountToString(time).c_str(),
83 EventTypeToString(type),
84 SourceTypeToString(source.type),
85 EventPhaseToString(phase)).c_str());
86#endif
87}
88
89uint32 SfNetLog::NextID() {
90 return mNextID++;
91}
92
93net::NetLog::LogLevel SfNetLog::GetLogLevel() const {
94 return LOG_ALL;
95}
96
97////////////////////////////////////////////////////////////////////////////////
98
99SfRequestContext::SfRequestContext() {
100 AString ua;
101 ua.append("stagefright/1.2 (Linux;Android ");
102
103#if (PROPERTY_VALUE_MAX < 8)
104#error "PROPERTY_VALUE_MAX must be at least 8"
105#endif
106
107 char value[PROPERTY_VALUE_MAX];
108 property_get("ro.build.version.release", value, "Unknown");
109 ua.append(value);
110 ua.append(")");
111
112 mUserAgent = ua.c_str();
113
114 net_log_ = new SfNetLog;
115
116 host_resolver_ =
117 net::CreateSystemHostResolver(
118 net::HostResolver::kDefaultParallelism,
119 NULL /* resolver_proc */,
120 net_log_);
121
122 ssl_config_service_ =
123 net::SSLConfigService::CreateSystemSSLConfigService();
124
Andreas Huberdb7dc9c2011-03-09 13:36:15 -0800125 proxy_service_ = net::ProxyService::CreateWithoutProxyResolver(
126 new net::ProxyConfigServiceAndroid, net_log_);
Andreas Huber5f5719e2011-03-08 15:59:28 -0800127
128 http_transaction_factory_ = new net::HttpCache(
129 host_resolver_,
130 dnsrr_resolver_,
131 dns_cert_checker_.get(),
132 proxy_service_.get(),
133 ssl_config_service_.get(),
Andreas Huber20660ee2011-03-09 14:41:28 -0800134 net::HttpAuthHandlerFactory::CreateDefault(host_resolver_),
Andreas Huber5f5719e2011-03-08 15:59:28 -0800135 network_delegate_,
136 net_log_,
137 NULL); // backend_factory
138}
139
140const std::string &SfRequestContext::GetUserAgent(const GURL &url) const {
141 return mUserAgent;
142}
143
144////////////////////////////////////////////////////////////////////////////////
145
146SfNetworkLibrary::SfNetworkLibrary() {}
147
148SfNetworkLibrary::VerifyResult SfNetworkLibrary::VerifyX509CertChain(
149 const std::vector<std::string>& cert_chain,
150 const std::string& hostname,
151 const std::string& auth_type) {
152 return VERIFY_OK;
153}
154
155////////////////////////////////////////////////////////////////////////////////
156
157SfDelegate::SfDelegate()
158 : mOwner(NULL),
159 mURLRequest(NULL),
160 mReadBuffer(new net::IOBufferWithSize(8192)),
161 mNumBytesRead(0),
162 mNumBytesTotal(0),
163 mDataDestination(NULL),
164 mAtEOS(false) {
165 InitializeNetworkThreadIfNecessary();
166}
167
168SfDelegate::~SfDelegate() {
169 CHECK(mURLRequest == NULL);
170}
171
172void SfDelegate::setOwner(ChromiumHTTPDataSource *owner) {
173 mOwner = owner;
174}
175
176void SfDelegate::OnReceivedRedirect(
177 URLRequest *request, const GURL &new_url, bool *defer_redirect) {
178 MY_LOGI("OnReceivedRedirect");
179}
180
181void SfDelegate::OnAuthRequired(
182 URLRequest *request, net::AuthChallengeInfo *auth_info) {
183 MY_LOGI("OnAuthRequired");
184
185 inherited::OnAuthRequired(request, auth_info);
186}
187
188void SfDelegate::OnCertificateRequested(
189 URLRequest *request, net::SSLCertRequestInfo *cert_request_info) {
190 MY_LOGI("OnCertificateRequested");
191
192 inherited::OnCertificateRequested(request, cert_request_info);
193}
194
195void SfDelegate::OnSSLCertificateError(
196 URLRequest *request, int cert_error, net::X509Certificate *cert) {
197 fprintf(stderr, "OnSSLCertificateError cert_error=%d\n", cert_error);
198
199 inherited::OnSSLCertificateError(request, cert_error, cert);
200}
201
202void SfDelegate::OnGetCookies(URLRequest *request, bool blocked_by_policy) {
203 MY_LOGI("OnGetCookies");
204}
205
206void SfDelegate::OnSetCookie(
207 URLRequest *request,
208 const std::string &cookie_line,
209 const net::CookieOptions &options,
210 bool blocked_by_policy) {
211 MY_LOGI("OnSetCookie");
212}
213
214void SfDelegate::OnResponseStarted(URLRequest *request) {
215 if (request->status().status() != URLRequestStatus::SUCCESS) {
216 MY_LOGI(StringPrintf(
217 "Request failed with status %d and os_error %d",
218 request->status().status(),
219 request->status().os_error()).c_str());
220
221 delete mURLRequest;
222 mURLRequest = NULL;
223
224 mOwner->onConnectionFailed(ERROR_IO);
225 return;
226 } else if (mRangeRequested && request->GetResponseCode() != 206) {
227 MY_LOGI(StringPrintf(
228 "We requested a content range, but server didn't "
229 "support that. (responded with %d)",
230 request->GetResponseCode()).c_str());
231
232 delete mURLRequest;
233 mURLRequest = NULL;
234
235 mOwner->onConnectionFailed(-EPIPE);
236 return;
237 } else if ((request->GetResponseCode() / 100) != 2) {
238 MY_LOGI(StringPrintf(
239 "Server responded with http status %d",
240 request->GetResponseCode()).c_str());
241
242 delete mURLRequest;
243 mURLRequest = NULL;
244
245 mOwner->onConnectionFailed(ERROR_IO);
246 return;
247 }
248
249 MY_LOGV("OnResponseStarted");
250
251 std::string headers;
252 request->GetAllResponseHeaders(&headers);
253
254 MY_LOGV(StringPrintf("response headers: %s", headers.c_str()).c_str());
255
256 mOwner->onConnectionEstablished(request->GetExpectedContentSize());
257}
258
259void SfDelegate::OnReadCompleted(URLRequest *request, int bytes_read) {
260 if (bytes_read == -1) {
261 MY_LOGI(StringPrintf(
262 "OnReadCompleted, read failed, status %d",
263 request->status().status()).c_str());
264
265 mOwner->onReadCompleted(ERROR_IO);
266 return;
267 }
268
269 MY_LOGV(StringPrintf("OnReadCompleted, read %d bytes", bytes_read).c_str());
270
271 if (bytes_read < 0) {
272 MY_LOGI(StringPrintf(
273 "Read failed w/ status %d\n",
274 request->status().status()).c_str());
275
276 mOwner->onReadCompleted(ERROR_IO);
277 return;
278 } else if (bytes_read == 0) {
279 mAtEOS = true;
280 mOwner->onReadCompleted(mNumBytesRead);
281 return;
282 }
283
284 CHECK_GT(bytes_read, 0);
285 CHECK_LE(mNumBytesRead + bytes_read, mNumBytesTotal);
286
287 memcpy((uint8_t *)mDataDestination + mNumBytesRead,
288 mReadBuffer->data(),
289 bytes_read);
290
291 mNumBytesRead += bytes_read;
292
293 readMore(request);
294}
295
296void SfDelegate::readMore(URLRequest *request) {
297 while (mNumBytesRead < mNumBytesTotal) {
298 size_t copy = mNumBytesTotal - mNumBytesRead;
299 if (copy > mReadBuffer->size()) {
300 copy = mReadBuffer->size();
301 }
302
303 int n;
304 if (request->Read(mReadBuffer, copy, &n)) {
305 MY_LOGV(StringPrintf("Read %d bytes directly.", n).c_str());
306
307 CHECK_LE((size_t)n, copy);
308
309 memcpy((uint8_t *)mDataDestination + mNumBytesRead,
310 mReadBuffer->data(),
311 n);
312
313 mNumBytesRead += n;
314
315 if (n == 0) {
316 mAtEOS = true;
317 break;
318 }
319 } else {
320 MY_LOGV("readMore pending read");
321
322 if (request->status().status() != URLRequestStatus::IO_PENDING) {
323 MY_LOGI(StringPrintf(
324 "Direct read failed w/ status %d\n",
325 request->status().status()).c_str());
326
327 mOwner->onReadCompleted(ERROR_IO);
328 return;
329 }
330
331 return;
332 }
333 }
334
335 mOwner->onReadCompleted(mNumBytesRead);
336}
337
338void SfDelegate::initiateConnection(
339 const char *uri,
340 const KeyedVector<String8, String8> *headers,
341 off64_t offset) {
342 GURL url(uri);
343
344 MessageLoop *loop = gNetworkThread->message_loop();
345 loop->PostTask(
346 FROM_HERE,
347 NewRunnableFunction(
348 &SfDelegate::OnInitiateConnectionWrapper,
349 this,
350 url,
351 headers,
352 offset));
353
354}
355
356// static
357void SfDelegate::OnInitiateConnectionWrapper(
358 SfDelegate *me, GURL url,
359 const KeyedVector<String8, String8> *headers,
360 off64_t offset) {
361 me->onInitiateConnection(url, headers, offset);
362}
363
364void SfDelegate::onInitiateConnection(
365 const GURL &url,
366 const KeyedVector<String8, String8> *extra,
367 off64_t offset) {
368 CHECK(mURLRequest == NULL);
369
370 mURLRequest = new URLRequest(url, this);
371 mAtEOS = false;
372
373 mRangeRequested = false;
374
375 if (offset != 0 || extra != NULL) {
376 net::HttpRequestHeaders headers =
377 mURLRequest->extra_request_headers();
378
379 if (offset != 0) {
380 headers.AddHeaderFromString(
381 StringPrintf("Range: bytes=%lld-", offset).c_str());
382
383 mRangeRequested = true;
384 }
385
386 if (extra != NULL) {
387 for (size_t i = 0; i < extra->size(); ++i) {
388 AString s;
389 s.append(extra->keyAt(i).string());
390 s.append(": ");
391 s.append(extra->valueAt(i).string());
392
393 headers.AddHeaderFromString(s.c_str());
394 }
395 }
396
397 mURLRequest->SetExtraRequestHeaders(headers);
398 }
399
400 mURLRequest->set_context(gReqContext);
401
402 mURLRequest->Start();
403}
404
405void SfDelegate::initiateDisconnect() {
406 MessageLoop *loop = gNetworkThread->message_loop();
407 loop->PostTask(
408 FROM_HERE,
409 NewRunnableFunction(
410 &SfDelegate::OnInitiateDisconnectWrapper, this));
411}
412
413// static
414void SfDelegate::OnInitiateDisconnectWrapper(SfDelegate *me) {
415 me->onInitiateDisconnect();
416}
417
418void SfDelegate::onInitiateDisconnect() {
419 mURLRequest->Cancel();
420
421 delete mURLRequest;
422 mURLRequest = NULL;
423
424 mOwner->onDisconnectComplete();
425}
426
427void SfDelegate::initiateRead(void *data, size_t size) {
428 MessageLoop *loop = gNetworkThread->message_loop();
429 loop->PostTask(
430 FROM_HERE,
431 NewRunnableFunction(
432 &SfDelegate::OnInitiateReadWrapper, this, data, size));
433}
434
435// static
436void SfDelegate::OnInitiateReadWrapper(
437 SfDelegate *me, void *data, size_t size) {
438 me->onInitiateRead(data, size);
439}
440
441void SfDelegate::onInitiateRead(void *data, size_t size) {
442 CHECK(mURLRequest != NULL);
443
444 mNumBytesRead = 0;
445 mNumBytesTotal = size;
446 mDataDestination = data;
447
448 if (mAtEOS) {
449 mOwner->onReadCompleted(0);
450 return;
451 }
452
453 readMore(mURLRequest);
454}
455
456} // namespace android
457