Merge branch 'master' into release-9
This commit is contained in:
commit
573e90c581
|
@ -1,4 +1,8 @@
|
|||
branches:
|
||||
only:
|
||||
- /^release-.*$/
|
||||
language: java
|
||||
script: mvn install
|
||||
jdk:
|
||||
- openjdk7
|
||||
- oraclejdk7
|
||||
|
|
|
@ -5,6 +5,6 @@ org.eclipse.jetty.SOURCE=false
|
|||
#org.eclipse.jetty.STACKS=false
|
||||
#org.eclipse.jetty.spdy.LEVEL=DEBUG
|
||||
#org.eclipse.jetty.server.LEVEL=DEBUG
|
||||
org.eclipse.jetty.io.LEVEL=DEBUG
|
||||
org.eclipse.jetty.io.ssl.LEVEL=DEBUG
|
||||
#org.eclipse.jetty.io.LEVEL=DEBUG
|
||||
#org.eclipse.jetty.io.ssl.LEVEL=DEBUG
|
||||
#org.eclipse.jetty.spdy.server.LEVEL=DEBUG
|
||||
|
|
|
@ -40,6 +40,7 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
|
|||
public static final int DEFAULT_MAX_CONTENT_LENGTH = 4096;
|
||||
public static final Logger LOG = Log.getLogger(AuthenticationProtocolHandler.class);
|
||||
private static final Pattern AUTHENTICATE_PATTERN = Pattern.compile("([^\\s]+)\\s+realm=\"([^\"]+)\"(.*)", Pattern.CASE_INSENSITIVE);
|
||||
private static final String AUTHENTICATION_ATTRIBUTE = AuthenticationProtocolHandler.class.getName() + ".authentication";
|
||||
|
||||
private final HttpClient client;
|
||||
private final int maxContentLength;
|
||||
|
@ -90,6 +91,15 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
|
|||
return;
|
||||
}
|
||||
|
||||
HttpConversation conversation = client.getConversation(request.getConversationID(), false);
|
||||
if (conversation.getAttribute(AUTHENTICATION_ATTRIBUTE) != null)
|
||||
{
|
||||
// We have already tried to authenticate, but we failed again
|
||||
LOG.debug("Bad credentials for {}", request);
|
||||
forwardSuccessComplete(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
HttpHeader header = getAuthenticateHeader();
|
||||
List<Authentication.HeaderInfo> headerInfos = parseAuthenticateHeader(response, header);
|
||||
if (headerInfos.isEmpty())
|
||||
|
@ -118,7 +128,6 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
|
|||
return;
|
||||
}
|
||||
|
||||
HttpConversation conversation = client.getConversation(request.getConversationID(), false);
|
||||
final Authentication.Result authnResult = authentication.authenticate(request, response, headerInfo, conversation);
|
||||
LOG.debug("Authentication result {}", authnResult);
|
||||
if (authnResult == null)
|
||||
|
@ -127,6 +136,8 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
|
|||
return;
|
||||
}
|
||||
|
||||
conversation.setAttribute(AUTHENTICATION_ATTRIBUTE, true);
|
||||
|
||||
Request newRequest = client.copyRequest(request, request.getURI());
|
||||
authnResult.apply(newRequest);
|
||||
newRequest.onResponseSuccess(new Response.SuccessListener()
|
||||
|
|
|
@ -63,6 +63,7 @@ import org.eclipse.jetty.io.ssl.SslConnection;
|
|||
import org.eclipse.jetty.util.Jetty;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
import org.eclipse.jetty.util.SocketAddressResolver;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -362,7 +363,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
*/
|
||||
public Request newRequest(String host, int port)
|
||||
{
|
||||
return newRequest(URI.create(address("http", host, port)));
|
||||
return newRequest(address("http", host, port));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -417,9 +418,11 @@ public class HttpClient extends ContainerLifeCycle
|
|||
return newRequest;
|
||||
}
|
||||
|
||||
private String address(String scheme, String host, int port)
|
||||
protected String address(String scheme, String host, int port)
|
||||
{
|
||||
return scheme + "://" + host + ":" + port;
|
||||
StringBuilder result = new StringBuilder();
|
||||
URIUtil.appendSchemeHostPort(result, scheme, host, port);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -900,6 +903,13 @@ public class HttpClient extends ContainerLifeCycle
|
|||
return encodingField;
|
||||
}
|
||||
|
||||
protected String normalizeHost(String host)
|
||||
{
|
||||
if (host != null && host.matches("\\[.*\\]"))
|
||||
return host.substring(1, host.length() - 1);
|
||||
return host;
|
||||
}
|
||||
|
||||
protected int normalizePort(String scheme, int port)
|
||||
{
|
||||
return port > 0 ? port : HttpScheme.HTTPS.is(scheme) ? 443 : 80;
|
||||
|
|
|
@ -18,14 +18,10 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.HttpCookie;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
@ -35,17 +31,14 @@ import org.eclipse.jetty.client.api.Connection;
|
|||
import org.eclipse.jetty.client.api.ContentProvider;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.util.StringContentProvider;
|
||||
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.HttpVersion;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.io.AbstractConnection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.util.Fields;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
@ -166,45 +159,12 @@ public class HttpConnection extends AbstractConnection implements Connection
|
|||
path = "/";
|
||||
request.path(path);
|
||||
}
|
||||
if (destination.isProxied() && HttpMethod.CONNECT != request.getMethod())
|
||||
if (destination.isProxied() && HttpMethod.CONNECT != method)
|
||||
{
|
||||
path = request.getURI().toString();
|
||||
request.path(path);
|
||||
}
|
||||
|
||||
Fields fields = request.getParams();
|
||||
if (!fields.isEmpty())
|
||||
{
|
||||
StringBuilder params = new StringBuilder();
|
||||
for (Iterator<Fields.Field> fieldIterator = fields.iterator(); fieldIterator.hasNext();)
|
||||
{
|
||||
Fields.Field field = fieldIterator.next();
|
||||
String[] values = field.values();
|
||||
for (int i = 0; i < values.length; ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
params.append("&");
|
||||
params.append(field.name()).append("=");
|
||||
params.append(urlEncode(values[i]));
|
||||
}
|
||||
if (fieldIterator.hasNext())
|
||||
params.append("&");
|
||||
}
|
||||
|
||||
// POST with no content, send parameters as body
|
||||
if (method == HttpMethod.POST && request.getContent() == null)
|
||||
{
|
||||
request.header(HttpHeader.CONTENT_TYPE, MimeTypes.Type.FORM_ENCODED.asString());
|
||||
request.content(new StringContentProvider(params.toString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
path += "?";
|
||||
path += params.toString();
|
||||
request.path(path);
|
||||
}
|
||||
}
|
||||
|
||||
// If we are HTTP 1.1, add the Host header
|
||||
if (version.getVersion() > 10)
|
||||
{
|
||||
|
@ -257,19 +217,6 @@ public class HttpConnection extends AbstractConnection implements Connection
|
|||
}
|
||||
}
|
||||
|
||||
private String urlEncode(String value)
|
||||
{
|
||||
String encoding = "UTF-8";
|
||||
try
|
||||
{
|
||||
return URLEncoder.encode(value, encoding);
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
throw new UnsupportedCharsetException(encoding);
|
||||
}
|
||||
}
|
||||
|
||||
public HttpExchange getExchange()
|
||||
{
|
||||
return exchange.get();
|
||||
|
|
|
@ -374,10 +374,9 @@ public class HttpReceiver implements HttpParser.ResponseHandler<ByteBuffer>
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean earlyEOF()
|
||||
public void earlyEOF()
|
||||
{
|
||||
failAndClose(new EOFException());
|
||||
return false;
|
||||
}
|
||||
|
||||
private void failAndClose(Throwable failure)
|
||||
|
|
|
@ -22,10 +22,12 @@ import java.io.IOException;
|
|||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
@ -62,6 +64,7 @@ public class HttpRequest implements Request
|
|||
private URI uri;
|
||||
private String scheme;
|
||||
private String path;
|
||||
private String query;
|
||||
private HttpMethod method;
|
||||
private HttpVersion version;
|
||||
private long idleTimeout;
|
||||
|
@ -80,35 +83,15 @@ public class HttpRequest implements Request
|
|||
this.client = client;
|
||||
this.conversation = conversation;
|
||||
scheme = uri.getScheme();
|
||||
host = uri.getHost();
|
||||
host = client.normalizeHost(uri.getHost());
|
||||
port = client.normalizePort(scheme, uri.getPort());
|
||||
path = uri.getRawPath();
|
||||
String query = uri.getRawQuery();
|
||||
if (query != null)
|
||||
{
|
||||
for (String nameValue : query.split("&"))
|
||||
{
|
||||
String[] parts = nameValue.split("=");
|
||||
param(parts[0], parts.length < 2 ? "" : urlDecode(parts[1]));
|
||||
}
|
||||
}
|
||||
query = uri.getRawQuery();
|
||||
extractParams(query);
|
||||
this.uri = buildURI();
|
||||
followRedirects(client.isFollowRedirects());
|
||||
}
|
||||
|
||||
private String urlDecode(String value)
|
||||
{
|
||||
String charset = "UTF-8";
|
||||
try
|
||||
{
|
||||
return URLDecoder.decode(value, charset);
|
||||
}
|
||||
catch (UnsupportedEncodingException x)
|
||||
{
|
||||
throw new UnsupportedCharsetException(charset);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getConversationID()
|
||||
{
|
||||
|
@ -163,11 +146,25 @@ public class HttpRequest implements Request
|
|||
@Override
|
||||
public Request path(String path)
|
||||
{
|
||||
this.path = path;
|
||||
URI uri = URI.create(path);
|
||||
this.path = uri.getRawPath();
|
||||
String query = uri.getRawQuery();
|
||||
if (query != null)
|
||||
{
|
||||
this.query = query;
|
||||
params.clear();
|
||||
extractParams(query);
|
||||
}
|
||||
this.uri = buildURI();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQuery()
|
||||
{
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getURI()
|
||||
{
|
||||
|
@ -191,13 +188,14 @@ public class HttpRequest implements Request
|
|||
public Request param(String name, String value)
|
||||
{
|
||||
params.add(name, value);
|
||||
this.query = buildQuery();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fields getParams()
|
||||
{
|
||||
return params;
|
||||
return new Fields(params, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -496,12 +494,73 @@ public class HttpRequest implements Request
|
|||
return aborted;
|
||||
}
|
||||
|
||||
private String buildQuery()
|
||||
{
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (Iterator<Fields.Field> iterator = params.iterator(); iterator.hasNext();)
|
||||
{
|
||||
Fields.Field field = iterator.next();
|
||||
String[] values = field.values();
|
||||
for (int i = 0; i < values.length; ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
result.append("&");
|
||||
result.append(field.name()).append("=");
|
||||
result.append(urlEncode(values[i]));
|
||||
}
|
||||
if (iterator.hasNext())
|
||||
result.append("&");
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private String urlEncode(String value)
|
||||
{
|
||||
String encoding = "UTF-8";
|
||||
try
|
||||
{
|
||||
return URLEncoder.encode(value, encoding);
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
throw new UnsupportedCharsetException(encoding);
|
||||
}
|
||||
}
|
||||
|
||||
private void extractParams(String query)
|
||||
{
|
||||
if (query != null)
|
||||
{
|
||||
for (String nameValue : query.split("&"))
|
||||
{
|
||||
String[] parts = nameValue.split("=");
|
||||
param(parts[0], parts.length < 2 ? "" : urlDecode(parts[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String urlDecode(String value)
|
||||
{
|
||||
String charset = "UTF-8";
|
||||
try
|
||||
{
|
||||
return URLDecoder.decode(value, charset);
|
||||
}
|
||||
catch (UnsupportedEncodingException x)
|
||||
{
|
||||
throw new UnsupportedCharsetException(charset);
|
||||
}
|
||||
}
|
||||
|
||||
private URI buildURI()
|
||||
{
|
||||
String path = getPath();
|
||||
String query = getQuery();
|
||||
if (query != null)
|
||||
path += "?" + query;
|
||||
URI result = URI.create(path);
|
||||
if (!result.isAbsolute())
|
||||
result = URI.create(getScheme() + "://" + getHost() + ":" + getPort() + path);
|
||||
result = URI.create(client.address(getScheme(), getHost(), getPort()) + path);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -172,7 +172,11 @@ public class HttpSender implements AsyncContentProvider.Listener
|
|||
{
|
||||
ContentProvider requestContent = request.getContent();
|
||||
long contentLength = requestContent == null ? -1 : requestContent.getLength();
|
||||
requestInfo = new HttpGenerator.RequestInfo(request.getVersion(), request.getHeaders(), contentLength, request.getMethod().asString(), request.getPath());
|
||||
String path = request.getPath();
|
||||
String query = request.getQuery();
|
||||
if (query != null)
|
||||
path += "?" + query;
|
||||
requestInfo = new HttpGenerator.RequestInfo(request.getVersion(), request.getHeaders(), contentLength, request.getMethod().asString(), path);
|
||||
break;
|
||||
}
|
||||
case NEED_HEADER:
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.client.api;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Path;
|
||||
import java.util.EventListener;
|
||||
|
@ -86,18 +87,33 @@ public interface Request
|
|||
Request method(HttpMethod method);
|
||||
|
||||
/**
|
||||
* @return the path of this request, such as "/"
|
||||
* @return the path of this request, such as "/" or "/path" - without the query
|
||||
* @see #getQuery()
|
||||
*/
|
||||
String getPath();
|
||||
|
||||
/**
|
||||
* @param path the path of this request, such as "/"
|
||||
* Specifies the path - and possibly the query - of this request.
|
||||
* If the query part is specified, parameter values must be properly
|
||||
* {@link URLEncoder#encode(String, String) UTF-8 URL encoded}.
|
||||
* For example, if the parameter value is the euro symbol € then the
|
||||
* query string must be "param=%E2%82%AC".
|
||||
* For transparent encoding of parameter values, use {@link #param(String, String)}.
|
||||
*
|
||||
* @param path the path of this request, such as "/" or "/path?param=1"
|
||||
* @return this request object
|
||||
*/
|
||||
Request path(String path);
|
||||
|
||||
/**
|
||||
* @return the full URI of this request such as "http://host:port/path"
|
||||
* @return the query string of this request such as "param=1"
|
||||
* @see #getPath()
|
||||
* @see #getParams()
|
||||
*/
|
||||
String getQuery();
|
||||
|
||||
/**
|
||||
* @return the full URI of this request such as "http://host:port/path?param=1"
|
||||
*/
|
||||
URI getURI();
|
||||
|
||||
|
@ -118,6 +134,9 @@ public interface Request
|
|||
Fields getParams();
|
||||
|
||||
/**
|
||||
* Adds a query parameter with the given name and value.
|
||||
* The value is {@link URLEncoder#encode(String, String) UTF-8 URL encoded}.
|
||||
*
|
||||
* @param name the name of the query parameter
|
||||
* @param value the value of the query parameter
|
||||
* @return this request object
|
||||
|
|
|
@ -20,7 +20,6 @@ package org.eclipse.jetty.client;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -94,8 +93,6 @@ public class ExternalSiteTest
|
|||
{
|
||||
Assert.assertTrue(result.isSucceeded());
|
||||
Assert.assertEquals(200, result.getResponse().getStatus());
|
||||
URI uri = result.getRequest().getURI();
|
||||
Assert.assertTrue(uri.getPort() > 0);
|
||||
latch2.countDown();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -304,4 +304,20 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest
|
|||
Assert.assertEquals(401, response.getStatus());
|
||||
Assert.assertTrue(requests.get().await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_BasicAuthentication_WithWrongPassword() throws Exception
|
||||
{
|
||||
startBasic(new EmptyServerHandler());
|
||||
|
||||
AuthenticationStore authenticationStore = client.getAuthenticationStore();
|
||||
URI uri = URI.create(scheme + "://localhost:" + connector.getLocalPort());
|
||||
BasicAuthentication authentication = new BasicAuthentication(uri, realm, "basic", "wrong");
|
||||
authenticationStore.addAuthentication(authentication);
|
||||
|
||||
Request request = client.newRequest("localhost", connector.getLocalPort()).scheme(scheme).path("/secure");
|
||||
ContentResponse response = request.timeout(555, TimeUnit.SECONDS).send();
|
||||
Assert.assertNotNull(response);
|
||||
Assert.assertEquals(401, response.getStatus());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,241 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.util.Fields;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class HttpClientURITest extends AbstractHttpClientServerTest
|
||||
{
|
||||
public HttpClientURITest(SslContextFactory sslContextFactory)
|
||||
{
|
||||
super(sslContextFactory);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIPv6Host() throws Exception
|
||||
{
|
||||
start(new EmptyServerHandler());
|
||||
|
||||
String host = "::1";
|
||||
Request request = client.newRequest(host, connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
.timeout(5, TimeUnit.SECONDS);
|
||||
|
||||
Assert.assertEquals(host, request.getHost());
|
||||
StringBuilder uri = new StringBuilder();
|
||||
URIUtil.appendSchemeHostPort(uri, scheme, host, connector.getLocalPort());
|
||||
Assert.assertEquals(uri.toString(), request.getURI().toString());
|
||||
|
||||
Assert.assertEquals(HttpStatus.OK_200, request.send().getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPath() throws Exception
|
||||
{
|
||||
final String path = "/path";
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
Assert.assertEquals(path, request.getRequestURI());
|
||||
}
|
||||
});
|
||||
|
||||
Request request = client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.path(path);
|
||||
|
||||
Assert.assertEquals(path, request.getPath());
|
||||
Assert.assertNull(request.getQuery());
|
||||
Fields params = request.getParams();
|
||||
Assert.assertEquals(0, params.size());
|
||||
Assert.assertTrue(request.getURI().toString().endsWith(path));
|
||||
|
||||
ContentResponse response = request.send();
|
||||
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathWithQuery() throws Exception
|
||||
{
|
||||
String name = "a";
|
||||
String value = "1";
|
||||
final String query = name + "=" + value;
|
||||
final String path = "/path";
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
Assert.assertEquals(path, request.getRequestURI());
|
||||
Assert.assertEquals(query, request.getQueryString());
|
||||
}
|
||||
});
|
||||
|
||||
Request request = client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.path(path + "?" + query);
|
||||
|
||||
Assert.assertEquals(path, request.getPath());
|
||||
Assert.assertEquals(query, request.getQuery());
|
||||
Fields params = request.getParams();
|
||||
Assert.assertEquals(1, params.size());
|
||||
Assert.assertEquals(value, params.get(name).value());
|
||||
|
||||
ContentResponse response = request.send();
|
||||
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathWithParam() throws Exception
|
||||
{
|
||||
String name = "a";
|
||||
String value = "1";
|
||||
final String query = name + "=" + value;
|
||||
final String path = "/path";
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
Assert.assertEquals(path, request.getRequestURI());
|
||||
Assert.assertEquals(query, request.getQueryString());
|
||||
}
|
||||
});
|
||||
|
||||
Request request = client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.path(path)
|
||||
.param(name, value);
|
||||
|
||||
Assert.assertEquals(path, request.getPath());
|
||||
Assert.assertEquals(query, request.getQuery());
|
||||
Fields params = request.getParams();
|
||||
Assert.assertEquals(1, params.size());
|
||||
Assert.assertEquals(value, params.get(name).value());
|
||||
|
||||
ContentResponse response = request.send();
|
||||
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathWithQueryAndParam() throws Exception
|
||||
{
|
||||
String name1 = "a";
|
||||
String value1 = "1";
|
||||
String name2 = "b";
|
||||
String value2 = "2";
|
||||
final String query = name1 + "=" + value1 + "&" + name2 + "=" + value2;
|
||||
final String path = "/path";
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
Assert.assertEquals(path, request.getRequestURI());
|
||||
Assert.assertEquals(query, request.getQueryString());
|
||||
}
|
||||
});
|
||||
|
||||
Request request = client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.path(path + "?" + name1 + "=" + value1)
|
||||
.param(name2, value2);
|
||||
|
||||
Assert.assertEquals(path, request.getPath());
|
||||
Assert.assertEquals(query, request.getQuery());
|
||||
Fields params = request.getParams();
|
||||
Assert.assertEquals(2, params.size());
|
||||
Assert.assertEquals(value1, params.get(name1).value());
|
||||
Assert.assertEquals(value2, params.get(name2).value());
|
||||
|
||||
ContentResponse response = request.send();
|
||||
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathWithQueryAndParamValueEncoded() throws Exception
|
||||
{
|
||||
final String name1 = "a";
|
||||
final String value1 = "\u20AC";
|
||||
final String encodedValue1 = URLEncoder.encode(value1, "UTF-8");
|
||||
final String name2 = "b";
|
||||
final String value2 = "\u00A5";
|
||||
String encodedValue2 = URLEncoder.encode(value2, "UTF-8");
|
||||
final String query = name1 + "=" + encodedValue1 + "&" + name2 + "=" + encodedValue2;
|
||||
final String path = "/path";
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
Assert.assertEquals(path, request.getRequestURI());
|
||||
Assert.assertEquals(query, request.getQueryString());
|
||||
Assert.assertEquals(value1, request.getParameter(name1));
|
||||
Assert.assertEquals(value2, request.getParameter(name2));
|
||||
}
|
||||
});
|
||||
|
||||
Request request = client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.path(path + "?" + name1 + "=" + encodedValue1)
|
||||
.param(name2, value2);
|
||||
|
||||
Assert.assertEquals(path, request.getPath());
|
||||
Assert.assertEquals(query, request.getQuery());
|
||||
Fields params = request.getParams();
|
||||
Assert.assertEquals(2, params.size());
|
||||
Assert.assertEquals(value1, params.get(name1).value());
|
||||
Assert.assertEquals(value2, params.get(name2).value());
|
||||
|
||||
ContentResponse response = request.send();
|
||||
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
}
|
||||
}
|
|
@ -24,6 +24,8 @@ import java.util.Arrays;
|
|||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
@ -66,7 +68,10 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
Assert.assertEquals(0, activeConnections.size());
|
||||
|
||||
final CountDownLatch headersLatch = new CountDownLatch(1);
|
||||
final CountDownLatch testLatch = new CountDownLatch(1);
|
||||
final CountDownLatch successLatch = new CountDownLatch(3);
|
||||
final AtomicBoolean failed = new AtomicBoolean(false);
|
||||
|
||||
client.newRequest(host, port)
|
||||
.scheme(scheme)
|
||||
.onRequestSuccess(new Request.SuccessListener()
|
||||
|
@ -82,9 +87,15 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
@Override
|
||||
public void onHeaders(Response response)
|
||||
{
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
Assert.assertEquals(1, activeConnections.size());
|
||||
headersLatch.countDown();
|
||||
try
|
||||
{
|
||||
testLatch.await();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
})
|
||||
.send(new Response.Listener.Empty()
|
||||
|
@ -98,16 +109,21 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
Assert.assertFalse(result.isFailed());
|
||||
failed.set(result.isFailed());
|
||||
successLatch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
Assert.assertTrue(headersLatch.await(5, TimeUnit.SECONDS));
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
Assert.assertEquals(1, activeConnections.size());
|
||||
testLatch.countDown();
|
||||
|
||||
Assert.assertTrue(successLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
Assert.assertEquals(1, idleConnections.size());
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
Assert.assertFalse(failed.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -127,6 +143,8 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
|
||||
final CountDownLatch beginLatch = new CountDownLatch(1);
|
||||
final CountDownLatch failureLatch = new CountDownLatch(2);
|
||||
final AtomicBoolean failed = new AtomicBoolean(false);
|
||||
|
||||
client.newRequest(host, port).scheme(scheme).listener(new Request.Listener.Empty()
|
||||
{
|
||||
@Override
|
||||
|
@ -146,9 +164,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
Assert.assertTrue(result.isFailed());
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
failed.set(result.isFailed());
|
||||
failureLatch.countDown();
|
||||
}
|
||||
});
|
||||
|
@ -158,6 +174,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
Assert.assertTrue(failed.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -176,6 +193,9 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
Assert.assertEquals(0, activeConnections.size());
|
||||
|
||||
final CountDownLatch successLatch = new CountDownLatch(3);
|
||||
final AtomicBoolean failed = new AtomicBoolean(false);
|
||||
final AtomicBoolean four_hundred = new AtomicBoolean(false);
|
||||
|
||||
client.newRequest(host, port)
|
||||
.scheme(scheme)
|
||||
.listener(new Request.Listener.Empty()
|
||||
|
@ -198,16 +218,16 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
@Override
|
||||
public void onSuccess(Response response)
|
||||
{
|
||||
Assert.assertEquals(400, response.getStatus());
|
||||
// 400 response also come with a Connection: close,
|
||||
// so the connection is closed and removed
|
||||
four_hundred.set(response.getStatus()==400);
|
||||
successLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
Assert.assertFalse(result.isFailed());
|
||||
failed.set(result.isFailed());
|
||||
successLatch.countDown();
|
||||
}
|
||||
});
|
||||
|
@ -216,6 +236,8 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
Assert.assertFalse(failed.get());
|
||||
Assert.assertTrue(four_hundred.get());
|
||||
}
|
||||
|
||||
@Slow
|
||||
|
@ -236,6 +258,8 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
|
||||
final long delay = 1000;
|
||||
final CountDownLatch successLatch = new CountDownLatch(3);
|
||||
final AtomicBoolean failed = new AtomicBoolean(false);
|
||||
final AtomicBoolean four_hundred = new AtomicBoolean(false);
|
||||
client.newRequest(host, port)
|
||||
.scheme(scheme)
|
||||
.listener(new Request.Listener.Empty()
|
||||
|
@ -271,16 +295,16 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
@Override
|
||||
public void onSuccess(Response response)
|
||||
{
|
||||
Assert.assertEquals(400, response.getStatus());
|
||||
// 400 response also come with a Connection: close,
|
||||
// so the connection is closed and removed
|
||||
four_hundred.set(response.getStatus()==400);
|
||||
successLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
Assert.assertFalse(result.isFailed());
|
||||
failed.set(result.isFailed());
|
||||
successLatch.countDown();
|
||||
}
|
||||
});
|
||||
|
@ -289,6 +313,8 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
Assert.assertFalse(failed.get());
|
||||
Assert.assertTrue(four_hundred.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -309,6 +335,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
server.stop();
|
||||
|
||||
final CountDownLatch failureLatch = new CountDownLatch(2);
|
||||
final AtomicBoolean failed = new AtomicBoolean(false);
|
||||
client.newRequest(host, port)
|
||||
.scheme(scheme)
|
||||
.onRequestFailure(new Request.FailureListener()
|
||||
|
@ -324,7 +351,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
Assert.assertTrue(result.isFailed());
|
||||
failed.set(result.isFailed());
|
||||
failureLatch.countDown();
|
||||
}
|
||||
});
|
||||
|
@ -333,6 +360,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
Assert.assertTrue(failed.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -359,6 +387,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
Assert.assertEquals(0, activeConnections.size());
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final AtomicBoolean failed = new AtomicBoolean(false);
|
||||
client.newRequest(host, port)
|
||||
.scheme(scheme)
|
||||
.send(new Response.Listener.Empty()
|
||||
|
@ -366,9 +395,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
Assert.assertFalse(result.isFailed());
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
failed.set(result.isFailed());
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
@ -377,6 +404,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
Assert.assertFalse(failed.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -410,6 +438,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
Log.getLogger(HttpConnection.class).info("Expecting java.lang.IllegalStateException: HttpParser{s=CLOSED,...");
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final AtomicBoolean failed = new AtomicBoolean(false);
|
||||
ByteBuffer buffer = ByteBuffer.allocate(16 * 1024 * 1024);
|
||||
Arrays.fill(buffer.array(),(byte)'x');
|
||||
client.newRequest(host, port)
|
||||
|
@ -420,8 +449,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
failed.set(result.isFailed());
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
@ -430,6 +458,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
Assert.assertTrue(failed.get());
|
||||
server.stop();
|
||||
}
|
||||
finally
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
|||
import org.eclipse.jetty.toolchain.test.PathAssert;
|
||||
import org.eclipse.jetty.toolchain.test.TestingDir;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
|
@ -290,9 +291,7 @@ public class XmlConfiguredJetty
|
|||
public URI getServerURI() throws UnknownHostException
|
||||
{
|
||||
StringBuilder uri = new StringBuilder();
|
||||
uri.append(getScheme()).append("://");
|
||||
uri.append(InetAddress.getLocalHost().getHostAddress());
|
||||
uri.append(":").append(getServerPort());
|
||||
URIUtil.appendSchemeHostPort(uri, getScheme(), InetAddress.getLocalHost().getHostAddress(), getServerPort());
|
||||
return URI.create(uri.toString());
|
||||
}
|
||||
|
||||
|
|
|
@ -100,9 +100,39 @@
|
|||
<type>war</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/webapps</outputDirectory>
|
||||
<outputDirectory>${assembly-directory}/webapps.demo</outputDirectory>
|
||||
<destFileName>test.war</destFileName>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty.tests</groupId>
|
||||
<artifactId>test-jaas-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>war</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/webapps.demo</outputDirectory>
|
||||
<destFileName>test-jaas.war</destFileName>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty.tests</groupId>
|
||||
<artifactId>test-jndi-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>war</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/webapps.demo</outputDirectory>
|
||||
<destFileName>test-jndi.war</destFileName>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty.tests</groupId>
|
||||
<artifactId>test-spec-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>war</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/webapps.demo</outputDirectory>
|
||||
<destFileName>test-spec.war</destFileName>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>test-proxy-webapp</artifactId>
|
||||
|
@ -110,7 +140,7 @@
|
|||
<type>war</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/webapps</outputDirectory>
|
||||
<outputDirectory>${assembly-directory}/webapps.demo</outputDirectory>
|
||||
<destFileName>xref-proxy.war</destFileName>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
|
@ -120,7 +150,7 @@
|
|||
<type>war</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/webapps</outputDirectory>
|
||||
<outputDirectory>${assembly-directory}/webapps.demo</outputDirectory>
|
||||
<destFileName>async-rest.war</destFileName>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
|
@ -173,6 +203,7 @@
|
|||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<execution>
|
||||
<id>unpack-setuid-config</id>
|
||||
<phase>process-resources</phase>
|
||||
|
@ -193,6 +224,70 @@
|
|||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<execution>
|
||||
<id>unpack-test-jaas-config</id>
|
||||
<phase>process-resources</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty.tests</groupId>
|
||||
<artifactId>test-jaas-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<execution>
|
||||
<id>unpack-test-jndi-config</id>
|
||||
<phase>process-resources</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty.tests</groupId>
|
||||
<artifactId>test-jndi-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<execution>
|
||||
<id>unpack-test-spec-config</id>
|
||||
<phase>process-resources</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty.tests</groupId>
|
||||
<artifactId>test-spec-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<execution>
|
||||
<id>copy-lib-deps</id>
|
||||
<phase>generate-resources</phase>
|
||||
|
|
|
@ -118,9 +118,9 @@ started()
|
|||
for T in 1 2 3 4 5 6 7 9 10 11 12 13 14 15
|
||||
do
|
||||
sleep 4
|
||||
[ -z "$(grep STARTED $1)" ] || return 0
|
||||
[ -z "$(grep STOPPED $1)" ] || return 1
|
||||
[ -z "$(grep FAILED $1)" ] || return 1
|
||||
[ -z "$(grep STARTED $1 2>/dev/null)" ] || return 0
|
||||
[ -z "$(grep STOPPED $1 2>/dev/null)" ] || return 1
|
||||
[ -z "$(grep FAILED $1 2>/dev/null)" ] || return 1
|
||||
local PID=$(cat "$2" 2>/dev/null) || return 1
|
||||
kill -0 "$PID" 2>/dev/null || return 1
|
||||
echo -n ". "
|
||||
|
@ -338,13 +338,17 @@ then
|
|||
fi
|
||||
|
||||
#####################################################
|
||||
# Find a PID for the pid file
|
||||
# Find a pid and state file
|
||||
#####################################################
|
||||
if [ -z "$JETTY_PID" ]
|
||||
then
|
||||
JETTY_PID="$JETTY_RUN/jetty.pid"
|
||||
fi
|
||||
JETTY_STATE=$(dirname $JETTY_PID)/jetty.state
|
||||
|
||||
if [ -z "$JETTY_STATE" ]
|
||||
then
|
||||
JETTY_STATE=$JETTY_HOME/jetty.state
|
||||
fi
|
||||
JAVA_OPTIONS+=("-Djetty.state=$JETTY_STATE")
|
||||
rm -f $JETTY_STATE
|
||||
|
||||
|
@ -415,8 +419,8 @@ if (( DEBUG ))
|
|||
then
|
||||
echo "JETTY_HOME = $JETTY_HOME"
|
||||
echo "JETTY_CONF = $JETTY_CONF"
|
||||
echo "JETTY_RUN = $JETTY_RUN"
|
||||
echo "JETTY_PID = $JETTY_PID"
|
||||
echo "JETTY_START = $JETTY_START"
|
||||
echo "JETTY_ARGS = $JETTY_ARGS"
|
||||
echo "CONFIGS = ${CONFIGS[*]}"
|
||||
echo "JAVA_OPTIONS = ${JAVA_OPTIONS[*]}"
|
||||
|
@ -566,22 +570,21 @@ case "$ACTION" in
|
|||
fi
|
||||
|
||||
exec "${RUN_CMD[@]}"
|
||||
|
||||
;;
|
||||
|
||||
check|status)
|
||||
echo "Checking arguments to Jetty: "
|
||||
echo "START_INI = $START_INI"
|
||||
echo "JETTY_HOME = $JETTY_HOME"
|
||||
echo "JETTY_CONF = $JETTY_CONF"
|
||||
echo "JETTY_RUN = $JETTY_RUN"
|
||||
echo "JETTY_PID = $JETTY_PID"
|
||||
echo "JETTY_PORT = $JETTY_PORT"
|
||||
echo "JETTY_START = $JETTY_START"
|
||||
echo "JETTY_LOGS = $JETTY_LOGS"
|
||||
echo "START_INI = $START_INI"
|
||||
echo "CONFIGS = ${CONFIGS[*]}"
|
||||
echo "JAVA_OPTIONS = ${JAVA_OPTIONS[*]}"
|
||||
echo "JAVA = $JAVA"
|
||||
echo "CLASSPATH = $CLASSPATH"
|
||||
echo "JAVA = $JAVA"
|
||||
echo "JAVA_OPTIONS = ${JAVA_OPTIONS[*]}"
|
||||
echo "JETTY_ARGS = $JETTY_ARGS"
|
||||
echo "RUN_CMD = ${RUN_CMD[*]}"
|
||||
echo
|
||||
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Configure the demos -->
|
||||
<!-- =============================================================== -->
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- ============================================================= -->
|
||||
<!-- Add webapps.demo to deployment manager scans -->
|
||||
<!-- ============================================================= -->
|
||||
<Ref refid="DeploymentManager">
|
||||
<Call id="webappprovider" name="addAppProvider">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.deploy.providers.WebAppProvider">
|
||||
<Set name="monitoredDirName"><Property name="jetty.home" default="." />/webapps.demo</Set>
|
||||
<Set name="defaultsDescriptor"><Property name="jetty.home" default="." />/etc/webdefault.xml</Set>
|
||||
<Set name="scanInterval">1</Set>
|
||||
<Set name="extractWars">true</Set>
|
||||
<Set name="configurationManager">
|
||||
<New class="org.eclipse.jetty.deploy.PropertiesConfigurationManager"/>
|
||||
</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
</Ref>
|
||||
|
||||
|
||||
<!-- ============================================================= -->
|
||||
<!-- Add rewrite rules -->
|
||||
<!-- ============================================================= -->
|
||||
<Ref refid="Rewrite">
|
||||
<!-- Add rule to protect against IE ssl bug -->
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.MsieSslRule"/>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- protect favicon handling -->
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
|
||||
<Set name="pattern">/favicon.ico</Set>
|
||||
<Set name="name">Cache-Control</Set>
|
||||
<Set name="value">Max-Age=3600,public</Set>
|
||||
<Set name="terminating">true</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- redirect from the welcome page to a specific page -->
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Set name="pattern">/test/rewrite/</Set>
|
||||
<Set name="replacement">/test/rewrite/info.html</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- replace the entire request URI -->
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Set name="pattern">/test/some/old/context</Set>
|
||||
<Set name="replacement">/test/rewritten/newcontext</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- replace the beginning of the request URI -->
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Set name="pattern">/test/rewrite/for/*</Set>
|
||||
<Set name="replacement">/test/rewritten/</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- reverse the order of the path sections -->
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewriteRegexRule">
|
||||
<Set name="regex">(.*?)/reverse/([^/]*)/(.*)</Set>
|
||||
<Set name="replacement">$1/reverse/$3/$2</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- add a cookie to each path visited -->
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.CookiePatternRule">
|
||||
<Set name="pattern">/*</Set>
|
||||
<Set name="name">visited</Set>
|
||||
<Set name="value">yes</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- actual redirect, instead of internal rewrite -->
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RedirectPatternRule">
|
||||
<Set name="pattern">/test/redirect/*</Set>
|
||||
<Set name="location">/test/redirected</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- add a response rule -->
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.ResponsePatternRule">
|
||||
<Set name="pattern">/400Error</Set>
|
||||
<Set name="code">400</Set>
|
||||
<Set name="reason">ResponsePatternRule Demo</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
</Ref>
|
||||
</Configure>
|
|
@ -0,0 +1,53 @@
|
|||
|
||||
# ===========================================================
|
||||
# Enable the demonstration web applications
|
||||
#
|
||||
# To disable the demos, either delete this file, move it out of
|
||||
# the start.d directory or rename it to not end with ".ini"
|
||||
# ===========================================================
|
||||
|
||||
# ===========================================================
|
||||
# Enable rewrite handler
|
||||
# -----------------------------------------------------------
|
||||
OPTIONS=rewrite
|
||||
etc/jetty-rewrite.xml
|
||||
|
||||
# ===========================================================
|
||||
# Add a deploy app provider to scan the webapps.demo directory
|
||||
# -----------------------------------------------------------
|
||||
etc/jetty-demo.xml
|
||||
|
||||
# ===========================================================
|
||||
# Enable the Jetty HTTP client APIs for use by demo webapps
|
||||
# -----------------------------------------------------------
|
||||
OPTIONS=client
|
||||
|
||||
# ===========================================================
|
||||
# Enable the test-realm login service for use by authentication
|
||||
# demonstrations
|
||||
# -----------------------------------------------------------
|
||||
etc/test-realm.xml
|
||||
|
||||
# ===========================================================
|
||||
# Enable JAAS test webapp
|
||||
# -----------------------------------------------------------
|
||||
OPTIONS=jaas
|
||||
jaas.login.conf=webapps.demo/test-jaas.d/login.conf
|
||||
etc/jetty-jaas.xml
|
||||
|
||||
# ===========================================================
|
||||
# Enable JNDI test webapp
|
||||
# -----------------------------------------------------------
|
||||
OPTIONS=jndi,jndi.demo
|
||||
|
||||
# ===========================================================
|
||||
# Enable additional webapp environment configurators
|
||||
# -----------------------------------------------------------
|
||||
OPTIONS=plus
|
||||
etc/jetty-plus.xml
|
||||
|
||||
# ===========================================================
|
||||
# Enable servlet 3.1 annotations
|
||||
# -----------------------------------------------------------
|
||||
OPTIONS=annotations
|
||||
etc/jetty-annotations.xml
|
|
@ -1,5 +1,6 @@
|
|||
#===========================================================
|
||||
# Jetty start.jar arguments
|
||||
#
|
||||
# The contents of this file, together with the start.ini
|
||||
# fragments found in start.d directory are used to build
|
||||
# the classpath and command line on a call to
|
||||
|
@ -21,50 +22,34 @@
|
|||
# + A JVM option like: -Xmx2000m
|
||||
# + A System Property like: -Dcom.sun.management.jmxremote
|
||||
#
|
||||
#-----------------------------------------------------------
|
||||
#
|
||||
# NOTE: The lines in this file may be uncommented to activate
|
||||
# features. Alternately, the lines may be copied to a ini file
|
||||
# in the start.d directory to enabled configuration without
|
||||
# editing this file. See start.d/900-demo.ini for an example.
|
||||
#
|
||||
# Future releases will switch start.d style configuration for
|
||||
# all features.
|
||||
#===========================================================
|
||||
|
||||
#===========================================================
|
||||
# The --exec option should be used if any of the JVM options
|
||||
# in this file are uncommented (eg -D* or -X*). Because a
|
||||
# JVM cannot change it's own options, the --exec flag causes
|
||||
# start.jar to fork a new JVM with the requested arguments.
|
||||
#
|
||||
# Alternately, a command line may be generated by running
|
||||
#
|
||||
# java -jar start.jar --exec-print
|
||||
#
|
||||
# and the results executed to start the jetty server.
|
||||
# For example --exec can be avoided if jetty is started on unix with
|
||||
#
|
||||
# eval $(java -jar start.jar --exec-print)
|
||||
#
|
||||
#-----------------------------------------------------------
|
||||
# --exec
|
||||
#===========================================================
|
||||
|
||||
#===========================================================
|
||||
# Configure Properties.
|
||||
# The properties defined here may be used by the
|
||||
# <Property name="myproperty"/> element in the XML files
|
||||
# passed to start.jar.
|
||||
# Alternately a file ending with ".properties" can be
|
||||
# added that will include multiple properties.
|
||||
# Properties, unlike SystemProperties, do not need --exec
|
||||
# to be specified.
|
||||
#-----------------------------------------------------------
|
||||
# jetty.home=.
|
||||
# jetty.logs=./logs
|
||||
# jetty.host=0.0.0.0
|
||||
#===========================================================
|
||||
|
||||
|
||||
#===========================================================
|
||||
# Configure JVM arguments.
|
||||
# Must be used with --exec or --exec-print
|
||||
# If JVM args are include in an ini file then --exec is needed
|
||||
# to start a new JVM from start.jar with the extra args.
|
||||
# If you wish to avoid an extra JVM running, place JVM args
|
||||
# on the normal command line and do not use --exec
|
||||
#-----------------------------------------------------------
|
||||
# -Dorg.apache.jasper.compiler.disablejsr199=true
|
||||
# --exec
|
||||
# -Xmx2000m
|
||||
# -Xmn512m
|
||||
# -XX:+UseConcMarkSweepGC
|
||||
# -XX:ParallelCMSThreads=2
|
||||
# -XX:+CMSClassUnloadingEnabled
|
||||
# -XX:+UseCMSCompactAtFullCollection
|
||||
# -XX:CMSInitiatingOccupancyFraction=80
|
||||
# -verbose:gc
|
||||
# -XX:+PrintGCDateStamps
|
||||
# -XX:+PrintGCTimeStamps
|
||||
|
@ -72,12 +57,10 @@
|
|||
# -XX:+PrintTenuringDistribution
|
||||
# -XX:+PrintCommandLineFlags
|
||||
# -XX:+DisableExplicitGC
|
||||
# -XX:+UseConcMarkSweepGC
|
||||
# -XX:ParallelCMSThreads=2
|
||||
# -XX:+CMSClassUnloadingEnabled
|
||||
# -XX:+UseCMSCompactAtFullCollection
|
||||
# -XX:CMSInitiatingOccupancyFraction=80
|
||||
#===========================================================
|
||||
|
||||
# -Dorg.apache.jasper.compiler.disablejsr199=true
|
||||
|
||||
|
||||
|
||||
#===========================================================
|
||||
# Default Server Options
|
||||
|
@ -87,8 +70,50 @@
|
|||
# Include the core jetty configuration file
|
||||
#-----------------------------------------------------------
|
||||
OPTIONS=Server,websocket,resources,ext
|
||||
threads.min=10
|
||||
threads.max=200
|
||||
threads.timeout=60000
|
||||
#jetty.host=myhost.com
|
||||
jetty.dump.start=false
|
||||
jetty.dump.stop=false
|
||||
|
||||
etc/jetty.xml
|
||||
|
||||
#===========================================================
|
||||
# JMX Management
|
||||
# To enable remote JMX access uncomment jmxremote and
|
||||
# enable --exec
|
||||
#-----------------------------------------------------------
|
||||
OPTIONS=jmx
|
||||
# jetty.jmxrmihost=localhost
|
||||
# jetty.jmxrmiport=1099
|
||||
# -Dcom.sun.management.jmxremote
|
||||
etc/jetty-jmx.xml
|
||||
|
||||
#===========================================================
|
||||
# Java Server Pages
|
||||
#-----------------------------------------------------------
|
||||
OPTIONS=jsp
|
||||
|
||||
#===========================================================
|
||||
# Request logger
|
||||
# Will add a handler to log all HTTP requests to a standard
|
||||
# request log format file.
|
||||
#-----------------------------------------------------------
|
||||
# requestlog.retain=90
|
||||
# requestlog.append=true
|
||||
# requestlog.extended=true
|
||||
# etc/jetty-requestlog.xml
|
||||
|
||||
|
||||
#===========================================================
|
||||
# stderr/stdout logging.
|
||||
# The following configuration will redirect stderr and stdout
|
||||
# to file which is rolled over daily.
|
||||
#-----------------------------------------------------------
|
||||
# jetty.log.retain=90
|
||||
# etc/jetty-logging.xml
|
||||
|
||||
|
||||
#===========================================================
|
||||
# Enable SetUID
|
||||
|
@ -96,59 +121,25 @@ etc/jetty.xml
|
|||
# starting as root you must change the run privledged to true
|
||||
#-----------------------------------------------------------
|
||||
# OPTIONS=setuid
|
||||
# etc/jetty-setuid.xml
|
||||
# jetty.startServerAsPrivileged=false
|
||||
# jetty.username=jetty
|
||||
# jetty.groupname=jetty
|
||||
# jetty.umask=002
|
||||
#===========================================================
|
||||
# etc/jetty-setuid.xml
|
||||
|
||||
#===========================================================
|
||||
# Server logging.
|
||||
# The following configuration will redirect stderr and stdout
|
||||
# to file which is rolled over daily.
|
||||
#-----------------------------------------------------------
|
||||
# etc/jetty-logging.xml
|
||||
#===========================================================
|
||||
|
||||
#===========================================================
|
||||
# JMX Management
|
||||
# To enable remote JMX access uncomment jmxremote and
|
||||
# enable --exec or use --exec-print (see above)
|
||||
#-----------------------------------------------------------
|
||||
OPTIONS=jmx
|
||||
# jetty.jmxrmihost=localhost
|
||||
# jetty.jmxrmiport=1099
|
||||
# -Dcom.sun.management.jmxremote
|
||||
etc/jetty-jmx.xml
|
||||
#===========================================================
|
||||
|
||||
#===========================================================
|
||||
# Java Server Pages
|
||||
#-----------------------------------------------------------
|
||||
OPTIONS=jsp
|
||||
#===========================================================
|
||||
|
||||
|
||||
#===========================================================
|
||||
# Annotations JNDI JAAS processing
|
||||
#-----------------------------------------------------------
|
||||
# OPTIONS=plus
|
||||
# etc/jetty-plus.xml
|
||||
# OPTIONS=annotations
|
||||
# etc/jetty-annotations.xml
|
||||
#===========================================================
|
||||
|
||||
#===========================================================
|
||||
# HTTP Connector
|
||||
#-----------------------------------------------------------
|
||||
# jetty.port=8080
|
||||
jetty.port=8080
|
||||
http.timeout=30000
|
||||
etc/jetty-http.xml
|
||||
#===========================================================
|
||||
|
||||
|
||||
#===========================================================
|
||||
# SSL Context
|
||||
# For use by HTTPS and SPDY
|
||||
# Create the keystore and trust store for use by
|
||||
# HTTPS and SPDY
|
||||
#-----------------------------------------------------------
|
||||
# jetty.keystore=etc/keystore
|
||||
# jetty.keystore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
|
||||
|
@ -157,65 +148,90 @@ etc/jetty-http.xml
|
|||
# jetty.truststore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
|
||||
# jetty.secure.port=8443
|
||||
# etc/jetty-ssl.xml
|
||||
#===========================================================
|
||||
|
||||
|
||||
#===========================================================
|
||||
# HTTPS Connector
|
||||
# Must be used with 200-ssl.ini
|
||||
#-----------------------------------------------------------
|
||||
# jetty.https.port=8443
|
||||
# etc/jetty-https.xml
|
||||
|
||||
|
||||
#===========================================================
|
||||
# NPN Next Protocol Negotiation
|
||||
#
|
||||
# The SPDY and HTTP/2.0 connectors require NPN. The jar for
|
||||
# NPN cannot be downloaded from eclipse. So the --download
|
||||
# option is used to install the NPN jar if it does not already
|
||||
# exist
|
||||
#
|
||||
#-----------------------------------------------------------
|
||||
# --exec
|
||||
# --download=http://repo1.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar:lib/npn/npn-boot-1.1.5.v20130313.jar
|
||||
# -Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar
|
||||
|
||||
|
||||
#===========================================================
|
||||
# SPDY Connector
|
||||
#
|
||||
# SPDY requires the NPN jar which must be separately downloaded:
|
||||
#
|
||||
# http://repo1.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar
|
||||
#
|
||||
# Which should be saved in lib/npn-boot-1.1.5.v20130313.jar
|
||||
#
|
||||
# To include the NPN jar on the boot path, you must either:
|
||||
#
|
||||
# a) enable --exec above and uncomment the -Xbootclass line
|
||||
# below
|
||||
#
|
||||
# b) Add -Xbootclasspath/p:lib/npn-boot-1.1.5.v20130313.jar
|
||||
# to the command line when running jetty.
|
||||
#
|
||||
# Requires SSL Context and NPN from above
|
||||
#-----------------------------------------------------------
|
||||
# OPTIONS=spdy
|
||||
# -Xbootclasspath/p:lib/npn-boot-1.1.5.v20130313.jar
|
||||
# jetty.spdy.port=8443
|
||||
# etc/jetty-spdy.xml
|
||||
#===========================================================
|
||||
|
||||
|
||||
#===========================================================
|
||||
# Webapplication Deployer
|
||||
#-----------------------------------------------------------
|
||||
etc/jetty-deploy.xml
|
||||
#===========================================================
|
||||
|
||||
|
||||
# ===========================================================
|
||||
# Enable JAAS
|
||||
# -----------------------------------------------------------
|
||||
# OPTIONS=jaas
|
||||
# jaas.login.conf=etc/login.conf
|
||||
# etc/jetty-jaas.xml
|
||||
|
||||
# ===========================================================
|
||||
# Enable JNDI
|
||||
# -----------------------------------------------------------
|
||||
# OPTIONS=jndi
|
||||
|
||||
# ===========================================================
|
||||
# Enable additional webapp environment configurators
|
||||
# -----------------------------------------------------------
|
||||
# OPTIONS=plus
|
||||
# etc/jetty-plus.xml
|
||||
|
||||
# ===========================================================
|
||||
# Enable servlet 3.1 annotations
|
||||
# -----------------------------------------------------------
|
||||
# OPTIONS=annotations
|
||||
# etc/jetty-annotations.xml
|
||||
|
||||
#===========================================================
|
||||
# Request logger
|
||||
# Will add a handler to log all HTTP requests to a standard
|
||||
# request log format file.
|
||||
# Other server features
|
||||
#-----------------------------------------------------------
|
||||
etc/jetty-requestlog.xml
|
||||
#===========================================================
|
||||
|
||||
#===========================================================
|
||||
# Additional configurations
|
||||
# See headers of individual files for explanations
|
||||
#-----------------------------------------------------------
|
||||
# etc/jetty-stats.xml
|
||||
# etc/jetty-debug.xml
|
||||
# etc/jetty-ipaccess.xml
|
||||
# etc/jetty-lowresources.xml
|
||||
#===========================================================
|
||||
# etc/jetty-stats.xml
|
||||
|
||||
|
||||
#===========================================================
|
||||
# Lookup additional ini files in start.d
|
||||
# Low resource managment
|
||||
#-----------------------------------------------------------
|
||||
start.d/
|
||||
# lowresources.period=1050
|
||||
# lowresources.lowResourcesIdleTimeout=200
|
||||
# lowresources.monitorThreads=true
|
||||
# lowresources.maxConnections=0
|
||||
# lowresources.maxMemory=0
|
||||
# lowresources.maxLowResourcesTime=5000
|
||||
# etc/jetty-lowresources.xml
|
||||
|
||||
|
||||
#===========================================================
|
||||
# The start.d directory contains the active start.ini fragments
|
||||
start.d/
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
This directory is scanned by the demo WebAppDeployer provider
|
||||
created in the etc/jetty-demo.xml file and enabled by the
|
||||
start.d/900-demo.ini file.
|
||||
|
||||
For normal deployment, use the webapps directory.
|
||||
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 101 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
@ -34,8 +34,9 @@
|
|||
<ul>
|
||||
<li><a href="/test/">Test Jetty Webapp</a></li>
|
||||
<li><a href="/async-rest/">Async Rest</a></li>
|
||||
<li><a href="/proxy/apidocs/">Transparent Proxy to Javadoc</a></li>
|
||||
<li><a href="/proxy/xref/">Transparent Proxy to Xref</a></li>
|
||||
<li><a href="/test-jaas/">JAAS Test</a></li>
|
||||
<li><a href="/test-jndi/">JNDI Test</a></li>
|
||||
<li><a href="/test-spec/">Servlet 3.1 Test</a></li>
|
||||
<li><a href="/oldContextPath/">Redirected Context</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
|
@ -44,6 +45,8 @@
|
|||
<ul>
|
||||
<li><a href="http://www.eclipse.org/jetty/">Jetty @ Eclipse Home</a></li>
|
||||
<li><a href="http://wiki.eclipse.org/Jetty">Jetty @ Eclipse Doco</a></li>
|
||||
<li><a href="/proxy/apidocs/">Javadoc</a> (via transparent proxy)</li>
|
||||
<li><a href="/proxy/xref/">Xref</a> (via transparent proxy)</li>
|
||||
<li><a
|
||||
href="http://docs.codehaus.org/display/JETTY/Jetty+Powered">Jetty Powered</a></li>
|
||||
</ul>
|
|
@ -33,7 +33,7 @@ import org.eclipse.jetty.util.Trie;
|
|||
*/
|
||||
public class HttpField
|
||||
{
|
||||
public final static Trie<HttpField> CACHE = new ArrayTrie<>(1024);
|
||||
public final static Trie<HttpField> CACHE = new ArrayTrie<>(2048);
|
||||
public final static Trie<HttpField> CONTENT_TYPE = new ArrayTrie<>(512);
|
||||
|
||||
static
|
||||
|
@ -77,10 +77,7 @@ public class HttpField
|
|||
}
|
||||
|
||||
// Add headers with null values so HttpParser can avoid looking up name again for unknown values
|
||||
Set<HttpHeader> headers = new HashSet<>();
|
||||
for (String key:CACHE.keySet())
|
||||
headers.add(CACHE.get(key).getHeader());
|
||||
for (HttpHeader h:headers)
|
||||
for (HttpHeader h:HttpHeader.values())
|
||||
if (!CACHE.put(new HttpField(h,(String)null)))
|
||||
throw new IllegalStateException("CACHE FULL");
|
||||
// Add some more common headers
|
||||
|
|
|
@ -110,7 +110,10 @@ public enum HttpMethod
|
|||
{
|
||||
if (buffer.hasArray())
|
||||
return lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.arrayOffset()+buffer.limit());
|
||||
return CACHE.getBest(buffer,0,buffer.remaining());
|
||||
|
||||
// TODO use cache and check for space
|
||||
// return CACHE.getBest(buffer,0,buffer.remaining());
|
||||
return null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.http.HttpTokens.EndOfContent;
|
||||
|
@ -26,6 +25,7 @@ import org.eclipse.jetty.util.ArrayTernaryTrie;
|
|||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.Trie;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
@ -80,13 +80,13 @@ public class HttpParser
|
|||
private String _methodString;
|
||||
private HttpVersion _version;
|
||||
private ByteBuffer _uri=ByteBuffer.allocate(INITIAL_URI_LENGTH); // Tune?
|
||||
private byte _eol;
|
||||
private EndOfContent _endOfContent;
|
||||
private long _contentLength;
|
||||
private long _contentPosition;
|
||||
private int _chunkLength;
|
||||
private int _chunkPosition;
|
||||
private boolean _headResponse;
|
||||
private boolean _cr;
|
||||
private ByteBuffer _contentChunk;
|
||||
private Trie<HttpField> _connectionFields;
|
||||
|
||||
|
@ -204,11 +204,81 @@ public class HttpParser
|
|||
return _state == state;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
private byte next(ByteBuffer buffer)
|
||||
{
|
||||
byte ch=buffer.get();
|
||||
|
||||
// If not a special character
|
||||
if (ch>=HttpTokens.SPACE || ch<0)
|
||||
{
|
||||
if (_cr)
|
||||
{
|
||||
badMessage(buffer,400,"Bad EOL");
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
if (ch>HttpTokens.SPACE)
|
||||
System.err.println("Next "+(char)ch);
|
||||
else
|
||||
System.err.println("Next ["+ch+"]");*/
|
||||
return ch;
|
||||
}
|
||||
|
||||
|
||||
// Only a LF acceptable after CR
|
||||
if (_cr)
|
||||
{
|
||||
_cr=false;
|
||||
if (ch==HttpTokens.LINE_FEED)
|
||||
return ch;
|
||||
|
||||
badMessage(buffer,400,"Bad EOL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If it is a CR
|
||||
if (ch==HttpTokens.CARRIAGE_RETURN)
|
||||
{
|
||||
// Skip CR and look for a LF
|
||||
if (buffer.hasRemaining())
|
||||
{
|
||||
if(_maxHeaderBytes>0 && _state.ordinal()<State.END.ordinal())
|
||||
_headerBytes++;
|
||||
ch=buffer.get();
|
||||
if (ch==HttpTokens.LINE_FEED)
|
||||
return ch;
|
||||
|
||||
badMessage(buffer,HttpStatus.BAD_REQUEST_400,null);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Defer lookup of LF
|
||||
_cr=true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Only LF or TAB acceptable special characters
|
||||
if (ch!=HttpTokens.LINE_FEED && ch!=HttpTokens.TAB)
|
||||
{
|
||||
badMessage(buffer,HttpStatus.BAD_REQUEST_400,null);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
if (ch>HttpTokens.SPACE)
|
||||
System.err.println("Next "+(char)ch);
|
||||
else
|
||||
System.err.println("Next ["+ch+"]");
|
||||
*/
|
||||
return ch;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/* Quick lookahead for the start state looking for a request method or a HTTP version,
|
||||
* otherwise skip white space until something else to parse.
|
||||
*/
|
||||
private void quickStart(ByteBuffer buffer)
|
||||
private boolean quickStart(ByteBuffer buffer)
|
||||
{
|
||||
// Quick start look
|
||||
while (_state==State.START && buffer.hasRemaining())
|
||||
|
@ -221,7 +291,7 @@ public class HttpParser
|
|||
_methodString = _method.asString();
|
||||
buffer.position(buffer.position()+_methodString.length()+1);
|
||||
setState(State.SPACE1);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (_responseHandler!=null)
|
||||
|
@ -231,27 +301,23 @@ public class HttpParser
|
|||
{
|
||||
buffer.position(buffer.position()+_version.asString().length()+1);
|
||||
setState(State.SPACE1);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
byte ch=buffer.get();
|
||||
|
||||
if (_eol == HttpTokens.CARRIAGE_RETURN && ch == HttpTokens.LINE_FEED)
|
||||
{
|
||||
_eol=HttpTokens.LINE_FEED;
|
||||
continue;
|
||||
}
|
||||
_eol=0;
|
||||
|
||||
if (ch > HttpTokens.SPACE || ch<0)
|
||||
byte ch=next(buffer);
|
||||
|
||||
if (ch > HttpTokens.SPACE)
|
||||
{
|
||||
_string.setLength(0);
|
||||
_string.append((char)ch);
|
||||
setState(_requestHandler!=null?State.METHOD:State.RESPONSE_VERSION);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (ch==-1)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String takeString()
|
||||
|
@ -281,7 +347,11 @@ public class HttpParser
|
|||
while (_state.ordinal()<State.HEADER.ordinal() && buffer.hasRemaining() && !return_from_parse)
|
||||
{
|
||||
// process each character
|
||||
byte ch=buffer.get();
|
||||
byte ch=next(buffer);
|
||||
if (ch==-1)
|
||||
return true;
|
||||
if (ch==0)
|
||||
continue;
|
||||
|
||||
if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
|
||||
{
|
||||
|
@ -301,13 +371,6 @@ public class HttpParser
|
|||
return true;
|
||||
}
|
||||
|
||||
if (_eol == HttpTokens.CARRIAGE_RETURN && ch == HttpTokens.LINE_FEED)
|
||||
{
|
||||
_eol=HttpTokens.LINE_FEED;
|
||||
continue;
|
||||
}
|
||||
_eol=0;
|
||||
|
||||
switch (_state)
|
||||
{
|
||||
case METHOD:
|
||||
|
@ -413,7 +476,6 @@ public class HttpParser
|
|||
else if (ch < HttpTokens.SPACE && ch>=0)
|
||||
{
|
||||
return_from_parse|=_responseHandler.startResponse(_version, _responseStatus, null);
|
||||
_eol=ch;
|
||||
setState(State.HEADER);
|
||||
}
|
||||
else
|
||||
|
@ -464,28 +526,39 @@ public class HttpParser
|
|||
{
|
||||
setState(State.REQUEST_VERSION);
|
||||
|
||||
// try quick look ahead
|
||||
// try quick look ahead for HTTP Version
|
||||
if (buffer.position()>0 && buffer.hasArray())
|
||||
{
|
||||
_version=HttpVersion.lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position()-1,buffer.arrayOffset()+buffer.limit());
|
||||
if (_version!=null)
|
||||
HttpVersion version=HttpVersion.lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position()-1,buffer.arrayOffset()+buffer.limit());
|
||||
if (version!=null)
|
||||
{
|
||||
_string.setLength(0);
|
||||
buffer.position(buffer.position()+_version.asString().length()-1);
|
||||
_eol=buffer.get();
|
||||
setState(State.HEADER);
|
||||
_uri.flip();
|
||||
return_from_parse|=_requestHandler.startRequest(_method,_methodString,_uri, _version);
|
||||
int pos = buffer.position()+version.asString().length()-1;
|
||||
if (pos<buffer.limit())
|
||||
{
|
||||
byte n=buffer.get(pos);
|
||||
if (n==HttpTokens.CARRIAGE_RETURN)
|
||||
{
|
||||
_cr=true;
|
||||
_version=version;
|
||||
_string.setLength(0);
|
||||
buffer.position(pos+1);
|
||||
}
|
||||
else if (n==HttpTokens.LINE_FEED)
|
||||
{
|
||||
_version=version;
|
||||
_string.setLength(0);
|
||||
buffer.position(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ch < HttpTokens.SPACE)
|
||||
else if (ch == HttpTokens.LINE_FEED)
|
||||
{
|
||||
if (_responseHandler!=null)
|
||||
{
|
||||
return_from_parse|=_responseHandler.startResponse(_version, _responseStatus, null);
|
||||
_eol=ch;
|
||||
setState(State.HEADER);
|
||||
}
|
||||
else
|
||||
|
@ -502,10 +575,10 @@ public class HttpParser
|
|||
break;
|
||||
|
||||
case REQUEST_VERSION:
|
||||
if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
|
||||
if (ch == HttpTokens.LINE_FEED)
|
||||
{
|
||||
String version = takeString();
|
||||
_version=HttpVersion.CACHE.get(version);
|
||||
if (_version==null)
|
||||
_version=HttpVersion.CACHE.get(takeString());
|
||||
if (_version==null)
|
||||
{
|
||||
badMessage(buffer,HttpStatus.BAD_REQUEST_400,"Unknown Version");
|
||||
|
@ -513,14 +586,13 @@ public class HttpParser
|
|||
}
|
||||
|
||||
// Should we try to cache header fields?
|
||||
if (_version.getVersion()>=HttpVersion.HTTP_1_1.getVersion())
|
||||
if (_connectionFields==null && _version.getVersion()>=HttpVersion.HTTP_1_1.getVersion())
|
||||
{
|
||||
int header_cache = _handler.getHeaderCacheSize();
|
||||
if (header_cache>0)
|
||||
_connectionFields=new ArrayTernaryTrie<>(header_cache);
|
||||
}
|
||||
|
||||
_eol=ch;
|
||||
setState(State.HEADER);
|
||||
_uri.flip();
|
||||
return_from_parse|=_requestHandler.startRequest(_method,_methodString,_uri, _version);
|
||||
|
@ -532,11 +604,10 @@ public class HttpParser
|
|||
break;
|
||||
|
||||
case REASON:
|
||||
if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
|
||||
if (ch == HttpTokens.LINE_FEED)
|
||||
{
|
||||
String reason=takeLengthString();
|
||||
|
||||
_eol=ch;
|
||||
setState(State.HEADER);
|
||||
return_from_parse|=_responseHandler.startResponse(_version, _responseStatus, reason);
|
||||
continue;
|
||||
|
@ -609,7 +680,8 @@ public class HttpParser
|
|||
return true;
|
||||
}
|
||||
|
||||
loop: for (int i = host.length(); i-- > 0;)
|
||||
int len=host.length();
|
||||
loop: for (int i = len; i-- > 0;)
|
||||
{
|
||||
char c2 = (char)(0xff & host.charAt(i));
|
||||
switch (c2)
|
||||
|
@ -620,6 +692,7 @@ public class HttpParser
|
|||
case ':':
|
||||
try
|
||||
{
|
||||
len=i;
|
||||
port = StringUtil.toInt(host.substring(i+1));
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
|
@ -628,10 +701,21 @@ public class HttpParser
|
|||
badMessage(buffer,HttpStatus.BAD_REQUEST_400,"Bad Host header");
|
||||
return true;
|
||||
}
|
||||
host = host.substring(0,i);
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
if (host.charAt(0)=='[')
|
||||
{
|
||||
if (host.charAt(len-1)!=']')
|
||||
{
|
||||
badMessage(buffer,HttpStatus.BAD_REQUEST_400,"Bad IPv6 Host header");
|
||||
return true;
|
||||
}
|
||||
host = host.substring(1,len-1);
|
||||
}
|
||||
else if (len!=host.length())
|
||||
host = host.substring(0,len);
|
||||
|
||||
if (_requestHandler!=null)
|
||||
_requestHandler.parsedHostHeader(host,port);
|
||||
|
||||
|
@ -652,6 +736,9 @@ public class HttpParser
|
|||
case CACHE_CONTROL:
|
||||
case USER_AGENT:
|
||||
add_to_connection_trie=_connectionFields!=null && _field==null;
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (add_to_connection_trie && !_connectionFields.isFull() && _header!=null && _valueString!=null)
|
||||
|
@ -676,7 +763,12 @@ public class HttpParser
|
|||
while (_state.ordinal()<State.END.ordinal() && buffer.hasRemaining() && !return_from_parse)
|
||||
{
|
||||
// process each character
|
||||
byte ch=buffer.get();
|
||||
byte ch=next(buffer);
|
||||
if (ch==-1)
|
||||
return true;
|
||||
if (ch==0)
|
||||
continue;
|
||||
|
||||
if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
|
||||
{
|
||||
LOG.warn("Header is too large >"+_maxHeaderBytes);
|
||||
|
@ -684,13 +776,6 @@ public class HttpParser
|
|||
return true;
|
||||
}
|
||||
|
||||
if (_eol == HttpTokens.CARRIAGE_RETURN && ch == HttpTokens.LINE_FEED)
|
||||
{
|
||||
_eol=HttpTokens.LINE_FEED;
|
||||
continue;
|
||||
}
|
||||
_eol=0;
|
||||
|
||||
switch (_state)
|
||||
{
|
||||
case HEADER:
|
||||
|
@ -735,10 +820,8 @@ public class HttpParser
|
|||
_field=null;
|
||||
|
||||
// now handle the ch
|
||||
if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
|
||||
if (ch == HttpTokens.LINE_FEED)
|
||||
{
|
||||
consumeCRLF(ch,buffer);
|
||||
|
||||
_contentPosition=0;
|
||||
|
||||
// End of headers!
|
||||
|
@ -796,44 +879,53 @@ public class HttpParser
|
|||
}
|
||||
else
|
||||
{
|
||||
if (buffer.remaining()>6)
|
||||
if (buffer.hasRemaining())
|
||||
{
|
||||
// Try a look ahead for the known header name and value.
|
||||
_field=_connectionFields==null?null:_connectionFields.getBest(buffer,-1,buffer.remaining());
|
||||
if (_field==null)
|
||||
_field=HttpField.CACHE.getBest(buffer,-1,buffer.remaining());
|
||||
HttpField field=_connectionFields==null?null:_connectionFields.getBest(buffer,-1,buffer.remaining());
|
||||
if (field==null)
|
||||
field=HttpField.CACHE.getBest(buffer,-1,buffer.remaining());
|
||||
|
||||
if (_field!=null)
|
||||
if (field!=null)
|
||||
{
|
||||
_header=_field.getHeader();
|
||||
_headerString=_field.getName();
|
||||
_valueString=_field.getValue();
|
||||
if (_valueString==null)
|
||||
String n=field.getName();
|
||||
String v=field.getValue();
|
||||
|
||||
if (v==null)
|
||||
{
|
||||
// Header only
|
||||
_header=field.getHeader();
|
||||
_headerString=n;
|
||||
setState(State.HEADER_VALUE);
|
||||
buffer.position(buffer.position()+_headerString.length()+1);
|
||||
_string.setLength(0);
|
||||
_length=0;
|
||||
_field=null;
|
||||
buffer.position(buffer.position()+n.length()+1);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
setState(State.HEADER_IN_VALUE);
|
||||
buffer.position(buffer.position()+_headerString.length()+_valueString.length()+1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Header and value
|
||||
int pos=buffer.position()+n.length()+v.length()+1;
|
||||
byte b=buffer.get(pos);
|
||||
|
||||
// Try a look ahead for the known header name.
|
||||
_header=HttpHeader.CACHE.getBest(buffer,-1,buffer.remaining());
|
||||
//_header=HttpHeader.CACHE.getBest(buffer.array(),buffer.arrayOffset()+buffer.position()-1,buffer.remaining()+1);
|
||||
if (_header!=null)
|
||||
{
|
||||
_headerString=_header.asString();
|
||||
_string.setLength(0);
|
||||
setState(State.HEADER_IN_NAME);
|
||||
buffer.position(buffer.position()+_headerString.length()-1);
|
||||
break;
|
||||
if (b==HttpTokens.CARRIAGE_RETURN || b==HttpTokens.LINE_FEED)
|
||||
{
|
||||
_field=field;
|
||||
_header=_field.getHeader();
|
||||
_headerString=n;
|
||||
_valueString=v;
|
||||
setState(State.HEADER_IN_VALUE);
|
||||
|
||||
if (b==HttpTokens.CARRIAGE_RETURN)
|
||||
{
|
||||
_cr=true;
|
||||
buffer.position(pos+1);
|
||||
}
|
||||
else
|
||||
buffer.position(pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -851,9 +943,7 @@ public class HttpParser
|
|||
case HEADER_NAME:
|
||||
switch(ch)
|
||||
{
|
||||
case HttpTokens.CARRIAGE_RETURN:
|
||||
case HttpTokens.LINE_FEED:
|
||||
consumeCRLF(ch,buffer);
|
||||
if (_headerString==null)
|
||||
{
|
||||
_headerString=takeLengthString();
|
||||
|
@ -888,9 +978,7 @@ public class HttpParser
|
|||
case HEADER_IN_NAME:
|
||||
switch(ch)
|
||||
{
|
||||
case HttpTokens.CARRIAGE_RETURN:
|
||||
case HttpTokens.LINE_FEED:
|
||||
consumeCRLF(ch,buffer);
|
||||
_headerString=takeString();
|
||||
_length=-1;
|
||||
_header=HttpHeader.CACHE.get(_headerString);
|
||||
|
@ -936,9 +1024,7 @@ public class HttpParser
|
|||
case HEADER_VALUE:
|
||||
switch(ch)
|
||||
{
|
||||
case HttpTokens.CARRIAGE_RETURN:
|
||||
case HttpTokens.LINE_FEED:
|
||||
consumeCRLF(ch,buffer);
|
||||
if (_length > 0)
|
||||
{
|
||||
if (_valueString!=null)
|
||||
|
@ -975,9 +1061,7 @@ public class HttpParser
|
|||
case HEADER_IN_VALUE:
|
||||
switch(ch)
|
||||
{
|
||||
case HttpTokens.CARRIAGE_RETURN:
|
||||
case HttpTokens.LINE_FEED:
|
||||
consumeCRLF(ch,buffer);
|
||||
if (_length > 0)
|
||||
{
|
||||
if (HttpHeaderValue.hasKnownValues(_header))
|
||||
|
@ -1030,17 +1114,6 @@ public class HttpParser
|
|||
return return_from_parse;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
private void consumeCRLF(byte ch, ByteBuffer buffer)
|
||||
{
|
||||
_eol=ch;
|
||||
if (_eol==HttpTokens.CARRIAGE_RETURN && buffer.hasRemaining() && buffer.get(buffer.position())==HttpTokens.LINE_FEED)
|
||||
{
|
||||
buffer.get();
|
||||
_eol=0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/**
|
||||
* Parse until next Event.
|
||||
|
@ -1059,7 +1132,8 @@ public class HttpParser
|
|||
_methodString=null;
|
||||
_endOfContent=EndOfContent.UNKNOWN_CONTENT;
|
||||
_header=null;
|
||||
quickStart(buffer);
|
||||
if(quickStart(buffer))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case CONTENT:
|
||||
|
@ -1077,18 +1151,18 @@ public class HttpParser
|
|||
case CLOSED:
|
||||
if (BufferUtil.hasContent(buffer))
|
||||
{
|
||||
int len=buffer.remaining();
|
||||
_headerBytes+=len;
|
||||
// Just ignore data when closed
|
||||
_headerBytes+=buffer.remaining();
|
||||
BufferUtil.clear(buffer);
|
||||
if (_headerBytes>_maxHeaderBytes)
|
||||
{
|
||||
Thread.sleep(100);
|
||||
String chars = BufferUtil.toDetailString(buffer);
|
||||
BufferUtil.clear(buffer);
|
||||
throw new IllegalStateException(String.format("%s %d/%d>%d data when CLOSED:%s",this,len,_headerBytes,_maxHeaderBytes,chars));
|
||||
// Don't want to waste time reading data of a closed request
|
||||
throw new IllegalStateException("too much data after closed");
|
||||
}
|
||||
BufferUtil.clear(buffer);
|
||||
}
|
||||
return false;
|
||||
default: break;
|
||||
|
||||
}
|
||||
|
||||
// Request/response line
|
||||
|
@ -1113,13 +1187,6 @@ public class HttpParser
|
|||
byte ch;
|
||||
while (_state.ordinal() > State.END.ordinal() && buffer.hasRemaining())
|
||||
{
|
||||
if (_eol == HttpTokens.CARRIAGE_RETURN && buffer.get(buffer.position()) == HttpTokens.LINE_FEED)
|
||||
{
|
||||
_eol=buffer.get();
|
||||
continue;
|
||||
}
|
||||
_eol=0;
|
||||
|
||||
switch (_state)
|
||||
{
|
||||
case EOF_CONTENT:
|
||||
|
@ -1169,31 +1236,24 @@ public class HttpParser
|
|||
|
||||
case CHUNKED_CONTENT:
|
||||
{
|
||||
ch=buffer.get(buffer.position());
|
||||
if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
|
||||
_eol=buffer.get();
|
||||
else if (ch <= HttpTokens.SPACE)
|
||||
buffer.get();
|
||||
else
|
||||
ch=next(buffer);
|
||||
if (ch>HttpTokens.SPACE)
|
||||
{
|
||||
_chunkLength=0;
|
||||
_chunkLength=TypeUtil.convertHexDigit(ch);
|
||||
_chunkPosition=0;
|
||||
setState(State.CHUNK_SIZE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CHUNK_SIZE:
|
||||
{
|
||||
ch=buffer.get();
|
||||
if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
|
||||
ch=next(buffer);
|
||||
if (ch == HttpTokens.LINE_FEED)
|
||||
{
|
||||
_eol=ch;
|
||||
|
||||
if (_chunkLength == 0)
|
||||
{
|
||||
if (_eol==HttpTokens.CARRIAGE_RETURN && buffer.hasRemaining() && buffer.get(buffer.position())==HttpTokens.LINE_FEED)
|
||||
_eol=buffer.get();
|
||||
setState(State.END);
|
||||
if (_handler.messageComplete())
|
||||
return true;
|
||||
|
@ -1203,27 +1263,18 @@ public class HttpParser
|
|||
}
|
||||
else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON)
|
||||
setState(State.CHUNK_PARAMS);
|
||||
else if (ch >= '0' && ch <= '9')
|
||||
_chunkLength=_chunkLength * 16 + (ch - '0');
|
||||
else if (ch >= 'a' && ch <= 'f')
|
||||
_chunkLength=_chunkLength * 16 + (10 + ch - 'a');
|
||||
else if (ch >= 'A' && ch <= 'F')
|
||||
_chunkLength=_chunkLength * 16 + (10 + ch - 'A');
|
||||
else
|
||||
throw new IOException("bad chunk char: " + ch);
|
||||
else
|
||||
_chunkLength=_chunkLength * 16 + TypeUtil.convertHexDigit(ch);
|
||||
break;
|
||||
}
|
||||
|
||||
case CHUNK_PARAMS:
|
||||
{
|
||||
ch=buffer.get();
|
||||
if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
|
||||
ch=next(buffer);
|
||||
if (ch == HttpTokens.LINE_FEED)
|
||||
{
|
||||
_eol=ch;
|
||||
if (_chunkLength == 0)
|
||||
{
|
||||
if (_eol==HttpTokens.CARRIAGE_RETURN && buffer.hasRemaining() && buffer.get(buffer.position())==HttpTokens.LINE_FEED)
|
||||
_eol=buffer.get();
|
||||
setState(State.END);
|
||||
if (_handler.messageComplete())
|
||||
return true;
|
||||
|
@ -1262,6 +1313,9 @@ public class HttpParser
|
|||
BufferUtil.clear(buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1340,8 +1394,19 @@ public class HttpParser
|
|||
case CLOSED:
|
||||
case END:
|
||||
break;
|
||||
|
||||
case EOF_CONTENT:
|
||||
_handler.messageComplete();
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG.warn("Closing {}",this);
|
||||
if (_state.ordinal()>State.END.ordinal())
|
||||
{
|
||||
_handler.earlyEOF();
|
||||
_handler.messageComplete();
|
||||
}
|
||||
else
|
||||
LOG.warn("Closing {}",this);
|
||||
}
|
||||
setState(State.CLOSED);
|
||||
_endOfContent=EndOfContent.UNKNOWN_CONTENT;
|
||||
|
@ -1369,6 +1434,7 @@ public class HttpParser
|
|||
/* ------------------------------------------------------------------------------- */
|
||||
private void setState(State state)
|
||||
{
|
||||
// LOG.debug("{} --> {}",_state,state);
|
||||
_state=state;
|
||||
}
|
||||
|
||||
|
@ -1405,8 +1471,18 @@ public class HttpParser
|
|||
*/
|
||||
public boolean parsedHeader(HttpField field);
|
||||
|
||||
public boolean earlyEOF();
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Called to signal that an EOF was received unexpectedly
|
||||
* during the parsing of a HTTP message
|
||||
* @return True if the parser should return to its caller
|
||||
*/
|
||||
public void earlyEOF();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Called to signal that a bad HTTP message has been received.
|
||||
* @param status The bad status to send
|
||||
* @param reason The textual reason for badness
|
||||
*/
|
||||
public void badMessage(int status, String reason);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -1443,5 +1519,9 @@ public class HttpParser
|
|||
public abstract boolean startResponse(HttpVersion version, int status, String reason);
|
||||
}
|
||||
|
||||
public Trie<HttpField> getFieldCache()
|
||||
{
|
||||
return _connectionFields;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -138,9 +138,8 @@ public class HttpTester
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean earlyEOF()
|
||||
public void earlyEOF()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -25,13 +25,12 @@ public interface HttpTokens
|
|||
{
|
||||
// Terminal symbols.
|
||||
static final byte COLON= (byte)':';
|
||||
static final byte SPACE= 0x20;
|
||||
static final byte CARRIAGE_RETURN= 0x0D;
|
||||
static final byte TAB= 0x09;
|
||||
static final byte LINE_FEED= 0x0A;
|
||||
static final byte CARRIAGE_RETURN= 0x0D;
|
||||
static final byte SPACE= 0x20;
|
||||
static final byte[] CRLF = {CARRIAGE_RETURN,LINE_FEED};
|
||||
static final byte SEMI_COLON= (byte)';';
|
||||
static final byte TAB= 0x09;
|
||||
|
||||
|
||||
public enum EndOfContent { UNKNOWN_CONTENT,NO_CONTENT,EOF_CONTENT,CONTENT_LENGTH,CHUNKED_CONTENT,SELF_DEFINING_CONTENT }
|
||||
|
||||
|
|
|
@ -546,6 +546,8 @@ public class HttpURI
|
|||
{
|
||||
if (_host==_port)
|
||||
return null;
|
||||
if (_raw[_host]=='[')
|
||||
return new String(_raw,_host+1,_port-_host-2,_charset);
|
||||
return new String(_raw,_host,_port-_host,_charset);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,9 +51,8 @@ public class HttpGeneratorServerTest
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean earlyEOF()
|
||||
public void earlyEOF()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -23,6 +23,8 @@ import static org.junit.Assert.assertFalse;
|
|||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.http.HttpParser.State;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
|
@ -50,11 +52,13 @@ public class HttpParserTest
|
|||
throw new IllegalStateException("!START");
|
||||
|
||||
// continue parsing
|
||||
while (!parser.isState(State.END) && buffer.hasRemaining())
|
||||
int remaining=buffer.remaining();
|
||||
while (!parser.isState(State.END) && remaining>0)
|
||||
{
|
||||
int remaining=buffer.remaining();
|
||||
int was_remaining=remaining;
|
||||
parser.parseNext(buffer);
|
||||
if (remaining==buffer.remaining())
|
||||
remaining=buffer.remaining();
|
||||
if (remaining==was_remaining)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -64,8 +68,8 @@ public class HttpParserTest
|
|||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer("POST /foo HTTP/1.0\015\012" + "\015\012");
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parseAll(parser,buffer);
|
||||
assertEquals("POST", _methodOrVersion);
|
||||
assertEquals("/foo", _uriOrStatus);
|
||||
|
@ -79,8 +83,8 @@ public class HttpParserTest
|
|||
ByteBuffer buffer= BufferUtil.toBuffer("GET /999\015\012");
|
||||
|
||||
_versionOrReason= null;
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parseAll(parser,buffer);
|
||||
assertEquals("GET", _methodOrVersion);
|
||||
assertEquals("/999", _uriOrStatus);
|
||||
|
@ -94,8 +98,8 @@ public class HttpParserTest
|
|||
ByteBuffer buffer= BufferUtil.toBuffer("POST /222 \015\012");
|
||||
|
||||
_versionOrReason= null;
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parseAll(parser,buffer);
|
||||
assertEquals("POST", _methodOrVersion);
|
||||
assertEquals("/222", _uriOrStatus);
|
||||
|
@ -108,8 +112,8 @@ public class HttpParserTest
|
|||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer("POST /fo\u0690 HTTP/1.0\015\012" + "\015\012",StringUtil.__UTF8_CHARSET);
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parseAll(parser,buffer);
|
||||
assertEquals("POST", _methodOrVersion);
|
||||
assertEquals("/fo\u0690", _uriOrStatus);
|
||||
|
@ -122,8 +126,8 @@ public class HttpParserTest
|
|||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer("POST /foo?param=\u0690 HTTP/1.0\015\012" + "\015\012",StringUtil.__UTF8_CHARSET);
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parseAll(parser,buffer);
|
||||
assertEquals("POST", _methodOrVersion);
|
||||
assertEquals("/foo?param=\u0690", _uriOrStatus);
|
||||
|
@ -136,8 +140,8 @@ public class HttpParserTest
|
|||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer("POST /123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/ HTTP/1.0\015\012" + "\015\012");
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parseAll(parser,buffer);
|
||||
assertEquals("POST", _methodOrVersion);
|
||||
assertEquals("/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/", _uriOrStatus);
|
||||
|
@ -149,10 +153,9 @@ public class HttpParserTest
|
|||
public void testConnect() throws Exception
|
||||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer("CONNECT 192.168.1.2:80 HTTP/1.1\015\012" + "\015\012");
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parseAll(parser,buffer);
|
||||
assertTrue(handler.request);
|
||||
assertEquals("CONNECT", _methodOrVersion);
|
||||
assertEquals("192.168.1.2:80", _uriOrStatus);
|
||||
assertEquals("HTTP/1.1", _versionOrReason);
|
||||
|
@ -182,8 +185,8 @@ public class HttpParserTest
|
|||
BufferUtil.put(b0,buffer);
|
||||
BufferUtil.flipToFlush(buffer,pos);
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parseAll(parser,buffer);
|
||||
|
||||
assertEquals("GET", _methodOrVersion);
|
||||
|
@ -230,8 +233,8 @@ public class HttpParserTest
|
|||
"Accept-Encoding: gzip, deflated\015\012" +
|
||||
"Accept: unknown\015\012" +
|
||||
"\015\012");
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parseAll(parser,buffer);
|
||||
|
||||
assertEquals("GET", _methodOrVersion);
|
||||
|
@ -260,6 +263,8 @@ public class HttpParserTest
|
|||
assertEquals(9, _h);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testHeaderParseLF() throws Exception
|
||||
{
|
||||
|
@ -278,8 +283,8 @@ public class HttpParserTest
|
|||
"Accept-Encoding: gzip, deflated\n" +
|
||||
"Accept: unknown\n" +
|
||||
"\n");
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parseAll(parser,buffer);
|
||||
|
||||
assertEquals("GET", _methodOrVersion);
|
||||
|
@ -328,9 +333,10 @@ public class HttpParserTest
|
|||
|
||||
for (int i=0;i<buffer.capacity()-4;i++)
|
||||
{
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
|
||||
// System.err.println(BufferUtil.toDetailString(buffer));
|
||||
buffer.position(2);
|
||||
buffer.limit(2+i);
|
||||
|
||||
|
@ -377,8 +383,8 @@ public class HttpParserTest
|
|||
+ "1a\015\012"
|
||||
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ\015\012"
|
||||
+ "0\015\012");
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parseAll(parser,buffer);
|
||||
|
||||
assertEquals("GET", _methodOrVersion);
|
||||
|
@ -421,8 +427,8 @@ public class HttpParserTest
|
|||
+ "0123456789\015\012");
|
||||
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("GET", _methodOrVersion);
|
||||
assertEquals("/mp", _uriOrStatus);
|
||||
|
@ -466,8 +472,8 @@ public class HttpParserTest
|
|||
+ "\015\012"
|
||||
+ "0123456789\015\012");
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
|
||||
HttpParser.ResponseHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("HTTP/1.1", _methodOrVersion);
|
||||
assertEquals("200", _uriOrStatus);
|
||||
|
@ -485,8 +491,8 @@ public class HttpParserTest
|
|||
+ "Connection: close\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
|
||||
HttpParser.ResponseHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("HTTP/1.1", _methodOrVersion);
|
||||
assertEquals("304", _uriOrStatus);
|
||||
|
@ -509,8 +515,8 @@ public class HttpParserTest
|
|||
+ "\015\012"
|
||||
+ "0123456789\015\012");
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
|
||||
HttpParser.ResponseHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("HTTP/1.1", _methodOrVersion);
|
||||
assertEquals("204", _uriOrStatus);
|
||||
|
@ -542,8 +548,8 @@ public class HttpParserTest
|
|||
+ "\015\012"
|
||||
+ "0123456789\015\012");
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
|
||||
HttpParser.ResponseHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("HTTP/1.1", _methodOrVersion);
|
||||
assertEquals("200", _uriOrStatus);
|
||||
|
@ -563,8 +569,8 @@ public class HttpParserTest
|
|||
+ "\015\012"
|
||||
+ "0123456789\015\012");
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
|
||||
HttpParser.ResponseHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("HTTP/1.1", _methodOrVersion);
|
||||
assertEquals("200", _uriOrStatus);
|
||||
|
@ -582,8 +588,8 @@ public class HttpParserTest
|
|||
+ "Content-Length: 10\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
|
||||
HttpParser.ResponseHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("HTTP/1.1", _methodOrVersion);
|
||||
assertEquals("304", _uriOrStatus);
|
||||
|
@ -601,8 +607,8 @@ public class HttpParserTest
|
|||
+ "Transfer-Encoding: chunked\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
|
||||
HttpParser.ResponseHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("HTTP/1.1", _methodOrVersion);
|
||||
assertEquals("101", _uriOrStatus);
|
||||
|
@ -624,8 +630,8 @@ public class HttpParserTest
|
|||
+ "HTTP/1.1 400 OK\015\012"); // extra data causes close
|
||||
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
|
||||
HttpParser.ResponseHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("HTTP/1.1", _methodOrVersion);
|
||||
|
@ -647,8 +653,8 @@ public class HttpParserTest
|
|||
+ "Connection: close\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
|
||||
parser.parseNext(buffer);
|
||||
assertEquals(null,_methodOrVersion);
|
||||
|
@ -667,8 +673,8 @@ public class HttpParserTest
|
|||
+ "Connection: close\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
|
||||
parser.parseNext(buffer);
|
||||
assertEquals(null,_methodOrVersion);
|
||||
|
@ -686,8 +692,8 @@ public class HttpParserTest
|
|||
+ "Connection: close\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
|
||||
HttpParser.ResponseHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
|
||||
parser.parseNext(buffer);
|
||||
assertEquals(null,_methodOrVersion);
|
||||
|
@ -705,8 +711,8 @@ public class HttpParserTest
|
|||
+ "Connection: close\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
|
||||
HttpParser.ResponseHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
|
||||
parser.parseNext(buffer);
|
||||
assertEquals(null,_methodOrVersion);
|
||||
|
@ -724,9 +730,9 @@ public class HttpParserTest
|
|||
+ "Connection: close\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
|
||||
|
||||
HttpParser.ResponseHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
|
||||
parser.parseNext(buffer);
|
||||
assertEquals(null,_methodOrVersion);
|
||||
assertEquals("No Status",_bad);
|
||||
|
@ -743,8 +749,23 @@ public class HttpParserTest
|
|||
+ "Connection: close\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
|
||||
parser.parseNext(buffer);
|
||||
assertEquals(null,_methodOrVersion);
|
||||
assertEquals("Unknown Version",_bad);
|
||||
assertFalse(buffer.hasRemaining());
|
||||
assertEquals(HttpParser.State.CLOSED,parser.getState());
|
||||
|
||||
buffer= BufferUtil.toBuffer(
|
||||
"GET / HTTP/1.01\015\012"
|
||||
+ "Content-Length: 0\015\012"
|
||||
+ "Connection: close\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
handler = new Handler();handler = new Handler();
|
||||
parser= new HttpParser(handler);
|
||||
|
||||
parser.parseNext(buffer);
|
||||
assertEquals(null,_methodOrVersion);
|
||||
|
@ -752,6 +773,42 @@ public class HttpParserTest
|
|||
assertFalse(buffer.hasRemaining());
|
||||
assertEquals(HttpParser.State.CLOSED,parser.getState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadCR() throws Exception
|
||||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer(
|
||||
"GET / HTTP/1.0\r\n"
|
||||
+ "Content-Length: 0\r"
|
||||
+ "Connection: close\r"
|
||||
+ "\r");
|
||||
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("Bad EOL",_bad);
|
||||
assertFalse(buffer.hasRemaining());
|
||||
assertEquals(HttpParser.State.CLOSED,parser.getState());
|
||||
|
||||
|
||||
buffer= BufferUtil.toBuffer(
|
||||
"GET / HTTP/1.0\r"
|
||||
+ "Content-Length: 0\r"
|
||||
+ "Connection: close\r"
|
||||
+ "\r");
|
||||
|
||||
handler = new Handler();
|
||||
parser= new HttpParser(handler);
|
||||
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("Bad EOL",_bad);
|
||||
assertFalse(buffer.hasRemaining());
|
||||
assertEquals(HttpParser.State.CLOSED,parser.getState());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testBadContentLength0() throws Exception
|
||||
|
@ -762,8 +819,8 @@ public class HttpParserTest
|
|||
+ "Connection: close\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("GET",_methodOrVersion);
|
||||
|
@ -781,8 +838,8 @@ public class HttpParserTest
|
|||
+ "Connection: close\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("GET",_methodOrVersion);
|
||||
|
@ -800,8 +857,8 @@ public class HttpParserTest
|
|||
+ "Connection: close\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("GET",_methodOrVersion);
|
||||
|
@ -809,7 +866,154 @@ public class HttpParserTest
|
|||
assertFalse(buffer.hasRemaining());
|
||||
assertEquals(HttpParser.State.CLOSED,parser.getState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHost() throws Exception
|
||||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer(
|
||||
"GET / HTTP/1.1\015\012"
|
||||
+ "Host: host\015\012"
|
||||
+ "Connection: close\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("host",_host);
|
||||
assertEquals(0,_port);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIPHost() throws Exception
|
||||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer(
|
||||
"GET / HTTP/1.1\015\012"
|
||||
+ "Host: 192.168.0.1\015\012"
|
||||
+ "Connection: close\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("192.168.0.1",_host);
|
||||
assertEquals(0,_port);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIPv6Host() throws Exception
|
||||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer(
|
||||
"GET / HTTP/1.1\015\012"
|
||||
+ "Host: [::1]\015\012"
|
||||
+ "Connection: close\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("::1",_host);
|
||||
assertEquals(0,_port);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadIPv6Host() throws Exception
|
||||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer(
|
||||
"GET / HTTP/1.1\015\012"
|
||||
+ "Host: [::1\015\012"
|
||||
+ "Connection: close\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("Bad IPv6 Host header",_bad);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHostPort() throws Exception
|
||||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer(
|
||||
"GET / HTTP/1.1\015\012"
|
||||
+ "Host: myhost:8888\015\012"
|
||||
+ "Connection: close\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("myhost",_host);
|
||||
assertEquals(8888,_port);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHostBadPort() throws Exception
|
||||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer(
|
||||
"GET / HTTP/1.1\015\012"
|
||||
+ "Host: myhost:xxx\015\012"
|
||||
+ "Connection: close\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("Bad Host header",_bad);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIPHostPort() throws Exception
|
||||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer(
|
||||
"GET / HTTP/1.1\015\012"
|
||||
+ "Host: 192.168.0.1:8888\015\012"
|
||||
+ "Connection: close\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("192.168.0.1",_host);
|
||||
assertEquals(8888,_port);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIPv6HostPort() throws Exception
|
||||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer(
|
||||
"GET / HTTP/1.1\015\012"
|
||||
+ "Host: [::1]:8888\015\012"
|
||||
+ "Connection: close\015\012"
|
||||
+ "\015\012");
|
||||
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parser.parseNext(buffer);
|
||||
assertEquals("::1",_host);
|
||||
assertEquals(8888,_port);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCachedField() throws Exception
|
||||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer(
|
||||
"GET / HTTP/1.1\r\n"+
|
||||
"Host: www.smh.com.au\r\n"+
|
||||
"\r\n");
|
||||
|
||||
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parseAll(parser,buffer);
|
||||
assertEquals("www.smh.com.au",parser.getFieldCache().get("Host: www.smh.com.au").getValue());
|
||||
HttpField field=_fields.get(0);
|
||||
|
||||
//System.err.println(parser.getFieldCache());
|
||||
|
||||
buffer.position(0);
|
||||
parseAll(parser,buffer);
|
||||
assertTrue(field==_fields.get(0));
|
||||
|
||||
}
|
||||
|
||||
@Before
|
||||
public void init()
|
||||
|
@ -826,11 +1030,14 @@ public class HttpParserTest
|
|||
_messageCompleted=false;
|
||||
}
|
||||
|
||||
private String _host;
|
||||
private int _port;
|
||||
private String _bad;
|
||||
private String _content;
|
||||
private String _methodOrVersion;
|
||||
private String _uriOrStatus;
|
||||
private String _versionOrReason;
|
||||
private List<HttpField> _fields=new ArrayList<>();
|
||||
private String[] _hdr;
|
||||
private String[] _val;
|
||||
private int _h;
|
||||
|
@ -858,6 +1065,7 @@ public class HttpParserTest
|
|||
@Override
|
||||
public boolean startRequest(HttpMethod httpMethod, String method, ByteBuffer uri, HttpVersion version)
|
||||
{
|
||||
_fields.clear();
|
||||
request=true;
|
||||
_h= -1;
|
||||
_hdr= new String[10];
|
||||
|
@ -875,6 +1083,7 @@ public class HttpParserTest
|
|||
@Override
|
||||
public boolean parsedHeader(HttpField field)
|
||||
{
|
||||
_fields.add(field);
|
||||
//System.err.println("header "+name+": "+value);
|
||||
_hdr[++_h]= field.getName();
|
||||
_val[_h]= field.getValue();
|
||||
|
@ -884,7 +1093,8 @@ public class HttpParserTest
|
|||
@Override
|
||||
public boolean parsedHostHeader(String host,int port)
|
||||
{
|
||||
// TODO test this
|
||||
_host=host;
|
||||
_port=port;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -921,6 +1131,7 @@ public class HttpParserTest
|
|||
@Override
|
||||
public boolean startResponse(HttpVersion version, int status, String reason)
|
||||
{
|
||||
_fields.clear();
|
||||
request=false;
|
||||
_methodOrVersion = version.asString();
|
||||
_uriOrStatus = Integer.toString(status);
|
||||
|
@ -936,9 +1147,8 @@ public class HttpParserTest
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean earlyEOF()
|
||||
public void earlyEOF()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -29,39 +29,51 @@ import org.junit.Test;
|
|||
/* ------------------------------------------------------------ */
|
||||
public class HttpURITest
|
||||
{
|
||||
public static final String __input = "http://example.com:8080/path/to/context?parameter=%22value%22#fragment";
|
||||
public static final String __scheme = "http";
|
||||
public static final String __host = "example.com";
|
||||
public static final int __port = 8080;
|
||||
public static final String __path = "/path/to/context";
|
||||
public static final String __query = "parameter=%22value%22";
|
||||
public static final String __fragment = "fragment";
|
||||
String[][] tests=
|
||||
{
|
||||
{"/path/to/context",null,null,"-1","/path/to/context",null,null,null},
|
||||
{"http://example.com/path/to/context;param?query=%22value%22#fragment","http","example.com","-1","/path/to/context","param","query=%22value%22","fragment"},
|
||||
{"http://[::1]/path/to/context;param?query=%22value%22#fragment","http","::1","-1","/path/to/context","param","query=%22value%22","fragment"},
|
||||
{"http://example.com:8080/path/to/context;param?query=%22value%22#fragment","http","example.com","8080","/path/to/context","param","query=%22value%22","fragment"},
|
||||
{"http://[::1]:8080/path/to/context;param?query=%22value%22#fragment","http","::1","8080","/path/to/context","param","query=%22value%22","fragment"},
|
||||
};
|
||||
|
||||
public static int
|
||||
INPUT=0,SCHEME=1,HOST=2,PORT=3,PATH=4,PARAM=5,QUERY=6,FRAGMENT=7;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testFromString() throws Exception
|
||||
{
|
||||
HttpURI uri = new HttpURI(__input);
|
||||
for (String[] test:tests)
|
||||
{
|
||||
HttpURI uri = new HttpURI(test[INPUT]);
|
||||
|
||||
assertEquals(__scheme, uri.getScheme());
|
||||
assertEquals(__host,uri.getHost());
|
||||
assertEquals(__port,uri.getPort());
|
||||
assertEquals(__path,uri.getPath());
|
||||
assertEquals(__query,uri.getQuery());
|
||||
assertEquals(__fragment,uri.getFragment());
|
||||
assertEquals(test[SCHEME], uri.getScheme());
|
||||
assertEquals(test[HOST], uri.getHost());
|
||||
assertEquals(Integer.parseInt(test[PORT]), uri.getPort());
|
||||
assertEquals(test[PATH], uri.getPath());
|
||||
assertEquals(test[PARAM], uri.getParam());
|
||||
assertEquals(test[QUERY], uri.getQuery());
|
||||
assertEquals(test[FRAGMENT], uri.getFragment());
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testFromURI() throws Exception
|
||||
{
|
||||
HttpURI uri = new HttpURI(new URI(__input));
|
||||
for (String[] test:tests)
|
||||
{
|
||||
HttpURI uri = new HttpURI(new URI(test[INPUT]));
|
||||
|
||||
assertEquals(__scheme, uri.getScheme());
|
||||
assertEquals(__host,uri.getHost());
|
||||
assertEquals(__port,uri.getPort());
|
||||
assertEquals(__path,uri.getPath());
|
||||
assertEquals(__query,uri.getQuery());
|
||||
assertEquals(__fragment,uri.getFragment());
|
||||
assertEquals(test[SCHEME], uri.getScheme());
|
||||
assertEquals(test[HOST], uri.getHost());
|
||||
assertEquals(Integer.parseInt(test[PORT]), uri.getPort());
|
||||
assertEquals(test[PATH], uri.getPath());
|
||||
assertEquals(test[PARAM], uri.getParam());
|
||||
assertEquals(test[QUERY], uri.getQuery());
|
||||
assertEquals(test[FRAGMENT], uri.getFragment());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.util.concurrent.Executor;
|
|||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jetty.util.BlockingCallback;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -112,13 +113,130 @@ public abstract class AbstractConnection implements Connection
|
|||
if (_state.compareAndSet(State.FILLING,State.FILLING_INTERESTED))
|
||||
break loop;
|
||||
break;
|
||||
|
||||
case FILLING_BLOCKED:
|
||||
if (_state.compareAndSet(State.FILLING_BLOCKED,State.FILLING_BLOCKED_INTERESTED))
|
||||
break loop;
|
||||
break;
|
||||
|
||||
case BLOCKED:
|
||||
if (_state.compareAndSet(State.BLOCKED,State.BLOCKED_INTERESTED))
|
||||
break loop;
|
||||
break;
|
||||
|
||||
case FILLING_BLOCKED_INTERESTED:
|
||||
case FILLING_INTERESTED:
|
||||
case BLOCKED_INTERESTED:
|
||||
case INTERESTED:
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void unblock()
|
||||
{
|
||||
LOG.debug("unblock {}",this);
|
||||
|
||||
loop:while(true)
|
||||
{
|
||||
switch(_state.get())
|
||||
{
|
||||
case FILLING_BLOCKED:
|
||||
if (_state.compareAndSet(State.FILLING_BLOCKED,State.FILLING))
|
||||
break loop;
|
||||
break;
|
||||
|
||||
case FILLING_BLOCKED_INTERESTED:
|
||||
if (_state.compareAndSet(State.FILLING_BLOCKED_INTERESTED,State.FILLING_INTERESTED))
|
||||
break loop;
|
||||
break;
|
||||
|
||||
case BLOCKED_INTERESTED:
|
||||
if (_state.compareAndSet(State.BLOCKED_INTERESTED,State.INTERESTED))
|
||||
{
|
||||
getEndPoint().fillInterested(_readCallback);
|
||||
break loop;
|
||||
}
|
||||
break;
|
||||
|
||||
case BLOCKED:
|
||||
if (_state.compareAndSet(State.BLOCKED,State.IDLE))
|
||||
break loop;
|
||||
break;
|
||||
|
||||
case FILLING:
|
||||
case IDLE:
|
||||
case FILLING_INTERESTED:
|
||||
case INTERESTED:
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
protected void block(final BlockingCallback callback)
|
||||
{
|
||||
LOG.debug("block {}",this);
|
||||
|
||||
final Callback blocked=new Callback()
|
||||
{
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
unblock();
|
||||
callback.succeeded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable x)
|
||||
{
|
||||
unblock();
|
||||
callback.failed(x);
|
||||
}
|
||||
};
|
||||
|
||||
loop:while(true)
|
||||
{
|
||||
switch(_state.get())
|
||||
{
|
||||
case IDLE:
|
||||
if (_state.compareAndSet(State.IDLE,State.BLOCKED))
|
||||
{
|
||||
getEndPoint().fillInterested(blocked);
|
||||
break loop;
|
||||
}
|
||||
break;
|
||||
|
||||
case FILLING:
|
||||
if (_state.compareAndSet(State.FILLING,State.FILLING_BLOCKED))
|
||||
{
|
||||
getEndPoint().fillInterested(blocked);
|
||||
break loop;
|
||||
}
|
||||
break;
|
||||
|
||||
case FILLING_INTERESTED:
|
||||
if (_state.compareAndSet(State.FILLING_INTERESTED,State.FILLING_BLOCKED_INTERESTED))
|
||||
{
|
||||
getEndPoint().fillInterested(blocked);
|
||||
break loop;
|
||||
}
|
||||
break;
|
||||
|
||||
case BLOCKED:
|
||||
case BLOCKED_INTERESTED:
|
||||
case FILLING_BLOCKED:
|
||||
case FILLING_BLOCKED_INTERESTED:
|
||||
throw new IllegalStateException("Already Blocked");
|
||||
|
||||
case INTERESTED:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Callback method invoked when the endpoint is ready to be read.</p>
|
||||
|
@ -225,7 +343,7 @@ public abstract class AbstractConnection implements Connection
|
|||
|
||||
private enum State
|
||||
{
|
||||
IDLE, INTERESTED, FILLING, FILLING_INTERESTED
|
||||
IDLE, INTERESTED, FILLING, FILLING_INTERESTED, FILLING_BLOCKED, BLOCKED, FILLING_BLOCKED_INTERESTED, BLOCKED_INTERESTED
|
||||
}
|
||||
|
||||
private class ReadCallback implements Callback, Runnable
|
||||
|
@ -247,12 +365,25 @@ public abstract class AbstractConnection implements Connection
|
|||
{
|
||||
case IDLE:
|
||||
case INTERESTED:
|
||||
throw new IllegalStateException();
|
||||
case BLOCKED:
|
||||
case BLOCKED_INTERESTED:
|
||||
LOG.warn(new IllegalStateException());
|
||||
return;
|
||||
|
||||
case FILLING:
|
||||
if (_state.compareAndSet(State.FILLING,State.IDLE))
|
||||
break loop;
|
||||
break;
|
||||
|
||||
case FILLING_BLOCKED:
|
||||
if (_state.compareAndSet(State.FILLING_BLOCKED,State.BLOCKED))
|
||||
break loop;
|
||||
break;
|
||||
|
||||
case FILLING_BLOCKED_INTERESTED:
|
||||
if (_state.compareAndSet(State.FILLING_BLOCKED_INTERESTED,State.BLOCKED_INTERESTED))
|
||||
break loop;
|
||||
break;
|
||||
|
||||
case FILLING_INTERESTED:
|
||||
if (_state.compareAndSet(State.FILLING_INTERESTED,State.INTERESTED))
|
||||
|
@ -266,7 +397,7 @@ public abstract class AbstractConnection implements Connection
|
|||
}
|
||||
}
|
||||
else
|
||||
LOG.warn(new Throwable());
|
||||
LOG.warn(new IllegalStateException());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -35,7 +35,6 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -167,20 +166,6 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
selector.submit(selector.new Accept(channel));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Registers a channel to perform non-blocking read/write operations.</p>
|
||||
* <p>This method is called just after a channel has been accepted by {@link ServerSocketChannel#accept()},
|
||||
* or just after having performed a blocking connect via {@link Socket#connect(SocketAddress, int)}.</p>
|
||||
*
|
||||
* @param channel the channel to register
|
||||
* @param attachment An attachment to be passed via the selection key to the {@link SelectorManager#newConnection(SocketChannel, EndPoint, Object)} method.
|
||||
*/
|
||||
public void accept(final SocketChannel channel, Object attachment)
|
||||
{
|
||||
final ManagedSelector selector = chooseSelector();
|
||||
selector.submit(selector.new Accept(channel, attachment));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
|
@ -333,7 +318,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
public class ManagedSelector extends AbstractLifeCycle implements Runnable, Dumpable
|
||||
{
|
||||
private final Queue<Runnable> _changes = new ConcurrentArrayQueue<>();
|
||||
|
||||
|
||||
private final int _id;
|
||||
private Selector _selector;
|
||||
private volatile Thread _thread;
|
||||
|
@ -699,18 +684,10 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
private class Accept implements Runnable
|
||||
{
|
||||
private final SocketChannel _channel;
|
||||
private final Object _attachment;
|
||||
|
||||
public Accept(SocketChannel channel)
|
||||
{
|
||||
this._channel = channel;
|
||||
this._attachment = null;
|
||||
}
|
||||
|
||||
public Accept(SocketChannel channel, Object attachment)
|
||||
{
|
||||
this._channel = channel;
|
||||
this._attachment = attachment;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -718,7 +695,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
try
|
||||
{
|
||||
SelectionKey key = _channel.register(_selector, 0, _attachment);
|
||||
SelectionKey key = _channel.register(_selector, 0, null);
|
||||
EndPoint endpoint = createEndPoint(_channel, key);
|
||||
key.attach(endpoint);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<!-- ======================================================== -->
|
||||
<Call class="java.lang.System" name="setProperty">
|
||||
<Arg>java.security.auth.login.config</Arg>
|
||||
<Arg><SystemProperty name="jetty.home" default="." />/etc/login.conf</Arg>
|
||||
<Arg><Property name="jetty.home" default="." />/<Property name="jaas.login.conf" default="etc/login.conf"/></Arg>
|
||||
</Call>
|
||||
|
||||
</Configure>
|
||||
|
|
|
@ -284,7 +284,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
/**
|
||||
* A wrapper for the Server object
|
||||
*/
|
||||
protected JettyServer server = JettyServer.getInstance();
|
||||
protected JettyServer server = new JettyServer();
|
||||
|
||||
|
||||
/**
|
||||
|
@ -494,6 +494,8 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
String tmp = System.getProperty(PORT_SYSPROPERTY, MavenServerConnector.DEFAULT_PORT_STR);
|
||||
httpConnector.setPort(Integer.parseInt(tmp.trim()));
|
||||
}
|
||||
if (httpConnector.getServer() == null)
|
||||
httpConnector.setServer(this.server);
|
||||
this.server.addConnector(httpConnector);
|
||||
}
|
||||
|
||||
|
@ -504,12 +506,13 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
//if <httpConnector> not configured in the pom, create one
|
||||
if (httpConnector == null)
|
||||
{
|
||||
httpConnector = new MavenServerConnector();
|
||||
httpConnector = new MavenServerConnector();
|
||||
//use any jetty.port settings provided
|
||||
String tmp = System.getProperty(PORT_SYSPROPERTY, MavenServerConnector.DEFAULT_PORT_STR);
|
||||
httpConnector.setPort(Integer.parseInt(tmp.trim()));
|
||||
}
|
||||
|
||||
if (httpConnector.getServer() == null)
|
||||
httpConnector.setServer(this.server);
|
||||
this.server.setConnectors(new Connector[] {httpConnector});
|
||||
}
|
||||
|
||||
|
|
|
@ -38,16 +38,6 @@ public class JettyServer extends org.eclipse.jetty.server.Server
|
|||
{
|
||||
public static final JettyServer __instance = new JettyServer();
|
||||
|
||||
/**
|
||||
* Singleton instance
|
||||
* @return
|
||||
*/
|
||||
public static JettyServer getInstance()
|
||||
{
|
||||
return __instance;
|
||||
}
|
||||
|
||||
|
||||
private RequestLog requestLog;
|
||||
private ContextHandlerCollection contexts;
|
||||
|
||||
|
@ -56,7 +46,7 @@ public class JettyServer extends org.eclipse.jetty.server.Server
|
|||
/**
|
||||
*
|
||||
*/
|
||||
private JettyServer()
|
||||
public JettyServer()
|
||||
{
|
||||
super();
|
||||
setStopAtShutdown(true);
|
||||
|
|
|
@ -19,21 +19,259 @@
|
|||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.ConnectionFactory;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.thread.Scheduler;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* MavenServerConnector
|
||||
*
|
||||
*
|
||||
* As the ServerConnector class does not have a no-arg constructor, and moreover requires
|
||||
* the server instance passed in to all its constructors, it cannot
|
||||
* be referenced in the pom.xml. This class wraps a ServerConnector, delaying setting the
|
||||
* server instance. Only a few of the setters from the ServerConnector class are supported.
|
||||
*/
|
||||
public class MavenServerConnector extends ServerConnector
|
||||
public class MavenServerConnector extends AbstractLifeCycle implements Connector
|
||||
{
|
||||
public static int DEFAULT_PORT = 8080;
|
||||
public static String DEFAULT_PORT_STR = String.valueOf(DEFAULT_PORT);
|
||||
public static int DEFAULT_MAX_IDLE_TIME = 30000;
|
||||
|
||||
private Server server;
|
||||
private ServerConnector delegate;
|
||||
private String host;
|
||||
private String name;
|
||||
private int port;
|
||||
private long idleTimeout;
|
||||
private int lingerTime;
|
||||
|
||||
|
||||
public MavenServerConnector()
|
||||
{
|
||||
super(JettyServer.getInstance());
|
||||
}
|
||||
|
||||
public void setServer(Server server)
|
||||
{
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public void setHost(String host)
|
||||
{
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public String getHost()
|
||||
{
|
||||
return this.host;
|
||||
}
|
||||
|
||||
public void setPort(int port)
|
||||
{
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public int getPort ()
|
||||
{
|
||||
return this.port;
|
||||
}
|
||||
|
||||
public void setName (String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setIdleTimeout(long idleTimeout)
|
||||
{
|
||||
this.idleTimeout = idleTimeout;
|
||||
}
|
||||
|
||||
public void setSoLingerTime(int lingerTime)
|
||||
{
|
||||
this.lingerTime = lingerTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
|
||||
if (this.server == null)
|
||||
throw new IllegalStateException("Server not set for MavenServerConnector");
|
||||
|
||||
this.delegate = new ServerConnector(this.server);
|
||||
this.delegate.setName(this.name);
|
||||
this.delegate.setPort(this.port);
|
||||
this.delegate.setHost(this.host);
|
||||
this.delegate.setIdleTimeout(idleTimeout);
|
||||
this.delegate.setSoLingerTime(lingerTime);
|
||||
this.delegate.start();
|
||||
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
this.delegate.stop();
|
||||
super.doStop();
|
||||
this.delegate = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.util.component.Graceful#shutdown()
|
||||
*/
|
||||
@Override
|
||||
public Future<Void> shutdown()
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.Connector#getServer()
|
||||
*/
|
||||
@Override
|
||||
public Server getServer()
|
||||
{
|
||||
return this.server;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.Connector#getExecutor()
|
||||
*/
|
||||
@Override
|
||||
public Executor getExecutor()
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getExecutor();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.Connector#getScheduler()
|
||||
*/
|
||||
@Override
|
||||
public Scheduler getScheduler()
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getScheduler();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.Connector#getByteBufferPool()
|
||||
*/
|
||||
@Override
|
||||
public ByteBufferPool getByteBufferPool()
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getByteBufferPool();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.Connector#getConnectionFactory(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public ConnectionFactory getConnectionFactory(String nextProtocol)
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getConnectionFactory(nextProtocol);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.Connector#getConnectionFactory(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> T getConnectionFactory(Class<T> factoryType)
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getConnectionFactory(factoryType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.Connector#getDefaultConnectionFactory()
|
||||
*/
|
||||
@Override
|
||||
public ConnectionFactory getDefaultConnectionFactory()
|
||||
{
|
||||
checkDelegate();
|
||||
return getDefaultConnectionFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.Connector#getConnectionFactories()
|
||||
*/
|
||||
@Override
|
||||
public Collection<ConnectionFactory> getConnectionFactories()
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getConnectionFactories();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.Connector#getProtocols()
|
||||
*/
|
||||
@Override
|
||||
public List<String> getProtocols()
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getProtocols();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.Connector#getIdleTimeout()
|
||||
*/
|
||||
@Override
|
||||
@ManagedAttribute("maximum time a connection can be idle before being closed (in ms)")
|
||||
public long getIdleTimeout()
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getIdleTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.Connector#getTransport()
|
||||
*/
|
||||
@Override
|
||||
public Object getTransport()
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getTransport();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.Connector#getConnectedEndPoints()
|
||||
*/
|
||||
@Override
|
||||
public Collection<EndPoint> getConnectedEndPoints()
|
||||
{
|
||||
checkDelegate();
|
||||
return this.delegate.getConnectedEndPoints();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.Connector#getName()
|
||||
*/
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return this.name;
|
||||
}
|
||||
|
||||
private void checkDelegate() throws IllegalStateException
|
||||
{
|
||||
if (this.delegate == null)
|
||||
throw new IllegalStateException ("MavenServerConnector delegate not ready");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ public class Starter
|
|||
private List<File> jettyXmls; // list of jetty.xml config files to apply - Mandatory
|
||||
private File contextXml; //name of context xml file to configure the webapp - Mandatory
|
||||
|
||||
private JettyServer server;
|
||||
private JettyServer server = new JettyServer();
|
||||
private JettyWebAppContext webApp;
|
||||
|
||||
|
||||
|
@ -120,8 +120,6 @@ public class Starter
|
|||
{
|
||||
LOG.debug("Starting Jetty Server ...");
|
||||
|
||||
this.server = JettyServer.getInstance();
|
||||
|
||||
//apply any configs from jetty.xml files first
|
||||
applyJettyXml ();
|
||||
|
||||
|
@ -132,6 +130,7 @@ public class Starter
|
|||
{
|
||||
//if a SystemProperty -Djetty.port=<portnum> has been supplied, use that as the default port
|
||||
MavenServerConnector httpConnector = new MavenServerConnector();
|
||||
httpConnector.setServer(this.server);
|
||||
String tmp = System.getProperty(PORT_SYSPROPERTY, MavenServerConnector.DEFAULT_PORT_STR);
|
||||
httpConnector.setPort(Integer.parseInt(tmp.trim()));
|
||||
connectors = new Connector[] {httpConnector};
|
||||
|
|
|
@ -149,7 +149,7 @@ public class MongoSessionManager extends NoSqlSessionManager
|
|||
}
|
||||
else
|
||||
{
|
||||
version = new Long(((Long)version).intValue() + 1);
|
||||
version = new Long(((Number)version).longValue() + 1);
|
||||
update.put("$inc",__version_1);
|
||||
}
|
||||
|
||||
|
|
|
@ -236,7 +236,7 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
// can define their own configuration.
|
||||
if ((enUrls == null || !enUrls.hasMoreElements()))
|
||||
{
|
||||
String tmp = DEFAULT_JETTYHOME+etcFile;
|
||||
String tmp = DEFAULT_JETTYHOME+(DEFAULT_JETTYHOME.endsWith("/")?"":"/")+etcFile;
|
||||
enUrls = BundleFileLocatorHelperFactory.getFactory().getHelper().findEntries(configurationBundle, tmp);
|
||||
LOG.info("Configuring jetty from bundle: "
|
||||
+ configurationBundle.getSymbolicName()
|
||||
|
|
|
@ -95,7 +95,7 @@
|
|||
<version>${exam.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ops4j.pax.runner</groupId>
|
||||
<artifactId>pax-runner-no-jcl</artifactId>
|
||||
|
@ -141,12 +141,14 @@
|
|||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- For sane logging -->
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>1.6.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
-->
|
||||
<!-- Orbit Servlet Deps -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.orbit</groupId>
|
||||
|
@ -258,7 +260,7 @@
|
|||
<version>${project.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-core</artifactId>
|
||||
|
@ -296,7 +298,7 @@
|
|||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-plus</artifactId>
|
||||
|
|
|
@ -78,17 +78,21 @@ public class TestJettyOSGiBootContextAsService
|
|||
// to pick up and deploy
|
||||
options.add(mavenBundle().groupId("org.eclipse.jetty.osgi").artifactId("test-jetty-osgi-context").versionAsInProject().start());
|
||||
|
||||
String logLevel = "WARN";
|
||||
// Enable Logging
|
||||
if (LOGGING_ENABLED)
|
||||
{
|
||||
options.addAll(Arrays.asList(options(
|
||||
// install log service using pax runners profile abstraction (there
|
||||
// are more profiles, like DS)
|
||||
// logProfile(),
|
||||
// this is how you set the default log level when using pax logging
|
||||
// (logProfile)
|
||||
systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("INFO"))));
|
||||
}
|
||||
logLevel = "INFO";
|
||||
|
||||
|
||||
options.addAll(Arrays.asList(options(
|
||||
// install log service using pax runners profile abstraction (there
|
||||
// are more profiles, like DS)
|
||||
// logProfile(),
|
||||
// this is how you set the default log level when using pax logging
|
||||
// (logProfile)
|
||||
systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value(logLevel),
|
||||
systemProperty("org.eclipse.jetty.LEVEL").value(logLevel))));
|
||||
|
||||
|
||||
return options.toArray(new Option[options.size()]);
|
||||
}
|
||||
|
@ -142,12 +146,14 @@ public class TestJettyOSGiBootContextAsService
|
|||
ServiceReference[] refs = bundleContext.getServiceReferences(ContextHandler.class.getName(), null);
|
||||
Assert.assertNotNull(refs);
|
||||
Assert.assertEquals(1, refs.length);
|
||||
String[] keys = refs[0].getPropertyKeys();
|
||||
//uncomment for debugging
|
||||
/*
|
||||
String[] keys = refs[0].getPropertyKeys();
|
||||
if (keys != null)
|
||||
{
|
||||
for (String k : keys)
|
||||
System.err.println("service property: " + k + ", " + refs[0].getProperty(k));
|
||||
}
|
||||
}*/
|
||||
ContextHandler ch = (ContextHandler) bundleContext.getService(refs[0]);
|
||||
Assert.assertEquals("/acme", ch.getContextPath());
|
||||
|
||||
|
|
|
@ -53,7 +53,6 @@ public class TestJettyOSGiBootCore
|
|||
public Option[] config()
|
||||
{
|
||||
VersionResolver resolver = MavenUtils.asInProject();
|
||||
System.err.println(resolver.getVersion("org.eclipse.jetty", "jetty-server"));
|
||||
ArrayList<Option> options = new ArrayList<Option>();
|
||||
TestOSGiUtil.addMoreOSGiContainers(options);
|
||||
options.addAll(provisionCoreJetty());
|
||||
|
|
|
@ -19,9 +19,13 @@
|
|||
package org.eclipse.jetty.osgi.test;
|
||||
|
||||
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
|
||||
import static org.ops4j.pax.exam.CoreOptions.systemProperty;
|
||||
import static org.ops4j.pax.exam.CoreOptions.options;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
@ -41,7 +45,8 @@ import org.osgi.framework.BundleContext;
|
|||
@RunWith(JUnit4TestRunner.class)
|
||||
public class TestJettyOSGiBootSpdy
|
||||
{
|
||||
|
||||
private static final boolean LOGGING_ENABLED = false;
|
||||
|
||||
private static final String JETTY_SPDY_PORT = "jetty.spdy.port";
|
||||
|
||||
private static final int DEFAULT_JETTY_SPDY_PORT = 9877;
|
||||
|
@ -61,6 +66,22 @@ public class TestJettyOSGiBootSpdy
|
|||
options.add(CoreOptions.junitBundles());
|
||||
options.addAll(TestJettyOSGiBootCore.httpServiceJetty());
|
||||
options.addAll(spdyJettyDependencies());
|
||||
|
||||
String logLevel = "WARN";
|
||||
|
||||
// Enable Logging
|
||||
if (LOGGING_ENABLED)
|
||||
logLevel = "INFO";
|
||||
|
||||
|
||||
options.addAll(Arrays.asList(options(
|
||||
// install log service using pax runners profile abstraction (there
|
||||
// are more profiles, like DS)
|
||||
// logProfile(),
|
||||
// this is how you set the default log level when using pax logging
|
||||
// (logProfile)
|
||||
systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value(logLevel),
|
||||
systemProperty("org.eclipse.jetty.LEVEL").value(logLevel))));
|
||||
return options.toArray(new Option[options.size()]);
|
||||
}
|
||||
|
||||
|
|
|
@ -77,18 +77,20 @@ public class TestJettyOSGiBootWebAppAsService
|
|||
options.addAll(configureJettyHomeAndPort("jetty-selector.xml"));
|
||||
options.add(CoreOptions.bootDelegationPackages("org.xml.sax", "org.xml.*", "org.w3c.*", "javax.xml.*"));
|
||||
options.addAll(TestJettyOSGiBootCore.coreJettyDependencies());
|
||||
|
||||
// Enable Logging
|
||||
|
||||
String logLevel = "WARN";
|
||||
if (LOGGING_ENABLED)
|
||||
{
|
||||
options.addAll(Arrays.asList(options(
|
||||
// install log service using pax runners profile abstraction (there
|
||||
// are more profiles, like DS)
|
||||
// logProfile(),
|
||||
// this is how you set the default log level when using pax logging
|
||||
// (logProfile)
|
||||
systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("INFO"))));
|
||||
}
|
||||
logLevel = "INFO";
|
||||
|
||||
|
||||
options.addAll(Arrays.asList(options(
|
||||
// install log service using pax runners profile abstraction (there
|
||||
// are more profiles, like DS)
|
||||
// logProfile(),
|
||||
// this is how you set the default log level when using pax logging
|
||||
// (logProfile)
|
||||
systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value(logLevel),
|
||||
systemProperty("org.eclipse.jetty.LEVEL").value(logLevel))));
|
||||
|
||||
options.addAll(jspDependencies());
|
||||
return options.toArray(new Option[options.size()]);
|
||||
|
|
|
@ -52,7 +52,7 @@ import org.osgi.framework.BundleContext;
|
|||
@RunWith(JUnit4TestRunner.class)
|
||||
public class TestJettyOSGiBootWithJsp
|
||||
{
|
||||
private static final boolean LOGGING_ENABLED = true;
|
||||
private static final boolean LOGGING_ENABLED = false;
|
||||
|
||||
private static final boolean REMOTE_DEBUGGING = false;
|
||||
|
||||
|
@ -72,18 +72,21 @@ public class TestJettyOSGiBootWithJsp
|
|||
options.add(CoreOptions.bootDelegationPackages("org.xml.sax", "org.xml.*", "org.w3c.*", "javax.xml.*"));
|
||||
options.addAll(TestJettyOSGiBootCore.coreJettyDependencies());
|
||||
|
||||
String logLevel = "WARN";
|
||||
|
||||
// Enable Logging
|
||||
if (LOGGING_ENABLED)
|
||||
{
|
||||
logLevel = "INFO";
|
||||
|
||||
options.addAll(Arrays.asList(options(
|
||||
// install log service using pax runners profile abstraction (there
|
||||
// are more profiles, like DS)
|
||||
// logProfile(),
|
||||
// this is how you set the default log level when using pax logging
|
||||
// (logProfile)
|
||||
systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("INFO"))));
|
||||
}
|
||||
|
||||
systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value(logLevel),
|
||||
systemProperty("org.eclipse.jetty.LEVEL").value(logLevel))));
|
||||
|
||||
options.addAll(jspDependencies());
|
||||
|
||||
// Remote JDWP Debugging, this won't work with the forked container.
|
||||
|
@ -119,7 +122,6 @@ public class TestJettyOSGiBootWithJsp
|
|||
+ etc
|
||||
+ "/jetty-testrealm.xml";
|
||||
options.add(systemProperty(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS).value(xmlConfigs));
|
||||
System.err.println(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS+"="+xmlConfigs);
|
||||
options.add(systemProperty("jetty.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT)));
|
||||
options.add(systemProperty("jetty.home").value(etcFolder.getParentFile().getAbsolutePath()));
|
||||
return options;
|
||||
|
@ -163,10 +165,6 @@ public class TestJettyOSGiBootWithJsp
|
|||
@Test
|
||||
public void testJspDump() throws Exception
|
||||
{
|
||||
|
||||
// System.err.println("http://127.0.0.1:9876/jsp/dump.jsp sleeping....");
|
||||
// Thread.currentThread().sleep(5000000);
|
||||
// now test the jsp/dump.jsp
|
||||
HttpClient client = new HttpClient();
|
||||
try
|
||||
{
|
||||
|
@ -175,7 +173,6 @@ public class TestJettyOSGiBootWithJsp
|
|||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
|
||||
String content = new String(response.getContent());
|
||||
System.err.println("content: " + content);
|
||||
Assert.assertTrue(content.contains("<tr><th>ServletPath:</th><td>/jsp/dump.jsp</td></tr>"));
|
||||
}
|
||||
finally
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# LOG4J levels: OFF, FATAL, ERROR, WARN, INFO, DEBUG, ALL
|
||||
#
|
||||
log4j.rootLogger=ALL,CONSOLE
|
||||
|
||||
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
|
||||
#log4j.appender.CONSOLE.threshold=INFO
|
||||
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
|
||||
#log4j.appender.CONSOLE.layout.ConversionPattern=%d %t [%5p][%c{1}] %m%n
|
||||
log4j.appender.CONSOLE.layout.ConversionPattern=%d [%5p][%c] %m%n
|
||||
|
||||
# Level tuning
|
||||
log4j.logger.org.eclipse.jetty=INFO
|
||||
log4j.logger.org.ops4j=WARN
|
|
@ -16,101 +16,9 @@
|
|||
<Set name="handler">
|
||||
<New id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
|
||||
<Set name="handler"><Ref refid="oldhandler"/></Set>
|
||||
<Set name="rewriteRequestURI">true</Set>
|
||||
<Set name="rewritePathInfo">false</Set>
|
||||
<Set name="originalPathAttribute">requestedPath</Set>
|
||||
|
||||
<!-- Add rule to protect against IE ssl bug -->
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.MsieSslRule"/>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- protect favicon handling -->
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
|
||||
<Set name="pattern">/favicon.ico</Set>
|
||||
<Set name="name">Cache-Control</Set>
|
||||
<Set name="value">Max-Age=3600,public</Set>
|
||||
<Set name="terminating">true</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- redirect from the welcome page to a specific page -->
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Set name="pattern">/test/rewrite/</Set>
|
||||
<Set name="replacement">/test/rewrite/info.html</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- replace the entire request URI -->
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Set name="pattern">/test/some/old/context</Set>
|
||||
<Set name="replacement">/test/rewritten/newcontext</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- replace the beginning of the request URI -->
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Set name="pattern">/test/rewrite/for/*</Set>
|
||||
<Set name="replacement">/test/rewritten/</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- reverse the order of the path sections -->
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewriteRegexRule">
|
||||
<Set name="regex">(.*?)/reverse/([^/]*)/(.*)</Set>
|
||||
<Set name="replacement">$1/reverse/$3/$2</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- add a cookie to each path visited -->
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.CookiePatternRule">
|
||||
<Set name="pattern">/*</Set>
|
||||
<Set name="name">visited</Set>
|
||||
<Set name="value">yes</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- actual redirect, instead of internal rewrite -->
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RedirectPatternRule">
|
||||
<Set name="pattern">/test/redirect/*</Set>
|
||||
<Set name="location">/test/redirected</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- add a response rule -->
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.ResponsePatternRule">
|
||||
<Set name="pattern">/400Error</Set>
|
||||
<Set name="code">400</Set>
|
||||
<Set name="reason">ResponsePatternRule Demo</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<Set name="rewriteRequestURI"><Property name="rewrite.rewriteRequestURI" default="true"/></Set>
|
||||
<Set name="rewritePathInfo"><Property name="rewrite.rewritePathInfo" default="false"/></Set>
|
||||
<Set name="originalPathAttribute"><Property name="rewrite.originalPathAttribute" default="requestedPath"/></Set>
|
||||
</New>
|
||||
</Set>
|
||||
|
||||
|
|
|
@ -27,9 +27,7 @@
|
|||
</goals>
|
||||
<configuration>
|
||||
<includes>**</includes>
|
||||
<excludes>**/MANIFEST.MF</excludes>
|
||||
<excludes>**/ECLIPSEF.RSA</excludes>
|
||||
<excludes>**/ECLIPSEF.SF</excludes>
|
||||
<excludes>**/MANIFEST.MF,META-INF/*.RSA,META-INF/*.DSA,META-INF/*.SF</excludes>
|
||||
<outputDirectory>${project.build.directory}/classes</outputDirectory>
|
||||
<overWriteReleases>false</overWriteReleases>
|
||||
<overWriteSnapshots>true</overWriteSnapshots>
|
||||
|
|
|
@ -551,23 +551,20 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
protected void processConstraintMappingWithMethodOmissions (ConstraintMapping mapping, Map<String, RoleInfo> mappings)
|
||||
{
|
||||
String[] omissions = mapping.getMethodOmissions();
|
||||
|
||||
for (String omission:omissions)
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i=0; i<omissions.length; i++)
|
||||
{
|
||||
//for each method omission, see if there is already a RoleInfo for it in mappings
|
||||
RoleInfo ri = mappings.get(omission+OMISSION_SUFFIX);
|
||||
if (ri == null)
|
||||
{
|
||||
//if not, make one
|
||||
ri = new RoleInfo();
|
||||
mappings.put(omission+OMISSION_SUFFIX, ri);
|
||||
}
|
||||
|
||||
//initialize RoleInfo or combine from ConstraintMapping
|
||||
configureRoleInfo(ri, mapping);
|
||||
if (i > 0)
|
||||
sb.append(".");
|
||||
sb.append(omissions[i]);
|
||||
}
|
||||
sb.append(OMISSION_SUFFIX);
|
||||
|
||||
RoleInfo ri = new RoleInfo();
|
||||
mappings.put(sb.toString(), ri);
|
||||
configureRoleInfo(ri, mapping);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -630,7 +627,7 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
* <ol>
|
||||
* <li>A mapping of an exact method name </li>
|
||||
* <li>A mapping will null key that matches every method name</li>
|
||||
* <li>Mappings with keys of the form "method.omission" that indicates it will match every method name EXCEPT that given</li>
|
||||
* <li>Mappings with keys of the form "<method>.<method>.<method>.omission" that indicates it will match every method name EXCEPT those given</li>
|
||||
* </ol>
|
||||
*
|
||||
* @see org.eclipse.jetty.security.SecurityHandler#prepareConstraintInfo(java.lang.String, org.eclipse.jetty.server.Request)
|
||||
|
@ -659,7 +656,7 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
//(ie matches because target method is not omitted, hence considered covered by the constraint)
|
||||
for (Entry<String, RoleInfo> entry: mappings.entrySet())
|
||||
{
|
||||
if (entry.getKey() != null && entry.getKey().contains(OMISSION_SUFFIX) && !(httpMethod+OMISSION_SUFFIX).equals(entry.getKey()))
|
||||
if (entry.getKey() != null && entry.getKey().endsWith(OMISSION_SUFFIX) && ! entry.getKey().contains(httpMethod))
|
||||
applicableConstraints.add(entry.getValue());
|
||||
}
|
||||
|
||||
|
|
|
@ -21,11 +21,11 @@ package org.eclipse.jetty.security.authentication;
|
|||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.BitSet;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
@ -53,24 +53,40 @@ import org.eclipse.jetty.util.security.Credential;
|
|||
* @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
|
||||
*
|
||||
* The nonce max age in ms can be set with the {@link SecurityHandler#setInitParameter(String, String)}
|
||||
* using the name "maxNonceAge"
|
||||
* using the name "maxNonceAge". The nonce max count can be set with {@link SecurityHandler#setInitParameter(String, String)}
|
||||
* using the name "maxNonceCount". When the age or count is exceeded, the nonce is considered stale.
|
||||
*/
|
||||
public class DigestAuthenticator extends LoginAuthenticator
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(DigestAuthenticator.class);
|
||||
SecureRandom _random = new SecureRandom();
|
||||
private long _maxNonceAgeMs = 60*1000;
|
||||
private ConcurrentMap<String, Nonce> _nonceCount = new ConcurrentHashMap<String, Nonce>();
|
||||
private int _maxNC=1024;
|
||||
private ConcurrentMap<String, Nonce> _nonceMap = new ConcurrentHashMap<String, Nonce>();
|
||||
private Queue<Nonce> _nonceQueue = new ConcurrentLinkedQueue<Nonce>();
|
||||
private static class Nonce
|
||||
{
|
||||
final String _nonce;
|
||||
final long _ts;
|
||||
AtomicInteger _nc=new AtomicInteger();
|
||||
public Nonce(String nonce, long ts)
|
||||
final BitSet _seen;
|
||||
|
||||
public Nonce(String nonce, long ts, int size)
|
||||
{
|
||||
_nonce=nonce;
|
||||
_ts=ts;
|
||||
_seen = new BitSet(size);
|
||||
}
|
||||
|
||||
public boolean seen(int count)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (count>=_seen.size())
|
||||
return true;
|
||||
boolean s=_seen.get(count);
|
||||
_seen.set(count);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,11 +108,31 @@ public class DigestAuthenticator extends LoginAuthenticator
|
|||
String mna=configuration.getInitParameter("maxNonceAge");
|
||||
if (mna!=null)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
_maxNonceAgeMs=Long.valueOf(mna);
|
||||
}
|
||||
_maxNonceAgeMs=Long.valueOf(mna);
|
||||
}
|
||||
String mnc=configuration.getInitParameter("maxNonceCount");
|
||||
if (mnc!=null)
|
||||
{
|
||||
_maxNC=Integer.valueOf(mnc);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public int getMaxNonceCount()
|
||||
{
|
||||
return _maxNC;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setMaxNonceCount(int maxNC)
|
||||
{
|
||||
_maxNC = maxNC;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public long getMaxNonceAge()
|
||||
{
|
||||
return _maxNonceAgeMs;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -238,9 +274,9 @@ public class DigestAuthenticator extends LoginAuthenticator
|
|||
byte[] nounce = new byte[24];
|
||||
_random.nextBytes(nounce);
|
||||
|
||||
nonce = new Nonce(new String(B64Code.encode(nounce)),request.getTimeStamp());
|
||||
nonce = new Nonce(new String(B64Code.encode(nounce)),request.getTimeStamp(),_maxNC);
|
||||
}
|
||||
while (_nonceCount.putIfAbsent(nonce._nonce,nonce)!=null);
|
||||
while (_nonceMap.putIfAbsent(nonce._nonce,nonce)!=null);
|
||||
_nonceQueue.add(nonce);
|
||||
|
||||
return nonce._nonce;
|
||||
|
@ -255,34 +291,27 @@ public class DigestAuthenticator extends LoginAuthenticator
|
|||
private int checkNonce(Digest digest, Request request)
|
||||
{
|
||||
// firstly let's expire old nonces
|
||||
long expired;
|
||||
synchronized (this)
|
||||
{
|
||||
expired = request.getTimeStamp()-_maxNonceAgeMs;
|
||||
}
|
||||
|
||||
long expired = request.getTimeStamp()-_maxNonceAgeMs;
|
||||
Nonce nonce=_nonceQueue.peek();
|
||||
while (nonce!=null && nonce._ts<expired)
|
||||
{
|
||||
_nonceQueue.remove(nonce);
|
||||
_nonceCount.remove(nonce._nonce);
|
||||
_nonceMap.remove(nonce._nonce);
|
||||
nonce=_nonceQueue.peek();
|
||||
}
|
||||
|
||||
|
||||
// Now check the requested nonce
|
||||
try
|
||||
{
|
||||
nonce = _nonceCount.get(digest.nonce);
|
||||
nonce = _nonceMap.get(digest.nonce);
|
||||
if (nonce==null)
|
||||
return 0;
|
||||
|
||||
long count = Long.parseLong(digest.nc,16);
|
||||
if (count>Integer.MAX_VALUE)
|
||||
if (count>=_maxNC)
|
||||
return 0;
|
||||
int old=nonce._nc.get();
|
||||
while (!nonce._nc.compareAndSet(old,(int)count))
|
||||
old=nonce._nc.get();
|
||||
if (count<=old)
|
||||
|
||||
if (nonce.seen((int)count))
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
|
@ -383,6 +412,7 @@ public class DigestAuthenticator extends LoginAuthenticator
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return username + "," + response;
|
||||
|
|
|
@ -25,6 +25,7 @@ import static org.junit.Assert.assertTrue;
|
|||
import static org.junit.matchers.JUnitMatchers.containsString;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
@ -33,12 +34,15 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.security.authentication.BasicAuthenticator;
|
||||
import org.eclipse.jetty.security.authentication.DigestAuthenticator;
|
||||
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
|
@ -52,7 +56,10 @@ import org.eclipse.jetty.server.handler.ContextHandler;
|
|||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||
import org.eclipse.jetty.server.session.SessionHandler;
|
||||
import org.eclipse.jetty.util.B64Code;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.eclipse.jetty.util.security.Credential;
|
||||
import org.eclipse.jetty.util.security.Password;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
@ -205,7 +212,6 @@ public class ConstraintTest
|
|||
@Test
|
||||
public void testBasic() throws Exception
|
||||
{
|
||||
|
||||
List<ConstraintMapping> list = new ArrayList<ConstraintMapping>(_security.getConstraintMappings());
|
||||
|
||||
Constraint constraint6 = new Constraint();
|
||||
|
@ -250,14 +256,11 @@ public class ConstraintTest
|
|||
_server.start();
|
||||
|
||||
String response;
|
||||
/*
|
||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n\r\n");
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
*/
|
||||
|
||||
response = _connector.getResponses("GET /ctx/forbid/info HTTP/1.0\r\n\r\n");
|
||||
assertThat(response,startsWith("HTTP/1.1 403 Forbidden"));
|
||||
/*
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
||||
assertThat(response,startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertThat(response,containsString("WWW-Authenticate: basic realm=\"TestRealm\""));
|
||||
|
@ -272,8 +275,7 @@ public class ConstraintTest
|
|||
"Authorization: Basic " + B64Code.encode("user:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
*/
|
||||
/*
|
||||
|
||||
// test admin
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n\r\n");
|
||||
assertThat(response,startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
|
@ -304,28 +306,159 @@ public class ConstraintTest
|
|||
response = _connector.getResponses("GET /ctx/omit/x HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("admin:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
//check POST is in role user
|
||||
response = _connector.getResponses("POST /ctx/omit/x HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user2:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
//check POST can be in role foo too
|
||||
response = _connector.getResponses("POST /ctx/omit/x HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user3:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
//check HEAD cannot be in role user
|
||||
response = _connector.getResponses("HEAD /ctx/omit/x HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user2:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));*/
|
||||
assertThat(response,startsWith("HTTP/1.1 403 "));
|
||||
}
|
||||
|
||||
|
||||
private static String CNONCE="1234567890";
|
||||
private String digest(String nonce, String username,String password,String uri,String nc) throws Exception
|
||||
{
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
byte[] ha1;
|
||||
// calc A1 digest
|
||||
md.update(username.getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte) ':');
|
||||
md.update("TestRealm".getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte) ':');
|
||||
md.update(password.getBytes(StringUtil.__ISO_8859_1));
|
||||
ha1 = md.digest();
|
||||
// calc A2 digest
|
||||
md.reset();
|
||||
md.update("GET".getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte) ':');
|
||||
md.update(uri.getBytes(StringUtil.__ISO_8859_1));
|
||||
byte[] ha2 = md.digest();
|
||||
|
||||
// calc digest
|
||||
// request-digest = <"> < KD ( H(A1), unq(nonce-value) ":"
|
||||
// nc-value ":" unq(cnonce-value) ":" unq(qop-value) ":" H(A2) )
|
||||
// <">
|
||||
// request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2)
|
||||
// ) > <">
|
||||
|
||||
md.update(TypeUtil.toString(ha1, 16).getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte) ':');
|
||||
md.update(nonce.getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte) ':');
|
||||
md.update(nc.getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte) ':');
|
||||
md.update(CNONCE.getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte) ':');
|
||||
md.update("auth".getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte) ':');
|
||||
md.update(TypeUtil.toString(ha2, 16).getBytes(StringUtil.__ISO_8859_1));
|
||||
byte[] digest = md.digest();
|
||||
|
||||
// check digest
|
||||
return TypeUtil.toString(digest, 16);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDigest() throws Exception
|
||||
{
|
||||
DigestAuthenticator authenticator = new DigestAuthenticator();
|
||||
authenticator.setMaxNonceCount(5);
|
||||
_security.setAuthenticator(authenticator);
|
||||
_security.setStrict(false);
|
||||
_server.start();
|
||||
|
||||
String response;
|
||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n\r\n");
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/forbid/info HTTP/1.0\r\n\r\n");
|
||||
assertThat(response,startsWith("HTTP/1.1 403 Forbidden"));
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
||||
assertThat(response,startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertThat(response,containsString("WWW-Authenticate: Digest realm=\"TestRealm\""));
|
||||
|
||||
Pattern nonceP = Pattern.compile("nonce=\"([^\"]*)\",");
|
||||
Matcher matcher = nonceP.matcher(response);
|
||||
assertTrue(matcher.find());
|
||||
String nonce=matcher.group(1);
|
||||
|
||||
|
||||
//wrong password
|
||||
String digest= digest(nonce,"user","WRONG","/ctx/auth/info","1");
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: Digest username=\"user\", qop=auth, cnonce=\"1234567890\", uri=\"/ctx/auth/info\", realm=\"TestRealm\", "+
|
||||
"nc=1, "+
|
||||
"nonce=\""+nonce+"\", "+
|
||||
"response=\""+digest+"\"\r\n"+
|
||||
"\r\n");
|
||||
assertThat(response,startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
|
||||
// right password
|
||||
digest= digest(nonce,"user","password","/ctx/auth/info","2");
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: Digest username=\"user\", qop=auth, cnonce=\"1234567890\", uri=\"/ctx/auth/info\", realm=\"TestRealm\", "+
|
||||
"nc=2, "+
|
||||
"nonce=\""+nonce+"\", "+
|
||||
"response=\""+digest+"\"\r\n"+
|
||||
"\r\n");
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
|
||||
// once only
|
||||
digest= digest(nonce,"user","password","/ctx/auth/info","2");
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: Digest username=\"user\", qop=auth, cnonce=\"1234567890\", uri=\"/ctx/auth/info\", realm=\"TestRealm\", "+
|
||||
"nc=2, "+
|
||||
"nonce=\""+nonce+"\", "+
|
||||
"response=\""+digest+"\"\r\n"+
|
||||
"\r\n");
|
||||
assertThat(response,startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
|
||||
// increasing
|
||||
digest= digest(nonce,"user","password","/ctx/auth/info","4");
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: Digest username=\"user\", qop=auth, cnonce=\"1234567890\", uri=\"/ctx/auth/info\", realm=\"TestRealm\", "+
|
||||
"nc=4, "+
|
||||
"nonce=\""+nonce+"\", "+
|
||||
"response=\""+digest+"\"\r\n"+
|
||||
"\r\n");
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
// out of order
|
||||
digest= digest(nonce,"user","password","/ctx/auth/info","3");
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: Digest username=\"user\", qop=auth, cnonce=\"1234567890\", uri=\"/ctx/auth/info\", realm=\"TestRealm\", "+
|
||||
"nc=3, "+
|
||||
"nonce=\""+nonce+"\", "+
|
||||
"response=\""+digest+"\"\r\n"+
|
||||
"\r\n");
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
// stale
|
||||
digest= digest(nonce,"user","password","/ctx/auth/info","5");
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: Digest username=\"user\", qop=auth, cnonce=\"1234567890\", uri=\"/ctx/auth/info\", realm=\"TestRealm\", "+
|
||||
"nc=5, "+
|
||||
"nonce=\""+nonce+"\", "+
|
||||
"response=\""+digest+"\"\r\n"+
|
||||
"\r\n");
|
||||
assertThat(response,startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertThat(response,containsString("stale=true"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFormDispatch() throws Exception
|
||||
|
@ -863,32 +996,32 @@ public class ConstraintTest
|
|||
String response;
|
||||
|
||||
response = _connector.getResponses("GET /ctx/data/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403"));
|
||||
assertThat(response,startsWith("HTTP/1.1 403"));
|
||||
|
||||
_config.setSecurePort(8443);
|
||||
_config.setSecureScheme("https");
|
||||
|
||||
response = _connector.getResponses("GET /ctx/data/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 302 Found"));
|
||||
assertThat(response,startsWith("HTTP/1.1 302 Found"));
|
||||
assertTrue(response.indexOf("Location") > 0);
|
||||
assertTrue(response.indexOf(":8443/ctx/data/info") > 0);
|
||||
|
||||
_config.setSecurePort(443);
|
||||
response = _connector.getResponses("GET /ctx/data/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 302 Found"));
|
||||
assertThat(response,startsWith("HTTP/1.1 302 Found"));
|
||||
assertTrue(response.indexOf("Location") > 0);
|
||||
assertTrue(response.indexOf(":443/ctx/data/info") < 0);
|
||||
|
||||
_config.setSecurePort(8443);
|
||||
response = _connector.getResponses("GET /ctx/data/info HTTP/1.0\r\nHost: wobble.com\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 302 Found"));
|
||||
assertThat(response,startsWith("HTTP/1.1 302 Found"));
|
||||
assertTrue(response.indexOf("Location") > 0);
|
||||
assertTrue(response.indexOf("https://wobble.com:8443/ctx/data/info") > 0);
|
||||
|
||||
_config.setSecurePort(443);
|
||||
response = _connector.getResponses("GET /ctx/data/info HTTP/1.0\r\nHost: wobble.com\r\n\r\n");
|
||||
System.err.println(response);
|
||||
assertTrue(response.startsWith("HTTP/1.1 302 Found"));
|
||||
assertThat(response,startsWith("HTTP/1.1 302 Found"));
|
||||
assertTrue(response.indexOf("Location") > 0);
|
||||
assertTrue(response.indexOf(":443") < 0);
|
||||
assertTrue(response.indexOf("https://wobble.com/ctx/data/info") > 0);
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
</Arg>
|
||||
<Set name="host"><Property name="jetty.host" /></Set>
|
||||
<Set name="port"><Property name="jetty.port" default="8080" /></Set>
|
||||
<Set name="idleTimeout">30000</Set>
|
||||
<Set name="idleTimeout"><Property name="http.timeout" default="30000"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
|
|
@ -10,12 +10,12 @@
|
|||
<Arg>
|
||||
<New class="org.eclipse.jetty.server.LowResourceMonitor">
|
||||
<Arg name="server"><Ref refid='Server'/></Arg>
|
||||
<Set name="period">1000</Set>
|
||||
<Set name="lowResourcesIdleTimeout">200</Set>
|
||||
<Set name="monitorThreads">true</Set>
|
||||
<Set name="maxConnections">0</Set>
|
||||
<Set name="maxMemory">0</Set>
|
||||
<Set name="maxLowResourcesTime">5000</Set>
|
||||
<Set name="period"><Property name="lowresources.period" default="1000"/></Set>
|
||||
<Set name="lowResourcesIdleTimeout"><Property name="lowresources.lowResourcesIdleTimeout" default="200"/></Set>
|
||||
<Set name="monitorThreads"><Property name="lowresources.monitorThreads" default="true"/></Set>
|
||||
<Set name="maxConnections"><Property name="lowresources.maxConnections" default="0"/></Set>
|
||||
<Set name="maxMemory"><Property name="lowresources.maxMemory" default="0"/></Set>
|
||||
<Set name="maxLowResourcesTime"><Property name="lowresources.maxLowResourcesTime" default="5000"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<New id="RequestLogImpl" class="org.eclipse.jetty.server.AsyncNCSARequestLog">
|
||||
<Set name="filename"><Property name="jetty.logs" default="./logs" />/yyyy_mm_dd.request.log</Set>
|
||||
<Set name="filenameDateFormat">yyyy_MM_dd</Set>
|
||||
<Set name="retainDays">90</Set>
|
||||
<Set name="append">true</Set>
|
||||
<Set name="extended">true</Set>
|
||||
<Set name="retainDays"><Property name="requestlog.retain" default="90"/></Set>
|
||||
<Set name="append"><Property name="requestlog.append" default="false"/></Set>
|
||||
<Set name="extended"><Property name="requestlog.extended" default="false"/></Set>
|
||||
<Set name="logCookies">false</Set>
|
||||
<Set name="LogTimeZone">GMT</Set>
|
||||
</New>
|
||||
|
|
|
@ -12,4 +12,7 @@
|
|||
<Set name="handler"><Ref refid="oldhandler" /></Set>
|
||||
</New>
|
||||
</Set>
|
||||
<Call class="org.eclipse.jetty.server.ConnectorStatistics" name="addToAllConnectors">
|
||||
<Arg><Ref refid="Server"/></Arg>
|
||||
</Call>
|
||||
</Configure>
|
||||
|
|
|
@ -44,9 +44,9 @@
|
|||
<!-- =========================================================== -->
|
||||
<Arg name="threadpool">
|
||||
<New id="threadpool" class="org.eclipse.jetty.util.thread.QueuedThreadPool">
|
||||
<Arg name="minThreads" type="int">10</Arg>
|
||||
<Arg name="maxThreads" type="int">200</Arg>
|
||||
<Arg name="idleTimeout" type="int">60000</Arg>
|
||||
<Arg name="minThreads" type="int"><Property name="threads.min" default="10"/></Arg>
|
||||
<Arg name="maxThreads" type="int"><Property name="threads.max" default="200"/></Arg>
|
||||
<Arg name="idleTimeout" type="int"><Property name="threads.timeout" default="60000"/></Arg>
|
||||
<Set name="detailedDump">false</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
@ -124,7 +124,7 @@
|
|||
<!-- =========================================================== -->
|
||||
<Set name="stopAtShutdown">true</Set>
|
||||
<Set name="stopTimeout">5000</Set>
|
||||
<Set name="dumpAfterStart">false</Set>
|
||||
<Set name="dumpBeforeStop">false</Set>
|
||||
<Set name="dumpAfterStart"><Property name="jetty.dump.start" default="false"/></Set>
|
||||
<Set name="dumpBeforeStop"><Property name="jetty.dump.stop" default="false"/></Set>
|
||||
|
||||
</Configure>
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.AsyncEvent;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import org.eclipse.jetty.server.handler.ContextHandler.Context;
|
||||
import org.eclipse.jetty.util.thread.Scheduler;
|
||||
|
||||
public class AsyncContextEvent extends AsyncEvent
|
||||
{
|
||||
final private Context _context;
|
||||
final private AsyncContextState _asyncContext;
|
||||
volatile HttpChannelState _state;
|
||||
private ServletContext _dispatchContext;
|
||||
private String _pathInContext;
|
||||
private Scheduler.Task _timeoutTask;
|
||||
private Throwable _throwable;
|
||||
|
||||
public AsyncContextEvent(Context context,AsyncContextState asyncContext, HttpChannelState state, Request baseRequest, ServletRequest request, ServletResponse response)
|
||||
{
|
||||
super(null,request,response,null);
|
||||
_context=context;
|
||||
_asyncContext=asyncContext;
|
||||
_state=state;
|
||||
|
||||
// If we haven't been async dispatched before
|
||||
if (baseRequest.getAttribute(AsyncContext.ASYNC_REQUEST_URI)==null)
|
||||
{
|
||||
// We are setting these attributes during startAsync, when the spec implies that
|
||||
// they are only available after a call to AsyncContext.dispatch(...);
|
||||
|
||||
// have we been forwarded before?
|
||||
String uri=(String)baseRequest.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
|
||||
if (uri!=null)
|
||||
{
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_REQUEST_URI,uri);
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH,baseRequest.getAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH));
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_SERVLET_PATH,baseRequest.getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH));
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_PATH_INFO,baseRequest.getAttribute(RequestDispatcher.FORWARD_PATH_INFO));
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_QUERY_STRING,baseRequest.getAttribute(RequestDispatcher.FORWARD_QUERY_STRING));
|
||||
}
|
||||
else
|
||||
{
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_REQUEST_URI,baseRequest.getRequestURI());
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH,baseRequest.getContextPath());
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_SERVLET_PATH,baseRequest.getServletPath());
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_PATH_INFO,baseRequest.getPathInfo());
|
||||
baseRequest.setAttribute(AsyncContext.ASYNC_QUERY_STRING,baseRequest.getQueryString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ServletContext getSuspendedContext()
|
||||
{
|
||||
return _context;
|
||||
}
|
||||
|
||||
public Context getContext()
|
||||
{
|
||||
return _context;
|
||||
}
|
||||
|
||||
public ServletContext getDispatchContext()
|
||||
{
|
||||
return _dispatchContext;
|
||||
}
|
||||
|
||||
public ServletContext getServletContext()
|
||||
{
|
||||
return _dispatchContext==null?_context:_dispatchContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The path in the context
|
||||
*/
|
||||
public String getPath()
|
||||
{
|
||||
return _pathInContext;
|
||||
}
|
||||
|
||||
public void setTimeoutTask(Scheduler.Task task)
|
||||
{
|
||||
_timeoutTask = task;
|
||||
}
|
||||
|
||||
public void cancelTimeoutTask()
|
||||
{
|
||||
Scheduler.Task task=_timeoutTask;
|
||||
_timeoutTask=null;
|
||||
if (task!=null)
|
||||
task.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncContext getAsyncContext()
|
||||
{
|
||||
return _asyncContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable getThrowable()
|
||||
{
|
||||
return _throwable;
|
||||
}
|
||||
|
||||
public void setThrowable(Throwable throwable)
|
||||
{
|
||||
_throwable=throwable;
|
||||
}
|
||||
|
||||
public void setDispatchTarget(ServletContext context, String path)
|
||||
{
|
||||
if (context!=null)
|
||||
_dispatchContext=context;
|
||||
if (path!=null)
|
||||
_pathInContext=path;
|
||||
}
|
||||
|
||||
|
||||
public void completed()
|
||||
{
|
||||
_asyncContext.reset();
|
||||
}
|
||||
|
||||
public HttpChannelState getHttpChannelState()
|
||||
{
|
||||
return _state;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.AsyncEvent;
|
||||
import javax.servlet.AsyncListener;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
|
||||
public class AsyncContextState implements AsyncContext
|
||||
{
|
||||
volatile HttpChannelState _state;
|
||||
|
||||
public AsyncContextState(HttpChannelState state)
|
||||
{
|
||||
_state=state;
|
||||
}
|
||||
|
||||
private HttpChannelState state()
|
||||
{
|
||||
HttpChannelState state=_state;
|
||||
if (state==null)
|
||||
throw new IllegalStateException("AsyncContext completed");
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(final AsyncListener listener, final ServletRequest request, final ServletResponse response)
|
||||
{
|
||||
AsyncListener wrap = new AsyncListener()
|
||||
{
|
||||
@Override
|
||||
public void onTimeout(AsyncEvent event) throws IOException
|
||||
{
|
||||
listener.onTimeout(new AsyncEvent(event.getAsyncContext(),request,response,event.getThrowable()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartAsync(AsyncEvent event) throws IOException
|
||||
{
|
||||
listener.onStartAsync(new AsyncEvent(event.getAsyncContext(),request,response,event.getThrowable()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(AsyncEvent event) throws IOException
|
||||
{
|
||||
listener.onComplete(new AsyncEvent(event.getAsyncContext(),request,response,event.getThrowable()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete(AsyncEvent event) throws IOException
|
||||
{
|
||||
listener.onComplete(new AsyncEvent(event.getAsyncContext(),request,response,event.getThrowable()));
|
||||
}
|
||||
};
|
||||
state().addListener(wrap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(AsyncListener listener)
|
||||
{
|
||||
state().addListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void complete()
|
||||
{
|
||||
state().complete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends AsyncListener> T createListener(Class<T> clazz) throws ServletException
|
||||
{
|
||||
try
|
||||
{
|
||||
return clazz.newInstance();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatch()
|
||||
{
|
||||
state().dispatch(null,null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatch(String path)
|
||||
{
|
||||
state().dispatch(null,path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatch(ServletContext context, String path)
|
||||
{
|
||||
state().dispatch(context,path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletRequest getRequest()
|
||||
{
|
||||
return state().getAsyncContextEvent().getSuppliedRequest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletResponse getResponse()
|
||||
{
|
||||
return state().getAsyncContextEvent().getSuppliedResponse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeout()
|
||||
{
|
||||
return state().getTimeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOriginalRequestAndResponse()
|
||||
{
|
||||
HttpChannel<?> channel=state().getHttpChannel();
|
||||
return channel.getRequest()==getRequest() && channel.getResponse()==getResponse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimeout(long arg0)
|
||||
{
|
||||
state().setTimeout(arg0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(final Runnable task)
|
||||
{
|
||||
state().getHttpChannel().execute(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
state().getAsyncContextEvent().getContext().getContextHandler().handle(task);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
_state=null;
|
||||
}
|
||||
|
||||
public HttpChannelState getHttpChannelState()
|
||||
{
|
||||
return state();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -23,14 +23,22 @@ import java.util.Arrays;
|
|||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.annotation.ManagedOperation;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Container;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.statistic.CounterStatistic;
|
||||
import org.eclipse.jetty.util.statistic.SampleStatistic;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** A Connector.Listener that gathers Connector and Connections Statistics.
|
||||
* Adding an instance of this class as with {@link AbstractConnector#addBean(Object)}
|
||||
* will register the listener with all connections accepted by that connector.
|
||||
*/
|
||||
@ManagedObject("Connector Statistics")
|
||||
public class ConnectorStatistics extends AbstractLifeCycle implements Dumpable, Connection.Listener
|
||||
{
|
||||
|
@ -52,78 +60,93 @@ public class ConnectorStatistics extends AbstractLifeCycle implements Dumpable,
|
|||
connectionClosed(System.currentTimeMillis()-connection.getCreatedTimeStamp(),connection.getMessagesIn(),connection.getMessagesOut());
|
||||
}
|
||||
|
||||
@ManagedAttribute("Total number of bytes received by this connector")
|
||||
public int getBytesIn()
|
||||
{
|
||||
// TODO
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ManagedAttribute("Total number of bytes sent by this connector")
|
||||
public int getBytesOut()
|
||||
{
|
||||
// TODO
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ManagedAttribute("Total number of connections seen by this connector")
|
||||
public int getConnections()
|
||||
{
|
||||
return (int)_connectionStats.getTotal();
|
||||
}
|
||||
|
||||
@ManagedAttribute("Connection duraton maximum in ms")
|
||||
public long getConnectionsDurationMax()
|
||||
{
|
||||
return _connectionDurationStats.getMax();
|
||||
}
|
||||
|
||||
@ManagedAttribute("Connection duraton mean in ms")
|
||||
public double getConnectionsDurationMean()
|
||||
{
|
||||
return _connectionDurationStats.getMean();
|
||||
}
|
||||
|
||||
@ManagedAttribute("Connection duraton standard deviation")
|
||||
public double getConnectionsDurationStdDev()
|
||||
{
|
||||
return _connectionDurationStats.getStdDev();
|
||||
}
|
||||
|
||||
@ManagedAttribute("Connection duraton total of all connections in ms")
|
||||
public long getConnectionsDurationTotal()
|
||||
{
|
||||
return _connectionDurationStats.getTotal();
|
||||
}
|
||||
|
||||
public int getConnectionsMessagesInMax()
|
||||
{
|
||||
return (int)_messagesIn.getMax();
|
||||
}
|
||||
|
||||
public double getConnectionsMessagesInMean()
|
||||
{
|
||||
return _messagesIn.getMean();
|
||||
}
|
||||
|
||||
public double getConnectionsMessagesInStdDev()
|
||||
{
|
||||
return _messagesIn.getStdDev();
|
||||
}
|
||||
|
||||
public int getConnectionsOpen()
|
||||
{
|
||||
return (int)_connectionStats.getCurrent();
|
||||
}
|
||||
|
||||
public int getConnectionsOpenMax()
|
||||
{
|
||||
return (int)_connectionStats.getMax();
|
||||
}
|
||||
|
||||
@ManagedAttribute("Messages In for all connections")
|
||||
public int getMessagesIn()
|
||||
{
|
||||
return (int)_messagesIn.getTotal();
|
||||
}
|
||||
|
||||
@ManagedAttribute("Messages In per connection maximum")
|
||||
public int getConnectionsMessagesInMax()
|
||||
{
|
||||
return (int)_messagesIn.getMax();
|
||||
}
|
||||
|
||||
@ManagedAttribute("Messages In per connection mean")
|
||||
public double getConnectionsMessagesInMean()
|
||||
{
|
||||
return _messagesIn.getMean();
|
||||
}
|
||||
|
||||
@ManagedAttribute("Messages In per connection standard deviation")
|
||||
public double getConnectionsMessagesInStdDev()
|
||||
{
|
||||
return _messagesIn.getStdDev();
|
||||
}
|
||||
|
||||
@ManagedAttribute("Connections open")
|
||||
public int getConnectionsOpen()
|
||||
{
|
||||
return (int)_connectionStats.getCurrent();
|
||||
}
|
||||
|
||||
@ManagedAttribute("Connections open maximum")
|
||||
public int getConnectionsOpenMax()
|
||||
{
|
||||
return (int)_connectionStats.getMax();
|
||||
}
|
||||
|
||||
@ManagedAttribute("Messages Out for all connections")
|
||||
public int getMessagesOut()
|
||||
{
|
||||
return (int)_messagesIn.getTotal();
|
||||
}
|
||||
|
||||
@ManagedAttribute("Connection statistics started ms since epoch")
|
||||
public long getStartedMillis()
|
||||
{
|
||||
long start = _startMillis.get();
|
||||
|
@ -141,6 +164,7 @@ public class ConnectorStatistics extends AbstractLifeCycle implements Dumpable,
|
|||
{
|
||||
}
|
||||
|
||||
@ManagedOperation("Reset the statistics")
|
||||
public void reset()
|
||||
{
|
||||
_startMillis.set(System.currentTimeMillis());
|
||||
|
@ -178,7 +202,6 @@ public class ConnectorStatistics extends AbstractLifeCycle implements Dumpable,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ManagedOperation("dump thread state")
|
||||
public String dump()
|
||||
|
@ -192,4 +215,13 @@ public class ConnectorStatistics extends AbstractLifeCycle implements Dumpable,
|
|||
ContainerLifeCycle.dumpObject(out,this);
|
||||
ContainerLifeCycle.dump(out,indent,Arrays.asList(new String[]{"connections="+_connectionStats,"duration="+_connectionDurationStats,"in="+_messagesIn,"out="+_messagesOut}));
|
||||
}
|
||||
|
||||
public static void addToAllConnectors(Server server)
|
||||
{
|
||||
for (Connector connector : server.getConnectors())
|
||||
{
|
||||
if (connector instanceof Container)
|
||||
((Container)connector).addBean(new ConnectorStatistics());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,8 +40,10 @@ import org.eclipse.jetty.http.HttpURI;
|
|||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.ChannelEndPoint;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.server.HttpChannelState.Next;
|
||||
import org.eclipse.jetty.server.handler.ErrorHandler;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
|
@ -215,6 +217,15 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
|
|||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
handle();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return True if the channel is ready to continue handling (ie it is not suspended)
|
||||
*/
|
||||
public boolean handle()
|
||||
{
|
||||
LOG.debug("{} handle enter", this);
|
||||
|
||||
|
@ -227,104 +238,104 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
|
|||
Thread.currentThread().setName(threadName + " - " + _uri);
|
||||
}
|
||||
|
||||
try
|
||||
// Loop here to handle async request redispatches.
|
||||
// The loop is controlled by the call to async.unhandle in the
|
||||
// finally block below. Unhandle will return false only if an async dispatch has
|
||||
// already happened when unhandle is called.
|
||||
HttpChannelState.Next next = _state.handling();
|
||||
while (next==Next.CONTINUE && getServer().isRunning())
|
||||
{
|
||||
// Loop here to handle async request redispatches.
|
||||
// The loop is controlled by the call to async.unhandle in the
|
||||
// finally block below. Unhandle will return false only if an async dispatch has
|
||||
// already happened when unhandle is called.
|
||||
boolean handling = _state.handling();
|
||||
|
||||
while (handling && getServer().isRunning())
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
_request.setHandled(false);
|
||||
_response.getHttpOutput().reopen();
|
||||
_request.setHandled(false);
|
||||
_response.getHttpOutput().reopen();
|
||||
|
||||
if (_state.isInitial())
|
||||
if (_state.isInitial())
|
||||
{
|
||||
_request.setTimeStamp(System.currentTimeMillis());
|
||||
_request.setDispatcherType(DispatcherType.REQUEST);
|
||||
|
||||
for (HttpConfiguration.Customizer customizer : _configuration.getCustomizers())
|
||||
customizer.customize(getConnector(),_configuration,_request);
|
||||
getServer().handle(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_request.getHttpChannelState().isExpired())
|
||||
{
|
||||
_request.setTimeStamp(System.currentTimeMillis());
|
||||
_request.setDispatcherType(DispatcherType.REQUEST);
|
||||
|
||||
for (HttpConfiguration.Customizer customizer : _configuration.getCustomizers())
|
||||
customizer.customize(getConnector(),_configuration,_request);
|
||||
getServer().handle(this);
|
||||
_request.setDispatcherType(DispatcherType.ERROR);
|
||||
_request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,new Integer(500));
|
||||
_request.setAttribute(RequestDispatcher.ERROR_MESSAGE,"Async Timeout");
|
||||
_request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI,_request.getRequestURI());
|
||||
_response.setStatusWithReason(500,"Async Timeout");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_request.getHttpChannelState().isExpired())
|
||||
{
|
||||
_request.setDispatcherType(DispatcherType.ERROR);
|
||||
_request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,new Integer(500));
|
||||
_request.setAttribute(RequestDispatcher.ERROR_MESSAGE,"Async Timeout");
|
||||
_request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI,_request.getRequestURI());
|
||||
_response.setStatusWithReason(500,"Async Timeout");
|
||||
}
|
||||
else
|
||||
_request.setDispatcherType(DispatcherType.ASYNC);
|
||||
getServer().handleAsync(this);
|
||||
}
|
||||
}
|
||||
catch (Error e)
|
||||
{
|
||||
if ("ContinuationThrowable".equals(e.getClass().getSimpleName()))
|
||||
LOG.ignore(e);
|
||||
else
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e instanceof EofException)
|
||||
LOG.debug(e);
|
||||
else
|
||||
LOG.warn(String.valueOf(_uri), e);
|
||||
_state.error(e);
|
||||
_request.setHandled(true);
|
||||
handleException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
handling = !_state.unhandle();
|
||||
_request.setDispatcherType(DispatcherType.ASYNC);
|
||||
getServer().handleAsync(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (threadName != null && LOG.isDebugEnabled())
|
||||
Thread.currentThread().setName(threadName);
|
||||
setCurrentHttpChannel(null);
|
||||
|
||||
if (_state.isCompleting())
|
||||
catch (Error e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_state.completed();
|
||||
|
||||
if (!_response.isCommitted() && !_request.isHandled())
|
||||
_response.sendError(404);
|
||||
|
||||
// Complete generating the response
|
||||
_response.complete();
|
||||
|
||||
}
|
||||
catch(EofException e)
|
||||
{
|
||||
if ("ContinuationThrowable".equals(e.getClass().getSimpleName()))
|
||||
LOG.ignore(e);
|
||||
else
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e instanceof EofException)
|
||||
LOG.debug(e);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_request.setHandled(true);
|
||||
_transport.completed();
|
||||
}
|
||||
else
|
||||
LOG.warn(String.valueOf(_uri), e);
|
||||
_state.error(e);
|
||||
_request.setHandled(true);
|
||||
handleException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
next = _state.unhandle();
|
||||
}
|
||||
|
||||
LOG.debug("{} handle exit", this);
|
||||
}
|
||||
|
||||
if (threadName != null && LOG.isDebugEnabled())
|
||||
Thread.currentThread().setName(threadName);
|
||||
setCurrentHttpChannel(null);
|
||||
|
||||
if (next==Next.COMPLETE)
|
||||
{
|
||||
try
|
||||
{
|
||||
_state.completed();
|
||||
|
||||
if (!_response.isCommitted() && !_request.isHandled())
|
||||
_response.sendError(404);
|
||||
|
||||
// Complete generating the response
|
||||
_response.complete();
|
||||
}
|
||||
catch(EofException e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
next=Next.RECYCLE;
|
||||
}
|
||||
}
|
||||
|
||||
if (next==Next.RECYCLE)
|
||||
{
|
||||
_request.setHandled(true);
|
||||
_transport.completed();
|
||||
}
|
||||
|
||||
LOG.debug("{} handle exit", this);
|
||||
|
||||
return next!=Next.WAIT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -380,11 +391,13 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s@%x{r=%s,a=%s}",
|
||||
return String.format("%s@%x{r=%s,a=%s,uri=%s}",
|
||||
getClass().getSimpleName(),
|
||||
hashCode(),
|
||||
_requests,
|
||||
_state.getState());
|
||||
_state.getState(),
|
||||
_state.getState()==HttpChannelState.State.IDLE?"-":_request.getRequestURI()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -555,10 +568,9 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean earlyEOF()
|
||||
public void earlyEOF()
|
||||
{
|
||||
_request.getHttpInput().earlyEOF();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -569,10 +581,9 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
|
|||
|
||||
try
|
||||
{
|
||||
if (_state.handling())
|
||||
if (_state.handling()==Next.CONTINUE)
|
||||
{
|
||||
commitResponse(new ResponseInfo(HttpVersion.HTTP_1_1,new HttpFields(),0,status,reason,false),null,true);
|
||||
_state.unhandle();
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
|
@ -580,8 +591,9 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
|
|||
LOG.warn(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_state.completed();
|
||||
{
|
||||
if (_state.unhandle()==Next.COMPLETE)
|
||||
_state.completed();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -664,4 +676,13 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
|
|||
{
|
||||
return _connector.getScheduler();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return true if the HttpChannel can efficiently use direct buffer (typically this means it is not over SSL or a multiplexed protocol)
|
||||
*/
|
||||
public boolean useDirectBuffers()
|
||||
{
|
||||
return getEndPoint() instanceof ChannelEndPoint;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,19 +21,15 @@ package org.eclipse.jetty.server;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.servlet.AsyncContext;
|
||||
|
||||
import javax.servlet.AsyncEvent;
|
||||
import javax.servlet.AsyncListener;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler.Context;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.Scheduler;
|
||||
|
@ -56,7 +52,7 @@ import org.eclipse.jetty.util.thread.Scheduler;
|
|||
* <tr><th align=right>COMPLETED:</th> <td></td> <td></td> <td></td> <td></td> <td></td> <td></td></tr>
|
||||
* </table>
|
||||
*/
|
||||
public class HttpChannelState implements AsyncContext
|
||||
public class HttpChannelState
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpChannelState.class);
|
||||
|
||||
|
@ -75,6 +71,14 @@ public class HttpChannelState implements AsyncContext
|
|||
COMPLETING, // Request is completable
|
||||
COMPLETED // Request is complete
|
||||
}
|
||||
|
||||
public enum Next
|
||||
{
|
||||
CONTINUE, // Continue handling the channel
|
||||
WAIT, // Wait for further events
|
||||
COMPLETE, // Complete the channel
|
||||
RECYCLE, // Channel is completed
|
||||
}
|
||||
|
||||
private final HttpChannel<?> _channel;
|
||||
private List<AsyncListener> _lastAsyncListeners;
|
||||
|
@ -86,7 +90,7 @@ public class HttpChannelState implements AsyncContext
|
|||
private boolean _expired;
|
||||
private volatile boolean _responseWrapped;
|
||||
private long _timeoutMs=DEFAULT_TIMEOUT;
|
||||
private AsyncEventState _event;
|
||||
private AsyncContextEvent _event;
|
||||
|
||||
protected HttpChannelState(HttpChannel<?> channel)
|
||||
{
|
||||
|
@ -103,7 +107,6 @@ public class HttpChannelState implements AsyncContext
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(AsyncListener listener)
|
||||
{
|
||||
synchronized(this)
|
||||
|
@ -114,19 +117,6 @@ public class HttpChannelState implements AsyncContext
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(AsyncListener listener,ServletRequest request, ServletResponse response)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
if (_asyncListeners==null)
|
||||
_asyncListeners=new ArrayList<>();
|
||||
_asyncListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setTimeout(long ms)
|
||||
{
|
||||
synchronized(this)
|
||||
|
@ -135,7 +125,6 @@ public class HttpChannelState implements AsyncContext
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeout()
|
||||
{
|
||||
synchronized(this)
|
||||
|
@ -144,7 +133,7 @@ public class HttpChannelState implements AsyncContext
|
|||
}
|
||||
}
|
||||
|
||||
public AsyncEventState getAsyncEventState()
|
||||
public AsyncContextEvent getAsyncContextEvent()
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
|
@ -173,9 +162,9 @@ public class HttpChannelState implements AsyncContext
|
|||
}
|
||||
|
||||
/**
|
||||
* @return true if the handling of the request should proceed
|
||||
* @return Next handling of the request should proceed
|
||||
*/
|
||||
protected boolean handling()
|
||||
protected Next handling()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
|
@ -197,12 +186,16 @@ public class HttpChannelState implements AsyncContext
|
|||
|
||||
case COMPLETECALLED:
|
||||
_state=State.COMPLETING;
|
||||
return false;
|
||||
return Next.COMPLETE;
|
||||
|
||||
case ASYNCWAIT:
|
||||
case COMPLETING:
|
||||
return Next.COMPLETE;
|
||||
|
||||
case ASYNCWAIT:
|
||||
return Next.WAIT;
|
||||
|
||||
case COMPLETED:
|
||||
return false;
|
||||
return Next.RECYCLE;
|
||||
|
||||
case REDISPATCH:
|
||||
_state=State.REDISPATCHED;
|
||||
|
@ -213,12 +206,13 @@ public class HttpChannelState implements AsyncContext
|
|||
}
|
||||
|
||||
_responseWrapped=false;
|
||||
return true;
|
||||
return Next.CONTINUE;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void startAsync()
|
||||
|
||||
public void startAsync(AsyncContextEvent event)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
|
@ -228,56 +222,15 @@ public class HttpChannelState implements AsyncContext
|
|||
case REDISPATCHED:
|
||||
_dispatched=false;
|
||||
_expired=false;
|
||||
_responseWrapped=event.getSuppliedResponse()!=_channel.getResponse();
|
||||
_responseWrapped=false;
|
||||
_event=new AsyncEventState(_channel.getRequest().getServletContext(),_channel.getRequest(),_channel.getResponse());
|
||||
_event=event;
|
||||
_state=State.ASYNCSTARTED;
|
||||
List<AsyncListener> listeners=_lastAsyncListeners;
|
||||
_lastAsyncListeners=_asyncListeners;
|
||||
if (listeners!=null)
|
||||
listeners.clear();
|
||||
_asyncListeners=listeners;
|
||||
if (_asyncListeners!=null)
|
||||
_asyncListeners.clear();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException(this.getStatusString());
|
||||
}
|
||||
}
|
||||
|
||||
if (_lastAsyncListeners!=null)
|
||||
{
|
||||
for (AsyncListener listener : _lastAsyncListeners)
|
||||
{
|
||||
try
|
||||
{
|
||||
listener.onStartAsync(_event);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void startAsync(final ServletContext context,final ServletRequest request,final ServletResponse response)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
switch(_state)
|
||||
{
|
||||
case DISPATCHED:
|
||||
case REDISPATCHED:
|
||||
_dispatched=false;
|
||||
_expired=false;
|
||||
_responseWrapped=response!=_channel.getResponse();
|
||||
_event=new AsyncEventState(context,request,response);
|
||||
_event._pathInContext = (request instanceof HttpServletRequest)?URIUtil.addPaths(((HttpServletRequest)request).getServletPath(),((HttpServletRequest)request).getPathInfo()):null;
|
||||
_state=State.ASYNCSTARTED;
|
||||
List<AsyncListener> listeners=_lastAsyncListeners;
|
||||
_lastAsyncListeners=_asyncListeners;
|
||||
_asyncListeners=listeners;
|
||||
if (_asyncListeners!=null)
|
||||
_asyncListeners.clear();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -306,7 +259,7 @@ public class HttpChannelState implements AsyncContext
|
|||
synchronized (this)
|
||||
{
|
||||
if (_event!=null)
|
||||
_event._cause=th;
|
||||
_event.setThrowable(th);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,10 +267,10 @@ public class HttpChannelState implements AsyncContext
|
|||
* Signal that the HttpConnection has finished handling the request.
|
||||
* For blocking connectors, this call may block if the request has
|
||||
* been suspended (startAsync called).
|
||||
* @return true if handling is complete, false if the request should
|
||||
* @return next actions
|
||||
* be handled again (eg because of a resume that happened before unhandle was called)
|
||||
*/
|
||||
protected boolean unhandle()
|
||||
protected Next unhandle()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
|
@ -326,7 +279,7 @@ public class HttpChannelState implements AsyncContext
|
|||
case REDISPATCHED:
|
||||
case DISPATCHED:
|
||||
_state=State.COMPLETING;
|
||||
return true;
|
||||
return Next.COMPLETE;
|
||||
|
||||
case IDLE:
|
||||
throw new IllegalStateException(this.getStatusString());
|
||||
|
@ -335,26 +288,17 @@ public class HttpChannelState implements AsyncContext
|
|||
_initial=false;
|
||||
_state=State.ASYNCWAIT;
|
||||
scheduleTimeout();
|
||||
if (_state==State.ASYNCWAIT)
|
||||
return true;
|
||||
else if (_state==State.COMPLETECALLED)
|
||||
{
|
||||
_state=State.COMPLETING;
|
||||
return true;
|
||||
}
|
||||
_initial=false;
|
||||
_state=State.REDISPATCHED;
|
||||
return false;
|
||||
return Next.WAIT;
|
||||
|
||||
case REDISPATCHING:
|
||||
_initial=false;
|
||||
_state=State.REDISPATCHED;
|
||||
return false;
|
||||
return Next.CONTINUE;
|
||||
|
||||
case COMPLETECALLED:
|
||||
_initial=false;
|
||||
_state=State.COMPLETING;
|
||||
return true;
|
||||
return Next.COMPLETE;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException(this.getStatusString());
|
||||
|
@ -362,26 +306,29 @@ public class HttpChannelState implements AsyncContext
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatch()
|
||||
public void dispatch(ServletContext context, String path)
|
||||
{
|
||||
boolean dispatch;
|
||||
synchronized (this)
|
||||
{
|
||||
|
||||
switch(_state)
|
||||
{
|
||||
case ASYNCSTARTED:
|
||||
_state=State.REDISPATCHING;
|
||||
_event.setDispatchTarget(context,path);
|
||||
_dispatched=true;
|
||||
return;
|
||||
|
||||
case ASYNCWAIT:
|
||||
dispatch=!_expired;
|
||||
_state=State.REDISPATCH;
|
||||
_event.setDispatchTarget(context,path);
|
||||
_dispatched=true;
|
||||
break;
|
||||
|
||||
case REDISPATCH:
|
||||
_event.setDispatchTarget(context,path);
|
||||
return;
|
||||
|
||||
default:
|
||||
|
@ -407,6 +354,7 @@ public class HttpChannelState implements AsyncContext
|
|||
protected void expired()
|
||||
{
|
||||
final List<AsyncListener> aListeners;
|
||||
AsyncEvent event;
|
||||
synchronized (this)
|
||||
{
|
||||
switch(_state)
|
||||
|
@ -414,6 +362,7 @@ public class HttpChannelState implements AsyncContext
|
|||
case ASYNCSTARTED:
|
||||
case ASYNCWAIT:
|
||||
_expired=true;
|
||||
event=_event;
|
||||
aListeners=_asyncListeners;
|
||||
break;
|
||||
default:
|
||||
|
@ -427,7 +376,7 @@ public class HttpChannelState implements AsyncContext
|
|||
{
|
||||
try
|
||||
{
|
||||
listener.onTimeout(_event);
|
||||
listener.onTimeout(event);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
@ -453,11 +402,10 @@ public class HttpChannelState implements AsyncContext
|
|||
scheduleDispatch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void complete()
|
||||
{
|
||||
// just like resume, except don't set _dispatched=true;
|
||||
boolean dispatch;
|
||||
boolean handle;
|
||||
synchronized (this)
|
||||
{
|
||||
switch(_state)
|
||||
|
@ -473,7 +421,7 @@ public class HttpChannelState implements AsyncContext
|
|||
|
||||
case ASYNCWAIT:
|
||||
_state=State.COMPLETECALLED;
|
||||
dispatch=!_expired;
|
||||
handle=!_expired;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -481,29 +429,21 @@ public class HttpChannelState implements AsyncContext
|
|||
}
|
||||
}
|
||||
|
||||
if (dispatch)
|
||||
if (handle)
|
||||
{
|
||||
cancelTimeout();
|
||||
scheduleDispatch();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends AsyncListener> T createListener(Class<T> clazz) throws ServletException
|
||||
{
|
||||
try
|
||||
{
|
||||
return clazz.newInstance();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
ContextHandler handler=getContextHandler();
|
||||
if (handler!=null)
|
||||
handler.handle(_channel);
|
||||
else
|
||||
_channel.handle();
|
||||
}
|
||||
}
|
||||
|
||||
protected void completed()
|
||||
{
|
||||
final List<AsyncListener> aListeners;
|
||||
final AsyncContextEvent event;
|
||||
synchronized (this)
|
||||
{
|
||||
switch(_state)
|
||||
|
@ -511,6 +451,8 @@ public class HttpChannelState implements AsyncContext
|
|||
case COMPLETING:
|
||||
_state=State.COMPLETED;
|
||||
aListeners=_asyncListeners;
|
||||
event=_event;
|
||||
_event=null;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -524,14 +466,14 @@ public class HttpChannelState implements AsyncContext
|
|||
{
|
||||
try
|
||||
{
|
||||
if (_event!=null && _event._cause!=null)
|
||||
if (event!=null && event.getThrowable()!=null)
|
||||
{
|
||||
_event.getSuppliedRequest().setAttribute(RequestDispatcher.ERROR_EXCEPTION,_event._cause);
|
||||
_event.getSuppliedRequest().setAttribute(RequestDispatcher.ERROR_MESSAGE,_event._cause.getMessage());
|
||||
listener.onError(_event);
|
||||
event.getSuppliedRequest().setAttribute(RequestDispatcher.ERROR_EXCEPTION,event.getThrowable());
|
||||
event.getSuppliedRequest().setAttribute(RequestDispatcher.ERROR_MESSAGE,event.getThrowable().getMessage());
|
||||
listener.onError(event);
|
||||
}
|
||||
else
|
||||
listener.onComplete(_event);
|
||||
listener.onComplete(event);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
@ -539,6 +481,9 @@ public class HttpChannelState implements AsyncContext
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event!=null)
|
||||
event.completed();
|
||||
}
|
||||
|
||||
protected void recycle()
|
||||
|
@ -563,14 +508,6 @@ public class HttpChannelState implements AsyncContext
|
|||
}
|
||||
}
|
||||
|
||||
public void cancel()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
cancelTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
protected void scheduleDispatch()
|
||||
{
|
||||
_channel.execute(_channel);
|
||||
|
@ -580,18 +517,14 @@ public class HttpChannelState implements AsyncContext
|
|||
{
|
||||
Scheduler scheduler = _channel.getScheduler();
|
||||
if (scheduler!=null && _timeoutMs>0)
|
||||
_event._timeout=scheduler.schedule(new AsyncTimeout(),_timeoutMs,TimeUnit.MILLISECONDS);
|
||||
_event.setTimeoutTask(scheduler.schedule(new AsyncTimeout(),_timeoutMs,TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
protected void cancelTimeout()
|
||||
{
|
||||
AsyncEventState event=_event;
|
||||
AsyncContextEvent event=_event;
|
||||
if (event!=null)
|
||||
{
|
||||
Scheduler.Task task=event._timeout;
|
||||
if (task!=null)
|
||||
task.cancel();
|
||||
}
|
||||
event.cancelTimeoutTask();
|
||||
}
|
||||
|
||||
public boolean isExpired()
|
||||
|
@ -656,73 +589,25 @@ public class HttpChannelState implements AsyncContext
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatch(ServletContext context, String path)
|
||||
{
|
||||
_event._dispatchContext=context;
|
||||
_event._pathInContext=path;
|
||||
dispatch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatch(String path)
|
||||
{
|
||||
_event._pathInContext=path;
|
||||
dispatch();
|
||||
}
|
||||
|
||||
public Request getBaseRequest()
|
||||
{
|
||||
return _channel.getRequest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletRequest getRequest()
|
||||
public HttpChannel<?> getHttpChannel()
|
||||
{
|
||||
if (_event!=null)
|
||||
return _event.getSuppliedRequest();
|
||||
return _channel.getRequest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletResponse getResponse()
|
||||
{
|
||||
if (_responseWrapped && _event!=null && _event.getSuppliedResponse()!=null)
|
||||
return _event.getSuppliedResponse();
|
||||
return _channel.getResponse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(final Runnable run)
|
||||
{
|
||||
final AsyncEventState event=_event;
|
||||
if (event!=null)
|
||||
{
|
||||
_channel.execute(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
((Context)event.getServletContext()).getContextHandler().handle(run);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOriginalRequestAndResponse()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
return (_event!=null && _event.getSuppliedRequest()==_channel.getRequest() && _event.getSuppliedResponse()==_channel.getResponse());
|
||||
}
|
||||
return _channel;
|
||||
}
|
||||
|
||||
public ContextHandler getContextHandler()
|
||||
{
|
||||
final AsyncEventState event=_event;
|
||||
final AsyncContextEvent event=_event;
|
||||
if (event!=null)
|
||||
return ((Context)event.getServletContext()).getContextHandler();
|
||||
{
|
||||
Context context=((Context)event.getServletContext());
|
||||
if (context!=null)
|
||||
return context.getContextHandler();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -757,70 +642,4 @@ public class HttpChannelState implements AsyncContext
|
|||
}
|
||||
}
|
||||
|
||||
public class AsyncEventState extends AsyncEvent
|
||||
{
|
||||
final private ServletContext _suspendedContext;
|
||||
private String _pathInContext;
|
||||
private Scheduler.Task _timeout;
|
||||
private ServletContext _dispatchContext;
|
||||
private Throwable _cause;
|
||||
|
||||
public AsyncEventState(ServletContext context, ServletRequest request, ServletResponse response)
|
||||
{
|
||||
super(HttpChannelState.this, request,response);
|
||||
_suspendedContext=context;
|
||||
|
||||
// Get the base request So we can remember the initial paths
|
||||
Request r=_channel.getRequest();
|
||||
|
||||
// If we haven't been async dispatched before
|
||||
if (r.getAttribute(AsyncContext.ASYNC_REQUEST_URI)==null)
|
||||
{
|
||||
// We are setting these attributes during startAsync, when the spec implies that
|
||||
// they are only available after a call to AsyncContext.dispatch(...);
|
||||
|
||||
// have we been forwarded before?
|
||||
String uri=(String)r.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
|
||||
if (uri!=null)
|
||||
{
|
||||
r.setAttribute(AsyncContext.ASYNC_REQUEST_URI,uri);
|
||||
r.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH,r.getAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH));
|
||||
r.setAttribute(AsyncContext.ASYNC_SERVLET_PATH,r.getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH));
|
||||
r.setAttribute(AsyncContext.ASYNC_PATH_INFO,r.getAttribute(RequestDispatcher.FORWARD_PATH_INFO));
|
||||
r.setAttribute(AsyncContext.ASYNC_QUERY_STRING,r.getAttribute(RequestDispatcher.FORWARD_QUERY_STRING));
|
||||
}
|
||||
else
|
||||
{
|
||||
r.setAttribute(AsyncContext.ASYNC_REQUEST_URI,r.getRequestURI());
|
||||
r.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH,r.getContextPath());
|
||||
r.setAttribute(AsyncContext.ASYNC_SERVLET_PATH,r.getServletPath());
|
||||
r.setAttribute(AsyncContext.ASYNC_PATH_INFO,r.getPathInfo());
|
||||
r.setAttribute(AsyncContext.ASYNC_QUERY_STRING,r.getQueryString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ServletContext getSuspendedContext()
|
||||
{
|
||||
return _suspendedContext;
|
||||
}
|
||||
|
||||
public ServletContext getDispatchContext()
|
||||
{
|
||||
return _dispatchContext;
|
||||
}
|
||||
|
||||
public ServletContext getServletContext()
|
||||
{
|
||||
return _dispatchContext==null?_suspendedContext:_dispatchContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The path in the context
|
||||
*/
|
||||
public String getPath()
|
||||
{
|
||||
return _pathInContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -207,8 +207,28 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
// Can the parser progress (even with an empty buffer)
|
||||
boolean call_channel=_parser.parseNext(_requestBuffer==null?BufferUtil.EMPTY_BUFFER:_requestBuffer);
|
||||
|
||||
// If there is a request buffer, we are re-entering here
|
||||
if (!call_channel && BufferUtil.isEmpty(_requestBuffer))
|
||||
// Parse the buffer
|
||||
if (call_channel)
|
||||
{
|
||||
// Parse as much content as there is available before calling the channel
|
||||
// this is both efficient (may queue many chunks), will correctly set available for 100 continues
|
||||
// and will drive the parser to completion if all content is available.
|
||||
while (_parser.inContentState())
|
||||
{
|
||||
if (!_parser.parseNext(_requestBuffer==null?BufferUtil.EMPTY_BUFFER:_requestBuffer))
|
||||
break;
|
||||
}
|
||||
|
||||
// The parser returned true, which indicates the channel is ready to handle a request.
|
||||
// Call the channel and this will either handle the request/response to completion OR,
|
||||
// if the request suspends, the request/response will be incomplete so the outer loop will exit.
|
||||
boolean handle=_channel.handle();
|
||||
|
||||
// Return if suspended or upgraded
|
||||
if (!handle || getEndPoint().getConnection()!=this)
|
||||
return;
|
||||
}
|
||||
else if (BufferUtil.isEmpty(_requestBuffer))
|
||||
{
|
||||
if (_requestBuffer == null)
|
||||
_requestBuffer = _bufferPool.acquire(getInputBufferSize(), REQUEST_BUFFER_DIRECT);
|
||||
|
@ -242,32 +262,14 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
releaseRequestBuffer();
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse what we have read
|
||||
call_channel=_parser.parseNext(_requestBuffer);
|
||||
}
|
||||
|
||||
// Parse the buffer
|
||||
if (call_channel)
|
||||
else
|
||||
{
|
||||
// Parse as much content as there is available before calling the channel
|
||||
// this is both efficient (may queue many chunks), will correctly set available for 100 continues
|
||||
// and will drive the parser to completion if all content is available.
|
||||
while (_parser.inContentState())
|
||||
{
|
||||
if (!_parser.parseNext(_requestBuffer==null?BufferUtil.EMPTY_BUFFER:_requestBuffer))
|
||||
break;
|
||||
}
|
||||
|
||||
// The parser returned true, which indicates the channel is ready to handle a request.
|
||||
// Call the channel and this will either handle the request/response to completion OR,
|
||||
// if the request suspends, the request/response will be incomplete so the outer loop will exit.
|
||||
|
||||
_channel.run();
|
||||
|
||||
// Return if suspended or upgraded
|
||||
if (_channel.getState().isSuspended() || getEndPoint().getConnection()!=this)
|
||||
return;
|
||||
// TODO work out how we can get here and a better way to handle it
|
||||
LOG.warn("Unexpected state: "+this+ " "+_channel+" "+_channel.getRequest());
|
||||
if (!_channel.getState().isSuspended())
|
||||
getEndPoint().close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -275,7 +277,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
{
|
||||
LOG.debug(e);
|
||||
}
|
||||
catch (IOException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
if (_parser.isIdle())
|
||||
LOG.debug(e);
|
||||
|
@ -283,11 +285,6 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
LOG.warn(this.toString(), e);
|
||||
close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(this.toString(), e);
|
||||
close();
|
||||
}
|
||||
finally
|
||||
{
|
||||
setCurrentConnection(null);
|
||||
|
@ -511,13 +508,6 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
getEndPoint().close();
|
||||
}
|
||||
}
|
||||
|
||||
// make sure that an oshut connection is driven towards close
|
||||
// TODO this is a little ugly
|
||||
if (getEndPoint().isOpen() && getEndPoint().isOutputShutdown())
|
||||
{
|
||||
fillInterested();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -559,11 +549,12 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
if (getEndPoint().isInputShutdown())
|
||||
{
|
||||
_parser.shutdownInput();
|
||||
shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait until we can read
|
||||
getEndPoint().fillInterested(_readBlocker);
|
||||
block(_readBlocker);
|
||||
LOG.debug("{} block readable on {}",this,_readBlocker);
|
||||
_readBlocker.block();
|
||||
|
||||
|
@ -618,7 +609,6 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
*/
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onAllContentConsumed()
|
||||
{
|
||||
|
@ -628,6 +618,12 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
*/
|
||||
releaseRequestBuffer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return super.toString()+"{"+_channel+","+HttpConnection.this+"}";
|
||||
}
|
||||
}
|
||||
|
||||
private class HttpChannelOverHttp extends HttpChannel<ByteBuffer>
|
||||
|
|
|
@ -96,32 +96,53 @@ public abstract class HttpInput<T> extends ServletInputStream
|
|||
T item = null;
|
||||
synchronized (lock())
|
||||
{
|
||||
while (item == null)
|
||||
// Get the current head of the input Q
|
||||
item = _inputQ.peekUnsafe();
|
||||
|
||||
// Skip empty items at the head of the queue
|
||||
while (item != null && remaining(item) == 0)
|
||||
{
|
||||
_inputQ.pollUnsafe();
|
||||
onContentConsumed(item);
|
||||
LOG.debug("{} consumed {}", this, item);
|
||||
item = _inputQ.peekUnsafe();
|
||||
while (item != null && remaining(item) == 0)
|
||||
|
||||
// If that was the last item then notify
|
||||
if (item==null)
|
||||
onAllContentConsumed();
|
||||
}
|
||||
|
||||
// If we have no item
|
||||
if (item == null)
|
||||
{
|
||||
// Was it unexpectedly EOF'd?
|
||||
if (isEarlyEOF())
|
||||
throw new EofException();
|
||||
|
||||
// check for EOF
|
||||
if (isShutdown())
|
||||
{
|
||||
_inputQ.pollUnsafe();
|
||||
onContentConsumed(item);
|
||||
LOG.debug("{} consumed {}", this, item);
|
||||
item = _inputQ.peekUnsafe();
|
||||
onEOF();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (item == null)
|
||||
// OK then block for some more content
|
||||
blockForContent();
|
||||
|
||||
// If still not content, we must be closed
|
||||
item = _inputQ.peekUnsafe();
|
||||
if (item==null)
|
||||
{
|
||||
onAllContentConsumed();
|
||||
|
||||
if (isEarlyEOF())
|
||||
throw new EofException();
|
||||
|
||||
// blockForContent will only return with no
|
||||
// content if it is closed.
|
||||
if (!isShutdown())
|
||||
LOG.warn("Unexpected !EOF: "+this);
|
||||
|
||||
// check for EOF
|
||||
if (isShutdown())
|
||||
{
|
||||
onEOF();
|
||||
return -1;
|
||||
}
|
||||
|
||||
blockForContent();
|
||||
onEOF();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -152,20 +173,34 @@ public abstract class HttpInput<T> extends ServletInputStream
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Called by this HttpInput to signal new content has been queued
|
||||
* @param item
|
||||
*/
|
||||
protected void onContentQueued(T item)
|
||||
{
|
||||
lock().notify();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Called by this HttpInput to signal all available content has been consumed
|
||||
*/
|
||||
protected void onAllContentConsumed()
|
||||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Called by this HttpInput to signal it has reached EOF
|
||||
*/
|
||||
protected void onEOF()
|
||||
{
|
||||
}
|
||||
|
||||
public boolean content(T item)
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Add some content to the input stream
|
||||
* @param item
|
||||
*/
|
||||
public void content(T item)
|
||||
{
|
||||
synchronized (lock())
|
||||
{
|
||||
|
@ -176,19 +211,26 @@ public abstract class HttpInput<T> extends ServletInputStream
|
|||
onContentQueued(item);
|
||||
LOG.debug("{} queued {}", this, item);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** This method should be called to signal to the HttpInput
|
||||
* that an EOF has arrived before all the expected content.
|
||||
* Typically this will result in an EOFException being thrown
|
||||
* from a subsequent read rather than a -1 return.
|
||||
*/
|
||||
public void earlyEOF()
|
||||
{
|
||||
synchronized (lock())
|
||||
{
|
||||
_earlyEOF = true;
|
||||
_inputEOF = true;
|
||||
lock().notify();
|
||||
LOG.debug("{} early EOF", this);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isEarlyEOF()
|
||||
{
|
||||
synchronized (lock())
|
||||
|
@ -197,6 +239,7 @@ public abstract class HttpInput<T> extends ServletInputStream
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void shutdown()
|
||||
{
|
||||
synchronized (lock())
|
||||
|
@ -207,6 +250,7 @@ public abstract class HttpInput<T> extends ServletInputStream
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isShutdown()
|
||||
{
|
||||
synchronized (lock())
|
||||
|
@ -215,13 +259,14 @@ public abstract class HttpInput<T> extends ServletInputStream
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void consumeAll()
|
||||
{
|
||||
synchronized (lock())
|
||||
{
|
||||
T item = _inputQ.peekUnsafe();
|
||||
while (!isShutdown() && !isEarlyEOF())
|
||||
{
|
||||
T item = _inputQ.peekUnsafe();
|
||||
while (item != null)
|
||||
{
|
||||
_inputQ.pollUnsafe();
|
||||
|
@ -235,6 +280,9 @@ public abstract class HttpInput<T> extends ServletInputStream
|
|||
try
|
||||
{
|
||||
blockForContent();
|
||||
item = _inputQ.peekUnsafe();
|
||||
if (item==null)
|
||||
break;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
|
|
|
@ -47,9 +47,6 @@ import org.eclipse.jetty.util.resource.Resource;
|
|||
*/
|
||||
public class HttpOutput extends ServletOutputStream
|
||||
{
|
||||
private static final boolean OUTPUT_BUFFER_DIRECT=false;
|
||||
private static final boolean CHANNEL_BUFFER_DIRECT=true;
|
||||
private static final boolean STREAM_BUFFER_DIRECT=false;
|
||||
private static Logger LOG = Log.getLogger(HttpOutput.class);
|
||||
private final HttpChannel<?> _channel;
|
||||
private boolean _closed;
|
||||
|
@ -165,8 +162,9 @@ public class HttpOutput extends ServletOutputStream
|
|||
return;
|
||||
}
|
||||
|
||||
// Allocate an aggregate buffer
|
||||
_aggregate = _channel.getByteBufferPool().acquire(size, OUTPUT_BUFFER_DIRECT);
|
||||
// Allocate an aggregate buffer.
|
||||
// Never direct as it is slow to do little writes to a direct buffer.
|
||||
_aggregate = _channel.getByteBufferPool().acquire(size, false);
|
||||
}
|
||||
|
||||
// Do we have space to aggregate ?
|
||||
|
@ -206,8 +204,10 @@ public class HttpOutput extends ServletOutputStream
|
|||
if (isClosed())
|
||||
throw new EOFException("Closed");
|
||||
|
||||
// Allocate an aggregate buffer.
|
||||
// Never direct as it is slow to do little writes to a direct buffer.
|
||||
if (_aggregate == null)
|
||||
_aggregate = _channel.getByteBufferPool().acquire(getBufferSize(), OUTPUT_BUFFER_DIRECT);
|
||||
_aggregate = _channel.getByteBufferPool().acquire(getBufferSize(), false);
|
||||
|
||||
BufferUtil.append(_aggregate, (byte)b);
|
||||
_written++;
|
||||
|
@ -256,7 +256,7 @@ public class HttpOutput extends ServletOutputStream
|
|||
if (etag!=null)
|
||||
response.getHttpFields().put(HttpHeader.ETAG,etag);
|
||||
|
||||
content = httpContent.getDirectBuffer();
|
||||
content = _channel.useDirectBuffers()?httpContent.getDirectBuffer():null;
|
||||
if (content == null)
|
||||
content = httpContent.getIndirectBuffer();
|
||||
if (content == null)
|
||||
|
@ -268,7 +268,7 @@ public class HttpOutput extends ServletOutputStream
|
|||
{
|
||||
Resource resource = (Resource)content;
|
||||
_channel.getResponse().getHttpFields().putDateField(HttpHeader.LAST_MODIFIED, resource.lastModified());
|
||||
content = resource.getInputStream();
|
||||
content=resource.getInputStream(); // Closed below
|
||||
}
|
||||
|
||||
// Process content.
|
||||
|
@ -279,9 +279,8 @@ public class HttpOutput extends ServletOutputStream
|
|||
}
|
||||
else if (content instanceof ReadableByteChannel)
|
||||
{
|
||||
ReadableByteChannel channel = (ReadableByteChannel)content;
|
||||
ByteBuffer buffer = _channel.getByteBufferPool().acquire(getBufferSize(), CHANNEL_BUFFER_DIRECT);
|
||||
try
|
||||
ByteBuffer buffer = _channel.getByteBufferPool().acquire(getBufferSize(), _channel.useDirectBuffers());
|
||||
try (ReadableByteChannel channel = (ReadableByteChannel)content;)
|
||||
{
|
||||
while(channel.isOpen())
|
||||
{
|
||||
|
@ -301,12 +300,12 @@ public class HttpOutput extends ServletOutputStream
|
|||
}
|
||||
else if (content instanceof InputStream)
|
||||
{
|
||||
InputStream in = (InputStream)content;
|
||||
ByteBuffer buffer = _channel.getByteBufferPool().acquire(getBufferSize(), STREAM_BUFFER_DIRECT);
|
||||
// allocate non direct buffer so array may be directly accessed.
|
||||
ByteBuffer buffer = _channel.getByteBufferPool().acquire(getBufferSize(), false);
|
||||
byte[] array = buffer.array();
|
||||
int offset=buffer.arrayOffset();
|
||||
int size=array.length-offset;
|
||||
try
|
||||
try (InputStream in = (InputStream)content;)
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
|
|
|
@ -81,7 +81,7 @@ public class InclusiveByteRange
|
|||
* @param size Size of the resource.
|
||||
* @return LazyList of satisfiable ranges
|
||||
*/
|
||||
public static List satisfiableRanges(Enumeration headers, long size)
|
||||
public static List<InclusiveByteRange> satisfiableRanges(Enumeration headers, long size)
|
||||
{
|
||||
Object satRanges=null;
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ import org.eclipse.jetty.http.HttpCookie;
|
|||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
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;
|
||||
|
@ -114,9 +115,9 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
*/
|
||||
public class Request implements HttpServletRequest
|
||||
{
|
||||
public static final String __MULTIPART_CONFIG_ELEMENT = "org.eclipse.multipartConfig";
|
||||
public static final String __MULTIPART_INPUT_STREAM = "org.eclipse.multiPartInputStream";
|
||||
public static final String __MULTIPART_CONTEXT = "org.eclipse.multiPartContext";
|
||||
public static final String __MULTIPART_CONFIG_ELEMENT = "org.eclipse.jetty.multipartConfig";
|
||||
public static final String __MULTIPART_INPUT_STREAM = "org.eclipse.jetty.multiPartInputStream";
|
||||
public static final String __MULTIPART_CONTEXT = "org.eclipse.jetty.multiPartContext";
|
||||
|
||||
private static final Logger LOG = Log.getLogger(Request.class);
|
||||
private static final Collection<Locale> __defaultLocale = Collections.singleton(Locale.getDefault());
|
||||
|
@ -203,7 +204,8 @@ public class Request implements HttpServletRequest
|
|||
private long _dispatchTime;
|
||||
private HttpURI _uri;
|
||||
private MultiPartInputStreamParser _multiPartInputStream; //if the request is a multi-part mime
|
||||
|
||||
private AsyncContextState _async;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Request(HttpChannel<?> channel, HttpInput<?> input)
|
||||
{
|
||||
|
@ -369,10 +371,11 @@ public class Request implements HttpServletRequest
|
|||
@Override
|
||||
public AsyncContext getAsyncContext()
|
||||
{
|
||||
HttpChannelState continuation = getHttpChannelState();
|
||||
if (continuation.isInitial() && !continuation.isAsync())
|
||||
throw new IllegalStateException(continuation.getStatusString());
|
||||
return continuation;
|
||||
HttpChannelState state = getHttpChannelState();
|
||||
if (_async==null || state.isInitial() && !state.isAsync())
|
||||
throw new IllegalStateException(state.getStatusString());
|
||||
|
||||
return _async;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -1027,19 +1030,8 @@ public class Request implements HttpServletRequest
|
|||
@Override
|
||||
public StringBuffer getRequestURL()
|
||||
{
|
||||
final StringBuffer url = new StringBuffer(48);
|
||||
String scheme = getScheme();
|
||||
int port = getServerPort();
|
||||
|
||||
url.append(scheme);
|
||||
url.append("://");
|
||||
url.append(getServerName());
|
||||
if (_port > 0 && ((scheme.equalsIgnoreCase(URIUtil.HTTP) && port != 80) || (scheme.equalsIgnoreCase(URIUtil.HTTPS) && port != 443)))
|
||||
{
|
||||
url.append(':');
|
||||
url.append(_port);
|
||||
}
|
||||
|
||||
final StringBuffer url = new StringBuffer(128);
|
||||
URIUtil.appendSchemeHostPort(url,getScheme(),getServerName(),getServerPort());
|
||||
url.append(getRequestURI());
|
||||
return url;
|
||||
}
|
||||
|
@ -1063,19 +1055,8 @@ public class Request implements HttpServletRequest
|
|||
*/
|
||||
public StringBuilder getRootURL()
|
||||
{
|
||||
StringBuilder url = new StringBuilder(48);
|
||||
String scheme = getScheme();
|
||||
int port = getServerPort();
|
||||
|
||||
url.append(scheme);
|
||||
url.append("://");
|
||||
url.append(getServerName());
|
||||
|
||||
if (port > 0 && ((scheme.equalsIgnoreCase("http") && port != 80) || (scheme.equalsIgnoreCase("https") && port != 443)))
|
||||
{
|
||||
url.append(':');
|
||||
url.append(port);
|
||||
}
|
||||
StringBuilder url = new StringBuilder(128);
|
||||
URIUtil.appendSchemeHostPort(url,getScheme(),getServerName(),getServerPort());
|
||||
return url;
|
||||
}
|
||||
|
||||
|
@ -1105,41 +1086,58 @@ public class Request implements HttpServletRequest
|
|||
|
||||
// Return host from absolute URI
|
||||
_serverName = _uri.getHost();
|
||||
_port = _uri.getPort();
|
||||
if (_serverName != null)
|
||||
{
|
||||
_port = _uri.getPort();
|
||||
return _serverName;
|
||||
}
|
||||
|
||||
// Return host from header field
|
||||
String hostPort = _fields.getStringField(HttpHeader.HOST);
|
||||
|
||||
_port=0;
|
||||
if (hostPort != null)
|
||||
{
|
||||
loop: for (int i = hostPort.length(); i-- > 0;)
|
||||
int len=hostPort.length();
|
||||
loop: for (int i = len; i-- > 0;)
|
||||
{
|
||||
char ch = (char)(0xff & hostPort.charAt(i));
|
||||
switch (ch)
|
||||
char c2 = (char)(0xff & hostPort.charAt(i));
|
||||
switch (c2)
|
||||
{
|
||||
case ']':
|
||||
break loop;
|
||||
|
||||
case ':':
|
||||
_serverName = hostPort.substring(0,i);
|
||||
try
|
||||
{
|
||||
len=i;
|
||||
_port = StringUtil.toInt(hostPort.substring(i+1));
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
_serverName=hostPort;
|
||||
_port=0;
|
||||
return _serverName;
|
||||
}
|
||||
return _serverName;
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
|
||||
if (_serverName == null || _port < 0)
|
||||
if (hostPort.charAt(0)=='[')
|
||||
{
|
||||
_serverName = hostPort;
|
||||
_port = 0;
|
||||
if (hostPort.charAt(len-1)!=']')
|
||||
{
|
||||
LOG.warn("Bad IPv6 "+hostPort);
|
||||
_serverName=hostPort;
|
||||
_port=0;
|
||||
return _serverName;
|
||||
}
|
||||
_serverName = hostPort.substring(1,len-1);
|
||||
}
|
||||
else if (len==hostPort.length())
|
||||
_serverName=hostPort;
|
||||
else
|
||||
_serverName = hostPort.substring(0,len);
|
||||
|
||||
return _serverName;
|
||||
}
|
||||
|
@ -1506,6 +1504,9 @@ public class Request implements HttpServletRequest
|
|||
|
||||
setAuthentication(Authentication.NOT_CHECKED);
|
||||
getHttpChannelState().recycle();
|
||||
if (_async!=null)
|
||||
_async.reset();
|
||||
_async=null;
|
||||
_asyncSupported = true;
|
||||
_handled = false;
|
||||
if (_context != null)
|
||||
|
@ -1989,8 +1990,11 @@ public class Request implements HttpServletRequest
|
|||
if (!_asyncSupported)
|
||||
throw new IllegalStateException("!asyncSupported");
|
||||
HttpChannelState state = getHttpChannelState();
|
||||
state.startAsync();
|
||||
return state;
|
||||
if (_async==null)
|
||||
_async=new AsyncContextState(state);
|
||||
AsyncContextEvent event = new AsyncContextEvent(_context,_async,state,this,this,getResponse());
|
||||
state.startAsync(event);
|
||||
return _async;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -2000,8 +2004,12 @@ public class Request implements HttpServletRequest
|
|||
if (!_asyncSupported)
|
||||
throw new IllegalStateException("!asyncSupported");
|
||||
HttpChannelState state = getHttpChannelState();
|
||||
state.startAsync(_context, servletRequest, servletResponse);
|
||||
return state;
|
||||
if (_async==null)
|
||||
_async=new AsyncContextState(state);
|
||||
AsyncContextEvent event = new AsyncContextEvent(_context,_async,state,this,servletRequest,servletResponse);
|
||||
event.setDispatchTarget(getServletContext(),URIUtil.addPaths(getServletPath(),getPathInfo()));
|
||||
state.startAsync(event);
|
||||
return _async;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -57,8 +57,8 @@ public class ResourceCache
|
|||
private final ResourceCache _parent;
|
||||
private final MimeTypes _mimeTypes;
|
||||
private final boolean _etagSupported;
|
||||
|
||||
private boolean _useFileMappedBuffer=true;
|
||||
private final boolean _useFileMappedBuffer;
|
||||
|
||||
private int _maxCachedFileSize =4*1024*1024;
|
||||
private int _maxCachedFiles=2048;
|
||||
private int _maxCacheSize =32*1024*1024;
|
||||
|
@ -142,12 +142,6 @@ public class ResourceCache
|
|||
return _useFileMappedBuffer;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setUseFileMappedBuffer(boolean useFileMappedBuffer)
|
||||
{
|
||||
_useFileMappedBuffer = useFileMappedBuffer;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void flushCache()
|
||||
{
|
||||
|
|
|
@ -753,6 +753,8 @@ public class Response implements HttpServletResponse
|
|||
break;
|
||||
case STREAM:
|
||||
getOutputStream().close();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -926,6 +928,7 @@ public class Response implements HttpServletResponse
|
|||
case TE:
|
||||
_fields.put(HttpHeader.CONNECTION, HttpHeaderValue.TE.toString());
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -965,6 +968,8 @@ public class Response implements HttpServletResponse
|
|||
case STREAM:
|
||||
case WRITER:
|
||||
_out.reset();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
_out.resetBuffer();
|
||||
|
@ -1023,7 +1028,7 @@ public class Response implements HttpServletResponse
|
|||
return _reason;
|
||||
}
|
||||
|
||||
public void complete() throws IOException
|
||||
public void complete()
|
||||
{
|
||||
_out.close();
|
||||
}
|
||||
|
|
|
@ -19,11 +19,9 @@
|
|||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -34,22 +32,18 @@ import java.util.TimerTask;
|
|||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.xml.validation.Schema;
|
||||
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpGenerator;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
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.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||
import org.eclipse.jetty.util.Attributes;
|
||||
|
@ -282,9 +276,9 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
{
|
||||
if (getStopAtShutdown())
|
||||
{
|
||||
ShutdownThread.register(this);
|
||||
ShutdownThread.register(this);
|
||||
}
|
||||
|
||||
|
||||
ShutdownMonitor.getInstance().start(); // initialize
|
||||
|
||||
LOG.info("jetty-"+getVersion());
|
||||
|
@ -318,7 +312,7 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
if (isDumpAfterStart())
|
||||
dumpStdErr();
|
||||
|
||||
|
||||
|
||||
// use DateCache timer for Date field reformat
|
||||
final HttpFields.DateGenerator date = new HttpFields.DateGenerator();
|
||||
long now=System.currentTimeMillis();
|
||||
|
@ -335,8 +329,8 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
this.cancel();
|
||||
}
|
||||
},tick,1000);
|
||||
|
||||
|
||||
|
||||
|
||||
mex.ifExceptionThrow();
|
||||
}
|
||||
|
||||
|
@ -374,7 +368,7 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
if (stopTimeout>0)
|
||||
{
|
||||
long stop_by=System.currentTimeMillis()+stopTimeout;
|
||||
LOG.info("Graceful shutdown {} by ",this,new Date(stop_by));
|
||||
LOG.debug("Graceful shutdown {} by ",this,new Date(stop_by));
|
||||
|
||||
// Wait for shutdowns
|
||||
for (Future<Void> future: futures)
|
||||
|
@ -476,16 +470,16 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
*/
|
||||
public void handleAsync(HttpChannel<?> connection) throws IOException, ServletException
|
||||
{
|
||||
final HttpChannelState async = connection.getRequest().getHttpChannelState();
|
||||
final HttpChannelState.AsyncEventState state = async.getAsyncEventState();
|
||||
final HttpChannelState state = connection.getRequest().getHttpChannelState();
|
||||
final AsyncContextEvent event = state.getAsyncContextEvent();
|
||||
|
||||
final Request baseRequest=connection.getRequest();
|
||||
final String path=state.getPath();
|
||||
final String path=event.getPath();
|
||||
|
||||
if (path!=null)
|
||||
{
|
||||
// this is a dispatch with a path
|
||||
ServletContext context=state.getServletContext();
|
||||
ServletContext context=event.getServletContext();
|
||||
HttpURI uri = new HttpURI(context==null?path:URIUtil.addPaths(context.getContextPath(),path));
|
||||
baseRequest.setUri(uri);
|
||||
baseRequest.setRequestURI(null);
|
||||
|
@ -495,8 +489,8 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
}
|
||||
|
||||
final String target=baseRequest.getPathInfo();
|
||||
final HttpServletRequest request=(HttpServletRequest)async.getRequest();
|
||||
final HttpServletResponse response=(HttpServletResponse)async.getResponse();
|
||||
final HttpServletRequest request=(HttpServletRequest)event.getSuppliedRequest();
|
||||
final HttpServletResponse response=(HttpServletResponse)event.getSuppliedResponse();
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
|
@ -509,7 +503,6 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void join() throws InterruptedException
|
||||
{
|
||||
|
@ -607,10 +600,10 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (connector==null)
|
||||
return null;
|
||||
|
||||
|
||||
ContextHandler context = getChildHandlerByClass(ContextHandler.class);
|
||||
|
||||
try
|
||||
|
@ -622,7 +615,7 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
host=context.getVirtualHosts()[0];
|
||||
if (host==null)
|
||||
host=InetAddress.getLocalHost().getHostAddress();
|
||||
|
||||
|
||||
String path=context==null?null:context.getContextPath();
|
||||
if (path==null)
|
||||
path="/";
|
||||
|
@ -634,7 +627,7 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String toString()
|
||||
|
@ -647,7 +640,7 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
{
|
||||
dumpBeans(out,indent,Collections.singleton(new ClassLoaderDump(this.getClass().getClassLoader())));
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static void main(String...args) throws Exception
|
||||
{
|
||||
|
|
|
@ -40,7 +40,6 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterRegistration;
|
||||
|
@ -104,11 +103,11 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
{
|
||||
public static int SERVLET_MAJOR_VERSION=3;
|
||||
public static int SERVLET_MINOR_VERSION=0;
|
||||
|
||||
|
||||
final private static String __unimplmented="Unimplemented - use org.eclipse.jetty.servlet.ServletContextHandler";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static final Logger LOG = Log.getLogger(ContextHandler.class);
|
||||
|
||||
private static final ThreadLocal<Context> __context = new ThreadLocal<Context>();
|
||||
|
@ -141,8 +140,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
return c.getContextHandler();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
protected Context _scontext;
|
||||
private final AttributesMap _attributes;
|
||||
private final Map<String, String> _initParams;
|
||||
|
@ -566,7 +565,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
public void addEventListener(EventListener listener)
|
||||
{
|
||||
_eventListeners.add(listener);
|
||||
|
||||
|
||||
if (listener instanceof ServletContextListener)
|
||||
_contextListeners.add((ServletContextListener)listener);
|
||||
|
||||
|
@ -579,7 +578,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
if (listener instanceof ServletRequestAttributeListener)
|
||||
_requestAttributeListeners.add((ServletRequestAttributeListener)listener);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Remove a context event listeners.
|
||||
|
@ -592,7 +591,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
public void removeEventListener(EventListener listener)
|
||||
{
|
||||
_eventListeners.remove(listener);
|
||||
|
||||
|
||||
if (listener instanceof ServletContextListener)
|
||||
_contextListeners.remove(listener);
|
||||
|
||||
|
@ -616,13 +615,13 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
{
|
||||
_programmaticListeners.add(listener);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected boolean isProgrammaticListener(EventListener listener)
|
||||
{
|
||||
return _programmaticListeners.contains(listener);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return true if this context is accepting new requests
|
||||
|
@ -725,7 +724,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
startContext();
|
||||
|
||||
_availability = Availability.AVAILABLE;
|
||||
LOG.info("started {}",this);
|
||||
LOG.info("Started {}", this);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -771,7 +770,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
ServletContextEvent event = new ServletContextEvent(_scontext);
|
||||
for (ServletContextListener listener:_contextListeners)
|
||||
callContextInitialized(listener, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -818,7 +817,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
if (!_contextListeners.isEmpty())
|
||||
{
|
||||
ServletContextEvent event = new ServletContextEvent(_scontext);
|
||||
for (int i = _contextListeners.size(); i-->0;)
|
||||
for (int i = _contextListeners.size(); i-->0;)
|
||||
callContextDestroyed(_contextListeners.get(i),event);
|
||||
}
|
||||
|
||||
|
@ -831,14 +830,14 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
String name = e.nextElement();
|
||||
checkManagedAttribute(name,null);
|
||||
}
|
||||
|
||||
|
||||
for (EventListener l : _programmaticListeners)
|
||||
removeEventListener(l);
|
||||
_programmaticListeners.clear();
|
||||
}
|
||||
finally
|
||||
{
|
||||
LOG.info("stopped {}",this);
|
||||
LOG.info("Stopped {}", this);
|
||||
__context.set(old_context);
|
||||
// reset the classloader
|
||||
if (_classLoader != null && current_thread!=null)
|
||||
|
@ -894,10 +893,10 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
default:
|
||||
match = contextVhost.equalsIgnoreCase(vhost);
|
||||
}
|
||||
|
||||
|
||||
if (match)
|
||||
break loop;
|
||||
|
||||
|
||||
}
|
||||
if (!match)
|
||||
return false;
|
||||
|
@ -1657,7 +1656,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
|
||||
return host;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Add an AliasCheck instance to possibly permit aliased resources
|
||||
|
@ -1667,7 +1666,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
{
|
||||
_aliasChecks.add(check);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return Mutable list of Alias checks
|
||||
|
@ -1798,7 +1797,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
return null;
|
||||
return _mimeTypes.getMimeByExtension(file);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* @see javax.servlet.ServletContext#getRequestDispatcher(java.lang.String)
|
||||
|
@ -2182,13 +2181,13 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
return _enabled;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class NoContext extends AttributesMap implements ServletContext
|
||||
{
|
||||
private int _effectiveMajorVersion = SERVLET_MAJOR_VERSION;
|
||||
private int _effectiveMinorVersion = SERVLET_MINOR_VERSION;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public NoContext()
|
||||
{
|
||||
|
@ -2522,8 +2521,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
LOG.warn(__unimplmented);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Interface to check aliases
|
||||
*/
|
||||
|
@ -2537,7 +2536,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
*/
|
||||
boolean check(String path, Resource resource);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Approve all aliases.
|
||||
|
@ -2550,7 +2549,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Approve Aliases with same suffix.
|
||||
* Eg. a symbolic link from /foobar.html to /somewhere/wibble.html would be
|
||||
|
@ -2568,8 +2567,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
return resource.getAlias().toString().endsWith(suffix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Approve Aliases with a path prefix.
|
||||
* Eg. a symbolic link from /dirA/foobar.html to /dirB/foobar.html would be
|
||||
|
@ -2589,7 +2588,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Approve Aliases of a non existent directory.
|
||||
* If a directory "/foobar/" does not exist, then the resource is
|
||||
* If a directory "/foobar/" does not exist, then the resource is
|
||||
* aliased to "/foobar". Accept such aliases.
|
||||
*/
|
||||
public static class ApproveNonExistentDirectoryAliases implements AliasCheck
|
||||
|
|
|
@ -27,6 +27,9 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.server.AbstractConnector;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.util.DateCache;
|
||||
|
@ -40,7 +43,7 @@ import org.eclipse.jetty.util.RolloverFileOutputStream;
|
|||
* and the current thread name is updated with information that will link
|
||||
* to the details in that output.
|
||||
*/
|
||||
public class DebugHandler extends HandlerWrapper
|
||||
public class DebugHandler extends HandlerWrapper implements Connection.Listener
|
||||
{
|
||||
private DateCache _date=new DateCache("HH:mm:ss", Locale.US);
|
||||
private OutputStream _out;
|
||||
|
@ -69,14 +72,10 @@ public class DebugHandler extends HandlerWrapper
|
|||
String ex=null;
|
||||
try
|
||||
{
|
||||
long now=System.currentTimeMillis();
|
||||
final String d=_date.format(now);
|
||||
final int ms=(int)(now%1000);
|
||||
|
||||
if (retry)
|
||||
_print.println(d+(ms>99?".":(ms>9?".0":".00"))+ms+":"+name+" RETRY");
|
||||
print(name,"RESUME");
|
||||
else
|
||||
_print.println(d+(ms>99?".":(ms>9?".0":".00"))+ms+":"+name+" "+baseRequest.getRemoteAddr()+" "+request.getMethod()+" "+baseRequest.getHeader("Cookie")+"; "+baseRequest.getHeader("User-Agent"));
|
||||
print(name,"REQUEST "+baseRequest.getRemoteAddr()+" "+request.getMethod()+" "+baseRequest.getHeader("Cookie")+"; "+baseRequest.getHeader("User-Agent"));
|
||||
thread.setName(name);
|
||||
|
||||
getHandler().handle(target,baseRequest,request,response);
|
||||
|
@ -104,21 +103,25 @@ public class DebugHandler extends HandlerWrapper
|
|||
finally
|
||||
{
|
||||
thread.setName(old_name);
|
||||
long now=System.currentTimeMillis();
|
||||
final String d=_date.format(now);
|
||||
final int ms=(int)(now%1000);
|
||||
suspend=baseRequest.getHttpChannelState().isSuspended();
|
||||
if (suspend)
|
||||
{
|
||||
request.setAttribute("org.eclipse.jetty.thread.name",name);
|
||||
_print.println(d+(ms>99?".":(ms>9?".0":".00"))+ms+":"+name+" SUSPEND");
|
||||
print(name,"SUSPEND");
|
||||
}
|
||||
else
|
||||
_print.println(d+(ms>99?".":(ms>9?".0":".00"))+ms+":"+name+" "+base_response.getStatus()+
|
||||
(ex==null?"":("/"+ex))+
|
||||
" "+base_response.getContentType());
|
||||
print(name,"RESPONSE "+base_response.getStatus()+(ex==null?"":("/"+ex))+" "+base_response.getContentType());
|
||||
}
|
||||
}
|
||||
|
||||
private void print(String name,String message)
|
||||
{
|
||||
long now=System.currentTimeMillis();
|
||||
final String d=_date.format(now);
|
||||
final int ms=(int)(now%1000);
|
||||
|
||||
_print.println(d+(ms>99?".":(ms>9?".0":".00"))+ms+":"+name+" "+message);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.server.handler.HandlerWrapper#doStart()
|
||||
|
@ -129,6 +132,11 @@ public class DebugHandler extends HandlerWrapper
|
|||
if (_out==null)
|
||||
_out=new RolloverFileOutputStream("./logs/yyyy_mm_dd.debug.log",true);
|
||||
_print=new PrintStream(_out);
|
||||
|
||||
for (Connector connector : getServer().getConnectors())
|
||||
if (connector instanceof AbstractConnector)
|
||||
((AbstractConnector)connector).addBean(this,false);
|
||||
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
|
@ -140,6 +148,9 @@ public class DebugHandler extends HandlerWrapper
|
|||
{
|
||||
super.doStop();
|
||||
_print.close();
|
||||
for (Connector connector : getServer().getConnectors())
|
||||
if (connector instanceof AbstractConnector)
|
||||
((AbstractConnector)connector).removeBean(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -157,4 +168,17 @@ public class DebugHandler extends HandlerWrapper
|
|||
{
|
||||
_out = out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpened(Connection connection)
|
||||
{
|
||||
print(Thread.currentThread().getName(),"OPENED "+connection.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed(Connection connection)
|
||||
{
|
||||
print(Thread.currentThread().getName(),"CLOSED "+connection.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.server.AsyncContextEvent;
|
||||
import org.eclipse.jetty.server.HttpChannelState;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
|
@ -76,12 +77,13 @@ public class StatisticsHandler extends HandlerWrapper
|
|||
public void onError(AsyncEvent event) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onComplete(AsyncEvent event) throws IOException
|
||||
{
|
||||
HttpChannelState state = (HttpChannelState)event.getAsyncContext();
|
||||
|
||||
HttpChannelState state = ((AsyncContextEvent)event).getHttpChannelState();
|
||||
|
||||
Request request = state.getBaseRequest();
|
||||
final long elapsed = System.currentTimeMillis()-request.getTimeStamp();
|
||||
|
||||
|
@ -93,7 +95,7 @@ public class StatisticsHandler extends HandlerWrapper
|
|||
if (!state.isDispatched())
|
||||
_asyncWaitStats.decrement();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -323,17 +323,20 @@ public class JDBCSessionManager extends AbstractSessionManager
|
|||
super.complete();
|
||||
try
|
||||
{
|
||||
if (_dirty)
|
||||
if (isValid())
|
||||
{
|
||||
//The session attributes have changed, write to the db, ensuring
|
||||
//http passivation/activation listeners called
|
||||
willPassivate();
|
||||
updateSession(this);
|
||||
didActivate();
|
||||
}
|
||||
else if ((getAccessed() - _lastSaved) >= (getSaveInterval() * 1000L))
|
||||
{
|
||||
updateSessionAccessTime(this);
|
||||
if (_dirty)
|
||||
{
|
||||
//The session attributes have changed, write to the db, ensuring
|
||||
//http passivation/activation listeners called
|
||||
willPassivate();
|
||||
updateSession(this);
|
||||
didActivate();
|
||||
}
|
||||
else if ((getAccessed() - _lastSaved) >= (getSaveInterval() * 1000L))
|
||||
{
|
||||
updateSessionAccessTime(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
@ -18,26 +18,38 @@
|
|||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.Socket;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Exchanger;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
@ -46,116 +58,129 @@ public class AsyncRequestReadTest
|
|||
{
|
||||
private static Server server;
|
||||
private static ServerConnector connector;
|
||||
private final static Exchanger<Long> __total=new Exchanger<Long>();
|
||||
private final static BlockingQueue<Long> __total=new BlockingArrayQueue<>();
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
@Before
|
||||
public void startServer() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
connector = new ServerConnector(server);
|
||||
connector.setIdleTimeout(10000);
|
||||
server.addConnector(connector);
|
||||
server.setHandler(new EmptyHandler());
|
||||
server.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopServer() throws Exception
|
||||
@After
|
||||
public void stopServer() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
server.join();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception
|
||||
public void testPipelined() throws Exception
|
||||
{
|
||||
final Socket socket = new Socket("localhost",connector.getLocalPort());
|
||||
server.setHandler(new AsyncStreamHandler());
|
||||
server.start();
|
||||
|
||||
try (final Socket socket = new Socket("localhost",connector.getLocalPort()))
|
||||
{
|
||||
socket.setSoTimeout(1000);
|
||||
|
||||
byte[] content = new byte[32*4096];
|
||||
Arrays.fill(content, (byte)120);
|
||||
|
||||
byte[] content = new byte[16*4096];
|
||||
Arrays.fill(content, (byte)120);
|
||||
OutputStream out = socket.getOutputStream();
|
||||
String header=
|
||||
"POST / HTTP/1.1\r\n"+
|
||||
"Host: localhost\r\n"+
|
||||
"Content-Length: "+content.length+"\r\n"+
|
||||
"Content-Type: bytes\r\n"+
|
||||
"\r\n";
|
||||
byte[] h=header.getBytes(StringUtil.__ISO_8859_1);
|
||||
out.write(h);
|
||||
out.write(content);
|
||||
|
||||
|
||||
header=
|
||||
"POST / HTTP/1.1\r\n"+
|
||||
"Host: localhost\r\n"+
|
||||
"Content-Length: "+content.length+"\r\n"+
|
||||
"Content-Type: bytes\r\n"+
|
||||
"Connection: close\r\n"+
|
||||
"\r\n";
|
||||
h=header.getBytes(StringUtil.__ISO_8859_1);
|
||||
out.write(h);
|
||||
out.write(content);
|
||||
out.flush();
|
||||
|
||||
OutputStream out = socket.getOutputStream();
|
||||
String header=
|
||||
"POST / HTTP/1.1\r\n"+
|
||||
"Host: localhost\r\n"+
|
||||
"Content-Length: "+content.length+"\r\n"+
|
||||
"Content-Type: bytes\r\n"+
|
||||
"Connection: close\r\n"+
|
||||
"\r\n";
|
||||
byte[] h=header.getBytes(StringUtil.__ISO_8859_1);
|
||||
InputStream in = socket.getInputStream();
|
||||
String response = IO.toString(in);
|
||||
assertTrue(response.indexOf("200 OK")>0);
|
||||
|
||||
out.write(h);
|
||||
out.flush();
|
||||
|
||||
out.write(content,0,4*4096);
|
||||
Thread.sleep(100);
|
||||
out.write(content,8192,4*4096);
|
||||
Thread.sleep(100);
|
||||
out.write(content,8*4096,content.length-8*4096);
|
||||
|
||||
out.flush();
|
||||
|
||||
InputStream in = socket.getInputStream();
|
||||
String response = IO.toString(in);
|
||||
assertTrue(response.indexOf("200 OK")>0);
|
||||
|
||||
long total=__total.exchange(0L,30,TimeUnit.SECONDS);
|
||||
assertEquals(content.length, total);
|
||||
long total=__total.poll(5,TimeUnit.SECONDS);
|
||||
assertEquals(content.length, total);
|
||||
total=__total.poll(5,TimeUnit.SECONDS);
|
||||
assertEquals(content.length, total);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void tests() throws Exception
|
||||
public void testAsyncReadsWithDelays() throws Exception
|
||||
{
|
||||
runTest(64,4,4,20);
|
||||
runTest(256,16,16,50);
|
||||
runTest(256,1,128,10);
|
||||
runTest(128*1024,1,64,10);
|
||||
runTest(256*1024,5321,10,100);
|
||||
runTest(512*1024,32*1024,10,10);
|
||||
server.setHandler(new AsyncStreamHandler());
|
||||
server.start();
|
||||
|
||||
asyncReadTest(64,4,4,20);
|
||||
asyncReadTest(256,16,16,50);
|
||||
asyncReadTest(256,1,128,10);
|
||||
asyncReadTest(128*1024,1,64,10);
|
||||
asyncReadTest(256*1024,5321,10,100);
|
||||
asyncReadTest(512*1024,32*1024,10,10);
|
||||
}
|
||||
|
||||
|
||||
public void runTest(int contentSize, int chunkSize, int chunks, int delayMS) throws Exception
|
||||
public void asyncReadTest(int contentSize, int chunkSize, int chunks, int delayMS) throws Exception
|
||||
{
|
||||
String tst=contentSize+","+chunkSize+","+chunks+","+delayMS;
|
||||
//System.err.println(tst);
|
||||
|
||||
final Socket socket = new Socket("localhost",connector.getLocalPort());
|
||||
|
||||
byte[] content = new byte[contentSize];
|
||||
Arrays.fill(content, (byte)120);
|
||||
|
||||
OutputStream out = socket.getOutputStream();
|
||||
out.write("POST / HTTP/1.1\r\n".getBytes());
|
||||
out.write("Host: localhost\r\n".getBytes());
|
||||
out.write(("Content-Length: "+content.length+"\r\n").getBytes());
|
||||
out.write("Content-Type: bytes\r\n".getBytes());
|
||||
out.write("Connection: close\r\n".getBytes());
|
||||
out.write("\r\n".getBytes());
|
||||
out.flush();
|
||||
|
||||
int offset=0;
|
||||
for (int i=0;i<chunks;i++)
|
||||
try(final Socket socket = new Socket("localhost",connector.getLocalPort()))
|
||||
{
|
||||
out.write(content,offset,chunkSize);
|
||||
offset+=chunkSize;
|
||||
Thread.sleep(delayMS);
|
||||
|
||||
byte[] content = new byte[contentSize];
|
||||
Arrays.fill(content, (byte)120);
|
||||
|
||||
OutputStream out = socket.getOutputStream();
|
||||
out.write("POST / HTTP/1.1\r\n".getBytes());
|
||||
out.write("Host: localhost\r\n".getBytes());
|
||||
out.write(("Content-Length: "+content.length+"\r\n").getBytes());
|
||||
out.write("Content-Type: bytes\r\n".getBytes());
|
||||
out.write("Connection: close\r\n".getBytes());
|
||||
out.write("\r\n".getBytes());
|
||||
out.flush();
|
||||
|
||||
int offset=0;
|
||||
for (int i=0;i<chunks;i++)
|
||||
{
|
||||
out.write(content,offset,chunkSize);
|
||||
offset+=chunkSize;
|
||||
Thread.sleep(delayMS);
|
||||
}
|
||||
out.write(content,offset,content.length-offset);
|
||||
|
||||
out.flush();
|
||||
|
||||
InputStream in = socket.getInputStream();
|
||||
String response = IO.toString(in);
|
||||
assertTrue(tst,response.indexOf("200 OK")>0);
|
||||
|
||||
long total=__total.poll(30,TimeUnit.SECONDS);
|
||||
assertEquals(tst,content.length, total);
|
||||
}
|
||||
out.write(content,offset,content.length-offset);
|
||||
|
||||
out.flush();
|
||||
|
||||
InputStream in = socket.getInputStream();
|
||||
String response = IO.toString(in);
|
||||
assertTrue(tst,response.indexOf("200 OK")>0);
|
||||
|
||||
long total=__total.exchange(0L,30,TimeUnit.SECONDS);
|
||||
assertEquals(tst,content.length, total);
|
||||
}
|
||||
|
||||
|
||||
private static class EmptyHandler extends AbstractHandler
|
||||
private static class AsyncStreamHandler extends AbstractHandler
|
||||
{
|
||||
@Override
|
||||
public void handle(String path, final Request request, HttpServletRequest httpRequest, final HttpServletResponse httpResponse) throws IOException, ServletException
|
||||
|
@ -164,6 +189,7 @@ public class AsyncRequestReadTest
|
|||
request.setHandled(true);
|
||||
|
||||
final AsyncContext async = request.startAsync();
|
||||
// System.err.println("handle "+request.getContentLength());
|
||||
|
||||
new Thread()
|
||||
{
|
||||
|
@ -171,9 +197,10 @@ public class AsyncRequestReadTest
|
|||
public void run()
|
||||
{
|
||||
long total=0;
|
||||
try
|
||||
try(InputStream in = request.getInputStream();)
|
||||
{
|
||||
InputStream in = request.getInputStream();
|
||||
// System.err.println("reading...");
|
||||
|
||||
byte[] b = new byte[4*4096];
|
||||
int read;
|
||||
while((read =in.read(b))>=0)
|
||||
|
@ -188,17 +215,156 @@ public class AsyncRequestReadTest
|
|||
{
|
||||
httpResponse.setStatus(200);
|
||||
async.complete();
|
||||
try
|
||||
{
|
||||
__total.exchange(total);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
// System.err.println("read "+total);
|
||||
__total.offer(total);
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPartialRead() throws Exception
|
||||
{
|
||||
server.setHandler(new PartialReaderHandler());
|
||||
server.start();
|
||||
|
||||
try (final Socket socket = new Socket("localhost",connector.getLocalPort()))
|
||||
{
|
||||
socket.setSoTimeout(1000);
|
||||
|
||||
byte[] content = new byte[32*4096];
|
||||
Arrays.fill(content, (byte)88);
|
||||
|
||||
OutputStream out = socket.getOutputStream();
|
||||
String header=
|
||||
"POST /?read=10 HTTP/1.1\r\n"+
|
||||
"Host: localhost\r\n"+
|
||||
"Content-Length: "+content.length+"\r\n"+
|
||||
"Content-Type: bytes\r\n"+
|
||||
"\r\n";
|
||||
byte[] h=header.getBytes(StringUtil.__ISO_8859_1);
|
||||
out.write(h);
|
||||
out.write(content);
|
||||
|
||||
header= "POST /?read=10 HTTP/1.1\r\n"+
|
||||
"Host: localhost\r\n"+
|
||||
"Content-Length: "+content.length+"\r\n"+
|
||||
"Content-Type: bytes\r\n"+
|
||||
"Connection: close\r\n"+
|
||||
"\r\n";
|
||||
h=header.getBytes(StringUtil.__ISO_8859_1);
|
||||
out.write(h);
|
||||
out.write(content);
|
||||
out.flush();
|
||||
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
assertThat(in.readLine(),containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(in.readLine(),containsString("Content-Length:"));
|
||||
assertThat(in.readLine(),containsString("Server:"));
|
||||
in.readLine();
|
||||
assertThat(in.readLine(),containsString("XXXXXXX"));
|
||||
assertThat(in.readLine(),containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(in.readLine(),containsString("Connection: close"));
|
||||
assertThat(in.readLine(),containsString("Server:"));
|
||||
in.readLine();
|
||||
assertThat(in.readLine(),containsString("XXXXXXX"));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPartialReadThenShutdown() throws Exception
|
||||
{
|
||||
server.setHandler(new PartialReaderHandler());
|
||||
server.start();
|
||||
|
||||
try (final Socket socket = new Socket("localhost",connector.getLocalPort()))
|
||||
{
|
||||
socket.setSoTimeout(10000);
|
||||
|
||||
byte[] content = new byte[32*4096];
|
||||
Arrays.fill(content, (byte)88);
|
||||
|
||||
OutputStream out = socket.getOutputStream();
|
||||
String header=
|
||||
"POST /?read=10 HTTP/1.1\r\n"+
|
||||
"Host: localhost\r\n"+
|
||||
"Content-Length: "+content.length+"\r\n"+
|
||||
"Content-Type: bytes\r\n"+
|
||||
"\r\n";
|
||||
byte[] h=header.getBytes(StringUtil.__ISO_8859_1);
|
||||
out.write(h);
|
||||
out.write(content,0,4096);
|
||||
out.flush();
|
||||
socket.shutdownOutput();
|
||||
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
assertThat(in.readLine(),containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(in.readLine(),containsString("Content-Length:"));
|
||||
assertThat(in.readLine(),containsString("Server:"));
|
||||
in.readLine();
|
||||
assertThat(in.readLine(),containsString("XXXXXXX"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPartialReadThenClose() throws Exception
|
||||
{
|
||||
server.setHandler(new PartialReaderHandler());
|
||||
server.start();
|
||||
|
||||
try (final Socket socket = new Socket("localhost",connector.getLocalPort()))
|
||||
{
|
||||
socket.setSoTimeout(1000);
|
||||
|
||||
byte[] content = new byte[32*4096];
|
||||
Arrays.fill(content, (byte)88);
|
||||
|
||||
OutputStream out = socket.getOutputStream();
|
||||
String header=
|
||||
"POST /?read=10 HTTP/1.1\r\n"+
|
||||
"Host: localhost\r\n"+
|
||||
"Content-Length: "+content.length+"\r\n"+
|
||||
"Content-Type: bytes\r\n"+
|
||||
"\r\n";
|
||||
byte[] h=header.getBytes(StringUtil.__ISO_8859_1);
|
||||
out.write(h);
|
||||
out.write(content,0,4096);
|
||||
out.flush();
|
||||
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
assertThat(in.readLine(),containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(in.readLine(),containsString("Content-Length:"));
|
||||
assertThat(in.readLine(),containsString("Server:"));
|
||||
in.readLine();
|
||||
assertThat(in.readLine(),containsString("XXXXXXX"));
|
||||
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static class PartialReaderHandler extends AbstractHandler
|
||||
{
|
||||
@Override
|
||||
public void handle(String path, final Request request, HttpServletRequest httpRequest, final HttpServletResponse httpResponse) throws IOException, ServletException
|
||||
{
|
||||
httpResponse.setStatus(200);
|
||||
request.setHandled(true);
|
||||
|
||||
BufferedReader in = request.getReader();
|
||||
PrintWriter out =httpResponse.getWriter();
|
||||
int read=Integer.valueOf(request.getParameter("read"));
|
||||
// System.err.println("read="+read);
|
||||
for (int i=read;i-->0;)
|
||||
{
|
||||
int c=in.read();
|
||||
if (c<0)
|
||||
break;
|
||||
out.write(c);
|
||||
}
|
||||
out.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import static org.junit.Assert.assertFalse;
|
|||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -44,6 +45,7 @@ public class CheckReverseProxyHeadersTest
|
|||
"X-Forwarded-For: 10.20.30.40\n" +
|
||||
"X-Forwarded-Host: example.com", new RequestValidator()
|
||||
{
|
||||
@Override
|
||||
public void validate(HttpServletRequest request)
|
||||
{
|
||||
assertEquals("example.com", request.getServerName());
|
||||
|
@ -55,6 +57,42 @@ public class CheckReverseProxyHeadersTest
|
|||
assertFalse(request.isSecure());
|
||||
}
|
||||
});
|
||||
|
||||
// IPv6 ProxyPass from example.com:80 to localhost:8080
|
||||
testRequest("Host: localhost:8080\n" +
|
||||
"X-Forwarded-For: 10.20.30.40\n" +
|
||||
"X-Forwarded-Host: [::1]", new RequestValidator()
|
||||
{
|
||||
@Override
|
||||
public void validate(HttpServletRequest request)
|
||||
{
|
||||
assertEquals("::1", request.getServerName());
|
||||
assertEquals(80, request.getServerPort());
|
||||
assertEquals("10.20.30.40", request.getRemoteAddr());
|
||||
assertEquals("10.20.30.40", request.getRemoteHost());
|
||||
assertEquals("[::1]", request.getHeader("Host"));
|
||||
assertEquals("http",request.getScheme());
|
||||
assertFalse(request.isSecure());
|
||||
}
|
||||
});
|
||||
|
||||
// IPv6 ProxyPass from example.com:80 to localhost:8080
|
||||
testRequest("Host: localhost:8080\n" +
|
||||
"X-Forwarded-For: 10.20.30.40\n" +
|
||||
"X-Forwarded-Host: [::1]:8888", new RequestValidator()
|
||||
{
|
||||
@Override
|
||||
public void validate(HttpServletRequest request)
|
||||
{
|
||||
assertEquals("::1", request.getServerName());
|
||||
assertEquals(8888, request.getServerPort());
|
||||
assertEquals("10.20.30.40", request.getRemoteAddr());
|
||||
assertEquals("10.20.30.40", request.getRemoteHost());
|
||||
assertEquals("[::1]:8888", request.getHeader("Host"));
|
||||
assertEquals("http",request.getScheme());
|
||||
assertFalse(request.isSecure());
|
||||
}
|
||||
});
|
||||
|
||||
// ProxyPass from example.com:81 to localhost:8080
|
||||
testRequest("Host: localhost:8080\n" +
|
||||
|
@ -63,6 +101,7 @@ public class CheckReverseProxyHeadersTest
|
|||
"X-Forwarded-Server: example.com\n"+
|
||||
"X-Forwarded-Proto: https", new RequestValidator()
|
||||
{
|
||||
@Override
|
||||
public void validate(HttpServletRequest request)
|
||||
{
|
||||
assertEquals("example.com", request.getServerName());
|
||||
|
@ -82,6 +121,7 @@ public class CheckReverseProxyHeadersTest
|
|||
"X-Forwarded-Server: example.com, rp.example.com\n"+
|
||||
"X-Forwarded-Proto: https, http", new RequestValidator()
|
||||
{
|
||||
@Override
|
||||
public void validate(HttpServletRequest request)
|
||||
{
|
||||
assertEquals("example.com", request.getServerName());
|
||||
|
@ -111,7 +151,8 @@ public class CheckReverseProxyHeadersTest
|
|||
try
|
||||
{
|
||||
server.start();
|
||||
connector.getResponses("GET / HTTP/1.1\r\n" +"Connection: close\r\n" + headers + "\r\n\r\n");
|
||||
connector.getResponses("GET / HTTP/1.1\r\n" +"Connection: close\r\n" + headers + "\r\n\r\n",
|
||||
1000,TimeUnit.SECONDS);
|
||||
|
||||
Error error = validationHandler.getError();
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ public class HttpConnectionTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testFragmentedChunk()
|
||||
public void testFragmentedChunk() throws Exception
|
||||
{
|
||||
String response=null;
|
||||
try
|
||||
|
@ -119,10 +119,9 @@ public class HttpConnectionTest
|
|||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
assertTrue(false);
|
||||
if (response!=null)
|
||||
if(response != null)
|
||||
System.err.println(response);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -249,7 +248,7 @@ public class HttpConnectionTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testCharset()
|
||||
public void testCharset() throws Exception
|
||||
{
|
||||
|
||||
String response=null;
|
||||
|
@ -306,10 +305,9 @@ public class HttpConnectionTest
|
|||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
assertTrue(false);
|
||||
if (response!=null)
|
||||
if(response != null)
|
||||
System.err.println(response);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -391,7 +389,7 @@ public class HttpConnectionTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testConnection()
|
||||
public void testConnection() throws Exception
|
||||
{
|
||||
String response=null;
|
||||
try
|
||||
|
@ -412,10 +410,9 @@ public class HttpConnectionTest
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
assertTrue(false);
|
||||
if (response!=null)
|
||||
System.err.println(response);
|
||||
if(response != null)
|
||||
System.err.println(response);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -525,7 +522,7 @@ public class HttpConnectionTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testAsterisk()
|
||||
public void testAsterisk() throws Exception
|
||||
{
|
||||
String response = null;
|
||||
|
||||
|
@ -572,10 +569,9 @@ public class HttpConnectionTest
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
assertTrue(false);
|
||||
if (response!=null)
|
||||
System.err.println(response);
|
||||
if(response != null)
|
||||
System.err.println(response);
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -585,7 +581,7 @@ public class HttpConnectionTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testCONNECT()
|
||||
public void testCONNECT() throws Exception
|
||||
{
|
||||
String response = null;
|
||||
|
||||
|
@ -601,10 +597,9 @@ public class HttpConnectionTest
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
assertTrue(false);
|
||||
if (response!=null)
|
||||
System.err.println(response);
|
||||
if(response != null)
|
||||
System.err.println(response);
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -960,7 +960,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
|||
|
||||
|
||||
String in = IO.toString(is);
|
||||
System.err.println(in);
|
||||
// System.err.println(in);
|
||||
|
||||
int index = in.indexOf("123456789");
|
||||
assertTrue(index > 0);
|
||||
|
|
|
@ -135,11 +135,11 @@ public class HttpURITest
|
|||
/*33*/ {"/?abc=test",null, null, null,null,"/", null,"abc=test",null},
|
||||
/*34*/ {"/#fragment",null, null, null,null,"/", null,null,"fragment"},
|
||||
/*35*/ {"http://192.0.0.1:8080/","http","//192.0.0.1:8080","192.0.0.1","8080","/",null,null,null},
|
||||
/*36*/ {"http://[2001:db8::1]:8080/","http","//[2001:db8::1]:8080","[2001:db8::1]","8080","/",null,null,null},
|
||||
/*37*/ {"http://user@[2001:db8::1]:8080/","http","//user@[2001:db8::1]:8080","[2001:db8::1]","8080","/",null,null,null},
|
||||
/*38*/ {"http://[2001:db8::1]/","http","//[2001:db8::1]","[2001:db8::1]",null,"/",null,null,null},
|
||||
/*36*/ {"http://[2001:db8::1]:8080/","http","//[2001:db8::1]:8080","2001:db8::1","8080","/",null,null,null},
|
||||
/*37*/ {"http://user@[2001:db8::1]:8080/","http","//user@[2001:db8::1]:8080","2001:db8::1","8080","/",null,null,null},
|
||||
/*38*/ {"http://[2001:db8::1]/","http","//[2001:db8::1]","2001:db8::1",null,"/",null,null,null},
|
||||
/*39*/ {"//[2001:db8::1]:8080/",null,null,null,null,"//[2001:db8::1]:8080/",null,null,null},
|
||||
/*40*/ {"http://user@[2001:db8::1]:8080/","http","//user@[2001:db8::1]:8080","[2001:db8::1]","8080","/",null,null,null},
|
||||
/*40*/ {"http://user@[2001:db8::1]:8080/","http","//user@[2001:db8::1]:8080","2001:db8::1","8080","/",null,null,null},
|
||||
/*41*/ {"*",null,null,null,null,"*",null, null,null}
|
||||
};
|
||||
|
||||
|
@ -366,7 +366,7 @@ public class HttpURITest
|
|||
{
|
||||
/* 0*/ {" localhost:8080 ","localhost","8080"},
|
||||
/* 1*/ {" 127.0.0.1:8080 ","127.0.0.1","8080"},
|
||||
/* 2*/ {" [127::0::0::1]:8080 ","[127::0::0::1]","8080"},
|
||||
/* 2*/ {" [127::0::0::1]:8080 ","127::0::0::1","8080"},
|
||||
/* 3*/ {" error ",null,null},
|
||||
/* 4*/ {" http://localhost:8080/ ",null,null},
|
||||
};
|
||||
|
@ -382,7 +382,7 @@ public class HttpURITest
|
|||
byte[] buf = connect_tests[i][0].getBytes(StringUtil.__UTF8);
|
||||
|
||||
uri.parseConnect(buf,2,buf.length-4);
|
||||
assertEquals("path"+i,connect_tests[i][1]+":"+connect_tests[i][2],uri.getPath());
|
||||
assertEquals("path"+i,connect_tests[i][0].trim(),uri.getPath());
|
||||
assertEquals("host"+i,connect_tests[i][1],uri.getHost());
|
||||
assertEquals("port"+i,Integer.parseInt(connect_tests[i][2]),uri.getPort());
|
||||
}
|
||||
|
|
|
@ -241,7 +241,7 @@ public class RequestTest
|
|||
multipart;
|
||||
|
||||
String responses=_connector.getResponses(request);
|
||||
System.err.println(responses);
|
||||
// System.err.println(responses);
|
||||
assertTrue(responses.startsWith("HTTP/1.1 200"));
|
||||
}
|
||||
|
||||
|
@ -354,6 +354,7 @@ public class RequestTest
|
|||
@Override
|
||||
public boolean check(HttpServletRequest request,HttpServletResponse response)
|
||||
{
|
||||
results.add(request.getRequestURL().toString());
|
||||
results.add(request.getRemoteAddr());
|
||||
results.add(request.getServerName());
|
||||
results.add(String.valueOf(request.getServerPort()));
|
||||
|
@ -361,71 +362,121 @@ public class RequestTest
|
|||
}
|
||||
};
|
||||
|
||||
String responses=_connector.getResponses(
|
||||
results.clear();
|
||||
_connector.getResponses(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: myhost\n"+
|
||||
"\n"+
|
||||
|
||||
"Connection: close\n"+
|
||||
"\n");
|
||||
int i=0;
|
||||
assertEquals("http://myhost/",results.get(i++));
|
||||
assertEquals("0.0.0.0",results.get(i++));
|
||||
assertEquals("myhost",results.get(i++));
|
||||
assertEquals("80",results.get(i++));
|
||||
|
||||
|
||||
results.clear();
|
||||
_connector.getResponses(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: myhost:8888\n"+
|
||||
"\n"+
|
||||
|
||||
"Connection: close\n"+
|
||||
"\n");
|
||||
i=0;
|
||||
assertEquals("http://myhost:8888/",results.get(i++));
|
||||
assertEquals("0.0.0.0",results.get(i++));
|
||||
assertEquals("myhost",results.get(i++));
|
||||
assertEquals("8888",results.get(i++));
|
||||
|
||||
|
||||
results.clear();
|
||||
_connector.getResponses(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: 1.2.3.4\n"+
|
||||
"\n"+
|
||||
|
||||
"Connection: close\n"+
|
||||
"\n");
|
||||
i=0;
|
||||
|
||||
assertEquals("http://1.2.3.4/",results.get(i++));
|
||||
assertEquals("0.0.0.0",results.get(i++));
|
||||
assertEquals("1.2.3.4",results.get(i++));
|
||||
assertEquals("80",results.get(i++));
|
||||
|
||||
|
||||
results.clear();
|
||||
_connector.getResponses(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: 1.2.3.4:8888\n"+
|
||||
"\n"+
|
||||
|
||||
"Connection: close\n"+
|
||||
"\n");
|
||||
i=0;
|
||||
assertEquals("http://1.2.3.4:8888/",results.get(i++));
|
||||
assertEquals("0.0.0.0",results.get(i++));
|
||||
assertEquals("1.2.3.4",results.get(i++));
|
||||
assertEquals("8888",results.get(i++));
|
||||
|
||||
|
||||
results.clear();
|
||||
_connector.getResponses(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: [::1]\n"+
|
||||
"\n"+
|
||||
|
||||
"Connection: close\n"+
|
||||
"\n");
|
||||
i=0;
|
||||
assertEquals("http://[::1]/",results.get(i++));
|
||||
assertEquals("0.0.0.0",results.get(i++));
|
||||
assertEquals("::1",results.get(i++));
|
||||
assertEquals("80",results.get(i++));
|
||||
|
||||
|
||||
results.clear();
|
||||
_connector.getResponses(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: [::1]:8888\n"+
|
||||
"\n"+
|
||||
|
||||
"Connection: close\n"+
|
||||
"\n");
|
||||
i=0;
|
||||
assertEquals("http://[::1]:8888/",results.get(i++));
|
||||
assertEquals("0.0.0.0",results.get(i++));
|
||||
assertEquals("::1",results.get(i++));
|
||||
assertEquals("8888",results.get(i++));
|
||||
|
||||
|
||||
results.clear();
|
||||
_connector.getResponses(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: [::1]\n"+
|
||||
"x-forwarded-for: remote\n"+
|
||||
"x-forwarded-proto: https\n"+
|
||||
"\n"+
|
||||
|
||||
"Connection: close\n"+
|
||||
"\n");
|
||||
i=0;
|
||||
assertEquals("https://[::1]/",results.get(i++));
|
||||
assertEquals("remote",results.get(i++));
|
||||
assertEquals("::1",results.get(i++));
|
||||
assertEquals("443",results.get(i++));
|
||||
|
||||
|
||||
results.clear();
|
||||
_connector.getResponses(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: [::1]:8888\n"+
|
||||
"Connection: close\n"+
|
||||
"x-forwarded-for: remote\n"+
|
||||
"x-forwarded-proto: https\n"+
|
||||
"\n",10,TimeUnit.SECONDS);
|
||||
|
||||
|
||||
int i=0;
|
||||
assertEquals("0.0.0.0",results.get(i++));
|
||||
assertEquals("myhost",results.get(i++));
|
||||
assertEquals("80",results.get(i++));
|
||||
assertEquals("0.0.0.0",results.get(i++));
|
||||
assertEquals("myhost",results.get(i++));
|
||||
assertEquals("8888",results.get(i++));
|
||||
assertEquals("0.0.0.0",results.get(i++));
|
||||
assertEquals("1.2.3.4",results.get(i++));
|
||||
assertEquals("80",results.get(i++));
|
||||
assertEquals("0.0.0.0",results.get(i++));
|
||||
assertEquals("1.2.3.4",results.get(i++));
|
||||
assertEquals("8888",results.get(i++));
|
||||
assertEquals("0.0.0.0",results.get(i++));
|
||||
assertEquals("[::1]",results.get(i++));
|
||||
assertEquals("80",results.get(i++));
|
||||
assertEquals("0.0.0.0",results.get(i++));
|
||||
assertEquals("[::1]",results.get(i++));
|
||||
assertEquals("8888",results.get(i++));
|
||||
"\n");
|
||||
i=0;
|
||||
|
||||
assertEquals("https://[::1]:8888/",results.get(i++));
|
||||
assertEquals("remote",results.get(i++));
|
||||
assertEquals("[::1]",results.get(i++));
|
||||
assertEquals("443",results.get(i++));
|
||||
assertEquals("remote",results.get(i++));
|
||||
assertEquals("[::1]",results.get(i++));
|
||||
assertEquals("::1",results.get(i++));
|
||||
assertEquals("8888",results.get(i++));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -432,43 +432,54 @@ public class ResponseTest
|
|||
String[][] tests = {
|
||||
// No cookie
|
||||
{"http://myhost:8888/other/location;jsessionid=12345?name=value","http://myhost:8888/other/location;jsessionid=12345?name=value"},
|
||||
{"/other/location;jsessionid=12345?name=value","http://myhost:8888/other/location;jsessionid=12345?name=value"},
|
||||
{"./location;jsessionid=12345?name=value","http://myhost:8888/path/location;jsessionid=12345?name=value"},
|
||||
{"/other/location;jsessionid=12345?name=value","http://@HOST@@PORT@/other/location;jsessionid=12345?name=value"},
|
||||
{"./location;jsessionid=12345?name=value","http://@HOST@@PORT@/path/location;jsessionid=12345?name=value"},
|
||||
|
||||
// From cookie
|
||||
{"/other/location","http://myhost:8888/other/location"},
|
||||
{"/other/l%20cation", "http://myhost:8888/other/l%20cation"},
|
||||
{"location", "http://myhost:8888/path/location"},
|
||||
{"./location", "http://myhost:8888/path/location"},
|
||||
{"../location", "http://myhost:8888/location"},
|
||||
{"/other/l%20cation", "http://myhost:8888/other/l%20cation"},
|
||||
{"l%20cation", "http://myhost:8888/path/l%20cation"},
|
||||
{"./l%20cation", "http://myhost:8888/path/l%20cation"},
|
||||
{"../l%20cation","http://myhost:8888/l%20cation"},
|
||||
{"../locati%C3%abn", "http://myhost:8888/locati%C3%ABn"},
|
||||
{"/other/location","http://@HOST@@PORT@/other/location"},
|
||||
{"/other/l%20cation", "http://@HOST@@PORT@/other/l%20cation"},
|
||||
{"location", "http://@HOST@@PORT@/path/location"},
|
||||
{"./location", "http://@HOST@@PORT@/path/location"},
|
||||
{"../location", "http://@HOST@@PORT@/location"},
|
||||
{"/other/l%20cation", "http://@HOST@@PORT@/other/l%20cation"},
|
||||
{"l%20cation", "http://@HOST@@PORT@/path/l%20cation"},
|
||||
{"./l%20cation", "http://@HOST@@PORT@/path/l%20cation"},
|
||||
{"../l%20cation","http://@HOST@@PORT@/l%20cation"},
|
||||
{"../locati%C3%abn", "http://@HOST@@PORT@/locati%C3%ABn"},
|
||||
{"http://somehost.com/other/location","http://somehost.com/other/location"},
|
||||
};
|
||||
|
||||
for (int i=0;i<tests.length;i++)
|
||||
int[] ports=new int[]{8080,80};
|
||||
String[] hosts=new String[]{"myhost","192.168.0.1","0::1"};
|
||||
for (int port : ports)
|
||||
{
|
||||
Response response = newResponse();
|
||||
Request request = response.getHttpChannel().getRequest();
|
||||
for (String host : hosts)
|
||||
{
|
||||
for (int i=0;i<tests.length;i++)
|
||||
{
|
||||
Response response = newResponse();
|
||||
Request request = response.getHttpChannel().getRequest();
|
||||
|
||||
request.setServerName("myhost");
|
||||
request.setServerPort(8888);
|
||||
request.setUri(new HttpURI("/path/info;param;jsessionid=12345?query=0&more=1#target"));
|
||||
request.setContextPath("/path");
|
||||
request.setRequestedSessionId("12345");
|
||||
request.setRequestedSessionIdFromCookie(i>2);
|
||||
HashSessionManager manager = new HashSessionManager();
|
||||
manager.setSessionIdManager(new HashSessionIdManager());
|
||||
request.setSessionManager(manager);
|
||||
request.setSession(new TestSession(manager, "12345"));
|
||||
manager.setCheckingRemoteSessionIdEncoding(false);
|
||||
request.setServerName(host);
|
||||
request.setServerPort(port);
|
||||
request.setUri(new HttpURI("/path/info;param;jsessionid=12345?query=0&more=1#target"));
|
||||
request.setContextPath("/path");
|
||||
request.setRequestedSessionId("12345");
|
||||
request.setRequestedSessionIdFromCookie(i>2);
|
||||
HashSessionManager manager = new HashSessionManager();
|
||||
manager.setSessionIdManager(new HashSessionIdManager());
|
||||
request.setSessionManager(manager);
|
||||
request.setSession(new TestSession(manager, "12345"));
|
||||
manager.setCheckingRemoteSessionIdEncoding(false);
|
||||
|
||||
response.sendRedirect(tests[i][0]);
|
||||
response.sendRedirect(tests[i][0]);
|
||||
|
||||
String location = response.getHeader("Location");
|
||||
assertEquals("test-"+i,tests[i][1],location);
|
||||
String location = response.getHeader("Location");
|
||||
|
||||
String expected=tests[i][1].replace("@HOST@",host.contains(":")?("["+host+"]"):host).replace("@PORT@",port==80?"":(":"+port));
|
||||
assertEquals("test-"+i+" "+host+":"+port,expected,location);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -122,46 +122,46 @@ public class StressTest
|
|||
q.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMinNonPersistent() throws Throwable
|
||||
{
|
||||
assumeTrue(!OS.IS_OSX);
|
||||
doThreads(10,10,false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Stress("Hey, its called StressTest for a reason")
|
||||
public void testMinNonPersistent() throws Throwable
|
||||
{
|
||||
doThreads(2,2,false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonPersistent() throws Throwable
|
||||
{
|
||||
// TODO needs to be further investigated
|
||||
assumeTrue(!OS.IS_OSX || PropertyFlag.isEnabled("test.stress"));
|
||||
assumeTrue(!OS.IS_OSX);
|
||||
|
||||
doThreads(10,10,false);
|
||||
if (PropertyFlag.isEnabled("test.stress"))
|
||||
{
|
||||
doThreads(20,20,false);
|
||||
Thread.sleep(1000);
|
||||
doThreads(200,10,false);
|
||||
Thread.sleep(1000);
|
||||
doThreads(200,200,false);
|
||||
}
|
||||
doThreads(20,20,false);
|
||||
Thread.sleep(1000);
|
||||
doThreads(200,10,false);
|
||||
Thread.sleep(1000);
|
||||
doThreads(200,200,false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMinPersistent() throws Throwable
|
||||
{
|
||||
// TODO needs to be further investigated
|
||||
assumeTrue(!OS.IS_OSX);
|
||||
doThreads(10,10,true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Stress("Hey, its called StressTest for a reason")
|
||||
public void testPersistent() throws Throwable
|
||||
{
|
||||
// TODO needs to be further investigated
|
||||
assumeTrue(!OS.IS_OSX || PropertyFlag.isEnabled("test.stress"));
|
||||
|
||||
doThreads(10,10,true);
|
||||
if (PropertyFlag.isEnabled("test.stress"))
|
||||
{
|
||||
doThreads(40,40,true);
|
||||
Thread.sleep(1000);
|
||||
doThreads(200,10,true);
|
||||
Thread.sleep(1000);
|
||||
doThreads(200,200,true);
|
||||
}
|
||||
assumeTrue(!OS.IS_OSX);
|
||||
doThreads(40,40,true);
|
||||
Thread.sleep(1000);
|
||||
doThreads(200,10,true);
|
||||
Thread.sleep(1000);
|
||||
doThreads(200,200,true);
|
||||
}
|
||||
|
||||
private void doThreads(int threadCount, final int loops, final boolean persistent) throws Throwable
|
||||
|
@ -238,7 +238,6 @@ public class StressTest
|
|||
{
|
||||
System.err.println("STALLED!!!");
|
||||
System.err.println(_server.getThreadPool().toString());
|
||||
((ServerConnector)(_server.getConnectors()[0])).dump();
|
||||
Thread.sleep(5000);
|
||||
System.exit(1);
|
||||
}
|
||||
|
|
|
@ -18,19 +18,11 @@
|
|||
|
||||
package org.eclipse.jetty.server.handler;
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.AsyncEvent;
|
||||
import javax.servlet.AsyncListener;
|
||||
|
@ -46,6 +38,12 @@ import org.junit.After;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class StatisticsHandlerTest
|
||||
{
|
||||
private Server _server;
|
||||
|
@ -60,7 +58,7 @@ public class StatisticsHandlerTest
|
|||
_server = new Server();
|
||||
|
||||
_connector = new LocalConnector(_server);
|
||||
_statistics=new ConnectorStatistics();
|
||||
_statistics = new ConnectorStatistics();
|
||||
_connector.addBean(_statistics);
|
||||
_server.addConnector(_connector);
|
||||
|
||||
|
@ -105,8 +103,8 @@ public class StatisticsHandlerTest
|
|||
_server.start();
|
||||
|
||||
String request = "GET / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"\r\n";
|
||||
"Host: localhost\r\n" +
|
||||
"\r\n";
|
||||
_connector.executeRequest(request);
|
||||
|
||||
barrier[0].await();
|
||||
|
@ -174,8 +172,8 @@ public class StatisticsHandlerTest
|
|||
assertEquals(2, _statsHandler.getResponses2xx());
|
||||
|
||||
_latchHandler.reset(2);
|
||||
barrier[0]=new CyclicBarrier(3);
|
||||
barrier[1]=new CyclicBarrier(3);
|
||||
barrier[0] = new CyclicBarrier(3);
|
||||
barrier[1] = new CyclicBarrier(3);
|
||||
|
||||
_connector.executeRequest(request);
|
||||
_connector.executeRequest(request);
|
||||
|
@ -208,37 +206,33 @@ public class StatisticsHandlerTest
|
|||
assertEquals(0, _statsHandler.getAsyncDispatches());
|
||||
assertEquals(0, _statsHandler.getExpires());
|
||||
assertEquals(4, _statsHandler.getResponses2xx());
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuspendResume() throws Exception
|
||||
{
|
||||
final long dispatchTime = 10;
|
||||
final long requestTime = 50;
|
||||
final AtomicReference<AsyncContext> asyncHolder = new AtomicReference<>();
|
||||
final CyclicBarrier barrier[] = { new CyclicBarrier(2), new CyclicBarrier(2), new CyclicBarrier(2)};
|
||||
final CyclicBarrier barrier[] = {new CyclicBarrier(2), new CyclicBarrier(2), new CyclicBarrier(2)};
|
||||
_statsHandler.setHandler(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException
|
||||
{
|
||||
request.setHandled(true);
|
||||
|
||||
try
|
||||
{
|
||||
barrier[0].await();
|
||||
|
||||
Thread.sleep(10);
|
||||
|
||||
Thread.sleep(dispatchTime);
|
||||
|
||||
if (asyncHolder.get() == null)
|
||||
{
|
||||
asyncHolder.set(request.startAsync());
|
||||
}
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
Thread.currentThread().interrupt();
|
||||
throw (IOException)new IOException().initCause(x);
|
||||
throw new ServletException(x);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -246,50 +240,41 @@ public class StatisticsHandlerTest
|
|||
{
|
||||
barrier[1].await();
|
||||
}
|
||||
catch (Exception x)
|
||||
catch (Exception ignored)
|
||||
{
|
||||
x.printStackTrace();
|
||||
Thread.currentThread().interrupt();
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
_server.start();
|
||||
|
||||
String request = "GET / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"\r\n";
|
||||
"Host: localhost\r\n" +
|
||||
"\r\n";
|
||||
_connector.executeRequest(request);
|
||||
|
||||
|
||||
barrier[0].await();
|
||||
|
||||
assertEquals(1, _statistics.getConnectionsOpen());
|
||||
|
||||
assertEquals(1, _statsHandler.getRequests());
|
||||
assertEquals(1, _statsHandler.getRequestsActive());
|
||||
assertEquals(1, _statsHandler.getDispatched());
|
||||
assertEquals(1, _statsHandler.getDispatchedActive());
|
||||
|
||||
barrier[1].await();
|
||||
|
||||
assertTrue(_latchHandler.await());
|
||||
assertNotNull(asyncHolder.get());
|
||||
assertTrue(asyncHolder.get()!=null);
|
||||
|
||||
assertEquals(1, _statsHandler.getRequests());
|
||||
assertEquals(1, _statsHandler.getRequestsActive());
|
||||
assertEquals(1, _statsHandler.getDispatched());
|
||||
assertEquals(0, _statsHandler.getDispatchedActive());
|
||||
|
||||
Thread.sleep(10);
|
||||
_latchHandler.reset();
|
||||
barrier[0].reset();
|
||||
barrier[1].reset();
|
||||
|
||||
Thread.sleep(50);
|
||||
Thread.sleep(requestTime);
|
||||
|
||||
asyncHolder.get().addListener(new AsyncListener()
|
||||
{
|
||||
|
@ -297,30 +282,34 @@ public class StatisticsHandlerTest
|
|||
public void onTimeout(AsyncEvent event) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onStartAsync(AsyncEvent event) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onError(AsyncEvent event) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onComplete(AsyncEvent event) throws IOException
|
||||
{
|
||||
try { barrier[2].await(); } catch(Exception e) {}
|
||||
try
|
||||
{
|
||||
barrier[2].await();
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
asyncHolder.get().dispatch();
|
||||
|
||||
barrier[0].await(); // entered app handler
|
||||
|
||||
assertEquals(1, _statistics.getConnectionsOpen());
|
||||
|
||||
assertEquals(1, _statsHandler.getRequests());
|
||||
assertEquals(1, _statsHandler.getRequestsActive());
|
||||
assertEquals(2, _statsHandler.getDispatched());
|
||||
|
@ -335,50 +324,49 @@ public class StatisticsHandlerTest
|
|||
assertEquals(2, _statsHandler.getDispatched());
|
||||
assertEquals(0, _statsHandler.getDispatchedActive());
|
||||
|
||||
|
||||
assertEquals(1, _statsHandler.getAsyncRequests());
|
||||
assertEquals(1, _statsHandler.getAsyncDispatches());
|
||||
assertEquals(0, _statsHandler.getExpires());
|
||||
assertEquals(1, _statsHandler.getResponses2xx());
|
||||
|
||||
assertThat(_statsHandler.getRequestTimeTotal(), greaterThanOrEqualTo(requestTime * 3 / 4));
|
||||
assertEquals(_statsHandler.getRequestTimeTotal(), _statsHandler.getRequestTimeMax());
|
||||
assertEquals(_statsHandler.getRequestTimeTotal(), _statsHandler.getRequestTimeMean(), 0.01);
|
||||
|
||||
assertThat(_statsHandler.getRequestTimeTotal(),greaterThanOrEqualTo(50L));
|
||||
assertEquals(_statsHandler.getRequestTimeTotal(),_statsHandler.getRequestTimeMax());
|
||||
assertEquals(_statsHandler.getRequestTimeTotal(),_statsHandler.getRequestTimeMean(), 0.01);
|
||||
|
||||
assertTrue(_statsHandler.getDispatchedTimeTotal()>=20);
|
||||
assertTrue(_statsHandler.getDispatchedTimeMean()+10<=_statsHandler.getDispatchedTimeTotal());
|
||||
assertTrue(_statsHandler.getDispatchedTimeMax()+10<=_statsHandler.getDispatchedTimeTotal());
|
||||
|
||||
assertThat(_statsHandler.getDispatchedTimeTotal(), greaterThanOrEqualTo(dispatchTime * 2 * 3 / 4));
|
||||
assertTrue(_statsHandler.getDispatchedTimeMean() + dispatchTime <= _statsHandler.getDispatchedTimeTotal());
|
||||
assertTrue(_statsHandler.getDispatchedTimeMax() + dispatchTime <= _statsHandler.getDispatchedTimeTotal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuspendExpire() throws Exception
|
||||
{
|
||||
final long dispatchTime = 10;
|
||||
final long timeout = 100;
|
||||
final AtomicReference<AsyncContext> asyncHolder = new AtomicReference<>();
|
||||
final CyclicBarrier barrier[] = { new CyclicBarrier(2), new CyclicBarrier(2), new CyclicBarrier(2)};
|
||||
final CyclicBarrier barrier[] = {new CyclicBarrier(2), new CyclicBarrier(2), new CyclicBarrier(2)};
|
||||
_statsHandler.setHandler(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException
|
||||
{
|
||||
request.setHandled(true);
|
||||
|
||||
try
|
||||
{
|
||||
barrier[0].await();
|
||||
Thread.sleep(10);
|
||||
|
||||
Thread.sleep(dispatchTime);
|
||||
|
||||
if (asyncHolder.get() == null)
|
||||
{
|
||||
AsyncContext async=request.startAsync();
|
||||
async.setTimeout(100);
|
||||
AsyncContext async = request.startAsync();
|
||||
asyncHolder.set(async);
|
||||
async.setTimeout(timeout);
|
||||
}
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
Thread.currentThread().interrupt();
|
||||
throw (IOException)new IOException().initCause(x);
|
||||
throw new ServletException(x);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -386,28 +374,22 @@ public class StatisticsHandlerTest
|
|||
{
|
||||
barrier[1].await();
|
||||
}
|
||||
catch (Exception x)
|
||||
catch (Exception ignored)
|
||||
{
|
||||
x.printStackTrace();
|
||||
Thread.currentThread().interrupt();
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
_server.start();
|
||||
|
||||
String request = "GET / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"\r\n";
|
||||
"Host: localhost\r\n" +
|
||||
"\r\n";
|
||||
_connector.executeRequest(request);
|
||||
|
||||
|
||||
barrier[0].await();
|
||||
|
||||
assertEquals(1, _statistics.getConnectionsOpen());
|
||||
|
||||
assertEquals(1, _statsHandler.getRequests());
|
||||
assertEquals(1, _statsHandler.getRequestsActive());
|
||||
assertEquals(1, _statsHandler.getDispatched());
|
||||
|
@ -423,31 +405,35 @@ public class StatisticsHandlerTest
|
|||
{
|
||||
event.getAsyncContext().complete();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onStartAsync(AsyncEvent event) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onError(AsyncEvent event) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onComplete(AsyncEvent event) throws IOException
|
||||
{
|
||||
try { barrier[2].await(); } catch(Exception e) {}
|
||||
try
|
||||
{
|
||||
barrier[2].await();
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
assertEquals(1, _statsHandler.getRequests());
|
||||
assertEquals(1, _statsHandler.getRequestsActive());
|
||||
assertEquals(1, _statsHandler.getDispatched());
|
||||
assertEquals(0, _statsHandler.getDispatchedActive());
|
||||
|
||||
|
||||
barrier[2].await();
|
||||
|
||||
assertEquals(1, _statsHandler.getRequests());
|
||||
|
@ -460,67 +446,42 @@ public class StatisticsHandlerTest
|
|||
assertEquals(1, _statsHandler.getExpires());
|
||||
assertEquals(1, _statsHandler.getResponses2xx());
|
||||
|
||||
assertTrue(_statsHandler.getRequestTimeTotal() >= (timeout + dispatchTime) * 3 / 4);
|
||||
assertEquals(_statsHandler.getRequestTimeTotal(), _statsHandler.getRequestTimeMax());
|
||||
assertEquals(_statsHandler.getRequestTimeTotal(), _statsHandler.getRequestTimeMean(), 0.01);
|
||||
|
||||
assertTrue(_statsHandler.getRequestTimeTotal()>=30);
|
||||
assertEquals(_statsHandler.getRequestTimeTotal(),_statsHandler.getRequestTimeMax());
|
||||
assertEquals(_statsHandler.getRequestTimeTotal(),_statsHandler.getRequestTimeMean(), 0.01);
|
||||
|
||||
assertThat(_statsHandler.getDispatchedTimeTotal(),greaterThanOrEqualTo(10L));
|
||||
|
||||
assertThat(_statsHandler.getDispatchedTimeTotal(), greaterThanOrEqualTo(dispatchTime * 3 / 4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuspendComplete() throws Exception
|
||||
{
|
||||
final long dispatchTime = 10;
|
||||
final AtomicReference<AsyncContext> asyncHolder = new AtomicReference<>();
|
||||
final CyclicBarrier barrier[] = { new CyclicBarrier(2), new CyclicBarrier(2), new CyclicBarrier(2)};
|
||||
final CyclicBarrier barrier[] = {new CyclicBarrier(2), new CyclicBarrier(2)};
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
_statsHandler.setHandler(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException
|
||||
{
|
||||
request.setHandled(true);
|
||||
|
||||
try
|
||||
{
|
||||
barrier[0].await();
|
||||
Thread.sleep(10);
|
||||
|
||||
Thread.sleep(dispatchTime);
|
||||
|
||||
if (asyncHolder.get() == null)
|
||||
{
|
||||
AsyncContext async=request.startAsync();
|
||||
async.setTimeout(1000);
|
||||
AsyncContext async = request.startAsync();
|
||||
asyncHolder.set(async);
|
||||
asyncHolder.get().addListener(new AsyncListener()
|
||||
{
|
||||
|
||||
@Override
|
||||
public void onTimeout(AsyncEvent event) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartAsync(AsyncEvent event) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(AsyncEvent event) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete(AsyncEvent event) throws IOException
|
||||
{
|
||||
try { barrier[2].await(); } catch(Exception e) {}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
Thread.currentThread().interrupt();
|
||||
throw (IOException)new IOException().initCause(x);
|
||||
throw new ServletException(x);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -528,11 +489,8 @@ public class StatisticsHandlerTest
|
|||
{
|
||||
barrier[1].await();
|
||||
}
|
||||
catch (Exception x)
|
||||
catch (Exception ignored)
|
||||
{
|
||||
x.printStackTrace();
|
||||
Thread.currentThread().interrupt();
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -541,21 +499,18 @@ public class StatisticsHandlerTest
|
|||
_server.start();
|
||||
|
||||
String request = "GET / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"\r\n";
|
||||
"Host: localhost\r\n" +
|
||||
"\r\n";
|
||||
_connector.executeRequest(request);
|
||||
|
||||
|
||||
barrier[0].await();
|
||||
|
||||
assertEquals(1, _statistics.getConnectionsOpen());
|
||||
|
||||
assertEquals(1, _statsHandler.getRequests());
|
||||
assertEquals(1, _statsHandler.getRequestsActive());
|
||||
assertEquals(1, _statsHandler.getDispatched());
|
||||
assertEquals(1, _statsHandler.getDispatchedActive());
|
||||
|
||||
|
||||
barrier[1].await();
|
||||
assertTrue(_latchHandler.await());
|
||||
assertNotNull(asyncHolder.get());
|
||||
|
@ -565,9 +520,39 @@ public class StatisticsHandlerTest
|
|||
assertEquals(1, _statsHandler.getDispatched());
|
||||
assertEquals(0, _statsHandler.getDispatchedActive());
|
||||
|
||||
Thread.sleep(10);
|
||||
asyncHolder.get().addListener(new AsyncListener()
|
||||
{
|
||||
@Override
|
||||
public void onTimeout(AsyncEvent event) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartAsync(AsyncEvent event) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(AsyncEvent event) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete(AsyncEvent event) throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
latch.countDown();
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
});
|
||||
long requestTime = 20;
|
||||
Thread.sleep(requestTime);
|
||||
asyncHolder.get().complete();
|
||||
barrier[2].await();
|
||||
latch.await();
|
||||
|
||||
assertEquals(1, _statsHandler.getRequests());
|
||||
assertEquals(0, _statsHandler.getRequestsActive());
|
||||
|
@ -579,17 +564,16 @@ public class StatisticsHandlerTest
|
|||
assertEquals(0, _statsHandler.getExpires());
|
||||
assertEquals(1, _statsHandler.getResponses2xx());
|
||||
|
||||
assertTrue(_statsHandler.getRequestTimeTotal()>=20);
|
||||
assertEquals(_statsHandler.getRequestTimeTotal(),_statsHandler.getRequestTimeMax());
|
||||
assertEquals(_statsHandler.getRequestTimeTotal(),_statsHandler.getRequestTimeMean(), 0.01);
|
||||
assertTrue(_statsHandler.getRequestTimeTotal() >= (dispatchTime + requestTime) * 3 / 4);
|
||||
assertEquals(_statsHandler.getRequestTimeTotal(), _statsHandler.getRequestTimeMax());
|
||||
assertEquals(_statsHandler.getRequestTimeTotal(), _statsHandler.getRequestTimeMean(), 0.01);
|
||||
|
||||
assertTrue(_statsHandler.getDispatchedTimeTotal()>=10);
|
||||
assertTrue(_statsHandler.getDispatchedTimeTotal()<_statsHandler.getRequestTimeTotal());
|
||||
assertEquals(_statsHandler.getDispatchedTimeTotal(),_statsHandler.getDispatchedTimeMax());
|
||||
assertEquals(_statsHandler.getDispatchedTimeTotal(),_statsHandler.getDispatchedTimeMean(), 0.01);
|
||||
assertTrue(_statsHandler.getDispatchedTimeTotal() >= dispatchTime * 3 / 4);
|
||||
assertTrue(_statsHandler.getDispatchedTimeTotal() < _statsHandler.getRequestTimeTotal());
|
||||
assertEquals(_statsHandler.getDispatchedTimeTotal(), _statsHandler.getDispatchedTimeMax());
|
||||
assertEquals(_statsHandler.getDispatchedTimeTotal(), _statsHandler.getDispatchedTimeMean(), 0.01);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This handler is external to the statistics handler and it is used to ensure that statistics handler's
|
||||
* handle() is fully executed before asserting its values in the tests, to avoid race conditions with the
|
||||
|
@ -602,7 +586,7 @@ public class StatisticsHandlerTest
|
|||
@Override
|
||||
public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException
|
||||
{
|
||||
final CountDownLatch latch=_latch;
|
||||
final CountDownLatch latch = _latch;
|
||||
try
|
||||
{
|
||||
super.handle(path, request, httpRequest, httpResponse);
|
||||
|
@ -615,12 +599,12 @@ public class StatisticsHandlerTest
|
|||
|
||||
private void reset()
|
||||
{
|
||||
_latch=new CountDownLatch(1);
|
||||
_latch = new CountDownLatch(1);
|
||||
}
|
||||
|
||||
private void reset(int count)
|
||||
{
|
||||
_latch=new CountDownLatch(count);
|
||||
_latch = new CountDownLatch(count);
|
||||
}
|
||||
|
||||
private boolean await() throws InterruptedException
|
||||
|
|
|
@ -125,7 +125,6 @@ public class SSLEngineTest
|
|||
{
|
||||
server.setHandler(new HelloWorldHandler());
|
||||
server.start();
|
||||
server.dumpStdErr();
|
||||
|
||||
SSLContext ctx=SSLContext.getInstance("TLS");
|
||||
ctx.init(null,SslContextFactory.TRUST_ALL_CERTS,new java.security.SecureRandom());
|
||||
|
|
|
@ -27,7 +27,6 @@ import java.net.URL;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletContext;
|
||||
|
@ -42,9 +41,8 @@ import org.eclipse.jetty.http.HttpFields;
|
|||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.http.PathMap.MappedEntry;
|
||||
import org.eclipse.jetty.io.WriterOutputStream;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.HttpChannel;
|
||||
import org.eclipse.jetty.server.HttpOutput;
|
||||
import org.eclipse.jetty.server.InclusiveByteRange;
|
||||
import org.eclipse.jetty.server.ResourceCache;
|
||||
|
@ -160,7 +158,6 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
private ServletHandler _servletHandler;
|
||||
private ServletHolder _defaultHolder;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void init()
|
||||
|
@ -268,7 +265,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
throw new UnavailableException(e.toString());
|
||||
}
|
||||
|
||||
_servletHandler= (ServletHandler) _contextHandler.getChildHandlerByClass(ServletHandler.class);
|
||||
_servletHandler= _contextHandler.getChildHandlerByClass(ServletHandler.class);
|
||||
for (ServletHolder h :_servletHandler.getServlets())
|
||||
if (h.getServletInstance()==this)
|
||||
_defaultHolder=h;
|
||||
|
@ -343,6 +340,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
* @param pathInContext The path to find a resource for.
|
||||
* @return The resource to serve.
|
||||
*/
|
||||
@Override
|
||||
public Resource getResource(String pathInContext)
|
||||
{
|
||||
Resource r=null;
|
||||
|
@ -632,7 +630,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
|
||||
if ((_welcomeServlets || _welcomeExactServlets) && welcome_servlet==null)
|
||||
{
|
||||
Map.Entry entry=_servletHandler.getHolderEntry(welcome_in_context);
|
||||
MappedEntry<?> entry=_servletHandler.getHolderEntry(welcome_in_context);
|
||||
if (entry!=null && entry.getValue()!=_defaultHolder &&
|
||||
(_welcomeServlets || (_welcomeExactServlets && entry.getKey().equals(welcome_in_context))))
|
||||
welcome_servlet=welcome_in_context;
|
||||
|
@ -828,24 +826,10 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
boolean include,
|
||||
Resource resource,
|
||||
HttpContent content,
|
||||
Enumeration reqRanges)
|
||||
Enumeration<String> reqRanges)
|
||||
throws IOException
|
||||
{
|
||||
boolean direct;
|
||||
long content_length;
|
||||
if (content==null)
|
||||
{
|
||||
direct=false;
|
||||
content_length=resource.length();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO sometimes we should be direct!
|
||||
Connector connector = HttpChannel.getCurrentHttpChannel().getConnector();
|
||||
direct=false;
|
||||
content_length=content.getContentLength();
|
||||
}
|
||||
|
||||
final long content_length = (content==null)?resource.length():content.getContentLength();
|
||||
|
||||
// Get the output stream (or writer)
|
||||
OutputStream out =null;
|
||||
|
@ -884,17 +868,8 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
}
|
||||
else
|
||||
{
|
||||
ByteBuffer buffer = direct?content.getDirectBuffer():content.getIndirectBuffer();
|
||||
if (buffer!=null)
|
||||
{
|
||||
writeHeaders(response,content,content_length);
|
||||
((HttpOutput)out).sendContent(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeHeaders(response,content,content_length);
|
||||
resource.writeTo(out,0,content_length);
|
||||
}
|
||||
writeHeaders(response,content,content_length);
|
||||
((HttpOutput)out).sendContent(content.getResource());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -914,7 +889,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
else
|
||||
{
|
||||
// Parse the satisfiable ranges
|
||||
List ranges =InclusiveByteRange.satisfiableRanges(reqRanges,content_length);
|
||||
List<InclusiveByteRange> ranges =InclusiveByteRange.satisfiableRanges(reqRanges,content_length);
|
||||
|
||||
// if there are no satisfiable ranges, send 416 response
|
||||
if (ranges==null || ranges.size()==0)
|
||||
|
@ -931,8 +906,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
// since were here now), send that range with a 216 response
|
||||
if ( ranges.size()== 1)
|
||||
{
|
||||
InclusiveByteRange singleSatisfiableRange =
|
||||
(InclusiveByteRange)ranges.get(0);
|
||||
InclusiveByteRange singleSatisfiableRange = ranges.get(0);
|
||||
long singleLength = singleSatisfiableRange.getSize(content_length);
|
||||
writeHeaders(response,content,singleLength );
|
||||
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
|
||||
|
@ -947,7 +921,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
// content-length header
|
||||
//
|
||||
writeHeaders(response,content,-1);
|
||||
String mimetype=(content.getContentType()==null?null:content.getContentType().toString());
|
||||
String mimetype=(content==null||content.getContentType()==null?null:content.getContentType().toString());
|
||||
if (mimetype==null)
|
||||
LOG.warn("Unknown mimetype for "+request.getRequestURI());
|
||||
MultiPartOutputStream multi = new MultiPartOutputStream(out);
|
||||
|
@ -971,7 +945,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
String[] header = new String[ranges.size()];
|
||||
for (int i=0;i<ranges.size();i++)
|
||||
{
|
||||
InclusiveByteRange ibr = (InclusiveByteRange) ranges.get(i);
|
||||
InclusiveByteRange ibr = ranges.get(i);
|
||||
header[i]=ibr.toHeaderRangeString(content_length);
|
||||
length+=
|
||||
((i>0)?2:0)+
|
||||
|
@ -986,7 +960,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
|
||||
for (int i=0;i<ranges.size();i++)
|
||||
{
|
||||
InclusiveByteRange ibr = (InclusiveByteRange) ranges.get(i);
|
||||
InclusiveByteRange ibr = ranges.get(i);
|
||||
multi.startPart(mimetype,new String[]{HttpHeader.CONTENT_RANGE+": "+header[i]});
|
||||
|
||||
long start=ibr.getFirst(content_length);
|
||||
|
@ -1023,7 +997,6 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void writeHeaders(HttpServletResponse response,HttpContent content,long count)
|
||||
throws IOException
|
||||
{
|
||||
if (content.getContentType()!=null && response.getContentType()==null)
|
||||
response.setContentType(content.getContentType().toString());
|
||||
|
|
|
@ -24,6 +24,7 @@ import javax.servlet.GenericServlet;
|
|||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.eclipse.jetty.server.Dispatcher;
|
||||
import org.eclipse.jetty.server.HttpConnection;
|
||||
|
@ -96,7 +97,11 @@ public class JspPropertyGroupServlet extends GenericServlet
|
|||
@Override
|
||||
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
|
||||
{
|
||||
Request request=(req instanceof Request)?(Request)req:HttpConnection.getCurrentConnection().getHttpChannel().getRequest();
|
||||
HttpServletRequest request = null;
|
||||
if (req instanceof HttpServletRequest)
|
||||
request = (HttpServletRequest)req;
|
||||
else
|
||||
throw new ServletException("Request not HttpServletRequest");
|
||||
|
||||
String servletPath=null;
|
||||
String pathInfo=null;
|
||||
|
|
|
@ -113,10 +113,10 @@ public class ServletHandler extends ScopedHandler
|
|||
private MultiMap<FilterMapping> _filterNameMappings;
|
||||
|
||||
private final Map<String,ServletHolder> _servletNameMap=new HashMap<>();
|
||||
private PathMap _servletPathMap;
|
||||
private PathMap<ServletHolder> _servletPathMap;
|
||||
|
||||
protected final ConcurrentMap _chainCache[] = new ConcurrentMap[FilterMapping.ALL];
|
||||
protected final Queue[] _chainLRU = new Queue[FilterMapping.ALL];
|
||||
protected final ConcurrentMap<?, ?> _chainCache[] = new ConcurrentMap[FilterMapping.ALL];
|
||||
protected final Queue<?>[] _chainLRU = new Queue[FilterMapping.ALL];
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -208,6 +208,9 @@ public class ServletHandler extends ScopedHandler
|
|||
_filterNameMappings=null;
|
||||
|
||||
_servletPathMap=null;
|
||||
|
||||
_matchBeforeIndex=-1;
|
||||
_matchAfterIndex=-1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -250,7 +253,7 @@ public class ServletHandler extends ScopedHandler
|
|||
* @param pathInContext Path within _context.
|
||||
* @return PathMap Entries pathspec to ServletHolder
|
||||
*/
|
||||
public PathMap.MappedEntry getHolderEntry(String pathInContext)
|
||||
public PathMap.MappedEntry<ServletHolder> getHolderEntry(String pathInContext)
|
||||
{
|
||||
if (_servletPathMap==null)
|
||||
return null;
|
||||
|
@ -331,10 +334,10 @@ public class ServletHandler extends ScopedHandler
|
|||
if (target.startsWith("/"))
|
||||
{
|
||||
// Look for the servlet by path
|
||||
PathMap.MappedEntry entry=getHolderEntry(target);
|
||||
PathMap.MappedEntry<ServletHolder> entry=getHolderEntry(target);
|
||||
if (entry!=null)
|
||||
{
|
||||
servlet_holder=(ServletHolder)entry.getValue();
|
||||
servlet_holder=entry.getValue();
|
||||
|
||||
String servlet_path_spec= entry.getKey();
|
||||
String servlet_path=entry.getMapped()!=null?entry.getMapped():PathMap.pathMatch(servlet_path_spec,target);
|
||||
|
@ -342,8 +345,8 @@ public class ServletHandler extends ScopedHandler
|
|||
|
||||
if (DispatcherType.INCLUDE.equals(type))
|
||||
{
|
||||
baseRequest.setAttribute(Dispatcher.INCLUDE_SERVLET_PATH,servlet_path);
|
||||
baseRequest.setAttribute(Dispatcher.INCLUDE_PATH_INFO, path_info);
|
||||
baseRequest.setAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH,servlet_path);
|
||||
baseRequest.setAttribute(RequestDispatcher.INCLUDE_PATH_INFO, path_info);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -615,8 +618,8 @@ public class ServletHandler extends ScopedHandler
|
|||
if (filters.size() > 0)
|
||||
chain= new CachedChain(filters, servletHolder);
|
||||
|
||||
final Map<String,FilterChain> cache=_chainCache[dispatch];
|
||||
final Queue<String> lru=_chainLRU[dispatch];
|
||||
final Map<String,FilterChain> cache=(Map<String, FilterChain>)_chainCache[dispatch];
|
||||
final Queue<String> lru=(Queue<String>)_chainLRU[dispatch];
|
||||
|
||||
// Do we have too many cached chains?
|
||||
while (_maxFilterChainsCacheSize>0 && cache.size()>=_maxFilterChainsCacheSize)
|
||||
|
@ -718,7 +721,7 @@ public class ServletHandler extends ScopedHandler
|
|||
{
|
||||
if (servlet.getClassName() == null && servlet.getForcedPath() != null)
|
||||
{
|
||||
ServletHolder forced_holder = (ServletHolder)_servletPathMap.match(servlet.getForcedPath());
|
||||
ServletHolder forced_holder = _servletPathMap.match(servlet.getForcedPath());
|
||||
if (forced_holder == null || forced_holder.getClassName() == null)
|
||||
{
|
||||
mx.add(new IllegalStateException("No forced path servlet for " + servlet.getForcedPath()));
|
||||
|
@ -1053,7 +1056,7 @@ public class ServletHandler extends ScopedHandler
|
|||
public void addFilterMapping (FilterMapping mapping)
|
||||
{
|
||||
if (mapping != null)
|
||||
{
|
||||
{
|
||||
Source source = (mapping.getFilterHolder()==null?null:mapping.getFilterHolder().getSource());
|
||||
FilterMapping[] mappings =getFilterMappings();
|
||||
if (mappings==null || mappings.length==0)
|
||||
|
|
|
@ -385,8 +385,8 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
|
|||
if (o==null)
|
||||
return;
|
||||
Servlet servlet = ((Servlet)o);
|
||||
servlet.destroy();
|
||||
getServletHandler().destroyServlet(servlet);
|
||||
servlet.destroy();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -103,6 +103,7 @@ public class AsyncContextTest
|
|||
Assert.assertEquals("servlet gets right path", "doGet:getServletPath:/servletPath", br.readLine());
|
||||
Assert.assertEquals("async context gets right path in get","doGet:async:getServletPath:/servletPath",br.readLine());
|
||||
Assert.assertEquals("async context gets right path in async","async:run:attr:servletPath:/servletPath",br.readLine());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -121,6 +122,16 @@ public class AsyncContextTest
|
|||
Assert.assertEquals("query string attr is correct","async:run:attr:queryString:dispatch=true",br.readLine());
|
||||
Assert.assertEquals("context path attr is correct","async:run:attr:contextPath:",br.readLine());
|
||||
Assert.assertEquals("request uri attr is correct","async:run:attr:requestURI:/servletPath",br.readLine());
|
||||
|
||||
try
|
||||
{
|
||||
__asyncContext.getRequest();
|
||||
Assert.fail();
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -193,8 +204,11 @@ public class AsyncContextTest
|
|||
@Test
|
||||
public void testDispatchRequestResponse() throws Exception
|
||||
{
|
||||
String request = "GET /forward?dispatchRequestResponse=true HTTP/1.1\r\n" + "Host: localhost\r\n"
|
||||
+ "Content-Type: application/x-www-form-urlencoded\r\n" + "Connection: close\r\n" + "\r\n";
|
||||
String request = "GET /forward?dispatchRequestResponse=true HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n";
|
||||
|
||||
String responseString = _connector.getResponses(request);
|
||||
|
||||
|
@ -233,10 +247,12 @@ public class AsyncContextTest
|
|||
}
|
||||
}
|
||||
|
||||
public static volatile AsyncContext __asyncContext;
|
||||
|
||||
private class AsyncDispatchingServlet extends HttpServlet
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, final HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
|
@ -253,13 +269,14 @@ public class AsyncContextTest
|
|||
{
|
||||
wrapped = true;
|
||||
asyncContext = request.startAsync(request, new Wrapper(response));
|
||||
__asyncContext=asyncContext;
|
||||
}
|
||||
else
|
||||
{
|
||||
asyncContext = request.startAsync();
|
||||
__asyncContext=asyncContext;
|
||||
}
|
||||
|
||||
|
||||
new Thread(new DispatchingRunnable(asyncContext, wrapped)).start();
|
||||
}
|
||||
}
|
||||
|
@ -301,12 +318,14 @@ public class AsyncContextTest
|
|||
if (request.getParameter("dispatch") != null)
|
||||
{
|
||||
AsyncContext asyncContext = request.startAsync(request,response);
|
||||
__asyncContext=asyncContext;
|
||||
asyncContext.dispatch("/servletPath2");
|
||||
}
|
||||
else
|
||||
{
|
||||
response.getOutputStream().print("doGet:getServletPath:" + request.getServletPath() + "\n");
|
||||
AsyncContext asyncContext = request.startAsync(request,response);
|
||||
__asyncContext=asyncContext;
|
||||
response.getOutputStream().print("doGet:async:getServletPath:" + ((HttpServletRequest)asyncContext.getRequest()).getServletPath() + "\n");
|
||||
asyncContext.start(new AsyncRunnable(asyncContext));
|
||||
|
||||
|
@ -323,6 +342,7 @@ public class AsyncContextTest
|
|||
{
|
||||
response.getOutputStream().print("doGet:getServletPath:" + request.getServletPath() + "\n");
|
||||
AsyncContext asyncContext = request.startAsync(request, response);
|
||||
__asyncContext=asyncContext;
|
||||
response.getOutputStream().print("doGet:async:getServletPath:" + ((HttpServletRequest)asyncContext.getRequest()).getServletPath() + "\n");
|
||||
asyncContext.start(new AsyncRunnable(asyncContext));
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
package org.eclipse.jetty.servlet;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -345,6 +344,45 @@ public class AsyncServletTest
|
|||
Assert.assertThat(response,Matchers.not(Matchers.containsString(content)));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAsyncRead() throws Exception
|
||||
{
|
||||
String header="GET /ctx/path/info?suspend=2000&resume=1500 HTTP/1.1\r\n"+
|
||||
"Host: localhost\r\n"+
|
||||
"Content-Length: 10\r\n"+
|
||||
"\r\n";
|
||||
String body="12345678\r\n";
|
||||
String close="GET /ctx/path/info HTTP/1.1\r\n"+
|
||||
"Host: localhost\r\n"+
|
||||
"Connection: close\r\n"+
|
||||
"\r\n";
|
||||
|
||||
try (Socket socket = new Socket("localhost",_port);)
|
||||
{
|
||||
socket.setSoTimeout(10000);
|
||||
socket.getOutputStream().write(header.getBytes("ISO-8859-1"));
|
||||
Thread.sleep(500);
|
||||
socket.getOutputStream().write(body.getBytes("ISO-8859-1"),0,2);
|
||||
Thread.sleep(500);
|
||||
socket.getOutputStream().write(body.getBytes("ISO-8859-1"),2,8);
|
||||
socket.getOutputStream().write(close.getBytes("ISO-8859-1"));
|
||||
|
||||
String response = IO.toString(socket.getInputStream());
|
||||
assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
|
||||
assertContains(
|
||||
"history: REQUEST\r\n"+
|
||||
"history: initial\r\n"+
|
||||
"history: suspend\r\n"+
|
||||
"history: async-read=10\r\n"+
|
||||
"history: resume\r\n"+
|
||||
"history: ASYNC\r\n"+
|
||||
"history: !initial\r\n"+
|
||||
"history: onComplete\r\n",response);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public synchronized String process(String query,String content) throws Exception
|
||||
{
|
||||
String request = "GET /ctx/path/info";
|
||||
|
@ -364,9 +402,8 @@ public class AsyncServletTest
|
|||
|
||||
int port=_port;
|
||||
String response=null;
|
||||
try
|
||||
try (Socket socket = new Socket("localhost",port);)
|
||||
{
|
||||
Socket socket = new Socket("localhost",port);
|
||||
socket.setSoTimeout(1000000);
|
||||
socket.getOutputStream().write(request.getBytes("UTF-8"));
|
||||
|
||||
|
@ -379,11 +416,10 @@ public class AsyncServletTest
|
|||
throw e;
|
||||
}
|
||||
|
||||
// System.err.println(response);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static class AsyncServlet extends HttpServlet
|
||||
|
@ -429,7 +465,7 @@ public class AsyncServletTest
|
|||
|
||||
if (request.getDispatcherType()==DispatcherType.REQUEST)
|
||||
{
|
||||
((HttpServletResponse)response).addHeader("history","initial");
|
||||
response.addHeader("history","initial");
|
||||
if (read_before>0)
|
||||
{
|
||||
byte[] buf=new byte[read_before];
|
||||
|
@ -442,6 +478,30 @@ public class AsyncServletTest
|
|||
while(b!=-1)
|
||||
b=in.read();
|
||||
}
|
||||
else if (request.getContentLength()>0)
|
||||
{
|
||||
new Thread()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
int c=0;
|
||||
try
|
||||
{
|
||||
InputStream in=request.getInputStream();
|
||||
int b=0;
|
||||
while(b!=-1)
|
||||
if((b=in.read())>=0)
|
||||
c++;
|
||||
response.addHeader("history","async-read="+c);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
if (suspend_for>=0)
|
||||
{
|
||||
|
@ -449,7 +509,7 @@ public class AsyncServletTest
|
|||
if (suspend_for>0)
|
||||
async.setTimeout(suspend_for);
|
||||
async.addListener(__listener);
|
||||
((HttpServletResponse)response).addHeader("history","suspend");
|
||||
response.addHeader("history","suspend");
|
||||
|
||||
if (complete_after>0)
|
||||
{
|
||||
|
@ -527,7 +587,7 @@ public class AsyncServletTest
|
|||
}
|
||||
else
|
||||
{
|
||||
((HttpServletResponse)response).addHeader("history","!initial");
|
||||
response.addHeader("history","!initial");
|
||||
|
||||
if (suspend2_for>=0 && request.getAttribute("2nd")==null)
|
||||
{
|
||||
|
@ -540,7 +600,7 @@ public class AsyncServletTest
|
|||
async.setTimeout(suspend2_for);
|
||||
}
|
||||
// continuation.addContinuationListener(__listener);
|
||||
((HttpServletResponse)response).addHeader("history","suspend");
|
||||
response.addHeader("history","suspend");
|
||||
|
||||
if (complete2_after>0)
|
||||
{
|
||||
|
@ -581,7 +641,7 @@ public class AsyncServletTest
|
|||
@Override
|
||||
public void run()
|
||||
{
|
||||
((HttpServletResponse)response).addHeader("history","resume");
|
||||
response.addHeader("history","resume");
|
||||
async.dispatch();
|
||||
}
|
||||
};
|
||||
|
@ -592,7 +652,7 @@ public class AsyncServletTest
|
|||
}
|
||||
else if (resume2_after==0)
|
||||
{
|
||||
((HttpServletResponse)response).addHeader("history","dispatch");
|
||||
response.addHeader("history","dispatch");
|
||||
async.dispatch();
|
||||
}
|
||||
}
|
||||
|
@ -633,15 +693,11 @@ public class AsyncServletTest
|
|||
@Override
|
||||
public void onStartAsync(AsyncEvent event) throws IOException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(AsyncEvent event) throws IOException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -89,6 +89,18 @@
|
|||
<npn.version>1.1.5.v20130313</npn.version>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>7u21</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>java.version</name>
|
||||
<value>1.7.0_21</value>
|
||||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<npn.version>1.1.5.v20130313</npn.version>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<modules>
|
||||
|
|
|
@ -59,7 +59,9 @@ public interface IStream extends Stream, Callback
|
|||
*/
|
||||
public void setStreamFrameListener(StreamFrameListener listener);
|
||||
|
||||
//TODO: javadoc thomas
|
||||
/**
|
||||
* @return the stream frame listener associated to this stream
|
||||
*/
|
||||
public StreamFrameListener getStreamFrameListener();
|
||||
|
||||
/**
|
||||
|
|
|
@ -32,7 +32,7 @@ public class PushSynInfo extends SynInfo
|
|||
private int associatedStreamId;
|
||||
|
||||
public PushSynInfo(int associatedStreamId, PushInfo pushInfo){
|
||||
super(pushInfo.getHeaders(), pushInfo.isClose());
|
||||
super(pushInfo.getTimeout(), pushInfo.getUnit(), pushInfo.getHeaders(), pushInfo.isClose(), (byte)0);
|
||||
this.associatedStreamId = associatedStreamId;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.spdy.server.http;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
@ -46,6 +47,7 @@ import org.eclipse.jetty.spdy.api.StreamStatus;
|
|||
import org.eclipse.jetty.util.BlockingCallback;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.ConcurrentArrayQueue;
|
||||
import org.eclipse.jetty.util.Fields;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -74,11 +76,21 @@ public class HttpTransportOverSPDY implements HttpTransport
|
|||
this.requestHeaders = requestHeaders;
|
||||
}
|
||||
|
||||
protected Stream getStream()
|
||||
{
|
||||
return stream;
|
||||
}
|
||||
|
||||
protected Fields getRequestHeaders()
|
||||
{
|
||||
return requestHeaders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("send {} {} {} {} last={}", this, stream, info, BufferUtil.toDetailString(content), lastContent);
|
||||
LOG.debug("Sending {} {} {} {} last={}", this, stream, info, BufferUtil.toDetailString(content), lastContent);
|
||||
|
||||
if (stream.isClosed() || stream.isReset())
|
||||
{
|
||||
|
@ -86,7 +98,6 @@ public class HttpTransportOverSPDY implements HttpTransport
|
|||
callback.failed(exception);
|
||||
return;
|
||||
}
|
||||
// new Throwable().printStackTrace();
|
||||
|
||||
// info==null content==null lastContent==false should not happen
|
||||
// info==null content==null lastContent==true signals no more content - complete
|
||||
|
@ -149,7 +160,7 @@ public class HttpTransportOverSPDY implements HttpTransport
|
|||
{
|
||||
// Is the stream still open?
|
||||
if (stream.isClosed() || stream.isReset())
|
||||
// tell the callback about the EOF
|
||||
// tell the callback about the EOF
|
||||
callback.failed(new EofException("stream closed"));
|
||||
else
|
||||
// send the data and let it call the callback
|
||||
|
@ -171,7 +182,6 @@ public class HttpTransportOverSPDY implements HttpTransport
|
|||
else
|
||||
// No data and no close so tell callback we are completed
|
||||
callback.succeeded();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -188,11 +198,10 @@ public class HttpTransportOverSPDY implements HttpTransport
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void completed()
|
||||
{
|
||||
LOG.debug("completed");
|
||||
LOG.debug("Completed");
|
||||
}
|
||||
|
||||
private void reply(Stream stream, ReplyInfo replyInfo)
|
||||
|
@ -206,65 +215,160 @@ public class HttpTransportOverSPDY implements HttpTransport
|
|||
short version = stream.getSession().getVersion();
|
||||
if (responseHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().startsWith("200") && !stream.isClosed())
|
||||
{
|
||||
// We have a 200 OK with some content to send, check the push strategy
|
||||
Fields.Field scheme = requestHeaders.get(HTTPSPDYHeader.SCHEME.name(version));
|
||||
Fields.Field host = requestHeaders.get(HTTPSPDYHeader.HOST.name(version));
|
||||
Fields.Field uri = requestHeaders.get(HTTPSPDYHeader.URI.name(version));
|
||||
Set<String> pushResources = pushStrategy.apply(stream, requestHeaders, responseHeaders);
|
||||
|
||||
for (String pushResource : pushResources)
|
||||
if (pushResources.size() > 0)
|
||||
{
|
||||
Fields pushHeaders = createPushHeaders(scheme, host, pushResource);
|
||||
final Fields pushRequestHeaders = createRequestHeaders(scheme, host, uri, pushResource);
|
||||
|
||||
// TODO: handle the timeout better
|
||||
stream.push(new PushInfo(0, TimeUnit.MILLISECONDS, pushHeaders, false), new Promise.Adapter<Stream>()
|
||||
{
|
||||
@Override
|
||||
public void succeeded(Stream pushStream)
|
||||
{
|
||||
HttpChannelOverSPDY pushChannel = newHttpChannelOverSPDY(pushStream, pushRequestHeaders);
|
||||
pushChannel.requestStart(pushRequestHeaders, true);
|
||||
}
|
||||
});
|
||||
PushResourceCoordinator pushResourceCoordinator = new PushResourceCoordinator(pushResources);
|
||||
pushResourceCoordinator.coordinate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Fields createRequestHeaders(Fields.Field scheme, Fields.Field host, Fields.Field uri, String pushResourcePath)
|
||||
private static class PushHttpTransportOverSPDY extends HttpTransportOverSPDY
|
||||
{
|
||||
final Fields newRequestHeaders = new Fields(requestHeaders, false);
|
||||
short version = stream.getSession().getVersion();
|
||||
newRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version), "GET");
|
||||
newRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
|
||||
newRequestHeaders.put(scheme);
|
||||
newRequestHeaders.put(host);
|
||||
newRequestHeaders.put(HTTPSPDYHeader.URI.name(version), pushResourcePath);
|
||||
String referrer = scheme.value() + "://" + host.value() + uri.value();
|
||||
newRequestHeaders.put("referer", referrer);
|
||||
newRequestHeaders.put("x-spdy-push", "true");
|
||||
return newRequestHeaders;
|
||||
}
|
||||
private final PushResourceCoordinator coordinator;
|
||||
|
||||
private Fields createPushHeaders(Fields.Field scheme, Fields.Field host, String pushResourcePath)
|
||||
{
|
||||
final Fields pushHeaders = new Fields();
|
||||
short version = stream.getSession().getVersion();
|
||||
if (version == SPDY.V2)
|
||||
pushHeaders.put(HTTPSPDYHeader.URI.name(version), scheme.value() + "://" + host.value() + pushResourcePath);
|
||||
else
|
||||
private PushHttpTransportOverSPDY(Connector connector, HttpConfiguration configuration, EndPoint endPoint,
|
||||
PushStrategy pushStrategy, Stream stream, Fields requestHeaders,
|
||||
PushResourceCoordinator coordinator)
|
||||
{
|
||||
pushHeaders.put(HTTPSPDYHeader.URI.name(version), pushResourcePath);
|
||||
pushHeaders.put(scheme);
|
||||
pushHeaders.put(host);
|
||||
super(connector, configuration, endPoint, pushStrategy, stream, requestHeaders);
|
||||
this.coordinator = coordinator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completed()
|
||||
{
|
||||
Stream stream = getStream();
|
||||
LOG.debug("Resource pushed for {} on {}",
|
||||
getRequestHeaders().get(HTTPSPDYHeader.URI.name(stream.getSession().getVersion())), stream);
|
||||
coordinator.complete();
|
||||
}
|
||||
return pushHeaders;
|
||||
}
|
||||
|
||||
private HttpChannelOverSPDY newHttpChannelOverSPDY(Stream pushStream, Fields pushRequestHeaders)
|
||||
private class PushResourceCoordinator
|
||||
{
|
||||
HttpTransport transport = new HttpTransportOverSPDY(connector, configuration, endPoint, pushStrategy, pushStream, pushRequestHeaders);
|
||||
HttpInputOverSPDY input = new HttpInputOverSPDY();
|
||||
return new HttpChannelOverSPDY(connector, configuration, endPoint, transport, input, pushStream);
|
||||
private final Queue<PushResource> queue = new ConcurrentArrayQueue<>();
|
||||
private final Set<String> resources;
|
||||
private boolean active;
|
||||
|
||||
private PushResourceCoordinator(Set<String> resources)
|
||||
{
|
||||
this.resources = resources;
|
||||
}
|
||||
|
||||
private void coordinate()
|
||||
{
|
||||
// Must send all push frames to the client at once before we
|
||||
// return from this method and send the main resource data
|
||||
for (String pushResource : resources)
|
||||
pushResource(pushResource);
|
||||
}
|
||||
|
||||
private void sendNextResourceData()
|
||||
{
|
||||
PushResource resource;
|
||||
synchronized (this)
|
||||
{
|
||||
if (active)
|
||||
return;
|
||||
resource = queue.poll();
|
||||
if (resource == null)
|
||||
return;
|
||||
active = true;
|
||||
}
|
||||
HttpChannelOverSPDY pushChannel = newHttpChannelOverSPDY(resource.getPushStream(), resource.getPushRequestHeaders());
|
||||
pushChannel.requestStart(resource.getPushRequestHeaders(), true);
|
||||
}
|
||||
|
||||
private HttpChannelOverSPDY newHttpChannelOverSPDY(Stream pushStream, Fields pushRequestHeaders)
|
||||
{
|
||||
HttpTransport transport = new PushHttpTransportOverSPDY(connector, configuration, endPoint, pushStrategy,
|
||||
pushStream, pushRequestHeaders, this);
|
||||
HttpInputOverSPDY input = new HttpInputOverSPDY();
|
||||
return new HttpChannelOverSPDY(connector, configuration, endPoint, transport, input, pushStream);
|
||||
}
|
||||
|
||||
private void pushResource(String pushResource)
|
||||
{
|
||||
final short version = stream.getSession().getVersion();
|
||||
Fields.Field scheme = requestHeaders.get(HTTPSPDYHeader.SCHEME.name(version));
|
||||
Fields.Field host = requestHeaders.get(HTTPSPDYHeader.HOST.name(version));
|
||||
Fields.Field uri = requestHeaders.get(HTTPSPDYHeader.URI.name(version));
|
||||
final Fields pushHeaders = createPushHeaders(scheme, host, pushResource);
|
||||
final Fields pushRequestHeaders = createRequestHeaders(scheme, host, uri, pushResource);
|
||||
|
||||
stream.push(new PushInfo(pushHeaders, false), new Promise.Adapter<Stream>()
|
||||
{
|
||||
@Override
|
||||
public void succeeded(Stream pushStream)
|
||||
{
|
||||
LOG.debug("Headers pushed for {} on {}", pushHeaders.get(HTTPSPDYHeader.URI.name(version)), pushStream);
|
||||
queue.offer(new PushResource(pushStream, pushRequestHeaders));
|
||||
sendNextResourceData();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Fields createRequestHeaders(Fields.Field scheme, Fields.Field host, Fields.Field uri, String pushResourcePath)
|
||||
{
|
||||
final Fields newRequestHeaders = new Fields(requestHeaders, false);
|
||||
short version = stream.getSession().getVersion();
|
||||
newRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version), "GET");
|
||||
newRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
|
||||
newRequestHeaders.put(scheme);
|
||||
newRequestHeaders.put(host);
|
||||
newRequestHeaders.put(HTTPSPDYHeader.URI.name(version), pushResourcePath);
|
||||
String referrer = scheme.value() + "://" + host.value() + uri.value();
|
||||
newRequestHeaders.put("referer", referrer);
|
||||
newRequestHeaders.put("x-spdy-push", "true");
|
||||
return newRequestHeaders;
|
||||
}
|
||||
|
||||
private Fields createPushHeaders(Fields.Field scheme, Fields.Field host, String pushResourcePath)
|
||||
{
|
||||
final Fields pushHeaders = new Fields();
|
||||
short version = stream.getSession().getVersion();
|
||||
if (version == SPDY.V2)
|
||||
pushHeaders.put(HTTPSPDYHeader.URI.name(version), scheme.value() + "://" + host.value() + pushResourcePath);
|
||||
else
|
||||
{
|
||||
pushHeaders.put(HTTPSPDYHeader.URI.name(version), pushResourcePath);
|
||||
pushHeaders.put(scheme);
|
||||
pushHeaders.put(host);
|
||||
}
|
||||
return pushHeaders;
|
||||
}
|
||||
|
||||
private void complete()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
active = false;
|
||||
}
|
||||
sendNextResourceData();
|
||||
}
|
||||
}
|
||||
|
||||
private static class PushResource
|
||||
{
|
||||
private final Stream pushStream;
|
||||
private final Fields pushRequestHeaders;
|
||||
|
||||
public PushResource(Stream pushStream, Fields pushRequestHeaders)
|
||||
{
|
||||
this.pushStream = pushStream;
|
||||
this.pushRequestHeaders = pushRequestHeaders;
|
||||
}
|
||||
|
||||
public Stream getPushStream()
|
||||
{
|
||||
return pushStream;
|
||||
}
|
||||
|
||||
public Fields getPushRequestHeaders()
|
||||
{
|
||||
return pushRequestHeaders;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ public interface PushStrategy
|
|||
/**
|
||||
* <p>Applies the SPDY push logic for the primary resource.</p>
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param stream the primary resource stream
|
||||
* @param requestHeaders the primary resource request headers
|
||||
* @param responseHeaders the primary resource response headers
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue