native_messaging_reader.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
15f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// Copyright 2013 The Chromium Authors. All rights reserved.
25f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// Use of this source code is governed by a BSD-style license that can be
35f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// found in the LICENSE file.
45f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
50bc735ffcfb223c0186419547abaa5c84482663eChris Lattner#include "remoting/host/native_messaging/native_messaging_reader.h"
60bc735ffcfb223c0186419547abaa5c84482663eChris Lattner
75f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include <string>
85f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
95f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include "base/bind.h"
105f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include "base/files/file.h"
115f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include "base/json/json_reader.h"
125f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include "base/location.h"
135f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include "base/sequenced_task_runner.h"
145f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include "base/single_thread_task_runner.h"
155f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include "base/stl_util.h"
165f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include "base/thread_task_runner_handle.h"
175f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include "base/threading/sequenced_worker_pool.h"
18a30cfe5026b12c28b7b575b48176e0a3543ce939Douglas Gregor#include "base/values.h"
19f122a138e39dbb29162abfa9a3d44091d8efa7afRichard Smith
20c042edd54face617a3b9d0b4b9d5a3ff229d0f48Douglas Gregornamespace {
215f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
2265e02fa80e1c185f18e5f81cefc30d75383a7301Douglas Gregor// uint32 is specified in the protocol as the type for the message header.
23d1194fbbf65374bfa3578eb40a547e4f97b497d1Ted Kremenektypedef uint32 MessageLengthType;
24651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
255f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerconst int kMessageHeaderSize = sizeof(MessageLengthType);
265f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
275f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// Limit the size of received messages, to avoid excessive memory-allocation in
288e23806863721495f9e1f84aed614f7afba774a3Douglas Gregor// this process, and potential overflow issues when casting to a signed 32-bit
298e23806863721495f9e1f84aed614f7afba774a3Douglas Gregor// int.
308c5a760b82e73ed90b560090772db97e2ae27b09Douglas Gregorconst MessageLengthType kMaximumMessageSize = 1024 * 1024;
315f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
325f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer}  // namespace
33c042edd54face617a3b9d0b4b9d5a3ff229d0f48Douglas Gregor
345f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencernamespace remoting {
355f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
36a24bd5d9ad79be50cec0e25364d8267e7623c33fJames Dennettclass NativeMessagingReader::Core {
37809d1be9820039b4cf6efa48246a0d70ffa13394James Dennett public:
3883d63c78810556d26b62ac4cbae2eda6cdd2570cSteve Naroff  Core(base::PlatformFile handle,
39a24bd5d9ad79be50cec0e25364d8267e7623c33fJames Dennett       scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
40cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor       scoped_refptr<base::SequencedTaskRunner> read_task_runner,
411eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump       base::WeakPtr<NativeMessagingReader> reader_);
42a24bd5d9ad79be50cec0e25364d8267e7623c33fJames Dennett  ~Core();
43dd3e5549e3c11e217078938aacf72f042eea5343Douglas Gregor
44dd3e5549e3c11e217078938aacf72f042eea5343Douglas Gregor  // Reads a message from the Native Messaging client and passes it to
4583d63c78810556d26b62ac4cbae2eda6cdd2570cSteve Naroff  // |message_callback_| on the originating thread. Called on the reader thread.
4683d63c78810556d26b62ac4cbae2eda6cdd2570cSteve Naroff  void ReadMessage();
47a24bd5d9ad79be50cec0e25364d8267e7623c33fJames Dennett
4883d63c78810556d26b62ac4cbae2eda6cdd2570cSteve Naroff private:
4983d63c78810556d26b62ac4cbae2eda6cdd2570cSteve Naroff  // Notify the reader's EOF callback when an error occurs or EOF is reached.
501eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  void NotifyEof();
51cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor
52cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor  base::File read_stream_;
5355ea75bf61a5d76f6453513d937944ce68181c6aArgyrios Kyrtzidis
5455ea75bf61a5d76f6453513d937944ce68181c6aArgyrios Kyrtzidis  base::WeakPtr<NativeMessagingReader> reader_;
5555ea75bf61a5d76f6453513d937944ce68181c6aArgyrios Kyrtzidis
56d3220dbeeadc4ac54ceecea8cf63f8d8be291d2aArgyrios Kyrtzidis  // Used to post the caller-supplied reader callbacks on the caller thread.
57d3220dbeeadc4ac54ceecea8cf63f8d8be291d2aArgyrios Kyrtzidis  scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
58d3220dbeeadc4ac54ceecea8cf63f8d8be291d2aArgyrios Kyrtzidis
59bc3f628815b3841dc99109e7f67f9afa7793bc94Lawrence Crowl  // Used to DCHECK that the reader code executes on the correct thread.
60bc3f628815b3841dc99109e7f67f9afa7793bc94Lawrence Crowl  scoped_refptr<base::SequencedTaskRunner> read_task_runner_;
61bc3f628815b3841dc99109e7f67f9afa7793bc94Lawrence Crowl
62bc3f628815b3841dc99109e7f67f9afa7793bc94Lawrence Crowl  DISALLOW_COPY_AND_ASSIGN(Core);
63cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor};
64cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor
65cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas GregorNativeMessagingReader::Core::Core(
66cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor    base::PlatformFile handle,
67cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor    scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
6865e02fa80e1c185f18e5f81cefc30d75383a7301Douglas Gregor    scoped_refptr<base::SequencedTaskRunner> read_task_runner,
6965e02fa80e1c185f18e5f81cefc30d75383a7301Douglas Gregor    base::WeakPtr<NativeMessagingReader> reader)
7065e02fa80e1c185f18e5f81cefc30d75383a7301Douglas Gregor    : read_stream_(handle),
7165e02fa80e1c185f18e5f81cefc30d75383a7301Douglas Gregor      reader_(reader),
7265e02fa80e1c185f18e5f81cefc30d75383a7301Douglas Gregor      caller_task_runner_(caller_task_runner),
7365e02fa80e1c185f18e5f81cefc30d75383a7301Douglas Gregor      read_task_runner_(read_task_runner) {
7465e02fa80e1c185f18e5f81cefc30d75383a7301Douglas Gregor}
7565e02fa80e1c185f18e5f81cefc30d75383a7301Douglas Gregor
76651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesNativeMessagingReader::Core::~Core() {}
77651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
78651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesvoid NativeMessagingReader::Core::ReadMessage() {
7965e02fa80e1c185f18e5f81cefc30d75383a7301Douglas Gregor  DCHECK(read_task_runner_->RunsTasksOnCurrentThread());
80a24bd5d9ad79be50cec0e25364d8267e7623c33fJames Dennett
8183d63c78810556d26b62ac4cbae2eda6cdd2570cSteve Naroff  // Keep reading messages until the stream is closed or an error occurs.
821eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  while (true) {
83cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor    MessageLengthType message_length;
84cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor    int read_result = read_stream_.ReadAtCurrentPos(
85cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor        reinterpret_cast<char*>(&message_length), kMessageHeaderSize);
86cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor    if (read_result != kMessageHeaderSize) {
87cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor      // 0 means EOF which is normal and should not be logged as an error.
88cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor      if (read_result != 0) {
89cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor        LOG(ERROR) << "Failed to read message header, read returned "
90a24bd5d9ad79be50cec0e25364d8267e7623c33fJames Dennett                   << read_result;
91a24bd5d9ad79be50cec0e25364d8267e7623c33fJames Dennett      }
9283d63c78810556d26b62ac4cbae2eda6cdd2570cSteve Naroff      NotifyEof();
938c5a760b82e73ed90b560090772db97e2ae27b09Douglas Gregor      return;
948c5a760b82e73ed90b560090772db97e2ae27b09Douglas Gregor    }
958c5a760b82e73ed90b560090772db97e2ae27b09Douglas Gregor
968c5a760b82e73ed90b560090772db97e2ae27b09Douglas Gregor    if (message_length > kMaximumMessageSize) {
978c5a760b82e73ed90b560090772db97e2ae27b09Douglas Gregor      LOG(ERROR) << "Message size too large: " << message_length;
9883d63c78810556d26b62ac4cbae2eda6cdd2570cSteve Naroff      NotifyEof();
998c5a760b82e73ed90b560090772db97e2ae27b09Douglas Gregor      return;
10065e02fa80e1c185f18e5f81cefc30d75383a7301Douglas Gregor    }
10165e02fa80e1c185f18e5f81cefc30d75383a7301Douglas Gregor
10265e02fa80e1c185f18e5f81cefc30d75383a7301Douglas Gregor    std::string message_json(message_length, '\0');
10365e02fa80e1c185f18e5f81cefc30d75383a7301Douglas Gregor    read_result = read_stream_.ReadAtCurrentPos(string_as_array(&message_json),
1041eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump                                                message_length);
105dd3e5549e3c11e217078938aacf72f042eea5343Douglas Gregor    if (read_result != static_cast<int>(message_length)) {
106d3220dbeeadc4ac54ceecea8cf63f8d8be291d2aArgyrios Kyrtzidis      LOG(ERROR) << "Failed to read message body, read returned "
107bc3f628815b3841dc99109e7f67f9afa7793bc94Lawrence Crowl                 << read_result;
108651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      NotifyEof();
1096bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      return;
1108c5a760b82e73ed90b560090772db97e2ae27b09Douglas Gregor    }
1118c5a760b82e73ed90b560090772db97e2ae27b09Douglas Gregor
1128c5a760b82e73ed90b560090772db97e2ae27b09Douglas Gregor    scoped_ptr<base::Value> message(base::JSONReader::Read(message_json));
1138c5a760b82e73ed90b560090772db97e2ae27b09Douglas Gregor    if (!message) {
114cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor      LOG(ERROR) << "Failed to parse JSON message: " << message;
115cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor      NotifyEof();
116cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor      return;
117cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor    }
118dd3e5549e3c11e217078938aacf72f042eea5343Douglas Gregor
119dd3e5549e3c11e217078938aacf72f042eea5343Douglas Gregor    // Notify callback of new message.
120cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor    caller_task_runner_->PostTask(
121bc3f628815b3841dc99109e7f67f9afa7793bc94Lawrence Crowl        FROM_HERE, base::Bind(&NativeMessagingReader::InvokeMessageCallback,
122bc3f628815b3841dc99109e7f67f9afa7793bc94Lawrence Crowl                              reader_, base::Passed(&message)));
123bc3f628815b3841dc99109e7f67f9afa7793bc94Lawrence Crowl  }
124bc3f628815b3841dc99109e7f67f9afa7793bc94Lawrence Crowl}
125bc3f628815b3841dc99109e7f67f9afa7793bc94Lawrence Crowl
126bc3f628815b3841dc99109e7f67f9afa7793bc94Lawrence Crowlvoid NativeMessagingReader::Core::NotifyEof() {
127bc3f628815b3841dc99109e7f67f9afa7793bc94Lawrence Crowl  DCHECK(read_task_runner_->RunsTasksOnCurrentThread());
128bc3f628815b3841dc99109e7f67f9afa7793bc94Lawrence Crowl  caller_task_runner_->PostTask(
129bc3f628815b3841dc99109e7f67f9afa7793bc94Lawrence Crowl      FROM_HERE,
130bc3f628815b3841dc99109e7f67f9afa7793bc94Lawrence Crowl      base::Bind(&NativeMessagingReader::InvokeEofCallback, reader_));
13183d63c78810556d26b62ac4cbae2eda6cdd2570cSteve Naroff}
13283d63c78810556d26b62ac4cbae2eda6cdd2570cSteve Naroff
133cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas GregorNativeMessagingReader::NativeMessagingReader(base::PlatformFile handle)
134cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor    : reader_thread_("Reader"),
135cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor      weak_factory_(this) {
136cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor  reader_thread_.Start();
137cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor  read_task_runner_ = reader_thread_.message_loop_proxy();
138cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor  core_.reset(new Core(handle, base::ThreadTaskRunnerHandle::Get(),
139cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor                       read_task_runner_, weak_factory_.GetWeakPtr()));
140cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor}
141cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor
142cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas GregorNativeMessagingReader::~NativeMessagingReader() {
143cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor  read_task_runner_->DeleteSoon(FROM_HERE, core_.release());
144cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor}
145cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor
146cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregorvoid NativeMessagingReader::Start(MessageCallback message_callback,
147a24bd5d9ad79be50cec0e25364d8267e7623c33fJames Dennett                                  base::Closure eof_callback) {
148a24bd5d9ad79be50cec0e25364d8267e7623c33fJames Dennett  message_callback_ = message_callback;
1495f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  eof_callback_ = eof_callback;
1509ee35f9f35452dec05c81fd1bbdd2f700872ea7fDaniel Dunbar
1519ee35f9f35452dec05c81fd1bbdd2f700872ea7fDaniel Dunbar  // base::Unretained is safe since |core_| is only deleted via the
1529ee35f9f35452dec05c81fd1bbdd2f700872ea7fDaniel Dunbar  // DeleteSoon task which is posted from this class's dtor.
1539ee35f9f35452dec05c81fd1bbdd2f700872ea7fDaniel Dunbar  read_task_runner_->PostTask(
15485ff9693b178658f9d8af7be30a086fb1ab81fddDaniel Dunbar      FROM_HERE, base::Bind(&NativeMessagingReader::Core::ReadMessage,
15585ff9693b178658f9d8af7be30a086fb1ab81fddDaniel Dunbar                            base::Unretained(core_.get())));
15685ff9693b178658f9d8af7be30a086fb1ab81fddDaniel Dunbar}
15785ff9693b178658f9d8af7be30a086fb1ab81fddDaniel Dunbar
15885ff9693b178658f9d8af7be30a086fb1ab81fddDaniel Dunbarvoid NativeMessagingReader::InvokeMessageCallback(
1599ee35f9f35452dec05c81fd1bbdd2f700872ea7fDaniel Dunbar    scoped_ptr<base::Value> message) {
1609ee35f9f35452dec05c81fd1bbdd2f700872ea7fDaniel Dunbar  message_callback_.Run(message.Pass());
161c042edd54face617a3b9d0b4b9d5a3ff229d0f48Douglas Gregor}
162cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenko
163c042edd54face617a3b9d0b4b9d5a3ff229d0f48Douglas Gregorvoid NativeMessagingReader::InvokeEofCallback() {
164651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  eof_callback_.Run();
1655f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer}
166a24bd5d9ad79be50cec0e25364d8267e7623c33fJames Dennett
167a24bd5d9ad79be50cec0e25364d8267e7623c33fJames Dennett}  // namespace remoting
16874a5fd8bcc68b540b58f6fcd2d80e6e926966e71Nico Weber