
org.asynchttpclient.RequestBuilderBase Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of async-http-client Show documentation
Show all versions of async-http-client Show documentation
The Async Http Client (AHC) classes.
/*
* Copyright 2010-2013 Ning, Inc.
*
* This program is licensed to you 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 org.asynchttpclient;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.resolver.DefaultNameResolver;
import io.netty.resolver.NameResolver;
import io.netty.util.concurrent.ImmediateEventExecutor;
import org.asynchttpclient.channel.ChannelPoolPartitioning;
import org.asynchttpclient.proxy.ProxyServer;
import org.asynchttpclient.request.body.generator.BodyGenerator;
import org.asynchttpclient.request.body.multipart.Part;
import org.asynchttpclient.uri.Uri;
import org.asynchttpclient.util.EnsuresNonNull;
import org.asynchttpclient.util.UriEncoder;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.InputStream;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.asynchttpclient.util.HttpUtils.extractContentTypeCharsetAttribute;
import static org.asynchttpclient.util.MiscUtils.isNonEmpty;
import static org.asynchttpclient.util.MiscUtils.withDefault;
/**
* Builder for {@link Request}
*
* @param the builder type
*/
public abstract class RequestBuilderBase> {
private static final Logger LOGGER = LoggerFactory.getLogger(RequestBuilderBase.class);
private static final Uri DEFAULT_REQUEST_URL = Uri.create("http://localhost");
public static final NameResolver DEFAULT_NAME_RESOLVER = new DefaultNameResolver(ImmediateEventExecutor.INSTANCE);
// builder only fields
protected UriEncoder uriEncoder;
protected @Nullable List queryParams;
protected @Nullable SignatureCalculator signatureCalculator;
// request fields
protected String method;
protected @Nullable Uri uri;
protected @Nullable InetAddress address;
protected @Nullable InetAddress localAddress;
protected HttpHeaders headers;
protected @Nullable ArrayList cookies;
protected byte @Nullable [] byteData;
protected @Nullable List compositeByteData;
protected @Nullable String stringData;
protected @Nullable ByteBuffer byteBufferData;
protected @Nullable ByteBuf byteBufData;
protected @Nullable InputStream streamData;
protected @Nullable BodyGenerator bodyGenerator;
protected @Nullable List formParams;
protected @Nullable List bodyParts;
protected @Nullable String virtualHost;
protected @Nullable ProxyServer proxyServer;
protected @Nullable Realm realm;
protected @Nullable File file;
protected @Nullable Boolean followRedirect;
protected @Nullable Duration requestTimeout;
protected @Nullable Duration readTimeout;
protected long rangeOffset;
protected @Nullable Charset charset;
protected ChannelPoolPartitioning channelPoolPartitioning = ChannelPoolPartitioning.PerHostChannelPoolPartitioning.INSTANCE;
protected NameResolver nameResolver = DEFAULT_NAME_RESOLVER;
protected RequestBuilderBase(String method, boolean disableUrlEncoding) {
this(method, disableUrlEncoding, true);
}
protected RequestBuilderBase(String method, boolean disableUrlEncoding, boolean validateHeaders) {
this.method = method;
uriEncoder = UriEncoder.uriEncoder(disableUrlEncoding);
headers = new DefaultHttpHeaders(validateHeaders);
}
protected RequestBuilderBase(Request prototype) {
this(prototype, false, false);
}
protected RequestBuilderBase(Request prototype, boolean disableUrlEncoding, boolean validateHeaders) {
method = prototype.getMethod();
uriEncoder = UriEncoder.uriEncoder(disableUrlEncoding);
uri = prototype.getUri();
address = prototype.getAddress();
localAddress = prototype.getLocalAddress();
headers = new DefaultHttpHeaders(validateHeaders);
headers.add(prototype.getHeaders());
if (isNonEmpty(prototype.getCookies())) {
cookies = new ArrayList<>(prototype.getCookies());
}
byteData = prototype.getByteData();
compositeByteData = prototype.getCompositeByteData();
stringData = prototype.getStringData();
byteBufferData = prototype.getByteBufferData();
byteBufData = prototype.getByteBufData();
streamData = prototype.getStreamData();
bodyGenerator = prototype.getBodyGenerator();
if (isNonEmpty(prototype.getFormParams())) {
formParams = new ArrayList<>(prototype.getFormParams());
}
if (isNonEmpty(prototype.getBodyParts())) {
bodyParts = new ArrayList<>(prototype.getBodyParts());
}
virtualHost = prototype.getVirtualHost();
proxyServer = prototype.getProxyServer();
realm = prototype.getRealm();
file = prototype.getFile();
followRedirect = prototype.getFollowRedirect();
requestTimeout = prototype.getRequestTimeout();
readTimeout = prototype.getReadTimeout();
rangeOffset = prototype.getRangeOffset();
charset = prototype.getCharset();
channelPoolPartitioning = prototype.getChannelPoolPartitioning();
nameResolver = prototype.getNameResolver();
}
@SuppressWarnings("unchecked")
private T asDerivedType() {
return (T) this;
}
public T setUrl(String url) {
return setUri(Uri.create(url));
}
public T setUri(Uri uri) {
this.uri = uri;
return asDerivedType();
}
public T setAddress(InetAddress address) {
this.address = address;
return asDerivedType();
}
public T setLocalAddress(InetAddress address) {
localAddress = address;
return asDerivedType();
}
public T setVirtualHost(String virtualHost) {
this.virtualHost = virtualHost;
return asDerivedType();
}
/**
* Remove all added headers
*
* @return {@code this}
*/
public T clearHeaders() {
headers.clear();
return asDerivedType();
}
/**
* @param name header name
* @param value header value to set
* @return {@code this}
* @see #setHeader(CharSequence, Object)
*/
public T setHeader(CharSequence name, String value) {
return setHeader(name, (Object) value);
}
/**
* Set uni-value header for the request
*
* @param name header name
* @param value header value to set
* @return {@code this}
*/
public T setHeader(CharSequence name, Object value) {
headers.set(name, value);
return asDerivedType();
}
/**
* Set multi-values header for the request
*
* @param name header name
* @param values {@code Iterable} with multiple header values to set
* @return {@code this}
*/
public T setHeader(CharSequence name, Iterable> values) {
headers.set(name, values);
return asDerivedType();
}
/**
* @param name header name
* @param value header value to add
* @return {@code this}
* @see #addHeader(CharSequence, Object)
*/
public T addHeader(CharSequence name, String value) {
return addHeader(name, (Object) value);
}
/**
* Add a header value for the request. If a header with {@code name} was set up for this request already -
* call will add one more header value and convert it to multi-value header
*
* @param name header name
* @param value header value to add
* @return {@code this}
*/
public T addHeader(CharSequence name, Object value) {
if (value == null) {
LOGGER.warn("Value was null, set to \"\"");
value = "";
}
headers.add(name, value);
return asDerivedType();
}
/**
* Add header values for the request. If a header with {@code name} was set up for this request already -
* call will add more header values and convert it to multi-value header
*
* @param name header name
* @param values {@code Iterable} with multiple header values to add
* @return {@code}
*/
public T addHeader(CharSequence name, Iterable> values) {
headers.add(name, values);
return asDerivedType();
}
public T setHeaders(HttpHeaders headers) {
if (headers == null) {
this.headers.clear();
} else {
this.headers = headers;
}
return asDerivedType();
}
/**
* Set request headers using a map {@code headers} of pair (Header name, Header values)
* This method could be used to set up multivalued headers
*
* @param headers map of header names as the map keys and header values {@link Iterable} as the map values
* @return {@code this}
*/
public T setHeaders(Map extends CharSequence, ? extends Iterable>> headers) {
clearHeaders();
if (headers != null) {
headers.forEach((name, values) -> this.headers.add(name, values));
}
return asDerivedType();
}
/**
* Set single-value request headers using a map {@code headers} of pairs (Header name, Header value).
* To set headers with multiple values use {@link #setHeaders(Map)}
*
* @param headers map of header names as the map keys and header values as the map values
* @return {@code this}
*/
public T setSingleHeaders(Map extends CharSequence, ?> headers) {
clearHeaders();
if (headers != null) {
headers.forEach((name, value) -> this.headers.add(name, value));
}
return asDerivedType();
}
@EnsuresNonNull("cookies")
private void lazyInitCookies() {
if (cookies == null) {
cookies = new ArrayList<>(3);
}
}
public T setCookies(Collection cookies) {
this.cookies = new ArrayList<>(cookies);
return asDerivedType();
}
public T addCookie(Cookie cookie) {
lazyInitCookies();
cookies.add(cookie);
return asDerivedType();
}
/**
* Add/replace a cookie based on its name
*
* @param cookie the new cookie
* @return this
*/
public T addOrReplaceCookie(Cookie cookie) {
return maybeAddOrReplaceCookie(cookie, true);
}
/**
* Add a cookie based on its name, if it does not exist yet. Cookies that
* are already set will be ignored.
*
* @param cookie the new cookie
* @return this
*/
public T addCookieIfUnset(Cookie cookie) {
return maybeAddOrReplaceCookie(cookie, false);
}
private T maybeAddOrReplaceCookie(Cookie cookie, boolean allowReplace) {
String cookieKey = cookie.name();
boolean replace = false;
int index = 0;
lazyInitCookies();
for (Cookie c : cookies) {
if (c.name().equals(cookieKey)) {
replace = true;
break;
}
index++;
}
if (!replace) {
cookies.add(cookie);
} else if (allowReplace) {
cookies.set(index, cookie);
}
return asDerivedType();
}
public void resetCookies() {
if (cookies != null) {
cookies.clear();
}
}
public void resetQuery() {
queryParams = null;
if (uri != null) {
uri = uri.withNewQuery(null);
}
}
public void resetFormParams() {
formParams = null;
}
public void resetNonMultipartData() {
byteData = null;
compositeByteData = null;
byteBufferData = null;
byteBufData = null;
stringData = null;
streamData = null;
bodyGenerator = null;
}
public void resetMultipartData() {
bodyParts = null;
}
public T setBody(File file) {
this.file = file;
return asDerivedType();
}
private void resetBody() {
resetFormParams();
resetNonMultipartData();
resetMultipartData();
}
public T setBody(byte[] data) {
resetBody();
byteData = data;
return asDerivedType();
}
public T setBody(List data) {
resetBody();
compositeByteData = data;
return asDerivedType();
}
public T setBody(String data) {
resetBody();
stringData = data;
return asDerivedType();
}
public T setBody(ByteBuffer data) {
resetBody();
byteBufferData = data;
return asDerivedType();
}
public T setBody(ByteBuf data) {
resetBody();
byteBufData = data;
return asDerivedType();
}
public T setBody(InputStream stream) {
resetBody();
streamData = stream;
return asDerivedType();
}
public T setBody(BodyGenerator bodyGenerator) {
this.bodyGenerator = bodyGenerator;
return asDerivedType();
}
@EnsuresNonNull("queryParams")
public T addQueryParam(String name, String value) {
if (queryParams == null) {
queryParams = new ArrayList<>(1);
}
queryParams.add(new Param(name, value));
return asDerivedType();
}
@EnsuresNonNull("queryParams")
public T addQueryParams(List params) {
if (queryParams == null) {
queryParams = params;
} else {
queryParams.addAll(params);
}
return asDerivedType();
}
public T setQueryParams(Map> map) {
return setQueryParams(Param.map2ParamList(map));
}
public T setQueryParams(@Nullable List params) {
// reset existing query
if (uri != null && isNonEmpty(uri.getQuery())) {
uri = uri.withNewQuery(null);
}
queryParams = params;
return asDerivedType();
}
@EnsuresNonNull("formParams")
public T addFormParam(String name, String value) {
resetNonMultipartData();
resetMultipartData();
if (formParams == null) {
formParams = new ArrayList<>(1);
}
formParams.add(new Param(name, value));
return asDerivedType();
}
public T setFormParams(Map> map) {
return setFormParams(Param.map2ParamList(map));
}
public T setFormParams(@Nullable List params) {
resetNonMultipartData();
resetMultipartData();
formParams = params;
return asDerivedType();
}
@EnsuresNonNull("bodyParts")
public T addBodyPart(Part bodyPart) {
resetFormParams();
resetNonMultipartData();
if (bodyParts == null) {
bodyParts = new ArrayList<>();
}
bodyParts.add(bodyPart);
return asDerivedType();
}
@EnsuresNonNull("bodyParts")
public T setBodyParts(List bodyParts) {
this.bodyParts = new ArrayList<>(bodyParts);
return asDerivedType();
}
public T setProxyServer(ProxyServer proxyServer) {
this.proxyServer = proxyServer;
return asDerivedType();
}
public T setProxyServer(ProxyServer.Builder proxyServerBuilder) {
proxyServer = proxyServerBuilder.build();
return asDerivedType();
}
public T setRealm(Realm.Builder realm) {
this.realm = realm.build();
return asDerivedType();
}
public T setRealm(Realm realm) {
this.realm = realm;
return asDerivedType();
}
public T setFollowRedirect(boolean followRedirect) {
this.followRedirect = followRedirect;
return asDerivedType();
}
public T setRequestTimeout(Duration requestTimeout) {
this.requestTimeout = requestTimeout;
return asDerivedType();
}
public T setReadTimeout(Duration readTimeout) {
this.readTimeout = readTimeout;
return asDerivedType();
}
public T setRangeOffset(long rangeOffset) {
this.rangeOffset = rangeOffset;
return asDerivedType();
}
public T setMethod(String method) {
this.method = method;
return asDerivedType();
}
public T setCharset(Charset charset) {
this.charset = charset;
return asDerivedType();
}
public T setChannelPoolPartitioning(ChannelPoolPartitioning channelPoolPartitioning) {
this.channelPoolPartitioning = channelPoolPartitioning;
return asDerivedType();
}
public T setNameResolver(NameResolver nameResolver) {
this.nameResolver = nameResolver;
return asDerivedType();
}
public T setSignatureCalculator(@Nullable SignatureCalculator signatureCalculator) {
this.signatureCalculator = signatureCalculator;
return asDerivedType();
}
private RequestBuilderBase> executeSignatureCalculator() {
if (signatureCalculator == null) {
return this;
}
// build a first version of the request, without signatureCalculator in play
RequestBuilder rb = new RequestBuilder(method);
// make copy of mutable collections, so we don't risk affecting
// original RequestBuilder
// call setFormParams first as it resets other fields
if (formParams != null) {
rb.setFormParams(formParams);
}
if (headers != null) {
rb.headers.add(headers);
}
if (cookies != null) {
rb.setCookies(cookies);
}
if (bodyParts != null) {
rb.setBodyParts(bodyParts);
}
// copy all other fields
// but rb.signatureCalculator, that's the whole point here
rb.uriEncoder = uriEncoder;
rb.queryParams = queryParams;
rb.uri = uri;
rb.address = address;
rb.localAddress = localAddress;
rb.byteData = byteData;
rb.compositeByteData = compositeByteData;
rb.stringData = stringData;
rb.byteBufferData = byteBufferData;
rb.byteBufData = byteBufData;
rb.streamData = streamData;
rb.bodyGenerator = bodyGenerator;
rb.virtualHost = virtualHost;
rb.proxyServer = proxyServer;
rb.realm = realm;
rb.file = file;
rb.followRedirect = followRedirect;
rb.requestTimeout = requestTimeout;
rb.rangeOffset = rangeOffset;
rb.charset = charset;
rb.channelPoolPartitioning = channelPoolPartitioning;
rb.nameResolver = nameResolver;
Request unsignedRequest = rb.build();
signatureCalculator.calculateAndAddSignature(unsignedRequest, rb);
return rb;
}
@EnsuresNonNull("charset")
private void updateCharset() {
String contentTypeHeader = headers.get(CONTENT_TYPE);
Charset contentTypeCharset = extractContentTypeCharsetAttribute(contentTypeHeader);
charset = withDefault(contentTypeCharset, withDefault(charset, UTF_8));
if (contentTypeHeader != null && contentTypeHeader.regionMatches(true, 0, "text/", 0, 5) && contentTypeCharset == null) {
// add explicit charset to content-type header
headers.set(CONTENT_TYPE, contentTypeHeader + "; charset=" + charset.name());
}
}
private Uri computeUri() {
Uri tempUri = uri;
if (tempUri == null) {
LOGGER.debug("setUrl hasn't been invoked. Using {}", DEFAULT_REQUEST_URL);
tempUri = DEFAULT_REQUEST_URL;
} else {
Uri.validateSupportedScheme(tempUri);
}
return uriEncoder.encode(tempUri, queryParams);
}
public Request build() {
updateCharset();
RequestBuilderBase> rb = executeSignatureCalculator();
Uri finalUri = rb.computeUri();
// make copies of mutable internal collections
List cookiesCopy = rb.cookies == null ? Collections.emptyList() : new ArrayList<>(rb.cookies);
List formParamsCopy = rb.formParams == null ? Collections.emptyList() : new ArrayList<>(rb.formParams);
List bodyPartsCopy = rb.bodyParts == null ? Collections.emptyList() : new ArrayList<>(rb.bodyParts);
return new DefaultRequest(rb.method,
finalUri,
rb.address,
rb.localAddress,
rb.headers,
cookiesCopy,
rb.byteData,
rb.compositeByteData,
rb.stringData,
rb.byteBufferData,
rb.byteBufData,
rb.streamData,
rb.bodyGenerator,
formParamsCopy,
bodyPartsCopy,
rb.virtualHost,
rb.proxyServer,
rb.realm,
rb.file,
rb.followRedirect,
rb.requestTimeout,
rb.readTimeout,
rb.rangeOffset,
rb.charset,
rb.channelPoolPartitioning,
rb.nameResolver);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy