1/*
2 *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/base/asynchttprequest.h"
12
13namespace rtc {
14
15enum {
16  MSG_TIMEOUT = SignalThread::ST_MSG_FIRST_AVAILABLE,
17  MSG_LAUNCH_REQUEST
18};
19static const int kDefaultHTTPTimeout = 30 * 1000;  // 30 sec
20
21///////////////////////////////////////////////////////////////////////////////
22// AsyncHttpRequest
23///////////////////////////////////////////////////////////////////////////////
24
25AsyncHttpRequest::AsyncHttpRequest(const std::string &user_agent)
26    : start_delay_(0),
27      firewall_(NULL),
28      port_(80),
29      secure_(false),
30      timeout_(kDefaultHTTPTimeout),
31      fail_redirect_(false),
32      factory_(Thread::Current()->socketserver(), user_agent),
33      pool_(&factory_),
34      client_(user_agent.c_str(), &pool_),
35      error_(HE_NONE) {
36  client_.SignalHttpClientComplete.connect(this,
37      &AsyncHttpRequest::OnComplete);
38}
39
40AsyncHttpRequest::~AsyncHttpRequest() {
41}
42
43void AsyncHttpRequest::OnWorkStart() {
44  if (start_delay_ <= 0) {
45    LaunchRequest();
46  } else {
47    Thread::Current()->PostDelayed(start_delay_, this, MSG_LAUNCH_REQUEST);
48  }
49}
50
51void AsyncHttpRequest::OnWorkStop() {
52  // worker is already quitting, no need to explicitly quit
53  LOG(LS_INFO) << "HttpRequest cancelled";
54}
55
56void AsyncHttpRequest::OnComplete(HttpClient* client, HttpErrorType error) {
57  Thread::Current()->Clear(this, MSG_TIMEOUT);
58
59  set_error(error);
60  if (!error) {
61    LOG(LS_INFO) << "HttpRequest completed successfully";
62
63    std::string value;
64    if (client_.response().hasHeader(HH_LOCATION, &value)) {
65      response_redirect_ = value.c_str();
66    }
67  } else {
68    LOG(LS_INFO) << "HttpRequest completed with error: " << error;
69  }
70
71  worker()->Quit();
72}
73
74void AsyncHttpRequest::OnMessage(Message* message) {
75  switch (message->message_id) {
76   case MSG_TIMEOUT:
77    LOG(LS_INFO) << "HttpRequest timed out";
78    client_.reset();
79    worker()->Quit();
80    break;
81   case MSG_LAUNCH_REQUEST:
82    LaunchRequest();
83    break;
84   default:
85    SignalThread::OnMessage(message);
86    break;
87  }
88}
89
90void AsyncHttpRequest::DoWork() {
91  // Do nothing while we wait for the request to finish. We only do this so
92  // that we can be a SignalThread; in the future this class should not be
93  // a SignalThread, since it does not need to spawn a new thread.
94  Thread::Current()->ProcessMessages(kForever);
95}
96
97void AsyncHttpRequest::LaunchRequest() {
98  factory_.SetProxy(proxy_);
99  if (secure_)
100    factory_.UseSSL(host_.c_str());
101
102  bool transparent_proxy = (port_ == 80) &&
103           ((proxy_.type == PROXY_HTTPS) || (proxy_.type == PROXY_UNKNOWN));
104  if (transparent_proxy) {
105    client_.set_proxy(proxy_);
106  }
107  client_.set_fail_redirect(fail_redirect_);
108  client_.set_server(SocketAddress(host_, port_));
109
110  LOG(LS_INFO) << "HttpRequest start: " << host_ + client_.request().path;
111
112  Thread::Current()->PostDelayed(timeout_, this, MSG_TIMEOUT);
113  client_.start();
114}
115
116}  // namespace rtc
117