Home | History | Annotate | Download | only in native_messaging
      1 // Copyright 2013 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 "remoting/host/native_messaging/native_messaging_writer.h"
      6 
      7 #include <string>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/json/json_writer.h"
     11 
     12 namespace {
     13 
     14 // 4-byte type used for the message header.
     15 typedef uint32 MessageLengthType;
     16 
     17 // Defined as an int, for passing to APIs that take an int, to avoid
     18 // signed/unsigned warnings about implicit cast.
     19 const int kMessageHeaderSize = sizeof(MessageLengthType);
     20 
     21 // Limit the size of sent messages, since Chrome will not accept messages
     22 // larger than 1MB, and this helps deal with the problem of integer overflow
     23 // when passing sizes to net::FileStream APIs that take |int| parameters.
     24 // This is defined as size_t (unsigned type) so it can be compared with the
     25 // result of std::string::length() without compiler warnings.
     26 const size_t kMaximumMessageSize = 1024 * 1024;
     27 
     28 // Performs the same task as FileStream::WriteSync(), but ensures that exactly
     29 // |buffer_length| bytes are written. Unlike WriteSync(), a partial write may
     30 // only occur as a result of end-of-file or fatal error. Returns the number of
     31 // bytes written (buffer_length) or an error-code <= 0.
     32 //
     33 // TODO(lambroslambrou): Add this method to net::FileStream, with unit-tests.
     34 // See http://crbug.com/232202.
     35 int WriteUntilComplete(net::FileStream* out,
     36                        const char* buffer, int buffer_length) {
     37   int written = 0;
     38   while (written < buffer_length) {
     39     int result = out->WriteSync(buffer + written, buffer_length - written);
     40     if (result <= 0) {
     41       return result;
     42     }
     43     DCHECK_LE(result, buffer_length - written);
     44     written += result;
     45   }
     46   return written;
     47 }
     48 
     49 }  // namespace
     50 
     51 namespace remoting {
     52 
     53 NativeMessagingWriter::NativeMessagingWriter(base::PlatformFile handle)
     54     : write_stream_(handle, base::PLATFORM_FILE_WRITE, NULL),
     55       fail_(false) {
     56 }
     57 
     58 NativeMessagingWriter::~NativeMessagingWriter() {
     59 }
     60 
     61 bool NativeMessagingWriter::WriteMessage(const base::Value& message) {
     62   if (fail_) {
     63     LOG(ERROR) << "Stream marked as corrupt.";
     64     return false;
     65   }
     66 
     67   std::string message_json;
     68   base::JSONWriter::Write(&message, &message_json);
     69 
     70   CHECK_LE(message_json.length(), kMaximumMessageSize);
     71 
     72   // Cast from size_t to the proper header type. The check above ensures this
     73   // won't overflow.
     74   MessageLengthType message_length =
     75       static_cast<MessageLengthType>(message_json.length());
     76 
     77   int result = WriteUntilComplete(
     78       &write_stream_, reinterpret_cast<char*>(&message_length),
     79       kMessageHeaderSize);
     80   if (result != kMessageHeaderSize) {
     81     LOG(ERROR) << "Failed to send message header, write returned " << result;
     82     fail_ = true;
     83     return false;
     84   }
     85 
     86   // The length check above ensures that the cast won't overflow a signed
     87   // 32-bit int.
     88   int message_length_as_int = message_length;
     89 
     90   // CHECK needed since data() is undefined on an empty std::string.
     91   CHECK(!message_json.empty());
     92   result = WriteUntilComplete(&write_stream_, message_json.data(),
     93                               message_length_as_int);
     94   if (result != message_length_as_int) {
     95     LOG(ERROR) << "Failed to send message body, write returned " << result;
     96     fail_ = true;
     97     return false;
     98   }
     99 
    100   return true;
    101 }
    102 
    103 }  // namespace remoting
    104