1// Copyright 2014 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/media_galleries/fileapi/safe_media_metadata_parser.h"
6
7#include "chrome/browser/extensions/blob_reader.h"
8#include "chrome/common/extensions/chrome_utility_extensions_messages.h"
9#include "content/public/browser/browser_thread.h"
10#include "content/public/browser/child_process_data.h"
11#include "content/public/browser/utility_process_host.h"
12
13using content::BrowserThread;
14
15namespace metadata {
16
17SafeMediaMetadataParser::SafeMediaMetadataParser(
18    Profile* profile, const std::string& blob_uuid, int64 blob_size,
19    const std::string& mime_type, bool get_attached_images)
20    : profile_(profile),
21      blob_uuid_(blob_uuid),
22      blob_size_(blob_size),
23      mime_type_(mime_type),
24      get_attached_images_(get_attached_images),
25      parser_state_(INITIAL_STATE) {
26  DCHECK_CURRENTLY_ON(BrowserThread::UI);
27}
28
29void SafeMediaMetadataParser::Start(const DoneCallback& callback) {
30  DCHECK_CURRENTLY_ON(BrowserThread::UI);
31
32  BrowserThread::PostTask(
33      BrowserThread::IO,
34      FROM_HERE,
35      base::Bind(&SafeMediaMetadataParser::StartWorkOnIOThread, this,
36                 callback));
37}
38
39SafeMediaMetadataParser::~SafeMediaMetadataParser() {
40}
41
42void SafeMediaMetadataParser::StartWorkOnIOThread(
43    const DoneCallback& callback) {
44  DCHECK_CURRENTLY_ON(BrowserThread::IO);
45  DCHECK_EQ(INITIAL_STATE, parser_state_);
46  DCHECK(!callback.is_null());
47
48  callback_ = callback;
49
50  utility_process_host_ = content::UtilityProcessHost::Create(
51      this, base::MessageLoopProxy::current())->AsWeakPtr();
52
53  utility_process_host_->Send(
54      new ChromeUtilityMsg_ParseMediaMetadata(mime_type_, blob_size_,
55                                              get_attached_images_));
56
57  parser_state_ = STARTED_PARSING_STATE;
58}
59
60void SafeMediaMetadataParser::OnParseMediaMetadataFinished(
61    bool parse_success, const base::DictionaryValue& metadata_dictionary,
62    const std::vector<AttachedImage>& attached_images) {
63  DCHECK_CURRENTLY_ON(BrowserThread::IO);
64  DCHECK(!callback_.is_null());
65
66  if (parser_state_ != STARTED_PARSING_STATE)
67    return;
68
69  // We need to make a scoped copy of this vector since it will be destroyed
70  // at the end of the IPC message handler.
71  scoped_ptr<std::vector<metadata::AttachedImage> > attached_images_copy =
72      make_scoped_ptr(new std::vector<metadata::AttachedImage>(
73          attached_images));
74
75  BrowserThread::PostTask(
76      BrowserThread::UI,
77      FROM_HERE,
78      base::Bind(callback_, parse_success,
79                 base::Passed(make_scoped_ptr(metadata_dictionary.DeepCopy())),
80                 base::Passed(&attached_images_copy)));
81  parser_state_ = FINISHED_PARSING_STATE;
82}
83
84void SafeMediaMetadataParser::OnUtilityProcessRequestBlobBytes(
85    int64 request_id, int64 byte_start, int64 length) {
86  DCHECK_CURRENTLY_ON(BrowserThread::IO);
87  BrowserThread::PostTask(
88      BrowserThread::UI,
89      FROM_HERE,
90      base::Bind(&SafeMediaMetadataParser::StartBlobReaderOnUIThread, this,
91                 request_id, byte_start, length));
92}
93
94void SafeMediaMetadataParser::StartBlobReaderOnUIThread(
95    int64 request_id, int64 byte_start, int64 length) {
96  DCHECK_CURRENTLY_ON(BrowserThread::UI);
97
98  // BlobReader is self-deleting.
99  BlobReader* reader = new BlobReader(profile_, blob_uuid_, base::Bind(
100      &SafeMediaMetadataParser::OnBlobReaderDoneOnUIThread, this, request_id));
101  reader->SetByteRange(byte_start, length);
102  reader->Start();
103}
104
105void SafeMediaMetadataParser::OnBlobReaderDoneOnUIThread(
106    int64 request_id, scoped_ptr<std::string> data,
107    int64 /* blob_total_size */) {
108  DCHECK_CURRENTLY_ON(BrowserThread::UI);
109  BrowserThread::PostTask(
110      BrowserThread::IO,
111      FROM_HERE,
112      base::Bind(&SafeMediaMetadataParser::FinishRequestBlobBytes, this,
113                 request_id, base::Passed(data.Pass())));
114}
115
116void SafeMediaMetadataParser::FinishRequestBlobBytes(
117    int64 request_id, scoped_ptr<std::string> data) {
118  DCHECK_CURRENTLY_ON(BrowserThread::IO);
119  if (!utility_process_host_.get())
120    return;
121  utility_process_host_->Send(new ChromeUtilityMsg_RequestBlobBytes_Finished(
122      request_id, *data));
123}
124
125void SafeMediaMetadataParser::OnProcessCrashed(int exit_code) {
126  DCHECK_CURRENTLY_ON(BrowserThread::IO);
127  DCHECK(!callback_.is_null());
128
129  BrowserThread::PostTask(
130      BrowserThread::UI,
131      FROM_HERE,
132      base::Bind(callback_, false,
133                 base::Passed(scoped_ptr<base::DictionaryValue>()),
134                 base::Passed(scoped_ptr<std::vector<AttachedImage> >())));
135  parser_state_ = FINISHED_PARSING_STATE;
136}
137
138bool SafeMediaMetadataParser::OnMessageReceived(const IPC::Message& message) {
139  bool handled = true;
140  IPC_BEGIN_MESSAGE_MAP(SafeMediaMetadataParser, message)
141    IPC_MESSAGE_HANDLER(
142        ChromeUtilityHostMsg_ParseMediaMetadata_Finished,
143        OnParseMediaMetadataFinished)
144    IPC_MESSAGE_HANDLER(
145        ChromeUtilityHostMsg_RequestBlobBytes,
146        OnUtilityProcessRequestBlobBytes)
147    IPC_MESSAGE_UNHANDLED(handled = false)
148  IPC_END_MESSAGE_MAP()
149  return handled;
150}
151
152}  // namespace metadata
153