/*
* Copyright 2015 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package io.reactivex.netty.protocol.http.ws.server;
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
import io.reactivex.netty.protocol.http.server.HttpServerRequest;
import io.reactivex.netty.protocol.http.server.HttpServerResponse;
import io.reactivex.netty.protocol.http.ws.server.Ws7To13UpgradeHandler.WebSocket7To13UpgradeAcceptedEvent;
import rx.Subscriber;
import static io.netty.handler.codec.http.HttpHeaderNames.*;
/**
* Implementation of {@link WebSocketHandshaker} for web socket spec versions 7.0 to 13.0 (includes final RFC)
*/
final class V7to13Handshaker extends WebSocketHandshaker {
private final State state;
private final HttpServerRequest<?> request;
private final WebSocketHandler handler;
private V7to13Handshaker(final State state, final HttpServerRequest<?> request, final WebSocketHandler handler) {
super(new OnSubscribe<Void>() {
@Override
public void call(Subscriber<? super Void> subscriber) {
state.upgradeResponse.unsafeNettyChannel()
.pipeline()
.fireUserEventTriggered(new WebSocket7To13UpgradeAcceptedEvent(subscriber, handler,
state, request));
}
});
this.state = state;
this.request = request;
this.handler = handler;
}
@Override
public WebSocketHandshaker subprotocol(String... subprotocols) {
return new V7to13Handshaker(new State(state, subprotocols), request, handler);
}
@Override
public WebSocketHandshaker allowExtensions(boolean allowExtensions) {
return new V7to13Handshaker(new State(state, allowExtensions), request, handler);
}
@Override
public WebSocketHandshaker location(String webSocketLocation) {
return new V7to13Handshaker(new State(state, webSocketLocation), request, handler);
}
@Override
public WebSocketHandshaker maxFramePayloadLength(int maxFramePayloadLength) {
return new V7to13Handshaker(new State(state, maxFramePayloadLength), request, handler);
}
static V7to13Handshaker createNew(WebSocketVersion version, HttpServerRequest<?> request,
HttpServerResponse<?> upgradeResponse, WebSocketHandler handler) {
return new V7to13Handshaker(new State(version, request, upgradeResponse), request, handler);
}
/*package-private, used by upgrade handler*/static final class State {
private final WebSocketVersion version;
private final HttpServerResponse<?> upgradeResponse;
private final String[] supportedSubProtocols;
private final String locationForV00;
private final boolean allowExtensions;
private final int maxFramePayloadLength;
private final String secWSkey;
private final String requestSubProtocols;
private State(WebSocketVersion version, HttpServerRequest<?> request, HttpServerResponse<?> upgradeResponse) {
this(getKey(request), getRequestedProtocols(request), version, upgradeResponse, null, null,
DEFAULT_ALLOW_EXTENSIONS, DEFAULT_MAX_FRAME_PAYLOAD_LENGTH);
}
private State(State current, String... subprotocols) {
this(current.secWSkey, current.requestSubProtocols, current.version, current.upgradeResponse,
subprotocols, current.locationForV00, current.allowExtensions, current.maxFramePayloadLength);
}
private State(State current, int maxFramePayloadLength) {
this(current.secWSkey, current.requestSubProtocols, current.version, current.upgradeResponse,
current.supportedSubProtocols, current.locationForV00, current.allowExtensions,
maxFramePayloadLength);
}
private State(State current, boolean allowExtensions) {
this(current.secWSkey, current.requestSubProtocols, current.version, current.upgradeResponse,
current.supportedSubProtocols, current.locationForV00, allowExtensions,
current.maxFramePayloadLength);
}
private State(String secWSkey, String requestSubProtocols, WebSocketVersion version,
HttpServerResponse<?> upgradeResponse, String[] supportedSubProtocols, String locationForV00,
boolean allowExtensions, int maxFramePayloadLength) {
this.secWSkey = secWSkey;
this.requestSubProtocols = requestSubProtocols;
this.version = version;
this.upgradeResponse = upgradeResponse;
this.supportedSubProtocols = supportedSubProtocols;
this.locationForV00 = locationForV00;
this.allowExtensions = allowExtensions;
this.maxFramePayloadLength = maxFramePayloadLength;
}
private static String getRequestedProtocols(HttpServerRequest<?> request) {
return request.getHeader(SEC_WEBSOCKET_PROTOCOL);
}
private static String getKey(HttpServerRequest<?> request) {
return request.getHeader(SEC_WEBSOCKET_KEY);
}
public WebSocketVersion getVersion() {
return version;
}
public HttpServerResponse<?> getUpgradeResponse() {
return upgradeResponse;
}
public String[] getSupportedSubProtocols() {
return supportedSubProtocols;
}
public String getLocationForV00() {
return locationForV00;
}
public boolean isAllowExtensions() {
return allowExtensions;
}
public int getMaxFramePayloadLength() {
return maxFramePayloadLength;
}
public String getSecWSkey() {
return secWSkey;
}
public String getRequestSubProtocols() {
return requestSubProtocols;
}
}
}