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/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"
25 const int kMaxRecursionDepth
= 100;
27 template<typename CharType
>
28 void LogBytes(const std::vector
<CharType
>& data
, std::string
* out
) {
30 // Windows has a GUI for logging, which can handle arbitrary binary data.
31 for (size_t i
= 0; i
< data
.size(); ++i
)
32 out
->push_back(data
[i
]);
34 // On POSIX, we log to stdout, which we assume can display ASCII.
35 static const size_t kMaxBytesToLog
= 100;
36 for (size_t i
= 0; i
< std::min(data
.size(), kMaxBytesToLog
); ++i
) {
38 out
->push_back(data
[i
]);
40 out
->append(StringPrintf("[%02X]", static_cast<unsigned char>(data
[i
])));
42 if (data
.size() > kMaxBytesToLog
) {
44 StringPrintf(" and %u more bytes",
45 static_cast<unsigned>(data
.size() - kMaxBytesToLog
)));
50 bool ReadValue(const Message
* m
, PickleIterator
* iter
, Value
** value
,
53 void WriteValue(Message
* m
, const Value
* value
, int recursion
) {
55 if (recursion
> kMaxRecursionDepth
) {
56 LOG(WARNING
) << "Max recursion depth hit in WriteValue.";
60 m
->WriteInt(value
->GetType());
62 switch (value
->GetType()) {
63 case Value::TYPE_NULL
:
65 case Value::TYPE_BOOLEAN
: {
67 result
= value
->GetAsBoolean(&val
);
72 case Value::TYPE_INTEGER
: {
74 result
= value
->GetAsInteger(&val
);
79 case Value::TYPE_DOUBLE
: {
81 result
= value
->GetAsDouble(&val
);
86 case Value::TYPE_STRING
: {
88 result
= value
->GetAsString(&val
);
93 case Value::TYPE_BINARY
: {
94 const base::BinaryValue
* binary
=
95 static_cast<const base::BinaryValue
*>(value
);
96 m
->WriteData(binary
->GetBuffer(), static_cast<int>(binary
->GetSize()));
99 case Value::TYPE_DICTIONARY
: {
100 const DictionaryValue
* dict
= static_cast<const DictionaryValue
*>(value
);
102 WriteParam(m
, static_cast<int>(dict
->size()));
104 for (DictionaryValue::key_iterator it
= dict
->begin_keys();
105 it
!= dict
->end_keys(); ++it
) {
107 if (dict
->GetWithoutPathExpansion(*it
, &subval
)) {
109 WriteValue(m
, subval
, recursion
+ 1);
111 NOTREACHED() << "DictionaryValue iterators are filthy liars.";
116 case Value::TYPE_LIST
: {
117 const ListValue
* list
= static_cast<const ListValue
*>(value
);
118 WriteParam(m
, static_cast<int>(list
->GetSize()));
119 for (size_t i
= 0; i
< list
->GetSize(); ++i
) {
121 if (list
->Get(i
, &subval
)) {
122 WriteValue(m
, subval
, recursion
+ 1);
124 NOTREACHED() << "ListValue::GetSize is a filthy liar.";
132 // Helper for ReadValue that reads a DictionaryValue into a pre-allocated
134 bool ReadDictionaryValue(const Message
* m
, PickleIterator
* iter
,
135 DictionaryValue
* value
, int recursion
) {
137 if (!ReadParam(m
, iter
, &size
))
140 for (int i
= 0; i
< size
; ++i
) {
143 if (!ReadParam(m
, iter
, &key
) ||
144 !ReadValue(m
, iter
, &subval
, recursion
+ 1))
146 value
->SetWithoutPathExpansion(key
, subval
);
152 // Helper for ReadValue that reads a ReadListValue into a pre-allocated
154 bool ReadListValue(const Message
* m
, PickleIterator
* iter
,
155 ListValue
* value
, int recursion
) {
157 if (!ReadParam(m
, iter
, &size
))
160 for (int i
= 0; i
< size
; ++i
) {
162 if (!ReadValue(m
, iter
, &subval
, recursion
+ 1))
164 value
->Set(i
, subval
);
170 bool ReadValue(const Message
* m
, PickleIterator
* iter
, Value
** value
,
172 if (recursion
> kMaxRecursionDepth
) {
173 LOG(WARNING
) << "Max recursion depth hit in ReadValue.";
178 if (!ReadParam(m
, iter
, &type
))
182 case Value::TYPE_NULL
:
183 *value
= Value::CreateNullValue();
185 case Value::TYPE_BOOLEAN
: {
187 if (!ReadParam(m
, iter
, &val
))
189 *value
= Value::CreateBooleanValue(val
);
192 case Value::TYPE_INTEGER
: {
194 if (!ReadParam(m
, iter
, &val
))
196 *value
= Value::CreateIntegerValue(val
);
199 case Value::TYPE_DOUBLE
: {
201 if (!ReadParam(m
, iter
, &val
))
203 *value
= Value::CreateDoubleValue(val
);
206 case Value::TYPE_STRING
: {
208 if (!ReadParam(m
, iter
, &val
))
210 *value
= Value::CreateStringValue(val
);
213 case Value::TYPE_BINARY
: {
216 if (!m
->ReadData(iter
, &data
, &length
))
218 *value
= base::BinaryValue::CreateWithCopiedBuffer(data
, length
);
221 case Value::TYPE_DICTIONARY
: {
222 scoped_ptr
<DictionaryValue
> val(new DictionaryValue());
223 if (!ReadDictionaryValue(m
, iter
, val
.get(), recursion
))
225 *value
= val
.release();
228 case Value::TYPE_LIST
: {
229 scoped_ptr
<ListValue
> val(new ListValue());
230 if (!ReadListValue(m
, iter
, val
.get(), recursion
))
232 *value
= val
.release();
244 // -----------------------------------------------------------------------------
254 LogData::~LogData() {
257 MessageIterator::MessageIterator(const Message
& m
) : iter_(m
) {
260 int MessageIterator::NextInt() const {
262 if (!iter_
.ReadInt(&val
))
267 const std::string
MessageIterator::NextString() const {
269 if (!iter_
.ReadString(&val
))
274 void ParamTraits
<bool>::Log(const param_type
& p
, std::string
* l
) {
275 l
->append(p
? "true" : "false");
278 void ParamTraits
<int>::Log(const param_type
& p
, std::string
* l
) {
279 l
->append(base::IntToString(p
));
282 void ParamTraits
<unsigned int>::Log(const param_type
& p
, std::string
* l
) {
283 l
->append(base::UintToString(p
));
286 void ParamTraits
<long>::Log(const param_type
& p
, std::string
* l
) {
287 l
->append(base::Int64ToString(static_cast<int64
>(p
)));
290 void ParamTraits
<unsigned long>::Log(const param_type
& p
, std::string
* l
) {
291 l
->append(base::Uint64ToString(static_cast<uint64
>(p
)));
294 void ParamTraits
<long long>::Log(const param_type
& p
, std::string
* l
) {
295 l
->append(base::Int64ToString(static_cast<int64
>(p
)));
298 void ParamTraits
<unsigned long long>::Log(const param_type
& p
, std::string
* l
) {
299 l
->append(base::Uint64ToString(p
));
302 void ParamTraits
<unsigned short>::Write(Message
* m
, const param_type
& p
) {
303 m
->WriteBytes(&p
, sizeof(param_type
));
306 bool ParamTraits
<unsigned short>::Read(const Message
* m
, PickleIterator
* iter
,
309 if (!m
->ReadBytes(iter
, &data
, sizeof(param_type
)))
311 memcpy(r
, data
, sizeof(param_type
));
315 void ParamTraits
<unsigned short>::Log(const param_type
& p
, std::string
* l
) {
316 l
->append(base::UintToString(p
));
319 void ParamTraits
<float>::Write(Message
* m
, const param_type
& p
) {
320 m
->WriteData(reinterpret_cast<const char*>(&p
), sizeof(param_type
));
323 bool ParamTraits
<float>::Read(const Message
* m
, PickleIterator
* iter
,
327 if (!m
->ReadData(iter
, &data
, &data_size
) ||
328 data_size
!= sizeof(param_type
)) {
332 memcpy(r
, data
, sizeof(param_type
));
336 void ParamTraits
<float>::Log(const param_type
& p
, std::string
* l
) {
337 l
->append(StringPrintf("%e", p
));
340 void ParamTraits
<double>::Write(Message
* m
, const param_type
& p
) {
341 m
->WriteData(reinterpret_cast<const char*>(&p
), sizeof(param_type
));
344 bool ParamTraits
<double>::Read(const Message
* m
, PickleIterator
* iter
,
348 if (!m
->ReadData(iter
, &data
, &data_size
) ||
349 data_size
!= sizeof(param_type
)) {
353 memcpy(r
, data
, sizeof(param_type
));
357 void ParamTraits
<double>::Log(const param_type
& p
, std::string
* l
) {
358 l
->append(StringPrintf("%e", p
));
362 void ParamTraits
<std::string
>::Log(const param_type
& p
, std::string
* l
) {
366 void ParamTraits
<std::wstring
>::Log(const param_type
& p
, std::string
* l
) {
367 l
->append(WideToUTF8(p
));
370 #if !defined(WCHAR_T_IS_UTF16)
371 void ParamTraits
<string16
>::Log(const param_type
& p
, std::string
* l
) {
372 l
->append(UTF16ToUTF8(p
));
376 void ParamTraits
<std::vector
<char> >::Write(Message
* m
, const param_type
& p
) {
378 m
->WriteData(NULL
, 0);
380 m
->WriteData(&p
.front(), static_cast<int>(p
.size()));
384 bool ParamTraits
<std::vector
<char> >::Read(const Message
* m
,
385 PickleIterator
* iter
,
389 if (!m
->ReadData(iter
, &data
, &data_size
) || data_size
< 0)
391 r
->resize(data_size
);
393 memcpy(&r
->front(), data
, data_size
);
397 void ParamTraits
<std::vector
<char> >::Log(const param_type
& p
, std::string
* l
) {
401 void ParamTraits
<std::vector
<unsigned char> >::Write(Message
* m
,
402 const param_type
& p
) {
404 m
->WriteData(NULL
, 0);
406 m
->WriteData(reinterpret_cast<const char*>(&p
.front()),
407 static_cast<int>(p
.size()));
411 bool ParamTraits
<std::vector
<unsigned char> >::Read(const Message
* m
,
412 PickleIterator
* iter
,
416 if (!m
->ReadData(iter
, &data
, &data_size
) || data_size
< 0)
418 r
->resize(data_size
);
420 memcpy(&r
->front(), data
, data_size
);
424 void ParamTraits
<std::vector
<unsigned char> >::Log(const param_type
& p
,
429 void ParamTraits
<std::vector
<bool> >::Write(Message
* m
, const param_type
& p
) {
430 WriteParam(m
, static_cast<int>(p
.size()));
431 for (size_t i
= 0; i
< p
.size(); i
++)
435 bool ParamTraits
<std::vector
<bool> >::Read(const Message
* m
,
436 PickleIterator
* iter
,
439 // ReadLength() checks for < 0 itself.
440 if (!m
->ReadLength(iter
, &size
))
443 for (int i
= 0; i
< size
; i
++) {
445 if (!ReadParam(m
, iter
, &value
))
452 void ParamTraits
<std::vector
<bool> >::Log(const param_type
& p
, std::string
* l
) {
453 for (size_t i
= 0; i
< p
.size(); ++i
) {
460 void ParamTraits
<DictionaryValue
>::Write(Message
* m
, const param_type
& p
) {
461 WriteValue(m
, &p
, 0);
464 bool ParamTraits
<DictionaryValue
>::Read(
465 const Message
* m
, PickleIterator
* iter
, param_type
* r
) {
467 if (!ReadParam(m
, iter
, &type
) || type
!= Value::TYPE_DICTIONARY
)
470 return ReadDictionaryValue(m
, iter
, r
, 0);
473 void ParamTraits
<DictionaryValue
>::Log(const param_type
& p
, std::string
* l
) {
475 base::JSONWriter::Write(&p
, &json
);
479 #if defined(OS_POSIX)
480 void ParamTraits
<base::FileDescriptor
>::Write(Message
* m
, const param_type
& p
) {
481 const bool valid
= p
.fd
>= 0;
482 WriteParam(m
, valid
);
485 if (!m
->WriteFileDescriptor(p
))
490 bool ParamTraits
<base::FileDescriptor
>::Read(const Message
* m
,
491 PickleIterator
* iter
,
494 if (!ReadParam(m
, iter
, &valid
))
499 r
->auto_close
= false;
503 return m
->ReadFileDescriptor(iter
, r
);
506 void ParamTraits
<base::FileDescriptor
>::Log(const param_type
& p
,
509 l
->append(StringPrintf("FD(%d auto-close)", p
.fd
));
511 l
->append(StringPrintf("FD(%d)", p
.fd
));
514 #endif // defined(OS_POSIX)
516 void ParamTraits
<FilePath
>::Write(Message
* m
, const param_type
& p
) {
517 ParamTraits
<FilePath::StringType
>::Write(m
, p
.value());
520 bool ParamTraits
<FilePath
>::Read(const Message
* m
,
521 PickleIterator
* iter
,
523 FilePath::StringType value
;
524 if (!ParamTraits
<FilePath::StringType
>::Read(m
, iter
, &value
))
526 *r
= FilePath(value
);
530 void ParamTraits
<FilePath
>::Log(const param_type
& p
, std::string
* l
) {
531 ParamTraits
<FilePath::StringType
>::Log(p
.value(), l
);
534 void ParamTraits
<ListValue
>::Write(Message
* m
, const param_type
& p
) {
535 WriteValue(m
, &p
, 0);
538 bool ParamTraits
<ListValue
>::Read(
539 const Message
* m
, PickleIterator
* iter
, param_type
* r
) {
541 if (!ReadParam(m
, iter
, &type
) || type
!= Value::TYPE_LIST
)
544 return ReadListValue(m
, iter
, r
, 0);
547 void ParamTraits
<ListValue
>::Log(const param_type
& p
, std::string
* l
) {
549 base::JSONWriter::Write(&p
, &json
);
553 void ParamTraits
<NullableString16
>::Write(Message
* m
, const param_type
& p
) {
554 WriteParam(m
, p
.string());
555 WriteParam(m
, p
.is_null());
558 bool ParamTraits
<NullableString16
>::Read(const Message
* m
, PickleIterator
* iter
,
561 if (!ReadParam(m
, iter
, &string
))
564 if (!ReadParam(m
, iter
, &is_null
))
566 *r
= NullableString16(string
, is_null
);
570 void ParamTraits
<NullableString16
>::Log(const param_type
& p
, std::string
* l
) {
572 LogParam(p
.string(), l
);
574 LogParam(p
.is_null(), l
);
578 void ParamTraits
<base::PlatformFileInfo
>::Write(Message
* m
,
579 const param_type
& p
) {
580 WriteParam(m
, p
.size
);
581 WriteParam(m
, p
.is_directory
);
582 WriteParam(m
, p
.last_modified
.ToDoubleT());
583 WriteParam(m
, p
.last_accessed
.ToDoubleT());
584 WriteParam(m
, p
.creation_time
.ToDoubleT());
587 bool ParamTraits
<base::PlatformFileInfo
>::Read(const Message
* m
,
588 PickleIterator
* iter
,
590 double last_modified
;
591 double last_accessed
;
592 double creation_time
;
594 ReadParam(m
, iter
, &p
->size
) &&
595 ReadParam(m
, iter
, &p
->is_directory
) &&
596 ReadParam(m
, iter
, &last_modified
) &&
597 ReadParam(m
, iter
, &last_accessed
) &&
598 ReadParam(m
, iter
, &creation_time
);
600 p
->last_modified
= base::Time::FromDoubleT(last_modified
);
601 p
->last_accessed
= base::Time::FromDoubleT(last_accessed
);
602 p
->creation_time
= base::Time::FromDoubleT(creation_time
);
607 void ParamTraits
<base::PlatformFileInfo
>::Log(const param_type
& p
,
612 LogParam(p
.is_directory
, l
);
614 LogParam(p
.last_modified
.ToDoubleT(), l
);
616 LogParam(p
.last_accessed
.ToDoubleT(), l
);
618 LogParam(p
.creation_time
.ToDoubleT(), l
);
622 void ParamTraits
<base::Time
>::Write(Message
* m
, const param_type
& p
) {
623 ParamTraits
<int64
>::Write(m
, p
.ToInternalValue());
626 bool ParamTraits
<base::Time
>::Read(const Message
* m
, PickleIterator
* iter
,
629 if (!ParamTraits
<int64
>::Read(m
, iter
, &value
))
631 *r
= base::Time::FromInternalValue(value
);
635 void ParamTraits
<base::Time
>::Log(const param_type
& p
, std::string
* l
) {
636 ParamTraits
<int64
>::Log(p
.ToInternalValue(), l
);
639 void ParamTraits
<base::TimeDelta
>::Write(Message
* m
, const param_type
& p
) {
640 ParamTraits
<int64
>::Write(m
, p
.ToInternalValue());
643 bool ParamTraits
<base::TimeDelta
>::Read(const Message
* m
,
644 PickleIterator
* iter
,
647 bool ret
= ParamTraits
<int64
>::Read(m
, iter
, &value
);
649 *r
= base::TimeDelta::FromInternalValue(value
);
654 void ParamTraits
<base::TimeDelta
>::Log(const param_type
& p
, std::string
* l
) {
655 ParamTraits
<int64
>::Log(p
.ToInternalValue(), l
);
658 void ParamTraits
<base::TimeTicks
>::Write(Message
* m
, const param_type
& p
) {
659 ParamTraits
<int64
>::Write(m
, p
.ToInternalValue());
662 bool ParamTraits
<base::TimeTicks
>::Read(const Message
* m
,
663 PickleIterator
* iter
,
666 bool ret
= ParamTraits
<int64
>::Read(m
, iter
, &value
);
668 *r
= base::TimeTicks::FromInternalValue(value
);
673 void ParamTraits
<base::TimeTicks
>::Log(const param_type
& p
, std::string
* l
) {
674 ParamTraits
<int64
>::Log(p
.ToInternalValue(), l
);
677 void ParamTraits
<IPC::ChannelHandle
>::Write(Message
* m
, const param_type
& p
) {
679 // On Windows marshalling pipe handle is not supported.
680 DCHECK(p
.pipe
.handle
== NULL
);
681 #endif // defined (OS_WIN)
682 WriteParam(m
, p
.name
);
683 #if defined(OS_POSIX)
684 WriteParam(m
, p
.socket
);
688 bool ParamTraits
<IPC::ChannelHandle
>::Read(const Message
* m
,
689 PickleIterator
* iter
,
691 return ReadParam(m
, iter
, &r
->name
)
692 #if defined(OS_POSIX)
693 && ReadParam(m
, iter
, &r
->socket
)
698 void ParamTraits
<IPC::ChannelHandle
>::Log(const param_type
& p
,
700 l
->append(StringPrintf("ChannelHandle(%s", p
.name
.c_str()));
701 #if defined(OS_POSIX)
703 ParamTraits
<base::FileDescriptor
>::Log(p
.socket
, l
);
708 void ParamTraits
<LogData
>::Write(Message
* m
, const param_type
& p
) {
709 WriteParam(m
, p
.channel
);
710 WriteParam(m
, p
.routing_id
);
711 WriteParam(m
, p
.type
);
712 WriteParam(m
, p
.flags
);
713 WriteParam(m
, p
.sent
);
714 WriteParam(m
, p
.receive
);
715 WriteParam(m
, p
.dispatch
);
716 WriteParam(m
, p
.params
);
719 bool ParamTraits
<LogData
>::Read(const Message
* m
,
720 PickleIterator
* iter
,
723 ReadParam(m
, iter
, &r
->channel
) &&
724 ReadParam(m
, iter
, &r
->routing_id
) &&
725 ReadParam(m
, iter
, &r
->type
) &&
726 ReadParam(m
, iter
, &r
->flags
) &&
727 ReadParam(m
, iter
, &r
->sent
) &&
728 ReadParam(m
, iter
, &r
->receive
) &&
729 ReadParam(m
, iter
, &r
->dispatch
) &&
730 ReadParam(m
, iter
, &r
->params
);
733 void ParamTraits
<LogData
>::Log(const param_type
& p
, std::string
* l
) {
734 // Doesn't make sense to implement this!
737 void ParamTraits
<Message
>::Write(Message
* m
, const Message
& p
) {
738 #if defined(OS_POSIX)
739 // We don't serialize the file descriptors in the nested message, so there
740 // better not be any.
741 DCHECK(!p
.HasFileDescriptors());
744 // Don't just write out the message. This is used to send messages between
745 // NaCl (Posix environment) and the browser (could be on Windows). The message
746 // header formats differ between these systems (so does handle sharing, but
747 // we already asserted we don't have any handles). So just write out the
748 // parts of the header we use.
750 // Be careful also to use only explicitly-sized types. The NaCl environment
751 // could be 64-bit and the host browser could be 32-bits. The nested message
752 // may or may not be safe to send between 32-bit and 64-bit systems, but we
753 // leave that up to the code sending the message to ensure.
754 m
->WriteUInt32(static_cast<uint32
>(p
.routing_id()));
755 m
->WriteUInt32(p
.type());
756 m
->WriteUInt32(p
.flags());
757 m
->WriteData(p
.payload(), static_cast<uint32
>(p
.payload_size()));
760 bool ParamTraits
<Message
>::Read(const Message
* m
, PickleIterator
* iter
,
762 uint32 routing_id
, type
, flags
;
763 if (!m
->ReadUInt32(iter
, &routing_id
) ||
764 !m
->ReadUInt32(iter
, &type
) ||
765 !m
->ReadUInt32(iter
, &flags
))
770 if (!m
->ReadData(iter
, &payload
, &payload_size
))
773 r
->SetHeaderValues(static_cast<int32
>(routing_id
), type
, flags
);
774 return r
->WriteBytes(payload
, payload_size
);
777 void ParamTraits
<Message
>::Log(const Message
& p
, std::string
* l
) {
778 l
->append("<IPC::Message>");
782 // Note that HWNDs/HANDLE/HCURSOR/HACCEL etc are always 32 bits, even on 64
784 void ParamTraits
<HANDLE
>::Write(Message
* m
, const param_type
& p
) {
785 m
->WriteUInt32(reinterpret_cast<uint32
>(p
));
788 bool ParamTraits
<HANDLE
>::Read(const Message
* m
, PickleIterator
* iter
,
791 if (!m
->ReadUInt32(iter
, &temp
))
793 *r
= reinterpret_cast<HANDLE
>(temp
);
797 void ParamTraits
<HANDLE
>::Log(const param_type
& p
, std::string
* l
) {
798 l
->append(StringPrintf("0x%X", p
));
801 void ParamTraits
<LOGFONT
>::Write(Message
* m
, const param_type
& p
) {
802 m
->WriteData(reinterpret_cast<const char*>(&p
), sizeof(LOGFONT
));
805 bool ParamTraits
<LOGFONT
>::Read(const Message
* m
, PickleIterator
* iter
,
809 bool result
= m
->ReadData(iter
, &data
, &data_size
);
810 if (result
&& data_size
== sizeof(LOGFONT
)) {
811 memcpy(r
, data
, sizeof(LOGFONT
));
820 void ParamTraits
<LOGFONT
>::Log(const param_type
& p
, std::string
* l
) {
821 l
->append(StringPrintf("<LOGFONT>"));
824 void ParamTraits
<MSG
>::Write(Message
* m
, const param_type
& p
) {
825 m
->WriteData(reinterpret_cast<const char*>(&p
), sizeof(MSG
));
828 bool ParamTraits
<MSG
>::Read(const Message
* m
, PickleIterator
* iter
,
832 bool result
= m
->ReadData(iter
, &data
, &data_size
);
833 if (result
&& data_size
== sizeof(MSG
)) {
834 memcpy(r
, data
, sizeof(MSG
));
843 void ParamTraits
<MSG
>::Log(const param_type
& p
, std::string
* l
) {