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 "content/public/browser/browser_thread.h"
12#include "content/public/browser/utility_process_host.h"
13#include "content/public/browser/utility_process_host_client.h"
14
15using content::BrowserThread;
16using content::UtilityProcessHost;
17using content::UtilityProcessHostClient;
18
19// This class coordinates a web resource unpack and parse task which is run in
20// a separate process.  Results are sent back to this class and routed to
21// the WebResourceService.
22class JSONAsynchronousUnpackerImpl
23    : public UtilityProcessHostClient,
24      public JSONAsynchronousUnpacker {
25 public:
26  explicit JSONAsynchronousUnpackerImpl(
27      JSONAsynchronousUnpackerDelegate* delegate)
28    : JSONAsynchronousUnpacker(delegate),
29      got_response_(false) {
30  }
31
32  virtual void Start(const std::string& json_data) OVERRIDE {
33    AddRef();  // balanced in Cleanup.
34
35    BrowserThread::ID thread_id;
36    CHECK(BrowserThread::GetCurrentThreadIdentifier(&thread_id));
37    BrowserThread::PostTask(
38        BrowserThread::IO, FROM_HERE,
39        base::Bind(
40            &JSONAsynchronousUnpackerImpl::StartProcessOnIOThread,
41            this, thread_id, json_data));
42  }
43
44 private:
45  virtual ~JSONAsynchronousUnpackerImpl() {}
46
47  // UtilityProcessHostClient.
48  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
49    bool handled = true;
50    IPC_BEGIN_MESSAGE_MAP(JSONAsynchronousUnpackerImpl, message)
51      IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_UnpackWebResource_Succeeded,
52                          OnUnpackWebResourceSucceeded)
53      IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_UnpackWebResource_Failed,
54                          OnUnpackWebResourceFailed)
55      IPC_MESSAGE_UNHANDLED(handled = false)
56    IPC_END_MESSAGE_MAP()
57    return handled;
58  }
59
60  virtual void OnProcessCrashed(int exit_code) OVERRIDE {
61    if (got_response_)
62      return;
63
64    OnUnpackWebResourceFailed(
65        "Utility process crashed while trying to retrieve web resources.");
66  }
67
68  void OnUnpackWebResourceSucceeded(
69      const base::DictionaryValue& parsed_json) {
70    if (delegate_)
71      delegate_->OnUnpackFinished(parsed_json);
72    Cleanup();
73  }
74
75  void OnUnpackWebResourceFailed(const std::string& error_message) {
76    if (delegate_)
77      delegate_->OnUnpackError(error_message);
78    Cleanup();
79  }
80
81  // Release reference and set got_response_.
82  void Cleanup() {
83    DCHECK(!got_response_);
84    got_response_ = true;
85    Release();
86  }
87
88  void StartProcessOnIOThread(BrowserThread::ID thread_id,
89                              const std::string& json_data) {
90    UtilityProcessHost* host = UtilityProcessHost::Create(
91        this, BrowserThread::GetMessageLoopProxyForThread(thread_id).get());
92    // TODO(mrc): get proper file path when we start using web resources
93    // that need to be unpacked.
94    host->Send(new ChromeUtilityMsg_UnpackWebResource(json_data));
95  }
96
97  // True if we got a response from the utility process and have cleaned up
98  // already.
99  bool got_response_;
100};
101
102JSONAsynchronousUnpacker* JSONAsynchronousUnpacker::Create(
103    JSONAsynchronousUnpackerDelegate* delegate) {
104  return new JSONAsynchronousUnpackerImpl(delegate);
105}
106
107