@@ -86,7 +86,7 @@ public class Draft_6455 extends Draft {
8686 /**
8787 * Attribute for the payload of the current continuous frame
8888 */
89- private List <ByteBuffer > byteBufferList ;
89+ private final List <ByteBuffer > byteBufferList ;
9090
9191 /**
9292 * Attribute for the current incomplete frame
@@ -98,6 +98,13 @@ public class Draft_6455 extends Draft {
9898 */
9999 private final Random reuseableRandom = new Random ();
100100
101+ /**
102+ * Attribute for the maximum allowed size of a frame
103+ *
104+ * @since 1.4.0
105+ */
106+ private int maxFrameSize ;
107+
101108 /**
102109 * Constructor for the websocket protocol specified by RFC 6455 with default extensions
103110 * @since 1.3.5
@@ -135,7 +142,32 @@ public Draft_6455( List<IExtension> inputExtensions ) {
135142 * @since 1.3.7
136143 */
137144 public Draft_6455 ( List <IExtension > inputExtensions , List <IProtocol > inputProtocols ) {
138- if (inputExtensions == null || inputProtocols == null ) {
145+ this (inputExtensions , inputProtocols , Integer .MAX_VALUE );
146+ }
147+
148+ /**
149+ * Constructor for the websocket protocol specified by RFC 6455 with custom extensions and protocols
150+ *
151+ * @param inputExtensions the extensions which should be used for this draft
152+ * @param inputMaxFrameSize the maximum allowed size of a frame (the real payload size, decoded frames can be bigger)
153+ *
154+ * @since 1.4.0
155+ */
156+ public Draft_6455 ( List <IExtension > inputExtensions , int inputMaxFrameSize ) {
157+ this (inputExtensions , Collections .<IProtocol >singletonList ( new Protocol ( "" )), inputMaxFrameSize );
158+ }
159+
160+ /**
161+ * Constructor for the websocket protocol specified by RFC 6455 with custom extensions and protocols
162+ *
163+ * @param inputExtensions the extensions which should be used for this draft
164+ * @param inputProtocols the protocols which should be used for this draft
165+ * @param inputMaxFrameSize the maximum allowed size of a frame (the real payload size, decoded frames can be bigger)
166+ *
167+ * @since 1.4.0
168+ */
169+ public Draft_6455 ( List <IExtension > inputExtensions , List <IProtocol > inputProtocols , int inputMaxFrameSize ) {
170+ if (inputExtensions == null || inputProtocols == null || inputMaxFrameSize < 1 ) {
139171 throw new IllegalArgumentException ();
140172 }
141173 knownExtensions = new ArrayList <IExtension >( inputExtensions .size ());
@@ -153,6 +185,7 @@ public Draft_6455( List<IExtension> inputExtensions , List<IProtocol> inputProto
153185 knownExtensions .add ( this .knownExtensions .size (), extension );
154186 }
155187 knownProtocols .addAll ( inputProtocols );
188+ maxFrameSize = inputMaxFrameSize ;
156189 }
157190
158191 @ Override
@@ -263,6 +296,17 @@ public IProtocol getProtocol() {
263296 return protocol ;
264297 }
265298
299+
300+ /**
301+ * Getter for the maximum allowed payload size which is used by this draft
302+ *
303+ * @return the size, which is allowed for the payload
304+ * @since 1.4.0
305+ */
306+ public int getMaxFrameSize () {
307+ return maxFrameSize ;
308+ }
309+
266310 /**
267311 * Getter for all available protocols for this draft
268312 * @return the protocols which are enabled for this draft
@@ -337,7 +381,7 @@ public Draft copyInstance() {
337381 for ( IProtocol protocol : getKnownProtocols () ) {
338382 newProtocols .add ( protocol .copyInstance () );
339383 }
340- return new Draft_6455 ( newExtensions , newProtocols );
384+ return new Draft_6455 ( newExtensions , newProtocols , maxFrameSize );
341385 }
342386
343387 @ Override
@@ -440,14 +484,18 @@ public Framedata translateSingleFrame( ByteBuffer buffer ) throws IncompleteExce
440484 bytes [i ] = buffer .get ( /*1 + i*/ );
441485 }
442486 long length = new BigInteger ( bytes ).longValue ();
443- if ( length > Integer .MAX_VALUE ) {
487+ if ( length > Integer .MAX_VALUE ) {
444488 log .trace ( "Limit exedeed: Payloadsize is to big..." );
445489 throw new LimitExedeedException ( "Payloadsize is to big..." );
446490 } else {
447491 payloadlength = ( int ) length ;
448492 }
449493 }
450494 }
495+ if ( payloadlength > maxFrameSize ) {
496+ log .trace ( "Payload limit reached. Allowed: {0} Current: {1}" , maxFrameSize , payloadlength );
497+ throw new LimitExedeedException ( "Payload limit reached." , maxFrameSize );
498+ }
451499
452500 // int maskskeystart = foff + realpacketsize;
453501 realpacketsize += ( MASK ? 4 : 0 );
@@ -682,13 +730,15 @@ public void processFrame( WebSocketImpl webSocketImpl, Framedata frame ) throws
682730 throw new InvalidDataException ( CloseFrame .PROTOCOL_ERROR , "Previous continuous frame sequence not completed." );
683731 }
684732 current_continuous_frame = frame ;
685- byteBufferList .add ( frame .getPayloadData () );
733+ addToBufferList (frame .getPayloadData ());
734+ checkBufferLimit ();
686735 } else if ( frame .isFin () ) {
687736 if ( current_continuous_frame == null ) {
688737 log .trace ( "Protocol error: Previous continuous frame sequence not completed." );
689738 throw new InvalidDataException ( CloseFrame .PROTOCOL_ERROR , "Continuous frame sequence was not started." );
690739 }
691- byteBufferList .add ( frame .getPayloadData () );
740+ addToBufferList (frame .getPayloadData ());
741+ checkBufferLimit ();
692742 if ( current_continuous_frame .getOpcode () == Opcode .TEXT ) {
693743 ((FramedataImpl1 ) current_continuous_frame ).setPayload ( getPayloadFromByteBufferList () );
694744 ((FramedataImpl1 ) current_continuous_frame ).isValid ();
@@ -709,7 +759,7 @@ public void processFrame( WebSocketImpl webSocketImpl, Framedata frame ) throws
709759 }
710760 }
711761 current_continuous_frame = null ;
712- byteBufferList . clear ();
762+ clearBufferList ();
713763 } else if ( current_continuous_frame == null ) {
714764 log .error ( "Protocol error: Continuous frame sequence was not started." );
715765 throw new InvalidDataException ( CloseFrame .PROTOCOL_ERROR , "Continuous frame sequence was not started." );
@@ -723,7 +773,7 @@ public void processFrame( WebSocketImpl webSocketImpl, Framedata frame ) throws
723773 }
724774 //Checking if the current continuous frame contains a correct payload with the other frames combined
725775 if ( curop == Opcode .CONTINUOUS && current_continuous_frame != null ) {
726- byteBufferList . add ( frame .getPayloadData () );
776+ addToBufferList ( frame .getPayloadData ());
727777 }
728778 } else if ( current_continuous_frame != null ) {
729779 log .error ( "Protocol error: Continuous frame sequence not completed." );
@@ -748,6 +798,38 @@ public void processFrame( WebSocketImpl webSocketImpl, Framedata frame ) throws
748798 }
749799 }
750800
801+ /**
802+ * Clear the current bytebuffer list
803+ */
804+ private void clearBufferList () {
805+ synchronized (byteBufferList ) {
806+ byteBufferList .clear ();
807+ }
808+ }
809+
810+ /**
811+ * Add a payload to the current bytebuffer list
812+ * @param payloadData the new payload
813+ */
814+ private void addToBufferList (ByteBuffer payloadData ) {
815+ synchronized (byteBufferList ) {
816+ byteBufferList .add (payloadData );
817+ }
818+ }
819+
820+ /**
821+ * Check the current size of the buffer and throw an exception if the size is bigger than the max allowed frame size
822+ * @throws LimitExedeedException if the current size is bigger than the allowed size
823+ */
824+ private void checkBufferLimit () throws LimitExedeedException {
825+ long totalSize = getByteBufferListSize ();
826+ if ( totalSize > maxFrameSize ) {
827+ clearBufferList ();
828+ log .trace ("Payload limit reached. Allowed: {0} Current: {1}" , maxFrameSize , totalSize );
829+ throw new LimitExedeedException (maxFrameSize );
830+ }
831+ }
832+
751833 @ Override
752834 public CloseHandshakeType getCloseHandshakeType () {
753835 return CloseHandshakeType .TWOWAY ;
@@ -760,24 +842,27 @@ public String toString() {
760842 result += " extension: " + getExtension ().toString ();
761843 if ( getProtocol () != null )
762844 result += " protocol: " + getProtocol ().toString ();
845+ result += " max frame size: " + this .maxFrameSize ;
763846 return result ;
764847 }
765848
766849 @ Override
767- public boolean equals ( Object o ) {
768- if ( this == o ) return true ;
769- if ( o == null || getClass () != o .getClass () ) return false ;
850+ public boolean equals (Object o ) {
851+ if ( this == o ) return true ;
852+ if ( o == null || getClass () != o .getClass ()) return false ;
770853
771- Draft_6455 that = ( Draft_6455 ) o ;
854+ Draft_6455 that = (Draft_6455 ) o ;
772855
773- if ( extension != null ? !extension .equals ( that .extension ) : that .extension != null ) return false ;
774- return protocol != null ? protocol .equals ( that .protocol ) : that .protocol == null ;
856+ if (maxFrameSize != that .getMaxFrameSize ()) return false ;
857+ if (extension != null ? !extension .equals (that .getExtension ()) : that .getExtension () != null ) return false ;
858+ return protocol != null ? protocol .equals (that .getProtocol ()) : that .getProtocol () == null ;
775859 }
776860
777861 @ Override
778862 public int hashCode () {
779863 int result = extension != null ? extension .hashCode () : 0 ;
780- result = 31 * result + ( protocol != null ? protocol .hashCode () : 0 );
864+ result = 31 * result + (protocol != null ? protocol .hashCode () : 0 );
865+ result = 31 * result + (int ) (maxFrameSize ^ (maxFrameSize >>> 32 ));
781866 return result ;
782867 }
783868
@@ -788,18 +873,32 @@ public int hashCode() {
788873 */
789874 private ByteBuffer getPayloadFromByteBufferList () throws LimitExedeedException {
790875 long totalSize = 0 ;
791- for ( ByteBuffer buffer : byteBufferList ) {
792- totalSize += buffer . limit ();
793- }
794- if ( totalSize > Integer . MAX_VALUE ) {
795- log . trace ( "Payloadsize is to big..." );
796- throw new LimitExedeedException ( "Payloadsize is to big..." );
797- }
798- ByteBuffer resultingByteBuffer = ByteBuffer . allocate ( ( int ) totalSize );
799- for ( ByteBuffer buffer : byteBufferList ) {
800- resultingByteBuffer . put ( buffer );
876+ ByteBuffer resultingByteBuffer ;
877+ synchronized ( byteBufferList ) {
878+ for ( ByteBuffer buffer : byteBufferList ) {
879+ totalSize += buffer . limit ();
880+ }
881+ checkBufferLimit ( );
882+ resultingByteBuffer = ByteBuffer . allocate ( ( int ) totalSize );
883+ for ( ByteBuffer buffer : byteBufferList ) {
884+ resultingByteBuffer . put ( buffer );
885+ }
801886 }
802887 resultingByteBuffer .flip ();
803888 return resultingByteBuffer ;
804889 }
890+
891+ /**
892+ * Get the current size of the resulting bytebuffer in the bytebuffer list
893+ * @return the size as long (to not get an integer overflow)
894+ */
895+ private long getByteBufferListSize () {
896+ long totalSize = 0 ;
897+ synchronized (byteBufferList ) {
898+ for (ByteBuffer buffer : byteBufferList ) {
899+ totalSize += buffer .limit ();
900+ }
901+ }
902+ return totalSize ;
903+ }
805904}
0 commit comments