/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2014 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * 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 org.wildfly.security.util;

import static org.wildfly.security._private.ElytronMessages.log;

import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;

/**
 * Utilities for URI manipulation and canonicalization.
 *
 * @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
 */
public final class URIUtil {
    private URIUtil() {}

    /**
     * Get the URI-friendly host name for the given socket address, without doing a reverse lookup under any circumstances.
     *
     * @param socketAddress the destination socket address
     * @return the URI host string
     */
    public static String getHostForURI(SocketAddress socketAddress) {
        if (socketAddress instanceof InetSocketAddress) {
            final InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress;
            final String hostString = inetSocketAddress.getHostString();
            final InetAddress address = inetSocketAddress.getAddress();
            if (address instanceof Inet6Address && hostString.equals(address.getHostAddress())) {
                return "[" + address.getHostAddress() + "]";
            } else {
                return hostString;
            }
        }
        throw log.invalidSocketAddressTypeForUri();
    }

    /**
     * Get the port number for the given socket address.  If the port number matches the given default port, then -1
     * is returned to allow the URI to use the default value.
     *
     * @param socketAddress the destination socket address
     * @param defaultPort the default port number for the URI scheme, or -1 if there is none or it is unknown
     * @return the URI port number
     */
    public static int getPortForURI(SocketAddress socketAddress, int defaultPort) {
        if (socketAddress instanceof InetSocketAddress) {
            final InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress;
            final int port = inetSocketAddress.getPort();
            if (port == defaultPort) {
                return -1;
            } else {
                return port;
            }
        }
        throw log.invalidSocketAddressTypeForUri();
    }

    /**
     * Create a URI from a socket address and additional information.
     *
     * @param scheme the URI scheme
     * @param socketAddress the destination socket address
     * @param defaultPort the scheme default port, or -1 if there is no standard default port
     * @return the URI
     * @throws URISyntaxException if the URI construction failed for some reason
     */
    public static URI createURI(String scheme, SocketAddress socketAddress, int defaultPort) throws URISyntaxException {
        return new URI(scheme, null, getHostForURI(socketAddress), getPortForURI(socketAddress, defaultPort), null, null, null);
    }

    /**
     * Create a URI from a socket address and additional information.
     *
     * @param scheme the URI scheme
     * @param socketAddress the destination socket address
     * @return the URI
     * @throws URISyntaxException if the URI construction failed for some reason
     */
    public static URI createURI(String scheme, SocketAddress socketAddress) throws URISyntaxException {
        return createURI(scheme, socketAddress, -1);
    }

    /**
     * Get the user name information from a URI, if any.
     *
     * @param uri the URI
     * @return the user name, or {@code null} if the URI did not contain a recoverable user name
     */
    public static String getUserFromURI(URI uri) {
        final String userInfo = uri.getUserInfo();
        if (userInfo != null) {
            return userInfo;
        }
        if ("domain".equals(uri.getScheme())) {
            final String ssp = uri.getSchemeSpecificPart();
            final int at = ssp.lastIndexOf('@');
            if (at == -1) {
                return null;
            }
            return ssp.substring(0, at);
        }
        return null;
    }

    /**
     * Get an Internet address for a URI destination, resolving the host name if necessary.
     *
     * @param uri the destination URI
     * @return the socket address, or {@code null} if no authority is present in the URI
     * @throws UnknownHostException if the URI host was existent but could not be resolved to a valid address
     */
    public static InetAddress getDestinationInetAddress(URI uri) throws UnknownHostException {
        final String host = uri.getHost();
        if (host == null) {
            return null;
        }
        final int length = host.length();
        if (length == 0) {
            return null;
        }
        return InetAddress.getByName(host);
    }

    /**
     * Get a socket address for a URI destination, resolving the host name if necessary.  If the host name could not
     * be resolved, an {@linkplain InetSocketAddress#isUnresolved() unresolved} address is returned.
     *
     * @param uri the destination URI
     * @param defaultPort the default port number for the URI scheme, or -1 if there is none or it is unknown
     * @return the socket address, or {@code null} if no authority is present in the URI or no port number could be determined
     */
    public static InetSocketAddress getDestinationInetSocketAddress(URI uri, int defaultPort) {
        final String host = uri.getHost();
        if (host == null) {
            return null;
        }
        final int length = host.length();
        if (length == 0) {
            return null;
        }
        int port = uri.getPort();
        if (port == -1) port = defaultPort;
        if (port == -1) {
            return null;
        }
        return new InetSocketAddress(host, port);
    }
}

@@ -1871,16 +1871,57 @@
 dress &&
+ hostString != null && address != null &&
  hostStr

Fix possible NPE in URIUtil