io.vertx.ext.web.client.impl.HttpRequestImpl.java Source code

Java tutorial

Introduction

Here is the source code for io.vertx.ext.web.client.impl.HttpRequestImpl.java

Source

/*
 * Copyright (c) 2011-2013 The original author or authors
 * ------------------------------------------------------
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Apache License v2.0 which accompanies this distribution.
 *
 *     The Eclipse Public License is available at
 *     http://www.eclipse.org/legal/epl-v10.html
 *
 *     The Apache License v2.0 is available at
 *     http://www.opensource.org/licenses/apache2.0.php
 *
 * You may elect to redistribute this code under either of these licenses.
 */
package io.vertx.ext.web.client.impl;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.QueryStringDecoder;
import io.netty.handler.codec.http.QueryStringEncoder;
import io.netty.handler.codec.http.multipart.HttpPostRequestEncoder;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.MultiMap;
import io.vertx.core.VertxException;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.CaseInsensitiveHeaders;
import io.vertx.core.http.HttpClient;
import io.vertx.core.http.HttpClientRequest;
import io.vertx.core.http.HttpClientResponse;
import io.vertx.core.http.HttpHeaders;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.RequestOptions;
import io.vertx.core.json.Json;
import io.vertx.core.json.JsonObject;
import io.vertx.core.streams.Pump;
import io.vertx.core.streams.ReadStream;
import io.vertx.ext.web.client.HttpRequest;
import io.vertx.ext.web.client.HttpResponse;
import io.vertx.ext.web.client.WebClientOptions;
import io.vertx.ext.web.codec.BodyCodec;
import io.vertx.ext.web.codec.spi.BodyStream;

import java.util.Map;

/**
 * @author <a href="mailto:julien@julienviet.com">Julien Viet</a>
 */
class HttpRequestImpl<T> implements HttpRequest<T> {

    private final HttpClient client;
    private final WebClientOptions options;
    private MultiMap params;
    private HttpMethod method;
    private int port;
    private String host;
    private String uri;
    private MultiMap headers;
    private long timeout = -1;
    private BodyCodec<T> codec;
    private boolean followRedirects;
    private boolean ssl;

    HttpRequestImpl(HttpClient client, HttpMethod method, boolean ssl, int port, String host, String uri,
            BodyCodec<T> codec, WebClientOptions options) {
        this.client = client;
        this.method = method;
        this.codec = codec;
        this.port = port;
        this.host = host;
        this.uri = uri;
        this.ssl = ssl;
        this.followRedirects = options.isFollowRedirects();
        this.options = options;
        if (options.isUserAgentEnabled()) {
            headers = new CaseInsensitiveHeaders().add(HttpHeaders.USER_AGENT, options.getUserAgent());
        }
    }

    private HttpRequestImpl(HttpRequestImpl<T> other) {
        this.client = other.client;
        this.options = other.options;
        this.method = other.method;
        this.port = other.port;
        this.host = other.host;
        this.timeout = other.timeout;
        this.uri = other.uri;
        this.headers = other.headers != null ? new CaseInsensitiveHeaders().addAll(other.headers) : null;
        this.params = other.params != null ? new CaseInsensitiveHeaders().addAll(other.params) : null;
        this.codec = other.codec;
        this.followRedirects = other.followRedirects;
    }

    @Override
    public <U> HttpRequest<U> as(BodyCodec<U> responseCodec) {
        codec = (BodyCodec<T>) responseCodec;
        return (HttpRequest<U>) this;
    }

    @Override
    public HttpRequest<T> method(HttpMethod value) {
        method = value;
        return this;
    }

    @Override
    public HttpRequest<T> port(int value) {
        port = value;
        return this;
    }

    @Override
    public HttpRequest<T> host(String value) {
        host = value;
        return this;
    }

    @Override
    public HttpRequest<T> uri(String value) {
        params = null;
        uri = value;
        return this;
    }

    @Override
    public HttpRequest<T> putHeader(String name, String value) {
        headers().set(name, value);
        return this;
    }

    @Override
    public MultiMap headers() {
        if (headers == null) {
            headers = new CaseInsensitiveHeaders();
        }
        return headers;
    }

    @Override
    public HttpRequest<T> ssl(boolean value) {
        ssl = value;
        return this;
    }

    @Override
    public HttpRequest<T> timeout(long value) {
        timeout = value;
        return this;
    }

    @Override
    public HttpRequest<T> addQueryParam(String paramName, String paramValue) {
        queryParams().add(paramName, paramValue);
        return this;
    }

    @Override
    public HttpRequest<T> setQueryParam(String paramName, String paramValue) {
        queryParams().set(paramName, paramValue);
        return this;
    }

    @Override
    public HttpRequest<T> followRedirects(boolean value) {
        followRedirects = value;
        return this;
    }

    @Override
    public MultiMap queryParams() {
        if (params == null) {
            params = new CaseInsensitiveHeaders();
        }
        if (params.isEmpty()) {
            int idx = uri.indexOf('?');
            if (idx >= 0) {
                QueryStringDecoder dec = new QueryStringDecoder(uri);
                dec.parameters().forEach((name, value) -> params.add(name, value));
                uri = uri.substring(0, idx);
            }
        }
        return params;
    }

    @Override
    public HttpRequest<T> copy() {
        return new HttpRequestImpl<T>(this);
    }

    @Override
    public void sendStream(ReadStream<Buffer> body, Handler<AsyncResult<HttpResponse<T>>> handler) {
        send(null, body, handler);
    }

    @Override
    public void send(Handler<AsyncResult<HttpResponse<T>>> handler) {
        send(null, null, handler);
    }

    @Override
    public void sendBuffer(Buffer body, Handler<AsyncResult<HttpResponse<T>>> handler) {
        send(null, body, handler);
    }

    @Override
    public void sendJsonObject(JsonObject body, Handler<AsyncResult<HttpResponse<T>>> handler) {
        send("application/json", body, handler);
    }

    @Override
    public void sendJson(Object body, Handler<AsyncResult<HttpResponse<T>>> handler) {
        send("application/json", body, handler);
    }

    @Override
    public void sendForm(MultiMap body, Handler<AsyncResult<HttpResponse<T>>> handler) {
        send("application/x-www-form-urlencoded", body, handler);
    }

    private void send(String contentType, Object body, Handler<AsyncResult<HttpResponse<T>>> handler) {

        Future<HttpClientResponse> responseFuture = Future.<HttpClientResponse>future().setHandler(ar -> {
            if (ar.succeeded()) {
                HttpClientResponse resp = ar.result();
                Future<HttpResponse<T>> fut = Future.future();
                fut.setHandler(handler);
                resp.exceptionHandler(err -> {
                    if (!fut.isComplete()) {
                        fut.fail(err);
                    }
                });
                resp.pause();
                codec.create(ar2 -> {
                    resp.resume();
                    if (ar2.succeeded()) {
                        BodyStream<T> stream = ar2.result();
                        stream.exceptionHandler(err -> {
                            if (!fut.isComplete()) {
                                fut.fail(err);
                            }
                        });
                        resp.endHandler(v -> {
                            if (!fut.isComplete()) {
                                stream.end();
                                if (stream.result().succeeded()) {
                                    fut.complete(new HttpResponseImpl<>(resp, null, stream.result().result()));
                                } else {
                                    fut.fail(stream.result().cause());
                                }
                            }
                        });
                        Pump responsePump = Pump.pump(resp, stream);
                        responsePump.start();
                    } else {
                        handler.handle(Future.failedFuture(ar2.cause()));
                    }
                });
            } else {
                handler.handle(Future.failedFuture(ar.cause()));
            }
        });

        HttpClientRequest req;
        String requestURI;
        if (params != null && params.size() > 0) {
            QueryStringEncoder enc = new QueryStringEncoder(uri);
            params.forEach(param -> {
                enc.addParam(param.getKey(), param.getValue());
            });
            requestURI = enc.toString();
        } else {
            requestURI = uri;
        }
        if (ssl != options.isSsl()) {
            req = client.request(method,
                    new RequestOptions().setSsl(ssl).setHost(host).setPort(port).setURI(requestURI));
        } else {
            req = client.request(method, port, host, requestURI);
        }
        req.setFollowRedirects(followRedirects);
        if (headers != null) {
            req.headers().addAll(headers);
        }
        req.exceptionHandler(err -> {
            if (!responseFuture.isComplete()) {
                responseFuture.fail(err);
            }
        });
        req.handler(resp -> {
            if (!responseFuture.isComplete()) {
                responseFuture.complete(resp);
            }
        });
        if (timeout > 0) {
            req.setTimeout(timeout);
        }
        if (body != null) {
            if (contentType != null) {
                String prev = req.headers().get(HttpHeaders.CONTENT_TYPE);
                if (prev == null) {
                    req.putHeader(HttpHeaders.CONTENT_TYPE, contentType);
                } else {
                    contentType = prev;
                }
            }
            if (body instanceof ReadStream<?>) {
                ReadStream<Buffer> stream = (ReadStream<Buffer>) body;
                if (headers == null || !headers.contains(HttpHeaders.CONTENT_LENGTH)) {
                    req.setChunked(true);
                }
                Pump pump = Pump.pump(stream, req);
                stream.exceptionHandler(err -> {
                    req.reset();
                    if (!responseFuture.isComplete()) {
                        responseFuture.fail(err);
                    }
                });
                stream.endHandler(v -> {
                    pump.stop();
                    req.end();
                });
                pump.start();
            } else {
                Buffer buffer;
                if (body instanceof Buffer) {
                    buffer = (Buffer) body;
                } else if (body instanceof MultiMap) {
                    try {
                        MultiMap attributes = (MultiMap) body;
                        boolean multipart = "multipart/form-data".equals(contentType);
                        DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1,
                                io.netty.handler.codec.http.HttpMethod.POST, "/");
                        HttpPostRequestEncoder encoder = new HttpPostRequestEncoder(request, multipart);
                        for (Map.Entry<String, String> attribute : attributes) {
                            encoder.addBodyAttribute(attribute.getKey(), attribute.getValue());
                        }
                        encoder.finalizeRequest();
                        for (String headerName : request.headers().names()) {
                            req.putHeader(headerName, request.headers().get(headerName));
                        }
                        if (encoder.isChunked()) {
                            buffer = Buffer.buffer();
                            while (true) {
                                HttpContent chunk = encoder.readChunk(new UnpooledByteBufAllocator(false));
                                ByteBuf content = chunk.content();
                                if (content.readableBytes() == 0) {
                                    break;
                                }
                                buffer.appendBuffer(Buffer.buffer(content));
                            }
                        } else {
                            ByteBuf content = request.content();
                            buffer = Buffer.buffer(content);
                        }
                    } catch (Exception e) {
                        throw new VertxException(e);
                    }
                } else if (body instanceof JsonObject) {
                    buffer = Buffer.buffer(((JsonObject) body).encode());
                } else {
                    buffer = Buffer.buffer(Json.encode(body));
                }
                req.end(buffer);
            }
        } else {
            req.end();
        }
    }
}