1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #ifndef _THRIFT_PROTOCOL_TDEBUGPROTOCOL_H_
21 #define _THRIFT_PROTOCOL_TDEBUGPROTOCOL_H_ 1
22
23 #include <thrift/protocol/TVirtualProtocol.h>
24
25 #include <memory>
26
27 namespace apache {
28 namespace thrift {
29 namespace protocol {
30
31 /*
32
33 !!! EXPERIMENTAL CODE !!!
34
35 This protocol is very much a work in progress.
36 It doesn't handle many cases properly.
37 It throws exceptions in many cases.
38 It probably segfaults in many cases.
39 Bug reports and feature requests are welcome.
40 Complaints are not. :R
41
42 */
43
44 /**
45 * Protocol that prints the payload in a nice human-readable format.
46 * Reading from this protocol is not supported.
47 *
48 */
49 class TDebugProtocol : public TVirtualProtocol<TDebugProtocol> {
50 private:
51 enum write_state_t { UNINIT, STRUCT, LIST, SET, MAP_KEY, MAP_VALUE };
52
53 public:
TDebugProtocol(std::shared_ptr<TTransport> trans)54 TDebugProtocol(std::shared_ptr<TTransport> trans)
55 : TVirtualProtocol<TDebugProtocol>(trans),
56 trans_(trans.get()),
57 string_limit_(DEFAULT_STRING_LIMIT),
58 string_prefix_size_(DEFAULT_STRING_PREFIX_SIZE) {
59 write_state_.push_back(UNINIT);
60 }
61
62 static const int32_t DEFAULT_STRING_LIMIT = 256;
63 static const int32_t DEFAULT_STRING_PREFIX_SIZE = 16;
64
setStringSizeLimit(int32_t string_limit)65 void setStringSizeLimit(int32_t string_limit) { string_limit_ = string_limit; }
66
setStringPrefixSize(int32_t string_prefix_size)67 void setStringPrefixSize(int32_t string_prefix_size) { string_prefix_size_ = string_prefix_size; }
68
69 uint32_t writeMessageBegin(const std::string& name,
70 const TMessageType messageType,
71 const int32_t seqid);
72
73 uint32_t writeMessageEnd();
74
75 uint32_t writeStructBegin(const char* name);
76
77 uint32_t writeStructEnd();
78
79 uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId);
80
81 uint32_t writeFieldEnd();
82
83 uint32_t writeFieldStop();
84
85 uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size);
86
87 uint32_t writeMapEnd();
88
89 uint32_t writeListBegin(const TType elemType, const uint32_t size);
90
91 uint32_t writeListEnd();
92
93 uint32_t writeSetBegin(const TType elemType, const uint32_t size);
94
95 uint32_t writeSetEnd();
96
97 uint32_t writeBool(const bool value);
98
99 uint32_t writeByte(const int8_t byte);
100
101 uint32_t writeI16(const int16_t i16);
102
103 uint32_t writeI32(const int32_t i32);
104
105 uint32_t writeI64(const int64_t i64);
106
107 uint32_t writeDouble(const double dub);
108
109 uint32_t writeString(const std::string& str);
110
111 uint32_t writeBinary(const std::string& str);
112
113 private:
114 void indentUp();
115 void indentDown();
116 uint32_t writePlain(const std::string& str);
117 uint32_t writeIndented(const std::string& str);
118 uint32_t startItem();
119 uint32_t endItem();
120 uint32_t writeItem(const std::string& str);
121
122 static std::string fieldTypeName(TType type);
123
124 TTransport* trans_;
125
126 int32_t string_limit_;
127 int32_t string_prefix_size_;
128
129 std::string indent_str_;
130 static const int indent_inc = 2;
131
132 std::vector<write_state_t> write_state_;
133 std::vector<int> list_idx_;
134 };
135
136 /**
137 * Constructs debug protocol handlers
138 */
139 class TDebugProtocolFactory : public TProtocolFactory {
140 public:
141 TDebugProtocolFactory() = default;
142 ~TDebugProtocolFactory() override = default;
143
getProtocol(std::shared_ptr<TTransport> trans)144 std::shared_ptr<TProtocol> getProtocol(std::shared_ptr<TTransport> trans) override {
145 return std::shared_ptr<TProtocol>(new TDebugProtocol(trans));
146 }
147 };
148 }
149 }
150 } // apache::thrift::protocol
151
152 // TODO(dreiss): Move (part of) ThriftDebugString into a .cpp file and remove this.
153 #include <thrift/transport/TBufferTransports.h>
154
155 namespace apache {
156 namespace thrift {
157
158 template <typename ThriftStruct>
ThriftDebugString(const ThriftStruct & ts)159 std::string ThriftDebugString(const ThriftStruct& ts) {
160 using namespace apache::thrift::transport;
161 using namespace apache::thrift::protocol;
162 auto* buffer = new TMemoryBuffer;
163 std::shared_ptr<TTransport> trans(buffer);
164 TDebugProtocol protocol(trans);
165
166 ts.write(&protocol);
167
168 uint8_t* buf;
169 uint32_t size;
170 buffer->getBuffer(&buf, &size);
171 return std::string((char*)buf, (unsigned int)size);
172 }
173
174 // TODO(dreiss): This is badly broken. Don't use it unless you are me.
175 #if 0
176 template<typename Object>
177 std::string DebugString(const std::vector<Object>& vec) {
178 using namespace apache::thrift::transport;
179 using namespace apache::thrift::protocol;
180 TMemoryBuffer* buffer = new TMemoryBuffer;
181 std::shared_ptr<TTransport> trans(buffer);
182 TDebugProtocol protocol(trans);
183
184 // I am gross!
185 protocol.writeStructBegin("SomeRandomVector");
186
187 // TODO: Fix this with a trait.
188 protocol.writeListBegin((TType)99, vec.size());
189 typename std::vector<Object>::const_iterator it;
190 for (it = vec.begin(); it != vec.end(); ++it) {
191 it->write(&protocol);
192 }
193 protocol.writeListEnd();
194
195 uint8_t* buf;
196 uint32_t size;
197 buffer->getBuffer(&buf, &size);
198 return std::string((char*)buf, (unsigned int)size);
199 }
200 #endif // 0
201 }
202 } // apache::thrift
203
204 #endif // #ifndef _THRIFT_PROTOCOL_TDEBUGPROTOCOL_H_
205