/*
* Copyright 2016 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.client.internal;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
import io.reactivex.netty.protocol.http.client.HttpClientRequest;
import io.reactivex.netty.protocol.http.client.HttpClientResponse;
import io.reactivex.netty.protocol.http.client.internal.HttpClientRequestImpl;
import io.reactivex.netty.protocol.http.client.internal.RawRequest;
import io.reactivex.netty.protocol.http.ws.client.WebSocketRequest;
import io.reactivex.netty.protocol.http.ws.client.WebSocketResponse;
import rx.Subscriber;
import rx.functions.Func1;
import static io.netty.handler.codec.http.HttpHeaderNames.*;
import static io.netty.handler.codec.http.HttpHeaderValues.*;
public final class WebSocketRequestImpl<O> extends WebSocketRequest<O> {
private final String[] subProtocolsRequested;
private final WebSocketVersion version;
private final HttpClientRequest<?, O> httpRequest;
private WebSocketRequestImpl(final HttpClientRequest<?, O> httpRequest) {
this(httpRequest, null, WebSocketVersion.V13);
}
private WebSocketRequestImpl(final HttpClientRequest<?, O> httpRequest, String[] subProtocolsRequested,
WebSocketVersion version) {
super(new OnSubscribe<WebSocketResponse<O>>() {
@Override
public void call(Subscriber<? super WebSocketResponse<O>> subscriber) {
httpRequest.map(new Func1<HttpClientResponse<O>, WebSocketResponseImpl<O>>() {
@Override
public WebSocketResponseImpl<O> call(HttpClientResponse<O> response) {
return new WebSocketResponseImpl<>(response);
}
}).unsafeSubscribe(subscriber);
}
});
this.httpRequest = httpRequest;
this.subProtocolsRequested = subProtocolsRequested;
this.version = version;
}
public String[] getSubProtocolsRequested() {
return subProtocolsRequested;
}
@Override
public WebSocketRequestImpl<O> requestSubProtocols(String... subProtocols) {
return new WebSocketRequestImpl<>(httpRequest.setHeader(SEC_WEBSOCKET_PROTOCOL,
expectedSubProtocol(subProtocols)), subProtocols,
version);
}
@Override
public WebSocketRequestImpl<O> version(int version) {
WebSocketVersion webSocketVersion;
switch (version) {
case 7:
webSocketVersion = WebSocketVersion.V07;
break;
case 8:
webSocketVersion = WebSocketVersion.V08;
break;
case 13:
webSocketVersion = WebSocketVersion.V13;
break;
default:
webSocketVersion = WebSocketVersion.UNKNOWN;
break;
}
return new WebSocketRequestImpl<>(httpRequest.setHeader(SEC_WEBSOCKET_VERSION, version),
subProtocolsRequested, webSocketVersion);
}
public static <O> WebSocketRequestImpl<O> createNew(final HttpClientRequestImpl<?, O> httpRequest) {
/*This makes a copy of the request so that we can safely make modifications to the underlying headers.*/
@SuppressWarnings("unchecked")
final HttpClientRequestImpl<?, O> upgradeRequest =
(HttpClientRequestImpl<?, O>) httpRequest.addHeader(HttpHeaderNames.UPGRADE, WEBSOCKET);
RawRequest<?, O> rawRequest = upgradeRequest.unsafeRawRequest();
HttpRequest headers = rawRequest.getHeaders();
headers.headers().add(CONNECTION, HttpHeaderValues.UPGRADE);
headers.headers().add(SEC_WEBSOCKET_VERSION, WebSocketVersion.V13.toHttpHeaderValue());
return new WebSocketRequestImpl<>(upgradeRequest);
}
private static String expectedSubProtocol(String[] subProtocols) {
if (null == subProtocols || subProtocols.length == 0) {
return null;
}
if (subProtocols.length == 1) {
return subProtocols[0];
}
StringBuilder builder = new StringBuilder();
for (String subProtocol : subProtocols) {
if (builder.length() != 0) {
builder.append(',');
}
builder.append(subProtocol);
}
return builder.toString();
}
}