io.werval.server.netty.NettyHttpFactories.java Source code

Java tutorial

Introduction

Here is the source code for io.werval.server.netty.NettyHttpFactories.java

Source

/*
 * Copyright (c) 2013-2015 the original author or authors
 *
 * 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.werval.server.netty;

import io.netty.channel.Channel;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.multipart.Attribute;
import io.netty.handler.codec.http.multipart.FileUpload;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.IncompatibleDataDecoderException;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException;
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
import io.werval.api.exceptions.WervalException;
import io.werval.api.http.FormUploads.Upload;
import io.werval.api.http.Headers;
import io.werval.api.http.ProtocolVersion;
import io.werval.api.http.Request;
import io.werval.spi.http.HttpBuildersSPI;
import io.werval.spi.http.HttpBuildersSPI.RequestBuilder;
import io.werval.runtime.http.FormUploadsInstance.UploadInstance;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static io.netty.handler.codec.http.HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED;
import static io.netty.handler.codec.http.HttpHeaders.Values.MULTIPART_FORM_DATA;
import static io.netty.handler.codec.http.HttpMethod.PATCH;
import static io.netty.handler.codec.http.HttpMethod.POST;
import static io.netty.handler.codec.http.HttpMethod.PUT;
import static io.werval.api.http.Headers.Names.CONTENT_TYPE;
import static io.werval.util.IllegalArguments.ensureNotEmpty;
import static io.werval.util.IllegalArguments.ensureNotNull;

/**
 * Factory methods used by the server.
 */
/* package */ final class NettyHttpFactories {
    /* package */ static String remoteAddressOf(Channel channel) {
        SocketAddress remoteAddress = channel.remoteAddress();
        if (remoteAddress == null || !(remoteAddress instanceof InetSocketAddress)) {
            return null;
        }
        InetAddress inetRemoteAddress = ((InetSocketAddress) remoteAddress).getAddress();
        if (inetRemoteAddress == null) {
            return null;
        }
        return inetRemoteAddress.getHostAddress();
    }

    /* package */ static Request requestOf(Charset defaultCharset, HttpBuildersSPI builders,
            String remoteSocketAddress, String identity, FullHttpRequest request)
            throws HttpRequestParsingException {
        ensureNotEmpty("Request Identity", identity);
        ensureNotNull("Netty FullHttpRequest", request);

        try {
            RequestBuilder builder = builders.newRequestBuilder().identifiedBy(identity)
                    .remoteSocketAddress(remoteSocketAddress)
                    .version(ProtocolVersion.valueOf(request.getProtocolVersion().text()))
                    .method(request.getMethod().name()).uri(request.getUri())
                    .headers(headersToMap(request.headers()));

            if (request.content().readableBytes() > 0 && (POST.equals(request.getMethod())
                    || PUT.equals(request.getMethod()) || PATCH.equals(request.getMethod()))) {
                Optional<String> contentType = Headers.extractContentMimeType(request.headers().get(CONTENT_TYPE));
                if (contentType.isPresent()) {
                    switch (contentType.get()) {
                    case APPLICATION_X_WWW_FORM_URLENCODED:
                    case MULTIPART_FORM_DATA:
                        try {
                            Map<String, List<String>> attributes = new LinkedHashMap<>();
                            Map<String, List<Upload>> uploads = new LinkedHashMap<>();
                            HttpPostRequestDecoder postDecoder = new HttpPostRequestDecoder(request);
                            for (InterfaceHttpData data : postDecoder.getBodyHttpDatas()) {
                                switch (data.getHttpDataType()) {
                                case Attribute:
                                    Attribute attribute = (Attribute) data;
                                    if (!attributes.containsKey(attribute.getName())) {
                                        attributes.put(attribute.getName(), new ArrayList<>());
                                    }
                                    attributes.get(attribute.getName()).add(attribute.getValue());
                                    break;
                                case FileUpload:
                                    FileUpload fileUpload = (FileUpload) data;
                                    if (!uploads.containsKey(fileUpload.getName())) {
                                        uploads.put(fileUpload.getName(), new ArrayList<>());
                                    }
                                    Upload upload;
                                    if (fileUpload.isInMemory()) {
                                        upload = new UploadInstance(fileUpload.getContentType(),
                                                fileUpload.getCharset(), fileUpload.getFilename(),
                                                new ByteBufByteSource(fileUpload.getByteBuf()).asBytes(),
                                                defaultCharset);
                                    } else {
                                        upload = new UploadInstance(fileUpload.getContentType(),
                                                fileUpload.getCharset(), fileUpload.getFilename(),
                                                fileUpload.getFile(), defaultCharset);
                                    }
                                    uploads.get(fileUpload.getName()).add(upload);
                                    break;
                                default:
                                    break;
                                }
                            }
                            builder = builder.bodyForm(attributes, uploads);
                            break;
                        } catch (ErrorDataDecoderException | IncompatibleDataDecoderException
                                | NotEnoughDataDecoderException | IOException ex) {
                            throw new WervalException("Form or multipart parsing error", ex);
                        }
                    default:
                        builder = builder.bodyBytes(new ByteBufByteSource(request.content()));
                        break;
                    }
                } else {
                    builder = builder.bodyBytes(new ByteBufByteSource(request.content()));
                }
            }
            return builder.build();
        } catch (Exception ex) {
            throw new HttpRequestParsingException(ex);
        }
    }

    private static Map<String, List<String>> headersToMap(HttpHeaders nettyHeaders) {
        Map<String, List<String>> headers = new HashMap<>();
        for (String name : nettyHeaders.names()) {
            if (!headers.containsKey(name)) {
                headers.put(name, new ArrayList<>());
            }
            for (String value : nettyHeaders.getAll(name)) {
                headers.get(name).add(value);
            }
        }
        return headers;
    }

    private NettyHttpFactories() {
    }
}