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