file_transfer_message_handler.cc 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. // Copyright 2017 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. #include "remoting/host/file_transfer/file_transfer_message_handler.h"
  5. #include <cstddef>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "base/callback_helpers.h"
  9. #include "base/logging.h"
  10. #include "base/path_service.h"
  11. #include "net/base/filename_util.h"
  12. #include "remoting/base/compound_buffer.h"
  13. #include "remoting/protocol/file_transfer_helpers.h"
  14. #include "url/gurl.h"
  15. namespace remoting {
  16. namespace {
  17. // Used if the provided filename can't be used. (E.g., if it is empty, or if
  18. // it consists entirely of disallowed characters.)
  19. constexpr char kDefaultFileName[] = "crd_transfer";
  20. // The max SCTP message size that can be safely sent in a cross-browser fashion
  21. // is 16 KiB. Thus, 8 KiB should be a safe value even with messaging overhead.
  22. constexpr std::size_t kChunkSize = 8192; // 8 KiB
  23. // The max number of chunks that should be queued for sending at one time. This
  24. // helps smooth out spiky IO latency.
  25. constexpr std::size_t kMaxQueuedChunks = 128; // 128 * 8 KiB = 1 MiB
  26. } // namespace
  27. FileTransferMessageHandler::FileTransferMessageHandler(
  28. const std::string& name,
  29. std::unique_ptr<protocol::MessagePipe> pipe,
  30. std::unique_ptr<FileOperations> file_operations)
  31. : protocol::NamedMessagePipeHandler(name, std::move(pipe)),
  32. file_operations_(std::move(file_operations)) {
  33. DCHECK(file_operations_);
  34. }
  35. FileTransferMessageHandler::~FileTransferMessageHandler() = default;
  36. void FileTransferMessageHandler::OnConnected() {}
  37. void FileTransferMessageHandler::OnIncomingMessage(
  38. std::unique_ptr<CompoundBuffer> buffer) {
  39. if (state_ == kFailed) {
  40. // Ignore any messages that come in after cancel or error.
  41. return;
  42. }
  43. protocol::FileTransfer message;
  44. CompoundBufferInputStream buffer_stream(buffer.get());
  45. if (!message.ParseFromZeroCopyStream(&buffer_stream)) {
  46. LOG(ERROR) << "Failed to parse message.";
  47. Cancel();
  48. SendError(protocol::MakeFileTransferError(
  49. FROM_HERE, protocol::FileTransfer_Error_Type_PROTOCOL_ERROR));
  50. return;
  51. }
  52. switch (message.message_case()) {
  53. // Writing messages.
  54. case protocol::FileTransfer::kMetadata:
  55. if (state_ != kConnected) {
  56. UnexpectedMessage(FROM_HERE, "metadata");
  57. return;
  58. }
  59. OnMetadata(std::move(*message.mutable_metadata()));
  60. return;
  61. case protocol::FileTransfer::kData:
  62. if (state_ != kWriting) {
  63. UnexpectedMessage(FROM_HERE, "data");
  64. return;
  65. }
  66. // The protocol buffer compiler only provides access to byte fields as
  67. // std::string. Unfortunately, unlike most C++ containers, std::string
  68. // doesn't guarantee that pointers to the data stay valid when the owning
  69. // container is moved. Because that guarantee is useful when passing
  70. // data and ownership through asynchronous function calls, the received
  71. // data is copied into a std::vector and passed around in that form.
  72. OnData(std::vector<std::uint8_t>(message.data().data().begin(),
  73. message.data().data().end()));
  74. return;
  75. case protocol::FileTransfer::kEnd:
  76. if (state_ != kWriting) {
  77. UnexpectedMessage(FROM_HERE, "end");
  78. return;
  79. }
  80. OnEnd();
  81. return;
  82. // Reading messages.
  83. case protocol::FileTransfer::kRequestTransfer:
  84. if (state_ != kConnected) {
  85. UnexpectedMessage(FROM_HERE, "request_transfer");
  86. return;
  87. }
  88. OnRequestTransfer();
  89. return;
  90. case protocol::FileTransfer::kSuccess:
  91. if (state_ != kEof) {
  92. UnexpectedMessage(FROM_HERE, "success");
  93. return;
  94. }
  95. OnSuccess();
  96. return;
  97. // Common messages.
  98. case protocol::FileTransfer::kError:
  99. OnError(std::move(*message.mutable_error()));
  100. return;
  101. case protocol::FileTransfer::MESSAGE_NOT_SET:
  102. LOG(ERROR) << "Received invalid file-transfer message.";
  103. Cancel();
  104. SendError(protocol::MakeFileTransferError(
  105. FROM_HERE, protocol::FileTransfer_Error_Type_PROTOCOL_ERROR));
  106. return;
  107. }
  108. }
  109. void FileTransferMessageHandler::OnDisconnecting() {}
  110. void FileTransferMessageHandler::OnMetadata(
  111. protocol::FileTransfer::Metadata metadata) {
  112. SetState(kWriting);
  113. // Unretained is sound because the callbacks won't be called after
  114. // BufferedFileWriter is destroyed, which is in turn owned by this
  115. // FileTransferMessageHandler.
  116. buffered_file_writer_.emplace(
  117. file_operations_->CreateWriter(),
  118. base::BindOnce(&FileTransferMessageHandler::OnWritingComplete,
  119. base::Unretained(this)),
  120. base::BindOnce(&FileTransferMessageHandler::OnWriteError,
  121. base::Unretained(this)));
  122. buffered_file_writer_->Start(
  123. // Ensure filename is safe, and convert from UTF-8 to a FilePath.
  124. net::GenerateFileName(GURL(), std::string(), std::string(),
  125. metadata.filename(), std::string(),
  126. kDefaultFileName));
  127. }
  128. void FileTransferMessageHandler::OnData(std::vector<std::uint8_t> data) {
  129. DCHECK_EQ(kWriting, state_);
  130. buffered_file_writer_->Write(std::move(data));
  131. }
  132. void FileTransferMessageHandler::OnEnd() {
  133. DCHECK_EQ(kWriting, state_);
  134. SetState(kClosed);
  135. buffered_file_writer_->Close();
  136. }
  137. void FileTransferMessageHandler::OnRequestTransfer() {
  138. SetState(kReading);
  139. file_reader_ = file_operations_->CreateReader();
  140. // Unretained is sound because FileReader will not call us after it is
  141. // destroyed, and we own it.
  142. file_reader_->Open(base::BindOnce(&FileTransferMessageHandler::OnOpenResult,
  143. base::Unretained(this)));
  144. }
  145. void FileTransferMessageHandler::OnSuccess() {
  146. DCHECK_EQ(kEof, state_);
  147. SetState(kClosed);
  148. // Ensure any resources tied to the reader's lifetime are released.
  149. file_reader_.reset();
  150. }
  151. void FileTransferMessageHandler::OnError(protocol::FileTransfer_Error error) {
  152. if (error.type() != protocol::FileTransfer_Error_Type_CANCELED) {
  153. LOG(ERROR) << "File transfer error from client: " << error;
  154. }
  155. Cancel();
  156. }
  157. void FileTransferMessageHandler::OnOpenResult(
  158. FileOperations::Reader::OpenResult result) {
  159. if (!result) {
  160. Cancel();
  161. SendError(result.error());
  162. return;
  163. }
  164. protocol::FileTransfer metadata_message;
  165. metadata_message.mutable_metadata()->set_filename(
  166. file_reader_->filename().AsUTF8Unsafe());
  167. metadata_message.mutable_metadata()->set_size(file_reader_->size());
  168. protocol::NamedMessagePipeHandler::Send(metadata_message, base::DoNothing());
  169. ReadNextChunk();
  170. }
  171. void FileTransferMessageHandler::OnReadResult(
  172. FileOperations::Reader::ReadResult result) {
  173. if (!result) {
  174. Cancel();
  175. SendError(result.error());
  176. return;
  177. }
  178. if (result->empty()) {
  179. SetState(kEof);
  180. protocol::FileTransfer end_message;
  181. end_message.mutable_end();
  182. protocol::NamedMessagePipeHandler::Send(end_message, base::DoNothing());
  183. } else {
  184. ++queued_chunks_;
  185. if (queued_chunks_ < kMaxQueuedChunks) {
  186. ReadNextChunk();
  187. }
  188. protocol::FileTransfer data_message;
  189. data_message.mutable_data()->set_data(
  190. std::string(result->begin(), result->end()));
  191. // Call Send last in case it invokes ReadNextChunk synchronously.
  192. protocol::NamedMessagePipeHandler::Send(
  193. data_message, base::BindOnce(&FileTransferMessageHandler::OnChunkSent,
  194. weak_ptr_factory_.GetWeakPtr()));
  195. }
  196. }
  197. void FileTransferMessageHandler::OnChunkSent() {
  198. --queued_chunks_;
  199. ReadNextChunk();
  200. }
  201. void FileTransferMessageHandler::OnWritingComplete() {
  202. protocol::FileTransfer success_message;
  203. success_message.mutable_success();
  204. protocol::NamedMessagePipeHandler::Send(success_message, base::DoNothing());
  205. }
  206. void FileTransferMessageHandler::OnWriteError(
  207. protocol::FileTransfer_Error error) {
  208. Cancel();
  209. SendError(std::move(error));
  210. }
  211. void FileTransferMessageHandler::ReadNextChunk() {
  212. // Make sure we haven't received an error from the client and that we're not
  213. // currently reading a chunk.
  214. if (state_ != kReading || file_reader_->state() != FileOperations::kReady) {
  215. return;
  216. }
  217. // Unretained is sound because file_reader_ is guaranteed not to execute any
  218. // callbacks after it is destroyed.
  219. file_reader_->ReadChunk(
  220. kChunkSize, base::BindOnce(&FileTransferMessageHandler::OnReadResult,
  221. base::Unretained(this)));
  222. }
  223. void FileTransferMessageHandler::Cancel() {
  224. SetState(kFailed);
  225. file_reader_.reset();
  226. // Will implicitly cancel if still in progress.
  227. buffered_file_writer_.reset();
  228. }
  229. void FileTransferMessageHandler::SendError(protocol::FileTransfer_Error error) {
  230. protocol::FileTransfer error_message;
  231. *error_message.mutable_error() = std::move(error);
  232. protocol::NamedMessagePipeHandler::Send(error_message, base::DoNothing());
  233. }
  234. void FileTransferMessageHandler::UnexpectedMessage(base::Location from_here,
  235. const char* message) {
  236. LOG(ERROR) << "Unexpected file-transfer message received: " << message
  237. << ". Current state: " << state_;
  238. Cancel();
  239. SendError(protocol::MakeFileTransferError(
  240. from_here, protocol::FileTransfer_Error_Type_PROTOCOL_ERROR));
  241. }
  242. void FileTransferMessageHandler::SetState(State state) {
  243. switch (state) {
  244. case kConnected:
  245. // This is the initial state, but should never be reached again.
  246. NOTREACHED();
  247. break;
  248. case kReading:
  249. DCHECK_EQ(kConnected, state_);
  250. break;
  251. case kWriting:
  252. DCHECK_EQ(kConnected, state_);
  253. break;
  254. case kEof:
  255. DCHECK_EQ(kReading, state_);
  256. break;
  257. case kClosed:
  258. DCHECK(state_ == kWriting || state_ == kEof);
  259. break;
  260. case kFailed:
  261. // Any state can change to kFailed.
  262. break;
  263. }
  264. state_ = state;
  265. }
  266. } // namespace remoting