/*
* 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.server;
import io.netty.channel.Channel;
import io.netty.handler.codec.DecoderResult;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.cookie.ClientCookieEncoder;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.util.ReferenceCountUtil;
import io.reactivex.netty.channel.ContentSource;
import io.reactivex.netty.protocol.http.CookiesHolder;
import io.reactivex.netty.protocol.http.internal.HttpContentSubscriberEvent;
import io.reactivex.netty.protocol.http.ws.server.WebSocketHandshaker;
import rx.Observable;
import rx.Observable.Transformer;
import rx.Subscriber;
import rx.functions.Func1;
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;
import static io.netty.handler.codec.http.HttpHeaderNames.*;
class HttpServerRequestImpl<T> extends HttpServerRequest<T> {
private final Channel nettyChannel;
private final HttpRequest nettyRequest;
private final CookiesHolder cookiesHolder;
private final UriInfoHolder uriInfoHolder;
private final ContentSource<T> contentSource;
HttpServerRequestImpl(HttpRequest nettyRequest, Channel nettyChannel) {
this.nettyRequest = nettyRequest;
this.nettyChannel = nettyChannel;
uriInfoHolder = new UriInfoHolder(this.nettyRequest.uri());
cookiesHolder = CookiesHolder.newServerRequestHolder(nettyRequest.headers());
contentSource = new ContentSource<>(nettyChannel, new Func1<Subscriber<? super T>, Object>() {
@Override
public Object call(Subscriber<? super T> subscriber) {
return new HttpContentSubscriberEvent<>(subscriber);
}
});
}
private HttpServerRequestImpl(HttpRequest nettyRequest, Channel nettyChannel, ContentSource<T> contentSource) {
this.nettyRequest = nettyRequest;
this.nettyChannel = nettyChannel;
uriInfoHolder = new UriInfoHolder(this.nettyRequest.uri());
cookiesHolder = CookiesHolder.newServerRequestHolder(nettyRequest.headers());
this.contentSource = contentSource;
}
@Override
public HttpMethod getHttpMethod() {
return nettyRequest.method();
}
@Override
public HttpVersion getHttpVersion() {
return nettyRequest.protocolVersion();
}
@Override
public String getUri() {
return uriInfoHolder.getRawUriString();
}
@Override
public String getDecodedPath() {
return uriInfoHolder.getPath();
}
@Override
public String getRawQueryString() {
return uriInfoHolder.getQueryString();
}
@Override
public Map<String, Set<Cookie>> getCookies() {
return cookiesHolder.getAllCookies();
}
@Override
public Map<String, List<String>> getQueryParameters() {
return uriInfoHolder.getQueryParameters();
}
@Override
public boolean containsHeader(CharSequence name) {
return nettyRequest.headers().contains(name);
}
@Override
public boolean containsHeader(CharSequence name, CharSequence value, boolean ignoreCaseValue) {
return nettyRequest.headers().contains(name, value, ignoreCaseValue);
}
@Override
public Iterator<Entry<CharSequence, CharSequence>> headerIterator() {
return nettyRequest.headers().iteratorCharSequence();
}
@Override
public String getHeader(CharSequence name) {
return nettyRequest.headers().get(name);
}
@Override
public String getHeader(CharSequence name, String defaultValue) {
return nettyRequest.headers().get(name, defaultValue);
}
@Override
public List<String> getAllHeaderValues(CharSequence name) {
return nettyRequest.headers().getAll(name);
}
@Override
public long getContentLength() {
return HttpUtil.getContentLength(nettyRequest);
}
@Override
public long getContentLength(long defaultValue) {
return HttpUtil.getContentLength(nettyRequest, defaultValue);
}
@Override
public long getDateHeader(CharSequence name) {
return nettyRequest.headers().getTimeMillis(name);
}
@Override
public long getDateHeader(CharSequence name, long defaultValue) {
return nettyRequest.headers().getTimeMillis(name, defaultValue);
}
@Override
public String getHostHeader() {
return nettyRequest.headers().get(HOST);
}
@Override
public String getHostHeader(String defaultValue) {
return nettyRequest.headers().get(HOST, defaultValue);
}
@Override
public int getIntHeader(CharSequence name) {
return nettyRequest.headers().getInt(name);
}
@Override
public int getIntHeader(CharSequence name, int defaultValue) {
return nettyRequest.headers().getInt(name, defaultValue);
}
@Override
public boolean is100ContinueExpected() {
return HttpUtil.is100ContinueExpected(nettyRequest);
}
@Override
public boolean isContentLengthSet() {
return HttpUtil.isContentLengthSet(nettyRequest);
}
@Override
public boolean isKeepAlive() {
return HttpUtil.isKeepAlive(nettyRequest);
}
@Override
public boolean isTransferEncodingChunked() {
return HttpUtil.isTransferEncodingChunked(nettyRequest);
}
@Override
public Set<String> getHeaderNames() {
return nettyRequest.headers().names();
}
@Override
public HttpServerRequest<T> addHeader(CharSequence name, Object value) {
nettyRequest.headers().add(name, value);
return this;
}
@Override
public HttpServerRequest<T> addCookie(Cookie cookie) {
nettyRequest.headers().add(COOKIE,
ClientCookieEncoder.STRICT.encode(cookie) /*Since this is a request object, cookies are
as if coming from a client*/);
return this;
}
@Override
public HttpServerRequest<T> addDateHeader(CharSequence name, Date value) {
nettyRequest.headers().add(name, value);
return this;
}
@Override
public HttpServerRequest<T> addDateHeader(CharSequence name, Iterable<Date> values) {
for (Date value : values) {
nettyRequest.headers().add(name, value);
}
return this;
}
@Override
public HttpServerRequest<T> addHeader(CharSequence name, Iterable<Object> values) {
nettyRequest.headers().add(name, values);
return this;
}
@Override
public HttpServerRequest<T> setDateHeader(CharSequence name, Date value) {
nettyRequest.headers().set(name, value);
return this;
}
@Override
public HttpServerRequest<T> setHeader(CharSequence name, Object value) {
nettyRequest.headers().set(name, value);
return this;
}
@Override
public HttpServerRequest<T> setDateHeader(CharSequence name, Iterable<Date> values) {
for (Date value : values) {
nettyRequest.headers().set(name, value);
}
return this;
}
@Override
public HttpServerRequest<T> setHeader(CharSequence name, Iterable<Object> values) {
nettyRequest.headers().add(name, values);
return this;
}
@Override
public HttpServerRequest<T> removeHeader(CharSequence name) {
nettyRequest.headers().remove(name);
return this;
}
@Override
public ContentSource<T> getContent() {
return contentSource;
}
@Override
public Observable<Void> discardContent() {
return getContent().map(new Func1<T, Void>() {
@Override
public Void call(T t) {
ReferenceCountUtil.release(t);
return null;
}
}).ignoreElements();
}
@Override
public Observable<Void> dispose() {
return discardContent().onErrorResumeNext(Observable.<Void>empty());
}
@Override
public boolean isWebSocketUpgradeRequested() {
return WebSocketHandshaker.isUpgradeRequested(this);
}
@Override
public <X> HttpServerRequest<X> transformContent(Transformer<T, X> transformer) {
return new HttpServerRequestImpl<>(nettyRequest, nettyChannel, contentSource.transform(transformer));
}
@Override
DecoderResult decoderResult() {
return nettyRequest.decoderResult();
}
}