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_frame/test/net/test_automation_provider.h"
6
7#include "base/command_line.h"
8#include "base/file_version_info.h"
9#include "base/path_service.h"
10#include "chrome/common/automation_messages.h"
11#include "chrome_frame/test/net/test_automation_resource_message_filter.h"
12#include "net/url_request/url_request_context.h"
13
14namespace {
15
16// A special command line switch to just run the unit tests without CF in
17// the picture.  Can be useful when the harness itself needs to be debugged.
18const char kNoCfTestRun[] = "no-cf-test-run";
19
20bool CFTestsDisabled() {
21  static bool switch_present = CommandLine::ForCurrentProcess()->
22      HasSwitch(kNoCfTestRun);
23  return switch_present;
24}
25
26}  // end namespace
27
28TestAutomationProvider* TestAutomationProvider::g_provider_instance_ = NULL;
29
30TestAutomationProvider::TestAutomationProvider(
31    Profile* profile,
32    TestAutomationProviderDelegate* delegate)
33    : AutomationProvider(profile), tab_handle_(-1), delegate_(delegate) {
34  // We need to register the protocol factory before the
35  // AutomationResourceMessageFilter registers the automation job factory to
36  // ensure that we don't inadvarently end up handling http requests which
37  // we don't expect. The initial chrome frame page for the network tests
38  // issues http requests which our test factory should not handle.
39  net::URLRequest::Deprecated::RegisterProtocolFactory(
40      "http", TestAutomationProvider::Factory);
41  net::URLRequest::Deprecated::RegisterProtocolFactory(
42      "https", TestAutomationProvider::Factory);
43  automation_resource_message_filter_ =
44      new TestAutomationResourceMessageFilter(this);
45  g_provider_instance_ = this;
46}
47
48TestAutomationProvider::~TestAutomationProvider() {
49  delegate_->OnProviderDestroyed();
50  g_provider_instance_ = NULL;
51}
52
53bool TestAutomationProvider::OnMessageReceived(const IPC::Message& msg) {
54  if (automation_resource_message_filter_->OnMessageReceived(msg))
55    return true;  // Message handled by the filter.
56
57  return __super::OnMessageReceived(msg);
58}
59
60// IPC override to grab the tab handle.
61bool TestAutomationProvider::Send(IPC::Message* msg) {
62  if (msg->type() == AutomationMsg_TabLoaded::ID) {
63    DCHECK(tab_handle_ == -1) << "Currently only support one tab";
64    tab_handle_ = msg->routing_id();
65    DVLOG(1) << "Got tab handle: " << tab_handle_;
66    DCHECK(tab_handle_ != -1 && tab_handle_ != 0);
67    delegate_->OnInitialTabLoaded();
68  }
69
70  return AutomationProvider::Send(msg);
71}
72
73net::URLRequestJob* TestAutomationProvider::Factory(
74    net::URLRequest* request,
75    net::NetworkDelegate* network_delegate,
76    const std::string& scheme) {
77  if (CFTestsDisabled())
78    return NULL;
79
80  if (request->url().SchemeIsHTTPOrHTTPS()) {
81    // Only look at requests that don't have any user data.
82    // ResourceDispatcherHost uses the user data for requests that it manages.
83    // We don't want to mess with those.
84
85    // We could also check if the current thread is our TestUrlRequest thread
86    // and only intercept requests that belong to that thread.
87    if (g_provider_instance_ && request->GetUserData(NULL) == NULL &&
88        g_provider_instance_->tab_handle_ != -1) {
89      // We generate our own request id which is also what
90      // ResourceDispatcherHost does (well, the id is actually generated by
91      // ResourceDispatcher).  Since these requests are divided into with
92      // and without userdata, we're OK.  However, just to make debugging
93      // a little easier, we have a significantly higher start value.
94      static int new_id = 0x00100000;
95      URLRequestAutomationJob* job = new URLRequestAutomationJob(
96          request, network_delegate,
97          request->context()->http_user_agent_settings(),
98          g_provider_instance_->tab_handle_, new_id++,
99          g_provider_instance_->automation_resource_message_filter_, false);
100      return job;
101    }
102  }
103
104  return NULL;
105}
106
107std::string TestAutomationProvider::GetProtocolVersion() {
108  // Return the version of npchrome_frame.dll.  We used to use
109  // chrome.dll, but the other end of the pipe in this case is
110  // actually npchrome_frame.dll (which fetches its version info from
111  // itself), and occasionally we run into RC dependency problems in
112  // incremental builds so that the version information does not get
113  // updated in one module but does in another, so better to use the
114  // exact same version to avoid hard-to-debug problems in development
115  // builds.
116  base::FilePath path;
117  PathService::Get(base::DIR_MODULE, &path);
118  path = path.AppendASCII("npchrome_frame.dll");
119
120  std::string version;
121  scoped_ptr<FileVersionInfo> version_info(
122      FileVersionInfo::CreateFileVersionInfo(path));
123  if (version_info.get()) {
124    version = WideToASCII(version_info->product_version());
125  }
126  return version;
127}
128
129// static
130TestAutomationProvider* TestAutomationProvider::NewAutomationProvider(
131    Profile* p, const std::string& channel,
132    TestAutomationProviderDelegate* delegate) {
133  TestAutomationProvider* automation = new TestAutomationProvider(p, delegate);
134  automation->InitializeChannel(channel);
135  automation->SetExpectedTabCount(1);
136  return automation;
137}
138