org.asynchttpclient.providers.netty.request.NettyRequests.java Source code

Java tutorial

Introduction

Here is the source code for org.asynchttpclient.providers.netty.request.NettyRequests.java

Source

/*
 * Copyright 2010-2013 Ning, Inc.
 *
 * Ning licenses this file 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.providers.netty.request;

import static org.asynchttpclient.providers.netty.util.HttpUtil.*;
import static org.asynchttpclient.util.AsyncHttpProviderUtils.DEFAULT_CHARSET;
import static org.asynchttpclient.util.MiscUtil.isNonEmpty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpVersion;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.asynchttpclient.AsyncHttpClientConfig;
import org.asynchttpclient.ProxyServer;
import org.asynchttpclient.Realm;
import org.asynchttpclient.Request;
import org.asynchttpclient.multipart.MultipartRequestEntity;
import org.asynchttpclient.ntlm.NTLMEngine;
import org.asynchttpclient.ntlm.NTLMEngineException;
import org.asynchttpclient.org.jboss.netty.handler.codec.http.CookieEncoder;
import org.asynchttpclient.providers.netty.NettyAsyncHttpProvider;
import org.asynchttpclient.providers.netty.ws.WebSocketUtil;
import org.asynchttpclient.spnego.SpnegoEngine;
import org.asynchttpclient.util.AsyncHttpProviderUtils;
import org.asynchttpclient.util.AuthenticatorUtils;
import org.asynchttpclient.util.UTF8UrlEncoder;

public class NettyRequests {

    public static final String GZIP_DEFLATE = HttpHeaders.Values.GZIP + "," + HttpHeaders.Values.DEFLATE;

    public static HttpRequest newNettyRequest(AsyncHttpClientConfig config, Request request, URI uri,
            boolean allowConnect, ProxyServer proxyServer) throws IOException {

        HttpMethod method = null;
        if (allowConnect && proxyServer != null && isSecure(uri))
            method = HttpMethod.CONNECT;
        else
            method = HttpMethod.valueOf(request.getMethod());

        String host = null;
        HttpVersion httpVersion;
        String requestUri;
        Map<String, Object> headers = new HashMap<String, Object>();
        String authorizationHeader = null;
        ByteBuf content = null;
        boolean webSocket = isWebSocket(uri);

        if (request.getVirtualHost() != null) {
            host = request.getVirtualHost();
        } else {
            host = AsyncHttpProviderUtils.getHost(uri);
        }

        if (method == HttpMethod.CONNECT) {
            httpVersion = HttpVersion.HTTP_1_0;
            requestUri = AsyncHttpProviderUtils.getAuthority(uri);
        } else {
            httpVersion = HttpVersion.HTTP_1_1;
            if (proxyServer != null && !(isSecure(uri) && config.isUseRelativeURIsWithSSLProxies()))
                requestUri = uri.toString();
            else if (uri.getRawQuery() != null)
                requestUri = uri.getRawPath() + "?" + uri.getRawQuery();
            else
                requestUri = uri.getRawPath();
        }

        if (webSocket) {
            headers.put(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET);
            headers.put(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE);
            headers.put(HttpHeaders.Names.ORIGIN, "http://" + uri.getHost() + ":"
                    + (uri.getPort() == -1 ? isSecure(uri.getScheme()) ? 443 : 80 : uri.getPort()));
            headers.put(HttpHeaders.Names.SEC_WEBSOCKET_KEY, WebSocketUtil.getKey());
            headers.put(HttpHeaders.Names.SEC_WEBSOCKET_VERSION, "13");
        }

        if (host != null) {
            if (request.getVirtualHost() != null || uri.getPort() == -1) {
                headers.put(HttpHeaders.Names.HOST, host);
            } else {
                headers.put(HttpHeaders.Names.HOST, host + ":" + uri.getPort());
            }
        } else {
            host = "127.0.0.1";
        }

        if (method != HttpMethod.CONNECT) {
            if (config.isCompressionEnabled()) {
                headers.put(HttpHeaders.Names.ACCEPT_ENCODING, GZIP_DEFLATE);
            }
        } else {
            List<String> auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION);
            if (isNTLM(auth)) {
                headers.put(HttpHeaders.Names.PROXY_AUTHORIZATION, auth.get(0));
            }
        }
        Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm();

        if (realm != null && realm.getUsePreemptiveAuth()) {

            String domain = realm.getNtlmDomain();
            if (proxyServer != null && proxyServer.getNtlmDomain() != null) {
                domain = proxyServer.getNtlmDomain();
            }

            String authHost = realm.getNtlmHost();
            if (proxyServer != null && proxyServer.getHost() != null) {
                host = proxyServer.getHost();
            }

            switch (realm.getAuthScheme()) {
            case BASIC:
                authorizationHeader = AuthenticatorUtils.computeBasicAuthentication(realm);
                break;
            case DIGEST:
                if (isNonEmpty(realm.getNonce())) {
                    try {
                        authorizationHeader = AuthenticatorUtils.computeDigestAuthentication(realm);
                    } catch (NoSuchAlgorithmException e) {
                        throw new SecurityException(e);
                    }
                }
                break;
            case NTLM:
                try {
                    String msg = NTLMEngine.INSTANCE.generateType1Msg("NTLM " + domain, authHost);
                    authorizationHeader = "NTLM " + msg;
                } catch (NTLMEngineException e) {
                    throw new IOException(e);
                }
                break;
            case KERBEROS:
            case SPNEGO:
                String challengeHeader = null;
                String server = proxyServer == null ? host : proxyServer.getHost();
                try {
                    challengeHeader = SpnegoEngine.instance().generateToken(server);
                } catch (Throwable e) {
                    throw new IOException(e);
                }
                authorizationHeader = "Negotiate " + challengeHeader;
                break;
            case NONE:
                break;
            default:
                throw new IllegalStateException("Invalid Authentication " + realm);
            }
        }

        if (!webSocket && !request.getHeaders().containsKey(HttpHeaders.Names.CONNECTION)) {
            headers.put(HttpHeaders.Names.CONNECTION, AsyncHttpProviderUtils.keepAliveHeaderValue(config));
        }

        if (proxyServer != null) {
            // FIXME Wikipedia says that Proxy-Connection was a misunderstanding of Connection http://en.wikipedia.org/wiki/List_of_HTTP_header_fields
            if (!request.getHeaders().containsKey("Proxy-Connection")) {
                headers.put("Proxy-Connection", AsyncHttpProviderUtils.keepAliveHeaderValue(config));
            }

            if (proxyServer.getPrincipal() != null) {
                if (isNonEmpty(proxyServer.getNtlmDomain())) {

                    List<String> auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION);
                    if (!isNTLM(auth)) {
                        try {
                            String msg = NTLMEngine.INSTANCE.generateType1Msg(proxyServer.getNtlmDomain(),
                                    proxyServer.getHost());
                            headers.put(HttpHeaders.Names.PROXY_AUTHORIZATION, "NTLM " + msg);
                        } catch (NTLMEngineException e) {
                            IOException ie = new IOException();
                            ie.initCause(e);
                            throw ie;
                        }
                    }
                } else {
                    headers.put(HttpHeaders.Names.PROXY_AUTHORIZATION,
                            AuthenticatorUtils.computeBasicAuthentication(proxyServer));
                }
            }
        }

        // Add default accept headers
        if (!request.getHeaders().containsKey(HttpHeaders.Names.ACCEPT)) {
            headers.put(HttpHeaders.Names.ACCEPT, "*/*");
        }

        String userAgentHeader = request.getHeaders().getFirstValue(HttpHeaders.Names.USER_AGENT);
        if (userAgentHeader != null) {
            headers.put(HttpHeaders.Names.USER_AGENT, userAgentHeader);
        } else if (config.getUserAgent() != null) {
            headers.put(HttpHeaders.Names.USER_AGENT, config.getUserAgent());
        } else {
            headers.put(HttpHeaders.Names.USER_AGENT,
                    AsyncHttpProviderUtils.constructUserAgent(NettyAsyncHttpProvider.class, config));
        }

        boolean hasDeferredContent = false;
        if (method != HttpMethod.CONNECT) {
            if (isNonEmpty(request.getCookies())) {
                headers.put(HttpHeaders.Names.COOKIE,
                        CookieEncoder.encodeClientSide(request.getCookies(), config.isRfc6265CookieEncoding()));
            }

            String bodyCharset = request.getBodyEncoding() == null ? DEFAULT_CHARSET : request.getBodyEncoding();

            if (request.getByteData() != null) {
                headers.put(HttpHeaders.Names.CONTENT_LENGTH, request.getByteData().length);
                content = Unpooled.wrappedBuffer(request.getByteData());

            } else if (request.getStringData() != null) {
                byte[] bytes = request.getStringData().getBytes(bodyCharset);
                headers.put(HttpHeaders.Names.CONTENT_LENGTH, bytes.length);
                content = Unpooled.wrappedBuffer(bytes);

            } else if (request.getStreamData() != null) {
                hasDeferredContent = true;
                headers.put(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED);

            } else if (isNonEmpty(request.getParams())) {
                StringBuilder sb = new StringBuilder();
                for (final Entry<String, List<String>> paramEntry : request.getParams()) {
                    final String key = paramEntry.getKey();
                    for (final String value : paramEntry.getValue()) {
                        UTF8UrlEncoder.appendEncoded(sb, key);
                        sb.append("=");
                        UTF8UrlEncoder.appendEncoded(sb, value);
                        sb.append("&");
                    }
                }
                sb.setLength(sb.length() - 1);
                byte[] bytes = sb.toString().getBytes(bodyCharset);
                headers.put(HttpHeaders.Names.CONTENT_LENGTH, bytes.length);
                content = Unpooled.wrappedBuffer(bytes);

                if (!request.getHeaders().containsKey(HttpHeaders.Names.CONTENT_TYPE)) {
                    headers.put(HttpHeaders.Names.CONTENT_TYPE,
                            HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED);
                }

            } else if (request.getParts() != null) {
                // FIXME use Netty multipart
                MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity(request.getParts(),
                        request.getHeaders());

                headers.put(HttpHeaders.Names.CONTENT_TYPE, mre.getContentType());
                if (mre.getContentLength() >= 0) {
                    headers.put(HttpHeaders.Names.CONTENT_LENGTH, mre.getContentLength());
                }
                hasDeferredContent = true;

            } else if (request.getFile() != null) {
                File file = request.getFile();
                if (!file.isFile()) {
                    throw new IOException(
                            String.format("File %s is not a file or doesn't exist", file.getAbsolutePath()));
                }
                headers.put(HttpHeaders.Names.CONTENT_LENGTH, file.length());
                hasDeferredContent = true;

            } else if (request.getBodyGenerator() != null) {
                hasDeferredContent = true;
            }
        }

        HttpRequest nettyRequest;
        if (hasDeferredContent) {
            nettyRequest = new DefaultHttpRequest(httpVersion, method, requestUri);
        } else if (content != null) {
            nettyRequest = new DefaultFullHttpRequest(httpVersion, method, requestUri, content);
        } else {
            nettyRequest = new DefaultFullHttpRequest(httpVersion, method, requestUri);
        }

        // assign headers as configured on request
        if (method != HttpMethod.CONNECT) {
            for (Entry<String, List<String>> header : request.getHeaders()) {
                nettyRequest.headers().set(header.getKey(), header.getValue());
            }
        }

        // override with computed ones
        for (Entry<String, Object> header : headers.entrySet()) {
            nettyRequest.headers().set(header.getKey(), header.getValue());
        }

        if (authorizationHeader != null) {
            // don't override authorization but append
            nettyRequest.headers().add(HttpHeaders.Names.AUTHORIZATION, authorizationHeader);
        }

        return nettyRequest;
    }
}