Skip to content

Commit 70e0ab3

Browse files
authored
Merge pull request TooTallNate#614 from marci4/protocol
Protocol
2 parents ca85bbf + 8393fda commit 70e0ab3

File tree

11 files changed

+1405
-74
lines changed

11 files changed

+1405
-74
lines changed

src/main/java/org/java_websocket/drafts/Draft_6455.java

Lines changed: 107 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
import org.java_websocket.extensions.*;
3232
import org.java_websocket.framing.*;
3333
import org.java_websocket.handshake.*;
34+
import org.java_websocket.protocols.IProtocol;
35+
import org.java_websocket.protocols.Protocol;
3436
import org.java_websocket.util.*;
3537
import org.java_websocket.util.Base64;
3638

@@ -57,6 +59,16 @@ public class Draft_6455 extends Draft {
5759
*/
5860
private List<IExtension> knownExtensions;
5961

62+
/**
63+
* Attribute for the used protocol in this draft
64+
*/
65+
private IProtocol protocol;
66+
67+
/**
68+
* Attribute for all available protocols in this draft
69+
*/
70+
private List<IProtocol> knownProtocols;
71+
6072
/**
6173
* Attribute for the current continuous frame
6274
*/
@@ -99,7 +111,21 @@ public Draft_6455( IExtension inputExtension ) {
99111
* @param inputExtensions the extensions which should be used for this draft
100112
*/
101113
public Draft_6455( List<IExtension> inputExtensions ) {
102-
knownExtensions = new ArrayList<IExtension>();
114+
this( inputExtensions, Collections.<IProtocol>singletonList( new Protocol( "" ) ));
115+
}
116+
117+
/**
118+
* Constructor for the websocket protocol specified by RFC 6455 with custom extensions and protocols
119+
*
120+
* @param inputExtensions the extensions which should be used for this draft
121+
* @param inputProtocols the protocols which should be used for this draft
122+
*/
123+
public Draft_6455( List<IExtension> inputExtensions , List<IProtocol> inputProtocols ) {
124+
if (inputExtensions == null || inputProtocols == null) {
125+
throw new IllegalArgumentException();
126+
}
127+
knownExtensions = new ArrayList<IExtension>( inputExtensions.size());
128+
knownProtocols = new ArrayList<IProtocol>( inputProtocols.size());
103129
boolean hasDefault = false;
104130
byteBufferList = new ArrayList<ByteBuffer>();
105131
for( IExtension inputExtension : inputExtensions ) {
@@ -112,24 +138,38 @@ public Draft_6455( List<IExtension> inputExtensions ) {
112138
if( !hasDefault ) {
113139
knownExtensions.add( this.knownExtensions.size(), extension );
114140
}
141+
knownProtocols.addAll( inputProtocols );
115142
}
116143

117144
@Override
118145
public HandshakeState acceptHandshakeAsServer( ClientHandshake handshakedata ) throws InvalidHandshakeException {
119146
int v = readVersion( handshakedata );
120147
if( v != 13 )
121148
return HandshakeState.NOT_MATCHED;
149+
HandshakeState extensionState= HandshakeState.NOT_MATCHED;
122150
String requestedExtension = handshakedata.getFieldValue( "Sec-WebSocket-Extensions" );
123151
for( IExtension knownExtension : knownExtensions ) {
124152
if( knownExtension.acceptProvidedExtensionAsServer( requestedExtension ) ) {
125153
extension = knownExtension;
126-
return HandshakeState.MATCHED;
154+
extensionState = HandshakeState.MATCHED;
155+
break;
156+
}
157+
}
158+
HandshakeState protocolState = HandshakeState.NOT_MATCHED;
159+
String requestedProtocol = handshakedata.getFieldValue( "Sec-WebSocket-Protocol" );
160+
for( IProtocol knownProtocol : knownProtocols ) {
161+
if( knownProtocol.acceptProvidedProtocol( requestedProtocol ) ) {
162+
protocol = knownProtocol;
163+
protocolState = HandshakeState.MATCHED;
164+
break;
127165
}
128166
}
167+
if (protocolState == HandshakeState.MATCHED && extensionState == HandshakeState.MATCHED) {
168+
return HandshakeState.MATCHED;
169+
}
129170
return HandshakeState.NOT_MATCHED;
130171
}
131172

132-
133173
@Override
134174
public HandshakeState acceptHandshakeAsClient( ClientHandshake request, ServerHandshake response ) throws InvalidHandshakeException {
135175
if (! basicAccept( response )) {
@@ -145,13 +185,27 @@ public HandshakeState acceptHandshakeAsClient( ClientHandshake request, ServerHa
145185
if( !seckey_challenge.equals( seckey_answere ) )
146186
return HandshakeState.NOT_MATCHED;
147187

188+
HandshakeState extensionState= HandshakeState.NOT_MATCHED;
148189
String requestedExtension = response.getFieldValue( "Sec-WebSocket-Extensions" );
149190
for( IExtension knownExtension : knownExtensions ) {
150191
if( knownExtension.acceptProvidedExtensionAsClient( requestedExtension ) ) {
151192
extension = knownExtension;
152-
return HandshakeState.MATCHED;
193+
extensionState = HandshakeState.MATCHED;
194+
break;
195+
}
196+
}
197+
HandshakeState protocolState = HandshakeState.NOT_MATCHED;
198+
String requestedProtocol = response.getFieldValue( "Sec-WebSocket-Protocol" );
199+
for( IProtocol knownProtocol : knownProtocols ) {
200+
if( knownProtocol.acceptProvidedProtocol( requestedProtocol ) ) {
201+
protocol = knownProtocol;
202+
protocolState = HandshakeState.MATCHED;
203+
break;
153204
}
154205
}
206+
if (protocolState == HandshakeState.MATCHED && extensionState == HandshakeState.MATCHED) {
207+
return HandshakeState.MATCHED;
208+
}
155209
return HandshakeState.NOT_MATCHED;
156210
}
157211

@@ -172,6 +226,23 @@ public List<IExtension> getKnownExtensions() {
172226
return knownExtensions;
173227
}
174228

229+
/**
230+
* Getter for the protocol which is used by this draft
231+
*
232+
* @return the protocol which is used or null, if handshake is not yet done or no valid protocols
233+
*/
234+
public IProtocol getProtocol() {
235+
return protocol;
236+
}
237+
238+
/**
239+
* Getter for all available protocols for this draft
240+
* @return the protocols which are enabled for this draft
241+
*/
242+
public List<IProtocol> getKnownProtocols() {
243+
return knownProtocols;
244+
}
245+
175246
@Override
176247
public ClientHandshakeBuilder postProcessHandshakeRequestAsClient( ClientHandshakeBuilder request ) {
177248
request.put( "Upgrade", "websocket" );
@@ -183,12 +254,27 @@ public ClientHandshakeBuilder postProcessHandshakeRequestAsClient( ClientHandsha
183254
StringBuilder requestedExtensions = new StringBuilder();
184255
for( IExtension knownExtension : knownExtensions ) {
185256
if( knownExtension.getProvidedExtensionAsClient() != null && knownExtension.getProvidedExtensionAsClient().length() != 0 ) {
186-
requestedExtensions.append( knownExtension.getProvidedExtensionAsClient() ).append( "; " );
257+
if (requestedExtensions.length() > 0) {
258+
requestedExtensions.append( ", " );
259+
}
260+
requestedExtensions.append( knownExtension.getProvidedExtensionAsClient() );
187261
}
188262
}
189263
if( requestedExtensions.length() != 0 ) {
190264
request.put( "Sec-WebSocket-Extensions", requestedExtensions.toString() );
191265
}
266+
StringBuilder requestedProtocols = new StringBuilder();
267+
for( IProtocol knownProtocol : knownProtocols ) {
268+
if( knownProtocol.getProvidedProtocol().length() != 0 ) {
269+
if (requestedProtocols.length() > 0) {
270+
requestedProtocols.append( ", " );
271+
}
272+
requestedProtocols.append( knownProtocol.getProvidedProtocol() );
273+
}
274+
}
275+
if( requestedProtocols.length() != 0 ) {
276+
request.put( "Sec-WebSocket-Protocol", requestedProtocols.toString() );
277+
}
192278
return request;
193279
}
194280

@@ -203,6 +289,9 @@ public HandshakeBuilder postProcessHandshakeResponseAsServer( ClientHandshake re
203289
if( getExtension().getProvidedExtensionAsServer().length() != 0 ) {
204290
response.put( "Sec-WebSocket-Extensions", getExtension().getProvidedExtensionAsServer() );
205291
}
292+
if( getProtocol() != null && getProtocol().getProvidedProtocol().length() != 0 ) {
293+
response.put( "Sec-WebSocket-Protocol", getProtocol().getProvidedProtocol() );
294+
}
206295
response.setHttpStatusMessage( "Web Socket Protocol Handshake" );
207296
response.put( "Server", "TooTallNate Java-WebSocket" );
208297
response.put( "Date", getServerTime() );
@@ -215,7 +304,11 @@ public Draft copyInstance() {
215304
for( IExtension extension : getKnownExtensions() ) {
216305
newExtensions.add( extension.copyInstance() );
217306
}
218-
return new Draft_6455( newExtensions );
307+
ArrayList<IProtocol> newProtocols = new ArrayList<IProtocol>();
308+
for( IProtocol protocol : getKnownProtocols() ) {
309+
newProtocols.add( protocol.copyInstance() );
310+
}
311+
return new Draft_6455( newExtensions, newProtocols );
219312
}
220313

221314
@Override
@@ -440,6 +533,7 @@ public void reset() {
440533
extension.reset();
441534
}
442535
extension = new DefaultExtension();
536+
protocol = null;
443537
}
444538

445539
/**
@@ -617,6 +711,8 @@ public String toString() {
617711
String result = super.toString();
618712
if( getExtension() != null )
619713
result += " extension: " + getExtension().toString();
714+
if ( getProtocol() != null )
715+
result += " protocol: " + getProtocol().toString();
620716
return result;
621717
}
622718

@@ -627,12 +723,15 @@ public boolean equals( Object o ) {
627723

628724
Draft_6455 that = ( Draft_6455 ) o;
629725

630-
return extension != null ? extension.equals( that.extension ) : that.extension == null;
726+
if( extension != null ? !extension.equals( that.extension ) : that.extension != null ) return false;
727+
return protocol != null ? protocol.equals( that.protocol ) : that.protocol == null;
631728
}
632729

633730
@Override
634731
public int hashCode() {
635-
return extension != null ? extension.hashCode() : 0;
732+
int result = extension != null ? extension.hashCode() : 0;
733+
result = 31 * result + ( protocol != null ? protocol.hashCode() : 0 );
734+
return result;
636735
}
637736

638737
/**

src/main/java/org/java_websocket/framing/FramedataImpl1.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,4 +239,32 @@ public static FramedataImpl1 get(Opcode opcode) {
239239
throw new IllegalArgumentException("Supplied opcode is invalid");
240240
}
241241
}
242+
243+
@Override
244+
public boolean equals( Object o ) {
245+
if( this == o ) return true;
246+
if( o == null || getClass() != o.getClass() ) return false;
247+
248+
FramedataImpl1 that = ( FramedataImpl1 ) o;
249+
250+
if( fin != that.fin ) return false;
251+
if( transferemasked != that.transferemasked ) return false;
252+
if( rsv1 != that.rsv1 ) return false;
253+
if( rsv2 != that.rsv2 ) return false;
254+
if( rsv3 != that.rsv3 ) return false;
255+
if( optcode != that.optcode ) return false;
256+
return unmaskedpayload != null ? unmaskedpayload.equals( that.unmaskedpayload ) : that.unmaskedpayload == null;
257+
}
258+
259+
@Override
260+
public int hashCode() {
261+
int result = ( fin ? 1 : 0 );
262+
result = 31 * result + optcode.hashCode();
263+
result = 31 * result + ( unmaskedpayload != null ? unmaskedpayload.hashCode() : 0 );
264+
result = 31 * result + ( transferemasked ? 1 : 0 );
265+
result = 31 * result + ( rsv1 ? 1 : 0 );
266+
result = 31 * result + ( rsv2 ? 1 : 0 );
267+
result = 31 * result + ( rsv3 ? 1 : 0 );
268+
return result;
269+
}
242270
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright (c) 2010-2017 Nathan Rajlich
3+
*
4+
* Permission is hereby granted, free of charge, to any person
5+
* obtaining a copy of this software and associated documentation
6+
* files (the "Software"), to deal in the Software without
7+
* restriction, including without limitation the rights to use,
8+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the
10+
* Software is furnished to do so, subject to the following
11+
* conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be
14+
* included in all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23+
* OTHER DEALINGS IN THE SOFTWARE.
24+
*/
25+
26+
package org.java_websocket.protocols;
27+
28+
/**
29+
* Interface which specifies all required methods for a Sec-WebSocket-Protocol
30+
*/
31+
public interface IProtocol {
32+
33+
/**
34+
* Check if the received Sec-WebSocket-Protocol header field contains a offer for the specific protocol
35+
*
36+
* @param inputProtocolHeader the received Sec-WebSocket-Protocol header field offered by the other endpoint
37+
* @return true, if the offer does fit to this specific protocol
38+
*/
39+
boolean acceptProvidedProtocol( String inputProtocolHeader );
40+
41+
/**
42+
* Return the specific Sec-WebSocket-protocol header offer for this protocol if the endpoint.
43+
* If the extension returns an empty string (""), the offer will not be included in the handshake.
44+
*
45+
* @return the specific Sec-WebSocket-Protocol header for this protocol
46+
*/
47+
String getProvidedProtocol();
48+
49+
/**
50+
* To prevent protocols to be used more than once the Websocket implementation should call this method in order to create a new usable version of a given protocol instance.
51+
* @return a copy of the protocol
52+
*/
53+
IProtocol copyInstance();
54+
55+
/**
56+
* Return a string which should contain the protocol name as well as additional information about the current configurations for this protocol (DEBUG purposes)
57+
*
58+
* @return a string containing the protocol name as well as additional information
59+
*/
60+
String toString();
61+
}

0 commit comments

Comments
 (0)