json_asynchronous_unpacker.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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/web_resource/json_asynchronous_unpacker.h"
6
7#include "base/command_line.h"
8#include "chrome/browser/web_resource/web_resource_service.h"
9#include "chrome/common/chrome_switches.h"
10#include "chrome/common/chrome_utility_messages.h"
11#include "chrome/common/web_resource/web_resource_unpacker.h"
12#include "content/public/browser/browser_thread.h"
13#include "content/public/browser/resource_dispatcher_host.h"
14#include "content/public/browser/utility_process_host.h"
15#include "content/public/browser/utility_process_host_client.h"
16
17using content::BrowserThread;
18using content::UtilityProcessHost;
19using content::UtilityProcessHostClient;
20
21// This class coordinates a web resource unpack and parse task which is run in
22// a separate process.  Results are sent back to this class and routed to
23// the WebResourceService.
24class JSONAsynchronousUnpackerImpl
25    : public UtilityProcessHostClient,
26      public JSONAsynchronousUnpacker {
27 public:
28  explicit JSONAsynchronousUnpackerImpl(
29      JSONAsynchronousUnpackerDelegate* delegate)
30    : JSONAsynchronousUnpacker(delegate),
31      got_response_(false) {
32  }
33
34  void Start(const std::string& json_data) {
35    AddRef();  // balanced in Cleanup.
36
37    // TODO(willchan): Look for a better signal of whether we're in a unit test
38    // or not. Using |ResourceDispatcherHost::Get()| for this is pretty lame.
39    // If we don't have a ResourceDispatcherHost, assume we're in a test and
40    // run the unpacker directly in-process.
41    bool use_utility_process =
42        content::ResourceDispatcherHost::Get() &&
43        !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess);
44    if (use_utility_process) {
45      BrowserThread::ID thread_id;
46      CHECK(BrowserThread::GetCurrentThreadIdentifier(&thread_id));
47      BrowserThread::PostTask(
48          BrowserThread::IO, FROM_HERE,
49          base::Bind(
50              &JSONAsynchronousUnpackerImpl::StartProcessOnIOThread,
51              this, thread_id, json_data));
52    } else {
53      WebResourceUnpacker unpacker(json_data);
54      if (unpacker.Run()) {
55        OnUnpackWebResourceSucceeded(*unpacker.parsed_json());
56      } else {
57        OnUnpackWebResourceFailed(unpacker.error_message());
58      }
59    }
60  }
61
62 private:
63  virtual ~JSONAsynchronousUnpackerImpl() {}
64
65  // UtilityProcessHostClient.
66  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
67    bool handled = true;
68    IPC_BEGIN_MESSAGE_MAP(JSONAsynchronousUnpackerImpl, message)
69      IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_UnpackWebResource_Succeeded,
70                          OnUnpackWebResourceSucceeded)
71      IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_UnpackWebResource_Failed,
72                          OnUnpackWebResourceFailed)
73      IPC_MESSAGE_UNHANDLED(handled = false)
74    IPC_END_MESSAGE_MAP()
75    return handled;
76  }
77
78  virtual void OnProcessCrashed(int exit_code) OVERRIDE {
79    if (got_response_)
80      return;
81
82    OnUnpackWebResourceFailed(
83        "Utility process crashed while trying to retrieve web resources.");
84  }
85
86  void OnUnpackWebResourceSucceeded(
87      const DictionaryValue& parsed_json) {
88    if (delegate_)
89      delegate_->OnUnpackFinished(parsed_json);
90    Cleanup();
91  }
92
93  void OnUnpackWebResourceFailed(const std::string& error_message) {
94    if (delegate_)
95      delegate_->OnUnpackError(error_message);
96    Cleanup();
97  }
98
99  // Release reference and set got_response_.
100  void Cleanup() {
101    DCHECK(!got_response_);
102    got_response_ = true;
103    Release();
104  }
105
106  void StartProcessOnIOThread(BrowserThread::ID thread_id,
107                              const std::string& json_data) {
108    UtilityProcessHost* host = UtilityProcessHost::Create(this, thread_id);
109    host->EnableZygote();
110    // TODO(mrc): get proper file path when we start using web resources
111    // that need to be unpacked.
112    host->Send(new ChromeUtilityMsg_UnpackWebResource(json_data));
113  }
114
115  // True if we got a response from the utility process and have cleaned up
116  // already.
117  bool got_response_;
118};
119
120JSONAsynchronousUnpacker* JSONAsynchronousUnpacker::Create(
121    JSONAsynchronousUnpackerDelegate* delegate) {
122  return new JSONAsynchronousUnpackerImpl(delegate);
123}
124
125