Skip to content

Commit

Permalink
Fix #6860 IPv6 Format
Browse files Browse the repository at this point in the history
Fix #6860 IPv6 format by adding a per context configuration.

Signed-off-by: Greg Wilkins <gregw@webtide.com>
  • Loading branch information
gregw committed Sep 17, 2021
1 parent 4fd1a4e commit 79395c5
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 142 deletions.
127 changes: 45 additions & 82 deletions jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
Expand Up @@ -18,82 +18,30 @@

package org.eclipse.jetty.server;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import org.eclipse.jetty.http.*;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandler.Context;
import org.eclipse.jetty.server.session.Session;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.util.*;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.charset.UnsupportedCharsetException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.servlet.AsyncContext;
import javax.servlet.AsyncListener;
import javax.servlet.DispatcherType;
import javax.servlet.MultipartConfigElement;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.ServletRequestWrapper;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpUpgradeHandler;
import javax.servlet.http.Part;

import org.eclipse.jetty.http.BadMessageException;
import org.eclipse.jetty.http.HostPortHttpField;
import org.eclipse.jetty.http.HttpCompliance;
import org.eclipse.jetty.http.HttpCookie;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandler.Context;
import org.eclipse.jetty.server.session.Session;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.util.Attributes;
import org.eclipse.jetty.util.AttributesMap;
import org.eclipse.jetty.util.HostPort;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.MultiMap;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.UrlEncoded;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;

/**
* Jetty Request.
Expand Down Expand Up @@ -998,7 +946,7 @@ public String getLocalAddr()
String name = InetAddress.getLocalHost().getHostAddress();
if (StringUtil.ALL_INTERFACES.equals(name))
return null;
return HostPort.normalizeHost(name);
return formatAddrOrHost(name);
}
catch (UnknownHostException e)
{
Expand All @@ -1014,7 +962,7 @@ public String getLocalAddr()
String result = address == null
? local.getHostString()
: address.getHostAddress();
return HostPort.normalizeHost(result);
return formatAddrOrHost(result);
}

/*
Expand All @@ -1027,15 +975,15 @@ public String getLocalName()
{
InetSocketAddress local = _channel.getLocalAddress();
if (local != null)
return HostPort.normalizeHost(local.getHostString());
return formatAddrOrHost(local.getHostString());
}

try
{
String name = InetAddress.getLocalHost().getHostName();
if (StringUtil.ALL_INTERFACES.equals(name))
return null;
return HostPort.normalizeHost(name);
return formatAddrOrHost(name);
}
catch (UnknownHostException e)
{
Expand Down Expand Up @@ -1247,8 +1195,7 @@ public InetSocketAddress getRemoteInetSocketAddress()
* @see javax.servlet.ServletRequest#getRemoteAddr()
*/
@Override
public String getRemoteAddr()
{
public String getRemoteAddr() {
InetSocketAddress remote = _remote;
if (remote == null)
remote = _channel.getRemoteAddress();
Expand All @@ -1257,12 +1204,10 @@ public String getRemoteAddr()

InetAddress address = remote.getAddress();
String result = address == null
? remote.getHostString()
: address.getHostAddress();
// Add IPv6 brackets if necessary, to be consistent
// with cases where _remote has been built from other
// sources such as forward headers or PROXY protocol.
return HostPort.normalizeHost(result);
? remote.getHostString()
: address.getHostAddress();

return formatAddrOrHost(result);
}

/*
Expand All @@ -1276,8 +1221,9 @@ public String getRemoteHost()
remote = _channel.getRemoteAddress();
if (remote == null)
return "";

// We want the URI host, so add IPv6 brackets if necessary.
return HostPort.normalizeHost(remote.getHostString());
return formatAddrOrHost(remote.getHostString());
}

/*
Expand Down Expand Up @@ -1432,12 +1378,12 @@ private String findServerName()
// Return host from connection
String name = getLocalName();
if (name != null)
return HostPort.normalizeHost(name);
return formatAddrOrHost(name);

// Return the local host
try
{
return HostPort.normalizeHost(InetAddress.getLocalHost().getHostAddress());
return formatAddrOrHost(InetAddress.getLocalHost().getHostAddress());
}
catch (UnknownHostException e)
{
Expand Down Expand Up @@ -2604,4 +2550,21 @@ public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) throws IO
{
throw new ServletException("HttpServletRequest.upgrade() not supported in Jetty");
}

private String formatAddrOrHost(String addr)
{
if (addr == null)
return addr;
if (getContext() == null || getContext().getContextHandler() == null)
return HostPort.normalizeHost(addr);
switch(getContext().getContextHandler().getIpv6Format())
{
case BRACKETED:
return HostPort.normalizeHost(addr);
case UNBRACKETED:
return HostPort.denormalizeHost(addr);
default:
return addr;
}
}
}
Expand Up @@ -18,6 +18,22 @@

package org.eclipse.jetty.server.handler;

import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.server.*;
import org.eclipse.jetty.util.*;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.DumpableCollection;
import org.eclipse.jetty.util.component.Graceful;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;

import javax.servlet.*;
import javax.servlet.FilterRegistration.Dynamic;
import javax.servlet.descriptor.JspConfigDescriptor;
import javax.servlet.http.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
Expand All @@ -27,68 +43,10 @@
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.FilterRegistration.Dynamic;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.SessionCookieConfig;
import javax.servlet.SessionTrackingMode;
import javax.servlet.descriptor.JspConfigDescriptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionIdListener;
import javax.servlet.http.HttpSessionListener;

import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.server.ClassLoaderDump;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Dispatcher;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HandlerContainer;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.Attributes;
import org.eclipse.jetty.util.AttributesMap;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.DumpableCollection;
import org.eclipse.jetty.util.component.Graceful;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;

/**
* ContextHandler.
Expand Down Expand Up @@ -188,7 +146,14 @@ public enum ContextStatus
INITIALIZED,
DESTROYED
}


public enum IPV6_FORMAT
{
BRACKETED,
UNBRACKETED,
UNCHANGED
};

protected ContextStatus _contextStatus = ContextStatus.NOTSET;
protected Context _scontext;
private final AttributesMap _attributes;
Expand Down Expand Up @@ -227,6 +192,7 @@ public enum ContextStatus
private final List<EventListener> _durableListeners = new CopyOnWriteArrayList<>();
private String[] _protectedTargets;
private final CopyOnWriteArrayList<AliasCheck> _aliasChecks = new CopyOnWriteArrayList<>();
private IPV6_FORMAT _ipv6Format = IPV6_FORMAT.BRACKETED;

public enum Availability
{
Expand Down Expand Up @@ -292,6 +258,17 @@ public Context getServletContext()
return _scontext;
}

@ManagedAttribute("The format of IPv6 addresses return from the servlet API")
public IPV6_FORMAT getIpv6Format()
{
return _ipv6Format;
}

public void setIpv6Format(IPV6_FORMAT ipv6Format)
{
_ipv6Format = _ipv6Format;
}

/**
* @return the allowNullPathInfo true if /context is not redirected to /context/
*/
Expand Down
18 changes: 18 additions & 0 deletions jetty-util/src/main/java/org/eclipse/jetty/util/HostPort.java
Expand Up @@ -156,6 +156,24 @@ public static String normalizeHost(String host)
return "[" + host + "]";
}

/**
* Denormalizes IPv6 address as per https://tools.ietf.org/html/rfc2732
* and https://tools.ietf.org/html/rfc6874,
* removing square brackets if they are present.
*
* @param host a host name, IPv4 address, IPv6 address or IPv6 literal
* @return a host name or an IPv4 address or an IPv6 address
*/
public static String denormalizeHost(String host)
{
// if it is normalized IPv6 or could not be IPv6, return
if (host.isEmpty() || host.charAt(0) != '[' || host.charAt(host.length() - 1) != ']')
return host;

// normalize with [ ]
return host.substring(1, host.length() - 2);
}

/**
* Parse a string representing a port validating it is a valid port value.
*
Expand Down

0 comments on commit 79395c5

Please sign in to comment.