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
10 * http://www.apache.org/licenses/LICENSE-2.0
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
21 * Defines the basic interface for a Thrift protocol and associated exception
24 * Most parts of the protocol API are typically not used in client code, as
25 * the actual serialization code is generated by thrift.codegen.* – the only
26 * interesting thing usually is that there are protocols which can be created
27 * from transports and passed around.
29 module thrift.protocol.base;
32 import thrift.transport.base;
35 * The field types Thrift protocols support.
38 STOP = 0, /// Used to mark the end of a sequence of fields.
54 * Types of Thrift RPC messages.
56 enum TMessageType : byte {
57 CALL = 1, /// Call of a normal, two-way RPC method.
58 REPLY = 2, /// Reply to a normal method call.
59 EXCEPTION = 3, /// Reply to a method call if target raised a TApplicationException.
60 ONEWAY = 4 /// Call of a one-way RPC method which is not followed by a reply.
64 * Descriptions of Thrift entities.
104 * Interface for a Thrift protocol implementation. Essentially, it defines
105 * a way of reading and writing all the base types, plus a mechanism for
106 * writing out structs with indexed fields.
108 * TProtocol objects should not be shared across multiple encoding contexts,
109 * as they may need to maintain internal state in some protocols (e.g. JSON).
110 * Note that is is acceptable for the TProtocol module to do its own internal
111 * buffered reads/writes to the underlying TTransport where appropriate (i.e.
112 * when parsing an input XML stream, reading could be batched rather than
113 * looking ahead character by character for a close tag).
115 interface TProtocol {
116 /// The underlying transport used by the protocol.
117 TTransport transport() @property;
123 void writeBool(bool b); ///
124 void writeByte(byte b); ///
125 void writeI16(short i16); ///
126 void writeI32(int i32); ///
127 void writeI64(long i64); ///
128 void writeDouble(double dub); ///
129 void writeString(string str); ///
130 void writeBinary(ubyte[] buf); ///
132 void writeMessageBegin(TMessage message); ///
133 void writeMessageEnd(); ///
134 void writeStructBegin(TStruct tstruct); ///
135 void writeStructEnd(); ///
136 void writeFieldBegin(TField field); ///
137 void writeFieldEnd(); ///
138 void writeFieldStop(); ///
139 void writeListBegin(TList list); ///
140 void writeListEnd(); ///
141 void writeMapBegin(TMap map); ///
142 void writeMapEnd(); ///
143 void writeSetBegin(TSet set); ///
144 void writeSetEnd(); ///
155 double readDouble(); ///
156 string readString(); ///
157 ubyte[] readBinary(); ///
159 TMessage readMessageBegin(); ///
160 void readMessageEnd(); ///
161 TStruct readStructBegin(); ///
162 void readStructEnd(); ///
163 TField readFieldBegin(); ///
164 void readFieldEnd(); ///
165 TList readListBegin(); ///
166 void readListEnd(); ///
167 TMap readMapBegin(); ///
168 void readMapEnd(); ///
169 TSet readSetBegin(); ///
170 void readSetEnd(); ///
173 * Reset any internal state back to a blank slate, if the protocol is
180 * true if T is a TProtocol.
182 template isTProtocol(T) {
183 enum isTProtocol = is(T : TProtocol);
187 static assert(isTProtocol!TProtocol);
188 static assert(!isTProtocol!void);
192 * Creates a protocol operating on a given transport.
194 interface TProtocolFactory {
196 TProtocol getProtocol(TTransport trans);
200 * A protocol-level exception.
202 class TProtocolException : TException {
203 /// The possible exception types.
215 this(Type type, string file = __FILE__, size_t line = __LINE__, Throwable next = null) {
216 static string msgForType(Type type) {
218 case Type.UNKNOWN: return "Unknown protocol exception";
219 case Type.INVALID_DATA: return "Invalid data";
220 case Type.NEGATIVE_SIZE: return "Negative size";
221 case Type.SIZE_LIMIT: return "Exceeded size limit";
222 case Type.BAD_VERSION: return "Invalid version";
223 case Type.NOT_IMPLEMENTED: return "Not implemented";
224 case Type.DEPTH_LIMIT: return "Exceeded size limit";
225 default: return "(Invalid exception type)";
228 this(msgForType(type), type, file, line, next);
232 this(string msg, string file = __FILE__, size_t line = __LINE__,
233 Throwable next = null)
235 this(msg, Type.UNKNOWN, file, line, next);
239 this(string msg, Type type, string file = __FILE__, size_t line = __LINE__,
240 Throwable next = null)
242 super(msg, file, line, next);
247 Type type() const @property {
256 * Skips a field of the given type on the protocol.
258 * The main purpose of skip() is to allow treating struct and container types,
259 * (where multiple primitive types have to be skipped) the same as scalar types
262 void skip(Protocol)(Protocol prot, TType type) if (is(Protocol : TProtocol)) {
293 prot.readStructBegin();
295 auto f = prot.readFieldBegin();
296 if (f.type == TType.STOP) break;
300 prot.readStructEnd();
304 auto l = prot.readListBegin();
305 foreach (i; 0 .. l.size) {
306 skip(prot, l.elemType);
312 auto m = prot.readMapBegin();
313 foreach (i; 0 .. m.size) {
314 skip(prot, m.keyType);
315 skip(prot, m.valueType);
321 auto s = prot.readSetBegin();
322 foreach (i; 0 .. s.size) {
323 skip(prot, s.elemType);
329 throw new TProtocolException(TProtocolException.Type.INVALID_DATA);
334 * Application-level exception.
336 * It is thrown if an RPC call went wrong on the application layer, e.g. if
337 * the receiver does not know the method name requested or a method invoked by
338 * the service processor throws an exception not part of the Thrift API.
340 class TApplicationException : TException {
341 /// The possible exception types.
344 UNKNOWN_METHOD = 1, ///
345 INVALID_MESSAGE_TYPE = 2, ///
346 WRONG_METHOD_NAME = 3, ///
347 BAD_SEQUENCE_ID = 4, ///
348 MISSING_RESULT = 5, ///
349 INTERNAL_ERROR = 6, ///
350 PROTOCOL_ERROR = 7, ///
351 INVALID_TRANSFORM = 8, ///
352 INVALID_PROTOCOL = 9, ///
353 UNSUPPORTED_CLIENT_TYPE = 10 ///
357 this(Type type, string file = __FILE__, size_t line = __LINE__, Throwable next = null) {
358 static string msgForType(Type type) {
360 case Type.UNKNOWN: return "Unknown application exception";
361 case Type.UNKNOWN_METHOD: return "Unknown method";
362 case Type.INVALID_MESSAGE_TYPE: return "Invalid message type";
363 case Type.WRONG_METHOD_NAME: return "Wrong method name";
364 case Type.BAD_SEQUENCE_ID: return "Bad sequence identifier";
365 case Type.MISSING_RESULT: return "Missing result";
366 case Type.INTERNAL_ERROR: return "Internal error";
367 case Type.PROTOCOL_ERROR: return "Protocol error";
368 case Type.INVALID_TRANSFORM: return "Invalid transform";
369 case Type.INVALID_PROTOCOL: return "Invalid protocol";
370 case Type.UNSUPPORTED_CLIENT_TYPE: return "Unsupported client type";
371 default: return "(Invalid exception type)";
374 this(msgForType(type), type, file, line, next);
378 this(string msg, string file = __FILE__, size_t line = __LINE__,
379 Throwable next = null)
381 this(msg, Type.UNKNOWN, file, line, next);
385 this(string msg, Type type, string file = __FILE__, size_t line = __LINE__,
386 Throwable next = null)
388 super(msg, file, line, next);
393 Type type() @property const {
397 // TODO: Replace hand-written read()/write() with thrift.codegen templates.
400 void read(TProtocol iprot) {
401 iprot.readStructBegin();
403 auto f = iprot.readFieldBegin();
404 if (f.type == TType.STOP) break;
408 if (f.type == TType.STRING) {
409 msg = iprot.readString();
415 if (f.type == TType.I32) {
416 type_ = cast(Type)iprot.readI32();
426 iprot.readStructEnd();
430 void write(TProtocol oprot) const {
431 oprot.writeStructBegin(TStruct("TApplicationException"));
434 oprot.writeFieldBegin(TField("message", TType.STRING, 1));
435 oprot.writeString(msg);
436 oprot.writeFieldEnd();
439 oprot.writeFieldBegin(TField("type", TType.I32, 2));
440 oprot.writeI32(type_);
441 oprot.writeFieldEnd();
443 oprot.writeFieldStop();
444 oprot.writeStructEnd();