Merged branch 'jetty-9.4.x' into 'master'.

This commit is contained in:
Simone Bordet 2016-07-21 17:50:51 +02:00
commit 98454b8726
7 changed files with 109 additions and 60 deletions

View File

@ -26,9 +26,31 @@ Which browser/OS supports which protocols can be https://en.wikipedia.org/wiki/T
* TLS v1.1 and v1.2: The protocols which should be used wherever possible.
All CBC based ciphers are supported since Java 7, the new GCM modes are supported since Java 8.
* TLS v1.0: Still supported but is affected by the link:https://cve.mitre.org/cgi-bin/cvename.cgi?name=cve-2014-3566[POODLE attack.]
To support older browsers this protocol version is still needed.
* SSL v3: is now deprecated and should *only* be enabled if you still need to support very old browsers like Internet Explorer 6 on Windows XP which does not support TLS 1.0 (or is disabled by default).
===== Older Protocols
Both TLS v1.0 and SSL v3 are no longer supported by default. If your Jetty implementation requires these protocols for legacy support, they can be enabled manually.
____
[NOTE]
Once TLS v1.3 is released, there will be no workaround available for TLS v1.0.
Plans for TLS v1.3 include banning ciphers with known vulnerabilities from being present at any level.
It is recommended to upgrade any clients using these ciphers as soon as possible or face being locked into a outdated version of Jetty, Java or even OS.
____
By default, Jetty exclused these ciphers in the link:{GITBROWSEURL}/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java#L253-L256[`SslContextFactory`.]
You can re-enable these by re-declaring the ciphers you want excluded in code:
[source, java, subs="{sub-order}"]
----
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setExcludeCipherSuites(
"SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
----
If, after making these changes, you still have issues using these ciphers they are likely being blocked at the JVM level.
Locate the `$JAVA_HOME/jre/lib/security/` directory for the `java.security` file and examine it for any configuration that is excluding _ciphers_ or _algorithms_ (depending on the version of the JVM you are using the nomenclature may be different).
[[understanding-certificates-and-keys]]
==== Understanding Certificates and Keys

View File

@ -191,6 +191,8 @@ public class FastCGIProxyServlet extends AsyncProxyServlet.Transparent
protected void customizeFastCGIHeaders(Request proxyRequest, HttpFields fastCGIHeaders)
{
fastCGIHeaders.remove("HTTP_PROXY");
fastCGIHeaders.put(FCGI.Headers.REMOTE_ADDR, (String)proxyRequest.getAttributes().get(REMOTE_ADDR_ATTRIBUTE));
fastCGIHeaders.put(FCGI.Headers.REMOTE_PORT, (String)proxyRequest.getAttributes().get(REMOTE_PORT_ATTRIBUTE));
fastCGIHeaders.put(FCGI.Headers.SERVER_NAME, (String)proxyRequest.getAttributes().get(SERVER_NAME_ATTRIBUTE));

View File

@ -225,6 +225,7 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection
@Override
public void recycle()
{
getStream().removeAttribute(IStream.CHANNEL_ATTRIBUTE);
super.recycle();
channels.offer(this);
}
@ -233,6 +234,7 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection
public void onCompleted()
{
super.onCompleted();
if (!getStream().isReset())
recycle();
}
@ -240,11 +242,12 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection
public void close()
{
IStream stream = getStream();
if (LOG.isDebugEnabled())
LOG.debug("HTTP2 Request #{}/{} rejected", stream.getId(), Integer.toHexString(stream.getSession().hashCode()));
stream.reset(new ResetFrame(stream.getId(), ErrorCode.ENHANCE_YOUR_CALM_ERROR.code), Callback.NOOP);
// Consume the existing queued data frames to
// avoid stalling the session flow control.
getHttpTransport().consumeInput();
recycle();
consumeInput();
}
}
}

View File

@ -192,6 +192,17 @@ public class HttpChannelOverHTTP2 extends HttpChannel
public Runnable requestContent(DataFrame frame, final Callback callback)
{
Stream stream = getStream();
if (stream.isReset())
{
// Consume previously queued content to
// enlarge the session flow control window.
consumeInput();
// Consume immediately this content.
callback.succeeded();
return null;
}
// We must copy the data since we do not know when the
// application will consume the bytes (we queue them by
// calling onContent()), and the parsing will continue
@ -234,7 +245,6 @@ public class HttpChannelOverHTTP2 extends HttpChannel
if (LOG.isDebugEnabled())
{
Stream stream = getStream();
LOG.debug("HTTP2 Request #{}/{}: {} bytes of {} content, handle: {}",
stream.getId(),
Integer.toHexString(stream.getSession().hashCode()),
@ -249,6 +259,11 @@ public class HttpChannelOverHTTP2 extends HttpChannel
return handle || delayed ? this : null;
}
protected void consumeInput()
{
getRequest().getHttpInput().consumeAll();
}
/**
* If the associated response has the Expect header set to 100 Continue,
* then accessing the input stream indicates that the handler/servlet

View File

@ -31,7 +31,6 @@ import org.eclipse.jetty.http2.frames.HeadersFrame;
import org.eclipse.jetty.http2.frames.PushPromiseFrame;
import org.eclipse.jetty.http2.frames.ResetFrame;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.HttpTransport;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
@ -218,17 +217,16 @@ public class HttpTransportOverHTTP2 implements HttpTransport
// If the stream is not closed, it is still reading the request content.
// Send a reset to the other end so that it stops sending data.
if (!stream.isClosed())
{
if (LOG.isDebugEnabled())
LOG.debug("HTTP2 Response #{}: unconsumed request content, resetting stream", stream.getId());
stream.reset(new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code), Callback.NOOP);
}
// Consume the existing queued data frames to
// avoid stalling the session flow control.
consumeInput();
}
protected void consumeInput()
{
HttpChannel channel = (HttpChannel)stream.getAttribute(IStream.CHANNEL_ATTRIBUTE);
channel.getRequest().getHttpInput().consumeAll();
HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttribute(IStream.CHANNEL_ATTRIBUTE);
channel.consumeInput();
}
@Override

View File

@ -627,6 +627,15 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
protected boolean sendResponse(MetaData.Response info, ByteBuffer content, boolean complete, final Callback callback)
{
boolean committing = _committed.compareAndSet(false, true);
if (LOG.isDebugEnabled())
LOG.debug("sendResponse info={} content={} complete={} committing={} callback={}",
info,
BufferUtil.toDetailString(content),
complete,
committing,
callback);
if (committing)
{
// We need an info to commit

View File

@ -84,7 +84,6 @@ public class CGI extends HttpServlet
private boolean _ignoreExitState;
private boolean _relative;
/* ------------------------------------------------------------ */
@Override
public void init() throws ServletException
{
@ -141,13 +140,13 @@ public class CGI extends HttpServlet
}
catch (IOException e)
{
LOG.warn("CGI: CGI bin failed - " + dir,e);
LOG.warn("CGI: CGI bin failed - " + dir, e);
return;
}
_path = getInitParameter("Path");
if (_path != null)
_env.set("PATH",_path);
_env.set("PATH", _path);
_ignoreExitState = "true".equalsIgnoreCase(getInitParameter("ignoreExitState"));
Enumeration<String> e = getInitParameterNames();
@ -155,21 +154,20 @@ public class CGI extends HttpServlet
{
String n = e.nextElement();
if (n != null && n.startsWith("ENV_"))
_env.set(n.substring(4),getInitParameter(n));
_env.set(n.substring(4), getInitParameter(n));
}
if (!_env.envMap.containsKey("SystemRoot"))
{
String os = System.getProperty("os.name");
if (os != null && os.toLowerCase(Locale.ENGLISH).indexOf("windows") != -1)
if (os != null && os.toLowerCase(Locale.ENGLISH).contains("windows"))
{
_env.set("SystemRoot","C:\\WINDOWS");
_env.set("SystemRoot", "C:\\WINDOWS");
}
}
_ok = true;
}
/* ------------------------------------------------------------ */
@Override
public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
{
@ -196,7 +194,7 @@ public class CGI extends HttpServlet
File execCmd = new File(_docRoot, pathInContext);
String pathInfo = pathInContext;
if(!_useFullPath)
if (!_useFullPath)
{
String path = pathInContext;
String info = "";
@ -205,9 +203,9 @@ public class CGI extends HttpServlet
while ((path.endsWith("/") || !execCmd.exists()) && path.length() >= 0)
{
int index = path.lastIndexOf('/');
path = path.substring(0,index);
info = pathInContext.substring(index,pathInContext.length());
execCmd = new File(_docRoot,path);
path = path.substring(0, index);
info = pathInContext.substring(index, pathInContext.length());
execCmd = new File(_docRoot, path);
}
if (path.length() == 0 || !execCmd.exists() || execCmd.isDirectory() || !execCmd.getCanonicalPath().equals(execCmd.getAbsolutePath()))
@ -217,18 +215,19 @@ public class CGI extends HttpServlet
pathInfo = info;
}
exec(execCmd,pathInfo,req,res);
exec(execCmd, pathInfo, req, res);
}
/** executes the CGI process
/*
/**
* executes the CGI process
*
* @param command the command to execute, this command is prefixed by
* the context parameter "commandPrefix".
* @param pathInfo The PATH_INFO to process,
* see http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getPathInfo%28%29. Cannot be null
* @param req
* @param res
* @exception IOException
* @param req the HTTP request
* @param res the HTTP response
* @throws IOException if the execution of the CGI process throws
*/
private void exec(File command, String pathInfo, HttpServletRequest req, HttpServletResponse res) throws IOException
{
@ -244,9 +243,9 @@ public class CGI extends HttpServlet
}
String bodyFormEncoded = null;
if ((HttpMethod.POST.equals(req.getMethod()) || HttpMethod.PUT.equals(req.getMethod())) && "application/x-www-form-urlencoded".equals(req.getContentType()))
if ((HttpMethod.POST.is(req.getMethod()) || HttpMethod.PUT.is(req.getMethod())) && "application/x-www-form-urlencoded".equals(req.getContentType()))
{
MultiMap<String> parameterMap = new MultiMap<String>();
MultiMap<String> parameterMap = new MultiMap<>();
Enumeration<String> names = req.getParameterNames();
while (names.hasMoreElements())
{
@ -299,7 +298,7 @@ public class CGI extends HttpServlet
String scriptPath;
String scriptName;
// use docRoot for scriptPath, too
if(_cgiBinProvided)
if (_cgiBinProvided)
{
scriptPath = command.getAbsolutePath();
scriptName = scriptPath.substring(_docRoot.getAbsolutePath().length());
@ -307,7 +306,7 @@ public class CGI extends HttpServlet
else
{
String requestURI = req.getRequestURI();
scriptName = requestURI.substring(0,requestURI.length() - pathInfo.length());
scriptName = requestURI.substring(0, requestURI.length() - pathInfo.length());
scriptPath = getServletContext().getRealPath(scriptName);
}
env.set("SCRIPT_FILENAME", scriptPath);
@ -322,12 +321,14 @@ public class CGI extends HttpServlet
while (enm.hasMoreElements())
{
String name = enm.nextElement();
if (name.equalsIgnoreCase("Proxy"))
continue;
String value = req.getHeader(name);
env.set("HTTP_" + name.toUpperCase(Locale.ENGLISH).replace('-','_'),value);
env.set("HTTP_" + name.toUpperCase(Locale.ENGLISH).replace('-', '_'), value);
}
// these extra ones were from printenv on www.dev.nomura.co.uk
env.set("HTTPS", (req.isSecure()?"ON":"OFF"));
env.set("HTTPS", (req.isSecure() ? "ON" : "OFF"));
// "DOCUMENT_ROOT" => root + "/docs",
// "SERVER_URL" => "NYI - http://us0245",
// "TZ" => System.getProperty("user.timezone"),
@ -339,13 +340,12 @@ public class CGI extends HttpServlet
String execCmd = absolutePath;
// escape the execCommand
if (execCmd.length() > 0 && execCmd.charAt(0) != '"' && execCmd.indexOf(" ") >= 0)
if (execCmd.length() > 0 && execCmd.charAt(0) != '"' && execCmd.contains(" "))
execCmd = "\"" + execCmd + "\"";
if (_cmdPrefix != null)
execCmd = _cmdPrefix + " " + execCmd;
assert execCmd != null;
LOG.debug("Environment: " + env.getExportString());
LOG.debug("Command: " + execCmd);
@ -360,7 +360,7 @@ public class CGI extends HttpServlet
// hook processes output to browser's input (sync)
// if browser closes stream, we should detect it and kill process...
OutputStream os = null;
AsyncContext async=req.startAsync();
AsyncContext async = req.startAsync();
try
{
async.start(new Runnable()
@ -393,7 +393,7 @@ public class CGI extends HttpServlet
int k = line.indexOf(':');
if (k > 0)
{
String key = line.substring(0,k).trim();
String key = line.substring(0, k).trim();
String value = line.substring(k + 1).trim();
if ("Location".equals(key))
{
@ -408,14 +408,14 @@ public class CGI extends HttpServlet
else
{
// add remaining header items to our response header
res.addHeader(key,value);
res.addHeader(key, value);
}
}
}
}
// copy cgi content to response stream...
os = res.getOutputStream();
IO.copy(inFromCgi,os);
IO.copy(inFromCgi, os);
p.waitFor();
if (!_ignoreExitState)
@ -425,7 +425,7 @@ public class CGI extends HttpServlet
{
LOG.warn("Non-zero exit status (" + exitValue + ") from CGI program: " + absolutePath);
if (!res.isCommitted())
res.sendError(500,"Failed to exec CGI");
res.sendError(500, "Failed to exec CGI");
}
}
}
@ -506,10 +506,9 @@ public class CGI extends HttpServlet
/**
* Utility method to get a line of text from the input stream.
*
* @param is
* the input stream
* @param is the input stream
* @return the line of text
* @throws IOException
* @throws IOException if reading from the input stream throws
*/
private static String getTextLineFromStream(InputStream is) throws IOException
{
@ -523,7 +522,6 @@ public class CGI extends HttpServlet
return buffer.toString().trim();
}
/* ------------------------------------------------------------ */
/**
* private utility class that manages the Environment passed to exec.
*/
@ -533,26 +531,28 @@ public class CGI extends HttpServlet
EnvList()
{
envMap = new HashMap<String, String>();
envMap = new HashMap<>();
}
EnvList(EnvList l)
{
envMap = new HashMap<String,String>(l.envMap);
envMap = new HashMap<>(l.envMap);
}
/**
* Set a name/value pair, null values will be treated as an empty String
*
* @param name the name
* @param value the value
*/
public void set(String name, String value)
{
envMap.put(name,name + "=" + StringUtil.nonNull(value));
envMap.put(name, name + "=" + StringUtil.nonNull(value));
}
/**
* Get representation suitable for passing to exec.
*
* @return the env map as an array
*/
public String[] getEnvArray()