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 package org.apache.thrift.protocol;
21 
22 import java.io.UnsupportedEncodingException;
23 import java.nio.ByteBuffer;
24 
25 import org.apache.thrift.TException;
26 import org.apache.thrift.transport.TTransport;
27 
28 /**
29  * Binary protocol implementation for thrift.
30  *
31  */
32 public class TBinaryProtocol extends TProtocol {
33   private static final TStruct ANONYMOUS_STRUCT = new TStruct();
34   private static final long NO_LENGTH_LIMIT = -1;
35 
36   protected static final int VERSION_MASK = 0xffff0000;
37   protected static final int VERSION_1 = 0x80010000;
38 
39   /**
40    * The maximum number of bytes to read from the transport for
41    * variable-length fields (such as strings or binary) or {@link #NO_LENGTH_LIMIT} for
42    * unlimited.
43    */
44   private final long stringLengthLimit_;
45 
46   /**
47    * The maximum number of elements to read from the network for
48    * containers (maps, sets, lists), or {@link #NO_LENGTH_LIMIT} for unlimited.
49    */
50   private final long containerLengthLimit_;
51 
52   protected boolean strictRead_;
53   protected boolean strictWrite_;
54 
55   private final byte[] inoutTemp = new byte[8];
56 
57   /**
58    * Factory
59    */
60   public static class Factory implements TProtocolFactory {
61     protected long stringLengthLimit_;
62     protected long containerLengthLimit_;
63     protected boolean strictRead_;
64     protected boolean strictWrite_;
65 
Factory()66     public Factory() {
67       this(false, true);
68     }
69 
Factory(boolean strictRead, boolean strictWrite)70     public Factory(boolean strictRead, boolean strictWrite) {
71       this(strictRead, strictWrite, NO_LENGTH_LIMIT, NO_LENGTH_LIMIT);
72     }
73 
Factory(long stringLengthLimit, long containerLengthLimit)74     public Factory(long stringLengthLimit, long containerLengthLimit) {
75       this(false, true, stringLengthLimit, containerLengthLimit);
76     }
77 
Factory(boolean strictRead, boolean strictWrite, long stringLengthLimit, long containerLengthLimit)78     public Factory(boolean strictRead, boolean strictWrite, long stringLengthLimit, long containerLengthLimit) {
79       stringLengthLimit_ = stringLengthLimit;
80       containerLengthLimit_ = containerLengthLimit;
81       strictRead_ = strictRead;
82       strictWrite_ = strictWrite;
83     }
84 
getProtocol(TTransport trans)85     public TProtocol getProtocol(TTransport trans) {
86       return new TBinaryProtocol(trans, stringLengthLimit_, containerLengthLimit_, strictRead_, strictWrite_);
87     }
88   }
89 
90   /**
91    * Constructor
92    */
TBinaryProtocol(TTransport trans)93   public TBinaryProtocol(TTransport trans) {
94     this(trans, false, true);
95   }
96 
TBinaryProtocol(TTransport trans, boolean strictRead, boolean strictWrite)97   public TBinaryProtocol(TTransport trans, boolean strictRead, boolean strictWrite) {
98     this(trans, NO_LENGTH_LIMIT, NO_LENGTH_LIMIT, strictRead, strictWrite);
99   }
100 
TBinaryProtocol(TTransport trans, long stringLengthLimit, long containerLengthLimit)101   public TBinaryProtocol(TTransport trans, long stringLengthLimit, long containerLengthLimit) {
102     this(trans, stringLengthLimit, containerLengthLimit, false, true);
103   }
104 
TBinaryProtocol(TTransport trans, long stringLengthLimit, long containerLengthLimit, boolean strictRead, boolean strictWrite)105   public TBinaryProtocol(TTransport trans, long stringLengthLimit, long containerLengthLimit, boolean strictRead, boolean strictWrite) {
106     super(trans);
107     stringLengthLimit_ = stringLengthLimit;
108     containerLengthLimit_ = containerLengthLimit;
109     strictRead_ = strictRead;
110     strictWrite_ = strictWrite;
111   }
112 
writeMessageBegin(TMessage message)113   public void writeMessageBegin(TMessage message) throws TException {
114     if (strictWrite_) {
115       int version = VERSION_1 | message.type;
116       writeI32(version);
117       writeString(message.name);
118       writeI32(message.seqid);
119     } else {
120       writeString(message.name);
121       writeByte(message.type);
122       writeI32(message.seqid);
123     }
124   }
125 
writeMessageEnd()126   public void writeMessageEnd() {}
127 
writeStructBegin(TStruct struct)128   public void writeStructBegin(TStruct struct) {}
129 
writeStructEnd()130   public void writeStructEnd() {}
131 
writeFieldBegin(TField field)132   public void writeFieldBegin(TField field) throws TException {
133     writeByte(field.type);
134     writeI16(field.id);
135   }
136 
writeFieldEnd()137   public void writeFieldEnd() {}
138 
writeFieldStop()139   public void writeFieldStop() throws TException {
140     writeByte(TType.STOP);
141   }
142 
writeMapBegin(TMap map)143   public void writeMapBegin(TMap map) throws TException {
144     writeByte(map.keyType);
145     writeByte(map.valueType);
146     writeI32(map.size);
147   }
148 
writeMapEnd()149   public void writeMapEnd() {}
150 
writeListBegin(TList list)151   public void writeListBegin(TList list) throws TException {
152     writeByte(list.elemType);
153     writeI32(list.size);
154   }
155 
writeListEnd()156   public void writeListEnd() {}
157 
writeSetBegin(TSet set)158   public void writeSetBegin(TSet set) throws TException {
159     writeByte(set.elemType);
160     writeI32(set.size);
161   }
162 
writeSetEnd()163   public void writeSetEnd() {}
164 
writeBool(boolean b)165   public void writeBool(boolean b) throws TException {
166     writeByte(b ? (byte)1 : (byte)0);
167   }
168 
writeByte(byte b)169   public void writeByte(byte b) throws TException {
170     inoutTemp[0] = b;
171     trans_.write(inoutTemp, 0, 1);
172   }
173 
writeI16(short i16)174   public void writeI16(short i16) throws TException {
175     inoutTemp[0] = (byte)(0xff & (i16 >> 8));
176     inoutTemp[1] = (byte)(0xff & (i16));
177     trans_.write(inoutTemp, 0, 2);
178   }
179 
writeI32(int i32)180   public void writeI32(int i32) throws TException {
181     inoutTemp[0] = (byte)(0xff & (i32 >> 24));
182     inoutTemp[1] = (byte)(0xff & (i32 >> 16));
183     inoutTemp[2] = (byte)(0xff & (i32 >> 8));
184     inoutTemp[3] = (byte)(0xff & (i32));
185     trans_.write(inoutTemp, 0, 4);
186   }
187 
writeI64(long i64)188   public void writeI64(long i64) throws TException {
189     inoutTemp[0] = (byte)(0xff & (i64 >> 56));
190     inoutTemp[1] = (byte)(0xff & (i64 >> 48));
191     inoutTemp[2] = (byte)(0xff & (i64 >> 40));
192     inoutTemp[3] = (byte)(0xff & (i64 >> 32));
193     inoutTemp[4] = (byte)(0xff & (i64 >> 24));
194     inoutTemp[5] = (byte)(0xff & (i64 >> 16));
195     inoutTemp[6] = (byte)(0xff & (i64 >> 8));
196     inoutTemp[7] = (byte)(0xff & (i64));
197     trans_.write(inoutTemp, 0, 8);
198   }
199 
writeDouble(double dub)200   public void writeDouble(double dub) throws TException {
201     writeI64(Double.doubleToLongBits(dub));
202   }
203 
writeString(String str)204   public void writeString(String str) throws TException {
205     try {
206       byte[] dat = str.getBytes("UTF-8");
207       writeI32(dat.length);
208       trans_.write(dat, 0, dat.length);
209     } catch (UnsupportedEncodingException uex) {
210       throw new TException("JVM DOES NOT SUPPORT UTF-8");
211     }
212   }
213 
writeBinary(ByteBuffer bin)214   public void writeBinary(ByteBuffer bin) throws TException {
215     int length = bin.limit() - bin.position();
216     writeI32(length);
217     trans_.write(bin.array(), bin.position() + bin.arrayOffset(), length);
218   }
219 
220   /**
221    * Reading methods.
222    */
223 
readMessageBegin()224   public TMessage readMessageBegin() throws TException {
225     int size = readI32();
226     if (size < 0) {
227       int version = size & VERSION_MASK;
228       if (version != VERSION_1) {
229         throw new TProtocolException(TProtocolException.BAD_VERSION, "Bad version in readMessageBegin");
230       }
231       return new TMessage(readString(), (byte)(size & 0x000000ff), readI32());
232     } else {
233       if (strictRead_) {
234         throw new TProtocolException(TProtocolException.BAD_VERSION, "Missing version in readMessageBegin, old client?");
235       }
236       return new TMessage(readStringBody(size), readByte(), readI32());
237     }
238   }
239 
readMessageEnd()240   public void readMessageEnd() {}
241 
readStructBegin()242   public TStruct readStructBegin() {
243     return ANONYMOUS_STRUCT;
244   }
245 
readStructEnd()246   public void readStructEnd() {}
247 
readFieldBegin()248   public TField readFieldBegin() throws TException {
249     byte type = readByte();
250     short id = type == TType.STOP ? 0 : readI16();
251     return new TField("", type, id);
252   }
253 
readFieldEnd()254   public void readFieldEnd() {}
255 
readMapBegin()256   public TMap readMapBegin() throws TException {
257     TMap map = new TMap(readByte(), readByte(), readI32());
258     checkContainerReadLength(map.size);
259     return map;
260   }
261 
readMapEnd()262   public void readMapEnd() {}
263 
readListBegin()264   public TList readListBegin() throws TException {
265     TList list = new TList(readByte(), readI32());
266     checkContainerReadLength(list.size);
267     return list;
268   }
269 
readListEnd()270   public void readListEnd() {}
271 
readSetBegin()272   public TSet readSetBegin() throws TException {
273     TSet set = new TSet(readByte(), readI32());
274     checkContainerReadLength(set.size);
275     return set;
276   }
277 
readSetEnd()278   public void readSetEnd() {}
279 
readBool()280   public boolean readBool() throws TException {
281     return (readByte() == 1);
282   }
283 
readByte()284   public byte readByte() throws TException {
285     if (trans_.getBytesRemainingInBuffer() >= 1) {
286       byte b = trans_.getBuffer()[trans_.getBufferPosition()];
287       trans_.consumeBuffer(1);
288       return b;
289     }
290     readAll(inoutTemp, 0, 1);
291     return inoutTemp[0];
292   }
293 
readI16()294   public short readI16() throws TException {
295     byte[] buf = inoutTemp;
296     int off = 0;
297 
298     if (trans_.getBytesRemainingInBuffer() >= 2) {
299       buf = trans_.getBuffer();
300       off = trans_.getBufferPosition();
301       trans_.consumeBuffer(2);
302     } else {
303       readAll(inoutTemp, 0, 2);
304     }
305 
306     return
307       (short)
308       (((buf[off] & 0xff) << 8) |
309        ((buf[off+1] & 0xff)));
310   }
311 
readI32()312   public int readI32() throws TException {
313     byte[] buf = inoutTemp;
314     int off = 0;
315 
316     if (trans_.getBytesRemainingInBuffer() >= 4) {
317       buf = trans_.getBuffer();
318       off = trans_.getBufferPosition();
319       trans_.consumeBuffer(4);
320     } else {
321       readAll(inoutTemp, 0, 4);
322     }
323     return
324       ((buf[off] & 0xff) << 24) |
325       ((buf[off+1] & 0xff) << 16) |
326       ((buf[off+2] & 0xff) <<  8) |
327       ((buf[off+3] & 0xff));
328   }
329 
readI64()330   public long readI64() throws TException {
331     byte[] buf = inoutTemp;
332     int off = 0;
333 
334     if (trans_.getBytesRemainingInBuffer() >= 8) {
335       buf = trans_.getBuffer();
336       off = trans_.getBufferPosition();
337       trans_.consumeBuffer(8);
338     } else {
339       readAll(inoutTemp, 0, 8);
340     }
341 
342     return
343       ((long)(buf[off]   & 0xff) << 56) |
344       ((long)(buf[off+1] & 0xff) << 48) |
345       ((long)(buf[off+2] & 0xff) << 40) |
346       ((long)(buf[off+3] & 0xff) << 32) |
347       ((long)(buf[off+4] & 0xff) << 24) |
348       ((long)(buf[off+5] & 0xff) << 16) |
349       ((long)(buf[off+6] & 0xff) <<  8) |
350       ((long)(buf[off+7] & 0xff));
351   }
352 
readDouble()353   public double readDouble() throws TException {
354     return Double.longBitsToDouble(readI64());
355   }
356 
readString()357   public String readString() throws TException {
358     int size = readI32();
359 
360     checkStringReadLength(size);
361 
362     if (trans_.getBytesRemainingInBuffer() >= size) {
363       try {
364         String s = new String(trans_.getBuffer(), trans_.getBufferPosition(), size, "UTF-8");
365         trans_.consumeBuffer(size);
366         return s;
367       } catch (UnsupportedEncodingException e) {
368         throw new TException("JVM DOES NOT SUPPORT UTF-8");
369       }
370     }
371 
372     return readStringBody(size);
373   }
374 
readStringBody(int size)375   public String readStringBody(int size) throws TException {
376     checkStringReadLength(size);
377     try {
378       byte[] buf = new byte[size];
379       trans_.readAll(buf, 0, size);
380       return new String(buf, "UTF-8");
381     } catch (UnsupportedEncodingException uex) {
382       throw new TException("JVM DOES NOT SUPPORT UTF-8");
383     }
384   }
385 
readBinary()386   public ByteBuffer readBinary() throws TException {
387     int size = readI32();
388 
389     checkStringReadLength(size);
390 
391     if (trans_.getBytesRemainingInBuffer() >= size) {
392       ByteBuffer bb = ByteBuffer.wrap(trans_.getBuffer(), trans_.getBufferPosition(), size);
393       trans_.consumeBuffer(size);
394       return bb;
395     }
396 
397     byte[] buf = new byte[size];
398     trans_.readAll(buf, 0, size);
399     return ByteBuffer.wrap(buf);
400   }
401 
checkStringReadLength(int length)402   private void checkStringReadLength(int length) throws TProtocolException {
403     if (length < 0) {
404       throw new TProtocolException(TProtocolException.NEGATIVE_SIZE,
405                                    "Negative length: " + length);
406     }
407     if (stringLengthLimit_ != NO_LENGTH_LIMIT && length > stringLengthLimit_) {
408       throw new TProtocolException(TProtocolException.SIZE_LIMIT,
409                                    "Length exceeded max allowed: " + length);
410     }
411   }
412 
checkContainerReadLength(int length)413   private void checkContainerReadLength(int length) throws TProtocolException {
414     if (length < 0) {
415       throw new TProtocolException(TProtocolException.NEGATIVE_SIZE,
416                                    "Negative length: " + length);
417     }
418     if (containerLengthLimit_ != NO_LENGTH_LIMIT && length > containerLengthLimit_) {
419       throw new TProtocolException(TProtocolException.SIZE_LIMIT,
420                                    "Length exceeded max allowed: " + length);
421     }
422   }
423 
readAll(byte[] buf, int off, int len)424   private int readAll(byte[] buf, int off, int len) throws TException {
425     return trans_.readAll(buf, off, len);
426   }
427 }
428