All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.micronaut.http.server.netty.handler.accesslog.element.ConnectionMetadata Maven / Gradle / Ivy

There is a newer version: 4.7.9
Show newest version
/*
 * Copyright 2017-2024 original 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
 *
 * https://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.micronaut.http.server.netty.handler.accesslog.element;

import io.micronaut.core.annotation.NonNull;
import io.netty.channel.Channel;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioDomainSocketChannel;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnixDomainSocketAddress;
import java.util.Optional;

/**
 * Connection-level metadata for logging e.g. addresses or ports.
 *
 * @since 4.6.0
 * @author Jonas Konrad
 */
public interface ConnectionMetadata {
    /**
     * The local address of this connection, if applicable.
     *
     * @return The local address
     */
    @NonNull
    Optional localAddress();

    /**
     * The remote address of this connection, if applicable.
     *
     * @return The remote address
     */
    @NonNull
    Optional remoteAddress();

    /**
     * Get the host address string of the given {@link SocketAddress} instance. This is usually the
     * numeric IP, but for unix domain socket it is the file path.
     *
     * @param a The address
     * @return The string representation, or {@link Optional#empty()} if this type of address is
     * not supported
     */
    static Optional getHostAddress(@NonNull SocketAddress a) {
        if (a instanceof InetSocketAddress addr) {
            return Optional.of(addr.getAddress().getHostAddress());
        } else {
            return getHostName(a);
        }
    }

    /**
     * Get the host name of the given {@link SocketAddress} instance. This is usually the DNS name
     * or IP, but for unix domain socket it is the file path.
     *
     * @param a The address
     * @return The string representation, or {@link Optional#empty()} if this type of address is
     * not supported
     */
    static Optional getHostName(@NonNull SocketAddress a) {
        if (a instanceof InetSocketAddress addr) {
            return Optional.of(addr.getAddress().getHostName());
        } else if (a instanceof UnixDomainSocketAddress addr) {
            return Optional.of(addr.getPath().toString())
                // remote address is empty string
                .filter(s -> !s.isEmpty());
        } else if (ConnectionMetadataImpl.DOMAIN_SOCKET_ADDRESS.isInstance(a)) {
            String path = ConnectionMetadataImpl.DomainSocketUtil.getPath(a);
            if (path.isEmpty() || path.equals("\0")) {
                return Optional.empty();
            }
            if (path.startsWith("\0")) {
                // *abstract* unix domain sockets start with a NUL byte
                path = "@" + path.substring(1);
            }
            return Optional.of(path);
        } else {
            return Optional.empty();
        }
    }

    /**
     * Create a new {@link ConnectionMetadata} instance for the given netty channel.
     *
     * @param channel The channel
     * @return The metadata, potentially {@link #empty()}
     */
    @NonNull
    static ConnectionMetadata ofNettyChannel(@NonNull Channel channel) {
        if (channel instanceof SocketChannel sc) {
            return new ConnectionMetadataImpl.SocketChannelMetadata(sc);
        } else if (ConnectionMetadataImpl.QUIC_CHANNEL != null && ConnectionMetadataImpl.QUIC_CHANNEL.isInstance(channel)) {
            return new ConnectionMetadataImpl.QuicChannelMetadata(channel);
        } else if (channel instanceof DatagramChannel || channel instanceof NioDomainSocketChannel || (ConnectionMetadataImpl.DOMAIN_SOCKET_CHANNEL != null && ConnectionMetadataImpl.DOMAIN_SOCKET_CHANNEL.isInstance(channel))) {
            return new ConnectionMetadataImpl.GenericChannelMetadata(channel);
        } else if (channel.parent() != null) {
            // QUIC / HTTP/2 stream channels
            return ofNettyChannel(channel.parent());
        } else {
            return empty();
        }
    }

    /**
     * Placeholder metadata for unsupported channel types.
     *
     * @return An empty metadata instance
     */
    @NonNull
    static ConnectionMetadata empty() {
        return ConnectionMetadataImpl.Empty.INSTANCE;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy