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. 4 5 #include "sync/engine/traffic_recorder.h" 6 7 #include "base/json/json_writer.h" 8 #include "base/logging.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "base/values.h" 11 #include "sync/protocol/proto_value_conversions.h" 12 #include "sync/protocol/sync.pb.h" 13 #include "sync/sessions/sync_session.h" 14 #include "sync/util/time.h" 15 16 namespace syncer { 17 18 // Return current time. 19 base::Time TrafficRecorder::GetTime() { 20 return base::Time::Now(); 21 } 22 23 TrafficRecorder::TrafficRecord::TrafficRecord(const std::string& message, 24 TrafficMessageType message_type, 25 bool truncated, 26 base::Time time) : 27 message(message), 28 message_type(message_type), 29 truncated(truncated), 30 timestamp(time) { 31 } 32 33 TrafficRecorder::TrafficRecord::TrafficRecord() 34 : message_type(UNKNOWN_MESSAGE_TYPE), 35 truncated(false) { 36 } 37 38 TrafficRecorder::TrafficRecord::~TrafficRecord() { 39 } 40 41 TrafficRecorder::TrafficRecorder(unsigned int max_messages, 42 unsigned int max_message_size) 43 : max_messages_(max_messages), 44 max_message_size_(max_message_size) { 45 } 46 47 TrafficRecorder::~TrafficRecorder() { 48 } 49 50 namespace { 51 const char* GetMessageTypeString(TrafficRecorder::TrafficMessageType type) { 52 switch(type) { 53 case TrafficRecorder::CLIENT_TO_SERVER_MESSAGE: 54 return "Request"; 55 case TrafficRecorder::CLIENT_TO_SERVER_RESPONSE: 56 return "Response"; 57 default: 58 NOTREACHED(); 59 return ""; 60 } 61 } 62 } 63 64 base::DictionaryValue* TrafficRecorder::TrafficRecord::ToValue() const { 65 scoped_ptr<base::DictionaryValue> value; 66 if (truncated) { 67 value.reset(new base::DictionaryValue()); 68 value->SetString("message_type", 69 GetMessageTypeString(message_type)); 70 value->SetBoolean("truncated", true); 71 } else if (message_type == TrafficRecorder::CLIENT_TO_SERVER_MESSAGE) { 72 sync_pb::ClientToServerMessage message_proto; 73 if (message_proto.ParseFromString(message)) 74 value.reset( 75 ClientToServerMessageToValue(message_proto, 76 false /* include_specifics */)); 77 } else if (message_type == TrafficRecorder::CLIENT_TO_SERVER_RESPONSE) { 78 sync_pb::ClientToServerResponse message_proto; 79 if (message_proto.ParseFromString(message)) 80 value.reset( 81 ClientToServerResponseToValue(message_proto, 82 false /* include_specifics */)); 83 } else { 84 NOTREACHED(); 85 } 86 87 value->SetString("timestamp", GetTimeDebugString(timestamp)); 88 89 return value.release(); 90 } 91 92 93 base::ListValue* TrafficRecorder::ToValue() const { 94 scoped_ptr<base::ListValue> value(new base::ListValue()); 95 std::deque<TrafficRecord>::const_iterator it; 96 for (it = records_.begin(); it != records_.end(); ++it) { 97 const TrafficRecord& record = *it; 98 value->Append(record.ToValue()); 99 } 100 101 return value.release(); 102 } 103 104 105 void TrafficRecorder::AddTrafficToQueue(TrafficRecord* record) { 106 records_.resize(records_.size() + 1); 107 std::swap(records_.back(), *record); 108 109 // We might have more records than our limit. 110 // Maintain the size invariant by deleting items. 111 while (records_.size() > max_messages_) { 112 records_.pop_front(); 113 } 114 } 115 116 void TrafficRecorder::StoreProtoInQueue( 117 const ::google::protobuf::MessageLite& msg, 118 TrafficMessageType type) { 119 bool truncated = false; 120 std::string message; 121 if (static_cast<unsigned int>(msg.ByteSize()) >= max_message_size_) { 122 // TODO(lipalani): Trim the specifics to fit in size. 123 truncated = true; 124 } else { 125 msg.SerializeToString(&message); 126 } 127 128 TrafficRecord record(message, type, truncated, GetTime()); 129 AddTrafficToQueue(&record); 130 } 131 132 void TrafficRecorder::RecordClientToServerMessage( 133 const sync_pb::ClientToServerMessage& msg) { 134 StoreProtoInQueue(msg, CLIENT_TO_SERVER_MESSAGE); 135 } 136 137 void TrafficRecorder::RecordClientToServerResponse( 138 const sync_pb::ClientToServerResponse& response) { 139 StoreProtoInQueue(response, CLIENT_TO_SERVER_RESPONSE); 140 } 141 142 } // namespace syncer 143 144