Java tutorial
/* * Copyright 2014 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.client; import io.netty.bootstrap.Bootstrap; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import io.reactivex.netty.channel.ObservableConnection; import io.reactivex.netty.client.ClientChannelFactory; import io.reactivex.netty.client.ClientConnectionFactory; import io.reactivex.netty.client.ClientMetricsEvent; import io.reactivex.netty.client.ConnectionPool; import io.reactivex.netty.client.ConnectionPoolBuilder; import io.reactivex.netty.client.RxClientImpl; import io.reactivex.netty.metrics.Clock; import io.reactivex.netty.metrics.MetricEventsSubject; import io.reactivex.netty.pipeline.PipelineConfigurator; import io.reactivex.netty.pipeline.PipelineConfiguratorComposite; import rx.Observable; import rx.functions.Action0; public class HttpClientImpl<I, O> extends RxClientImpl<HttpClientRequest<I>, HttpClientResponse<O>> implements HttpClient<I, O> { public HttpClientImpl(String name, ServerInfo serverInfo, Bootstrap clientBootstrap, PipelineConfigurator<HttpClientResponse<O>, HttpClientRequest<I>> pipelineConfigurator, ClientConfig clientConfig, ClientChannelFactory<HttpClientResponse<O>, HttpClientRequest<I>> channelFactory, ClientConnectionFactory<HttpClientResponse<O>, HttpClientRequest<I>, ? extends ObservableConnection<HttpClientResponse<O>, HttpClientRequest<I>>> connectionFactory, MetricEventsSubject<ClientMetricsEvent<?>> eventsSubject) { super(name, serverInfo, clientBootstrap, pipelineConfigurator, clientConfig, channelFactory, connectionFactory, eventsSubject); } public HttpClientImpl(String name, ServerInfo serverInfo, Bootstrap clientBootstrap, PipelineConfigurator<HttpClientResponse<O>, HttpClientRequest<I>> pipelineConfigurator, ClientConfig clientConfig, ConnectionPoolBuilder<HttpClientResponse<O>, HttpClientRequest<I>> poolBuilder, MetricEventsSubject<ClientMetricsEvent<?>> eventsSubject) { super(name, serverInfo, clientBootstrap, pipelineConfigurator, clientConfig, poolBuilder, eventsSubject); } @Override public Observable<HttpClientResponse<O>> submit(HttpClientRequest<I> request) { return submit(request, connect()); } @Override public Observable<HttpClientResponse<O>> submit(HttpClientRequest<I> request, ClientConfig config) { return submit(request, connect(), config); } protected Observable<HttpClientResponse<O>> submit(final HttpClientRequest<I> request, Observable<ObservableConnection<HttpClientResponse<O>, HttpClientRequest<I>>> connectionObservable) { return submit(request, connectionObservable, null == clientConfig ? HttpClientConfig.Builder.newDefaultConfig() : clientConfig); } protected Observable<HttpClientResponse<O>> submit(final HttpClientRequest<I> request, final Observable<ObservableConnection<HttpClientResponse<O>, HttpClientRequest<I>>> connectionObservable, final ClientConfig config) { final long startTimeMillis = Clock.newStartTimeMillis(); HttpClientConfig httpClientConfig; if (config instanceof HttpClientConfig) { httpClientConfig = (HttpClientConfig) config; } else { httpClientConfig = new HttpClientConfig(config); } boolean followRedirect = shouldFollowRedirectForRequest(httpClientConfig, request); enrichRequest(request, httpClientConfig); Observable<HttpClientResponse<O>> toReturn = connectionObservable .lift(new RequestProcessingOperator<I, O>(request, eventsSubject)); if (followRedirect) { toReturn = toReturn.lift(new RedirectOperator<I, O>(request, this, httpClientConfig)); } return toReturn.finallyDo(new Action0() { @Override public void call() { eventsSubject.onEvent(HttpClientMetricsEvent.REQUEST_PROCESSING_COMPLETE, Clock.onEndMillis(startTimeMillis)); } }); } @Override protected PipelineConfigurator<HttpClientResponse<O>, HttpClientRequest<I>> adaptPipelineConfigurator( PipelineConfigurator<HttpClientResponse<O>, HttpClientRequest<I>> pipelineConfigurator, ClientConfig clientConfig, MetricEventsSubject<ClientMetricsEvent<?>> eventsSubject) { PipelineConfigurator<HttpClientResponse<O>, HttpClientRequest<I>> configurator = new PipelineConfiguratorComposite<HttpClientResponse<O>, HttpClientRequest<I>>( pipelineConfigurator, new ClientRequiredConfigurator<I, O>(eventsSubject)); return super.adaptPipelineConfigurator(configurator, clientConfig, eventsSubject); } protected boolean shouldFollowRedirectForRequest(HttpClientConfig config, HttpClientRequest<I> request) { HttpClientConfig.RedirectsHandling redirectsHandling = config.getFollowRedirect(); switch (redirectsHandling) { case Enable: return true; case Disable: return false; case Undefined: return request.getMethod() == HttpMethod.HEAD || request.getMethod() == HttpMethod.GET; default: return false; } } /*visible for testing*/ ConnectionPool<HttpClientResponse<O>, HttpClientRequest<I>> getConnectionPool() { return pool; } private void enrichRequest(HttpClientRequest<I> request, ClientConfig config) { request.setDynamicUriParts(serverInfo.getHost(), serverInfo.getPort(), false /*Set when we handle https*/); if (!request.getHeaders().contains(HttpHeaders.Names.HOST)) { request.getHeaders().add(HttpHeaders.Names.HOST, serverInfo.getHost()); } if (config instanceof HttpClientConfig) { HttpClientConfig httpClientConfig = (HttpClientConfig) config; if (httpClientConfig.getUserAgent() != null && request.getHeaders().get(HttpHeaders.Names.USER_AGENT) == null) { request.getHeaders().set(HttpHeaders.Names.USER_AGENT, httpClientConfig.getUserAgent()); } } } }