1 // Copyright (c) 2012 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.
5 #include "ipc/ipc_message_utils.h"
7 #include "base/files/file_path.h"
8 #include "base/json/json_writer.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/nullable_string16.h"
11 #include "base/string_number_conversions.h"
12 #include "base/time.h"
13 #include "base/utf_string_conversions.h"
14 #include "base/values.h"
15 #include "ipc/ipc_channel_handle.h"
18 #include "ipc/file_descriptor_set_posix.h"
27 const int kMaxRecursionDepth
= 100;
29 template<typename CharType
>
30 void LogBytes(const std::vector
<CharType
>& data
, std::string
* out
) {
32 // Windows has a GUI for logging, which can handle arbitrary binary data.
33 for (size_t i
= 0; i
< data
.size(); ++i
)
34 out
->push_back(data
[i
]);
36 // On POSIX, we log to stdout, which we assume can display ASCII.
37 static const size_t kMaxBytesToLog
= 100;
38 for (size_t i
= 0; i
< std::min(data
.size(), kMaxBytesToLog
); ++i
) {
40 out
->push_back(data
[i
]);
42 out
->append(StringPrintf("[%02X]", static_cast<unsigned char>(data
[i
])));
44 if (data
.size() > kMaxBytesToLog
) {
46 StringPrintf(" and %u more bytes",
47 static_cast<unsigned>(data
.size() - kMaxBytesToLog
)));
52 bool ReadValue(const Message
* m
, PickleIterator
* iter
, Value
** value
,
55 void WriteValue(Message
* m
, const Value
* value
, int recursion
) {
57 if (recursion
> kMaxRecursionDepth
) {
58 LOG(WARNING
) << "Max recursion depth hit in WriteValue.";
62 m
->WriteInt(value
->GetType());
64 switch (value
->GetType()) {
65 case Value::TYPE_NULL
:
67 case Value::TYPE_BOOLEAN
: {
69 result
= value
->GetAsBoolean(&val
);
74 case Value::TYPE_INTEGER
: {
76 result
= value
->GetAsInteger(&val
);
81 case Value::TYPE_DOUBLE
: {
83 result
= value
->GetAsDouble(&val
);
88 case Value::TYPE_STRING
: {
90 result
= value
->GetAsString(&val
);
95 case Value::TYPE_BINARY
: {
96 const base::BinaryValue
* binary
=
97 static_cast<const base::BinaryValue
*>(value
);
98 m
->WriteData(binary
->GetBuffer(), static_cast<int>(binary
->GetSize()));
101 case Value::TYPE_DICTIONARY
: {
102 const DictionaryValue
* dict
= static_cast<const DictionaryValue
*>(value
);
104 WriteParam(m
, static_cast<int>(dict
->size()));
106 for (DictionaryValue::Iterator
it(*dict
); !it
.IsAtEnd(); it
.Advance()) {
107 WriteParam(m
, it
.key());
108 WriteValue(m
, &it
.value(), recursion
+ 1);
112 case Value::TYPE_LIST
: {
113 const ListValue
* list
= static_cast<const ListValue
*>(value
);
114 WriteParam(m
, static_cast<int>(list
->GetSize()));
115 for (ListValue::const_iterator it
= list
->begin(); it
!= list
->end();
117 WriteValue(m
, *it
, recursion
+ 1);
124 // Helper for ReadValue that reads a DictionaryValue into a pre-allocated
126 bool ReadDictionaryValue(const Message
* m
, PickleIterator
* iter
,
127 DictionaryValue
* value
, int recursion
) {
129 if (!ReadParam(m
, iter
, &size
))
132 for (int i
= 0; i
< size
; ++i
) {
135 if (!ReadParam(m
, iter
, &key
) ||
136 !ReadValue(m
, iter
, &subval
, recursion
+ 1))
138 value
->SetWithoutPathExpansion(key
, subval
);
144 // Helper for ReadValue that reads a ReadListValue into a pre-allocated
146 bool ReadListValue(const Message
* m
, PickleIterator
* iter
,
147 ListValue
* value
, int recursion
) {
149 if (!ReadParam(m
, iter
, &size
))
152 for (int i
= 0; i
< size
; ++i
) {
154 if (!ReadValue(m
, iter
, &subval
, recursion
+ 1))
156 value
->Set(i
, subval
);
162 bool ReadValue(const Message
* m
, PickleIterator
* iter
, Value
** value
,
164 if (recursion
> kMaxRecursionDepth
) {
165 LOG(WARNING
) << "Max recursion depth hit in ReadValue.";
170 if (!ReadParam(m
, iter
, &type
))
174 case Value::TYPE_NULL
:
175 *value
= Value::CreateNullValue();
177 case Value::TYPE_BOOLEAN
: {
179 if (!ReadParam(m
, iter
, &val
))
181 *value
= new base::FundamentalValue(val
);
184 case Value::TYPE_INTEGER
: {
186 if (!ReadParam(m
, iter
, &val
))
188 *value
= new base::FundamentalValue(val
);
191 case Value::TYPE_DOUBLE
: {
193 if (!ReadParam(m
, iter
, &val
))
195 *value
= new base::FundamentalValue(val
);
198 case Value::TYPE_STRING
: {
200 if (!ReadParam(m
, iter
, &val
))
202 *value
= new base::StringValue(val
);
205 case Value::TYPE_BINARY
: {
208 if (!m
->ReadData(iter
, &data
, &length
))
210 *value
= base::BinaryValue::CreateWithCopiedBuffer(data
, length
);
213 case Value::TYPE_DICTIONARY
: {
214 scoped_ptr
<DictionaryValue
> val(new DictionaryValue());
215 if (!ReadDictionaryValue(m
, iter
, val
.get(), recursion
))
217 *value
= val
.release();
220 case Value::TYPE_LIST
: {
221 scoped_ptr
<ListValue
> val(new ListValue());
222 if (!ReadListValue(m
, iter
, val
.get(), recursion
))
224 *value
= val
.release();
236 // -----------------------------------------------------------------------------
246 LogData::~LogData() {
249 void ParamTraits
<bool>::Log(const param_type
& p
, std::string
* l
) {
250 l
->append(p
? "true" : "false");
253 void ParamTraits
<int>::Log(const param_type
& p
, std::string
* l
) {
254 l
->append(base::IntToString(p
));
257 void ParamTraits
<unsigned int>::Log(const param_type
& p
, std::string
* l
) {
258 l
->append(base::UintToString(p
));
261 void ParamTraits
<long>::Log(const param_type
& p
, std::string
* l
) {
262 l
->append(base::Int64ToString(static_cast<int64
>(p
)));
265 void ParamTraits
<unsigned long>::Log(const param_type
& p
, std::string
* l
) {
266 l
->append(base::Uint64ToString(static_cast<uint64
>(p
)));
269 void ParamTraits
<long long>::Log(const param_type
& p
, std::string
* l
) {
270 l
->append(base::Int64ToString(static_cast<int64
>(p
)));
273 void ParamTraits
<unsigned long long>::Log(const param_type
& p
, std::string
* l
) {
274 l
->append(base::Uint64ToString(p
));
277 void ParamTraits
<unsigned short>::Write(Message
* m
, const param_type
& p
) {
278 m
->WriteBytes(&p
, sizeof(param_type
));
281 bool ParamTraits
<unsigned short>::Read(const Message
* m
, PickleIterator
* iter
,
284 if (!m
->ReadBytes(iter
, &data
, sizeof(param_type
)))
286 memcpy(r
, data
, sizeof(param_type
));
290 void ParamTraits
<unsigned short>::Log(const param_type
& p
, std::string
* l
) {
291 l
->append(base::UintToString(p
));
294 void ParamTraits
<float>::Write(Message
* m
, const param_type
& p
) {
295 m
->WriteData(reinterpret_cast<const char*>(&p
), sizeof(param_type
));
298 bool ParamTraits
<float>::Read(const Message
* m
, PickleIterator
* iter
,
302 if (!m
->ReadData(iter
, &data
, &data_size
) ||
303 data_size
!= sizeof(param_type
)) {
307 memcpy(r
, data
, sizeof(param_type
));
311 void ParamTraits
<float>::Log(const param_type
& p
, std::string
* l
) {
312 l
->append(StringPrintf("%e", p
));
315 void ParamTraits
<double>::Write(Message
* m
, const param_type
& p
) {
316 m
->WriteData(reinterpret_cast<const char*>(&p
), sizeof(param_type
));
319 bool ParamTraits
<double>::Read(const Message
* m
, PickleIterator
* iter
,
323 if (!m
->ReadData(iter
, &data
, &data_size
) ||
324 data_size
!= sizeof(param_type
)) {
328 memcpy(r
, data
, sizeof(param_type
));
332 void ParamTraits
<double>::Log(const param_type
& p
, std::string
* l
) {
333 l
->append(StringPrintf("%e", p
));
337 void ParamTraits
<std::string
>::Log(const param_type
& p
, std::string
* l
) {
341 void ParamTraits
<std::wstring
>::Log(const param_type
& p
, std::string
* l
) {
342 l
->append(WideToUTF8(p
));
345 #if !defined(WCHAR_T_IS_UTF16)
346 void ParamTraits
<string16
>::Log(const param_type
& p
, std::string
* l
) {
347 l
->append(UTF16ToUTF8(p
));
351 void ParamTraits
<std::vector
<char> >::Write(Message
* m
, const param_type
& p
) {
353 m
->WriteData(NULL
, 0);
355 m
->WriteData(&p
.front(), static_cast<int>(p
.size()));
359 bool ParamTraits
<std::vector
<char> >::Read(const Message
* m
,
360 PickleIterator
* iter
,
364 if (!m
->ReadData(iter
, &data
, &data_size
) || data_size
< 0)
366 r
->resize(data_size
);
368 memcpy(&r
->front(), data
, data_size
);
372 void ParamTraits
<std::vector
<char> >::Log(const param_type
& p
, std::string
* l
) {
376 void ParamTraits
<std::vector
<unsigned char> >::Write(Message
* m
,
377 const param_type
& p
) {
379 m
->WriteData(NULL
, 0);
381 m
->WriteData(reinterpret_cast<const char*>(&p
.front()),
382 static_cast<int>(p
.size()));
386 bool ParamTraits
<std::vector
<unsigned char> >::Read(const Message
* m
,
387 PickleIterator
* iter
,
391 if (!m
->ReadData(iter
, &data
, &data_size
) || data_size
< 0)
393 r
->resize(data_size
);
395 memcpy(&r
->front(), data
, data_size
);
399 void ParamTraits
<std::vector
<unsigned char> >::Log(const param_type
& p
,
404 void ParamTraits
<std::vector
<bool> >::Write(Message
* m
, const param_type
& p
) {
405 WriteParam(m
, static_cast<int>(p
.size()));
406 for (size_t i
= 0; i
< p
.size(); i
++)
410 bool ParamTraits
<std::vector
<bool> >::Read(const Message
* m
,
411 PickleIterator
* iter
,
414 // ReadLength() checks for < 0 itself.
415 if (!m
->ReadLength(iter
, &size
))
418 for (int i
= 0; i
< size
; i
++) {
420 if (!ReadParam(m
, iter
, &value
))
427 void ParamTraits
<std::vector
<bool> >::Log(const param_type
& p
, std::string
* l
) {
428 for (size_t i
= 0; i
< p
.size(); ++i
) {
435 void ParamTraits
<DictionaryValue
>::Write(Message
* m
, const param_type
& p
) {
436 WriteValue(m
, &p
, 0);
439 bool ParamTraits
<DictionaryValue
>::Read(
440 const Message
* m
, PickleIterator
* iter
, param_type
* r
) {
442 if (!ReadParam(m
, iter
, &type
) || type
!= Value::TYPE_DICTIONARY
)
445 return ReadDictionaryValue(m
, iter
, r
, 0);
448 void ParamTraits
<DictionaryValue
>::Log(const param_type
& p
, std::string
* l
) {
450 base::JSONWriter::Write(&p
, &json
);
454 #if defined(OS_POSIX)
455 void ParamTraits
<base::FileDescriptor
>::Write(Message
* m
, const param_type
& p
) {
456 const bool valid
= p
.fd
>= 0;
457 WriteParam(m
, valid
);
460 if (!m
->WriteFileDescriptor(p
))
465 bool ParamTraits
<base::FileDescriptor
>::Read(const Message
* m
,
466 PickleIterator
* iter
,
469 if (!ReadParam(m
, iter
, &valid
))
474 r
->auto_close
= false;
478 return m
->ReadFileDescriptor(iter
, r
);
481 void ParamTraits
<base::FileDescriptor
>::Log(const param_type
& p
,
484 l
->append(StringPrintf("FD(%d auto-close)", p
.fd
));
486 l
->append(StringPrintf("FD(%d)", p
.fd
));
489 #endif // defined(OS_POSIX)
491 void ParamTraits
<base::FilePath
>::Write(Message
* m
, const param_type
& p
) {
495 bool ParamTraits
<base::FilePath
>::Read(const Message
* m
,
496 PickleIterator
* iter
,
498 return r
->ReadFromPickle(iter
);
501 void ParamTraits
<base::FilePath
>::Log(const param_type
& p
, std::string
* l
) {
502 ParamTraits
<base::FilePath::StringType
>::Log(p
.value(), l
);
505 void ParamTraits
<ListValue
>::Write(Message
* m
, const param_type
& p
) {
506 WriteValue(m
, &p
, 0);
509 bool ParamTraits
<ListValue
>::Read(
510 const Message
* m
, PickleIterator
* iter
, param_type
* r
) {
512 if (!ReadParam(m
, iter
, &type
) || type
!= Value::TYPE_LIST
)
515 return ReadListValue(m
, iter
, r
, 0);
518 void ParamTraits
<ListValue
>::Log(const param_type
& p
, std::string
* l
) {
520 base::JSONWriter::Write(&p
, &json
);
524 void ParamTraits
<NullableString16
>::Write(Message
* m
, const param_type
& p
) {
525 WriteParam(m
, p
.string());
526 WriteParam(m
, p
.is_null());
529 bool ParamTraits
<NullableString16
>::Read(const Message
* m
, PickleIterator
* iter
,
532 if (!ReadParam(m
, iter
, &string
))
535 if (!ReadParam(m
, iter
, &is_null
))
537 *r
= NullableString16(string
, is_null
);
541 void ParamTraits
<NullableString16
>::Log(const param_type
& p
, std::string
* l
) {
543 LogParam(p
.string(), l
);
545 LogParam(p
.is_null(), l
);
549 void ParamTraits
<base::PlatformFileInfo
>::Write(Message
* m
,
550 const param_type
& p
) {
551 WriteParam(m
, p
.size
);
552 WriteParam(m
, p
.is_directory
);
553 WriteParam(m
, p
.last_modified
.ToDoubleT());
554 WriteParam(m
, p
.last_accessed
.ToDoubleT());
555 WriteParam(m
, p
.creation_time
.ToDoubleT());
558 bool ParamTraits
<base::PlatformFileInfo
>::Read(const Message
* m
,
559 PickleIterator
* iter
,
561 double last_modified
;
562 double last_accessed
;
563 double creation_time
;
565 ReadParam(m
, iter
, &p
->size
) &&
566 ReadParam(m
, iter
, &p
->is_directory
) &&
567 ReadParam(m
, iter
, &last_modified
) &&
568 ReadParam(m
, iter
, &last_accessed
) &&
569 ReadParam(m
, iter
, &creation_time
);
571 p
->last_modified
= base::Time::FromDoubleT(last_modified
);
572 p
->last_accessed
= base::Time::FromDoubleT(last_accessed
);
573 p
->creation_time
= base::Time::FromDoubleT(creation_time
);
578 void ParamTraits
<base::PlatformFileInfo
>::Log(const param_type
& p
,
583 LogParam(p
.is_directory
, l
);
585 LogParam(p
.last_modified
.ToDoubleT(), l
);
587 LogParam(p
.last_accessed
.ToDoubleT(), l
);
589 LogParam(p
.creation_time
.ToDoubleT(), l
);
593 void ParamTraits
<base::Time
>::Write(Message
* m
, const param_type
& p
) {
594 ParamTraits
<int64
>::Write(m
, p
.ToInternalValue());
597 bool ParamTraits
<base::Time
>::Read(const Message
* m
, PickleIterator
* iter
,
600 if (!ParamTraits
<int64
>::Read(m
, iter
, &value
))
602 *r
= base::Time::FromInternalValue(value
);
606 void ParamTraits
<base::Time
>::Log(const param_type
& p
, std::string
* l
) {
607 ParamTraits
<int64
>::Log(p
.ToInternalValue(), l
);
610 void ParamTraits
<base::TimeDelta
>::Write(Message
* m
, const param_type
& p
) {
611 ParamTraits
<int64
>::Write(m
, p
.ToInternalValue());
614 bool ParamTraits
<base::TimeDelta
>::Read(const Message
* m
,
615 PickleIterator
* iter
,
618 bool ret
= ParamTraits
<int64
>::Read(m
, iter
, &value
);
620 *r
= base::TimeDelta::FromInternalValue(value
);
625 void ParamTraits
<base::TimeDelta
>::Log(const param_type
& p
, std::string
* l
) {
626 ParamTraits
<int64
>::Log(p
.ToInternalValue(), l
);
629 void ParamTraits
<base::TimeTicks
>::Write(Message
* m
, const param_type
& p
) {
630 ParamTraits
<int64
>::Write(m
, p
.ToInternalValue());
633 bool ParamTraits
<base::TimeTicks
>::Read(const Message
* m
,
634 PickleIterator
* iter
,
637 bool ret
= ParamTraits
<int64
>::Read(m
, iter
, &value
);
639 *r
= base::TimeTicks::FromInternalValue(value
);
644 void ParamTraits
<base::TimeTicks
>::Log(const param_type
& p
, std::string
* l
) {
645 ParamTraits
<int64
>::Log(p
.ToInternalValue(), l
);
648 void ParamTraits
<IPC::ChannelHandle
>::Write(Message
* m
, const param_type
& p
) {
650 // On Windows marshalling pipe handle is not supported.
651 DCHECK(p
.pipe
.handle
== NULL
);
652 #endif // defined (OS_WIN)
653 WriteParam(m
, p
.name
);
654 #if defined(OS_POSIX)
655 WriteParam(m
, p
.socket
);
659 bool ParamTraits
<IPC::ChannelHandle
>::Read(const Message
* m
,
660 PickleIterator
* iter
,
662 return ReadParam(m
, iter
, &r
->name
)
663 #if defined(OS_POSIX)
664 && ReadParam(m
, iter
, &r
->socket
)
669 void ParamTraits
<IPC::ChannelHandle
>::Log(const param_type
& p
,
671 l
->append(StringPrintf("ChannelHandle(%s", p
.name
.c_str()));
672 #if defined(OS_POSIX)
674 ParamTraits
<base::FileDescriptor
>::Log(p
.socket
, l
);
679 void ParamTraits
<LogData
>::Write(Message
* m
, const param_type
& p
) {
680 WriteParam(m
, p
.channel
);
681 WriteParam(m
, p
.routing_id
);
682 WriteParam(m
, p
.type
);
683 WriteParam(m
, p
.flags
);
684 WriteParam(m
, p
.sent
);
685 WriteParam(m
, p
.receive
);
686 WriteParam(m
, p
.dispatch
);
687 WriteParam(m
, p
.message_name
);
688 WriteParam(m
, p
.params
);
691 bool ParamTraits
<LogData
>::Read(const Message
* m
,
692 PickleIterator
* iter
,
695 ReadParam(m
, iter
, &r
->channel
) &&
696 ReadParam(m
, iter
, &r
->routing_id
) &&
697 ReadParam(m
, iter
, &r
->type
) &&
698 ReadParam(m
, iter
, &r
->flags
) &&
699 ReadParam(m
, iter
, &r
->sent
) &&
700 ReadParam(m
, iter
, &r
->receive
) &&
701 ReadParam(m
, iter
, &r
->dispatch
) &&
702 ReadParam(m
, iter
, &r
->message_name
) &&
703 ReadParam(m
, iter
, &r
->params
);
706 void ParamTraits
<LogData
>::Log(const param_type
& p
, std::string
* l
) {
707 // Doesn't make sense to implement this!
710 void ParamTraits
<Message
>::Write(Message
* m
, const Message
& p
) {
711 #if defined(OS_POSIX)
712 // We don't serialize the file descriptors in the nested message, so there
713 // better not be any.
714 DCHECK(!p
.HasFileDescriptors());
717 // Don't just write out the message. This is used to send messages between
718 // NaCl (Posix environment) and the browser (could be on Windows). The message
719 // header formats differ between these systems (so does handle sharing, but
720 // we already asserted we don't have any handles). So just write out the
721 // parts of the header we use.
723 // Be careful also to use only explicitly-sized types. The NaCl environment
724 // could be 64-bit and the host browser could be 32-bits. The nested message
725 // may or may not be safe to send between 32-bit and 64-bit systems, but we
726 // leave that up to the code sending the message to ensure.
727 m
->WriteUInt32(static_cast<uint32
>(p
.routing_id()));
728 m
->WriteUInt32(p
.type());
729 m
->WriteUInt32(p
.flags());
730 m
->WriteData(p
.payload(), static_cast<uint32
>(p
.payload_size()));
733 bool ParamTraits
<Message
>::Read(const Message
* m
, PickleIterator
* iter
,
735 uint32 routing_id
, type
, flags
;
736 if (!m
->ReadUInt32(iter
, &routing_id
) ||
737 !m
->ReadUInt32(iter
, &type
) ||
738 !m
->ReadUInt32(iter
, &flags
))
743 if (!m
->ReadData(iter
, &payload
, &payload_size
))
746 r
->SetHeaderValues(static_cast<int32
>(routing_id
), type
, flags
);
747 return r
->WriteBytes(payload
, payload_size
);
750 void ParamTraits
<Message
>::Log(const Message
& p
, std::string
* l
) {
751 l
->append("<IPC::Message>");
755 // Note that HWNDs/HANDLE/HCURSOR/HACCEL etc are always 32 bits, even on 64
756 // bit systems. That's why we use the Windows macros to convert to 32 bits.
757 void ParamTraits
<HANDLE
>::Write(Message
* m
, const param_type
& p
) {
758 m
->WriteInt(HandleToLong(p
));
761 bool ParamTraits
<HANDLE
>::Read(const Message
* m
, PickleIterator
* iter
,
764 if (!m
->ReadInt(iter
, &temp
))
766 *r
= LongToHandle(temp
);
770 void ParamTraits
<HANDLE
>::Log(const param_type
& p
, std::string
* l
) {
771 l
->append(StringPrintf("0x%X", p
));
774 void ParamTraits
<LOGFONT
>::Write(Message
* m
, const param_type
& p
) {
775 m
->WriteData(reinterpret_cast<const char*>(&p
), sizeof(LOGFONT
));
778 bool ParamTraits
<LOGFONT
>::Read(const Message
* m
, PickleIterator
* iter
,
782 if (m
->ReadData(iter
, &data
, &data_size
) && data_size
== sizeof(LOGFONT
)) {
783 const LOGFONT
*font
= reinterpret_cast<LOGFONT
*>(const_cast<char*>(data
));
784 if (_tcsnlen(font
->lfFaceName
, LF_FACESIZE
) < LF_FACESIZE
) {
785 memcpy(r
, data
, sizeof(LOGFONT
));
794 void ParamTraits
<LOGFONT
>::Log(const param_type
& p
, std::string
* l
) {
795 l
->append(StringPrintf("<LOGFONT>"));
798 void ParamTraits
<MSG
>::Write(Message
* m
, const param_type
& p
) {
799 m
->WriteData(reinterpret_cast<const char*>(&p
), sizeof(MSG
));
802 bool ParamTraits
<MSG
>::Read(const Message
* m
, PickleIterator
* iter
,
806 bool result
= m
->ReadData(iter
, &data
, &data_size
);
807 if (result
&& data_size
== sizeof(MSG
)) {
808 memcpy(r
, data
, sizeof(MSG
));
817 void ParamTraits
<MSG
>::Log(const param_type
& p
, std::string
* l
) {