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