/* * 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.channel.Channel; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.codec.http.cookie.Cookie; import io.netty.handler.codec.http.websocketx.WebSocketFrame; import io.reactivex.netty.channel.Connection; import io.reactivex.netty.channel.ContentSource; import io.reactivex.netty.client.ClientConnectionToChannelBridge; import io.reactivex.netty.protocol.http.client.HttpClientResponse; import io.reactivex.netty.protocol.http.internal.AbstractHttpConnectionBridge; import io.reactivex.netty.protocol.http.sse.ServerSentEvent; import io.reactivex.netty.protocol.http.ws.WebSocketConnection; import io.reactivex.netty.protocol.http.ws.client.WebSocketResponse; import rx.Observable; import rx.Observable.Transformer; import java.text.ParseException; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; public final class WebSocketResponseImpl<T> extends WebSocketResponse<T> { private final HttpClientResponse<T> delegate; private final WebSocketConnection wsConnection; private final Channel channel; public WebSocketResponseImpl(HttpClientResponse<T> delegate) { this.delegate = delegate; @SuppressWarnings("unchecked") Connection<WebSocketFrame, WebSocketFrame> cast = (Connection<WebSocketFrame, WebSocketFrame>) delegate.unsafeConnection(); channel = cast.unsafeNettyChannel(); wsConnection = new WebSocketConnection(cast); } @Override public Observable<WebSocketConnection> getWebSocketConnection() { if (isUpgraded()) { /*Do not pool connection once upgraded to WS. A closing handshake closes the channel*/ channel.attr(ClientConnectionToChannelBridge.DISCARD_CONNECTION).set(true); channel.attr(AbstractHttpConnectionBridge.CONNECTION_UPGRADED).set(true); return Observable.just(wsConnection); } else { return Observable.error(new IllegalStateException("WebSocket upgrade rejected by the server.")); } } @Override public HttpVersion getHttpVersion() { return delegate.getHttpVersion(); } @Override public HttpResponseStatus getStatus() { return delegate.getStatus(); } @Override public Map<String, Set<Cookie>> getCookies() { return delegate.getCookies(); } @Override public boolean containsHeader(CharSequence name) { return delegate.containsHeader(name); } @Override public boolean containsHeader(CharSequence name, CharSequence value, boolean ignoreCaseValue) { return delegate.containsHeader(name, value, ignoreCaseValue); } @Override public Iterator<Entry<CharSequence, CharSequence>> headerIterator() { return delegate.headerIterator(); } @Override public String getHeader(CharSequence name) { return delegate.getHeader(name); } @Override public String getHeader(CharSequence name, String defaultValue) { return delegate.getHeader(name, defaultValue); } @Override public List<String> getAllHeaderValues(CharSequence name) { return delegate.getAllHeaderValues(name); } @Override public long getContentLength() { return delegate.getContentLength(); } @Override public long getContentLength(long defaultValue) { return delegate.getContentLength(defaultValue); } @Override public long getDateHeader(CharSequence name) throws ParseException { return delegate.getDateHeader(name); } @Override public long getDateHeader(CharSequence name, long defaultValue) { return delegate.getDateHeader(name, defaultValue); } @Override public String getHostHeader() { return delegate.getHostHeader(); } @Override public String getHost(String defaultValue) { return delegate.getHost(defaultValue); } @Override public int getIntHeader(CharSequence name) { return delegate.getIntHeader(name); } @Override public int getIntHeader(CharSequence name, int defaultValue) { return delegate.getIntHeader(name, defaultValue); } @Override public boolean isContentLengthSet() { return delegate.isContentLengthSet(); } @Override public boolean isKeepAlive() { return delegate.isKeepAlive(); } @Override public boolean isTransferEncodingChunked() { return delegate.isTransferEncodingChunked(); } @Override public Set<String> getHeaderNames() { return delegate.getHeaderNames(); } @Override public HttpClientResponse<T> addHeader(CharSequence name, Object value) { return delegate.addHeader(name, value); } @Override public HttpClientResponse<T> addCookie( Cookie cookie) { return delegate.addCookie(cookie); } @Override public HttpClientResponse<T> addDateHeader(CharSequence name, Date value) { return delegate.addDateHeader(name, value); } @Override public HttpClientResponse<T> addDateHeader(CharSequence name, Iterable<Date> values) { return delegate.addDateHeader(name, values); } @Override public HttpClientResponse<T> addHeader(CharSequence name, Iterable<Object> values) { return delegate.addHeader(name, values); } @Override public HttpClientResponse<T> setDateHeader(CharSequence name, Date value) { return delegate.setDateHeader(name, value); } @Override public HttpClientResponse<T> setHeader(CharSequence name, Object value) { return delegate.setHeader(name, value); } @Override public HttpClientResponse<T> setDateHeader(CharSequence name, Iterable<Date> values) { return delegate.setDateHeader(name, values); } @Override public HttpClientResponse<T> setHeader(CharSequence name, Iterable<Object> values) { return delegate.setHeader(name, values); } @Override public HttpClientResponse<T> removeHeader(CharSequence name) { return delegate.removeHeader(name); } @Override public ContentSource<ServerSentEvent> getContentAsServerSentEvents() { return delegate.getContentAsServerSentEvents(); } @Override public ContentSource<T> getContent() { return delegate.getContent(); } @Override public Observable<Void> discardContent() { return delegate.discardContent(); } @Override public <TT> HttpClientResponse<TT> transformContent(Transformer<T, TT> transformer) { return delegate.transformContent(transformer); } @Override public Channel unsafeNettyChannel() { return delegate.unsafeNettyChannel(); } @Override public Connection<?, ?> unsafeConnection() { return delegate.unsafeConnection(); } @Override public String toString() { return delegate.toString(); } }