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