Merge branch 'master' of ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project
This commit is contained in:
commit
cb295e708d
|
@ -6,6 +6,7 @@ jetty-7.5.0.RC1 - 19 August 2011
|
||||||
+ 335001 Eliminate expected exceptions from log when running in JBoss
|
+ 335001 Eliminate expected exceptions from log when running in JBoss
|
||||||
+ 355103 Make allowCredentials default to true in CrossOriginFilter
|
+ 355103 Make allowCredentials default to true in CrossOriginFilter
|
||||||
+ 355162 Allow creating an empty resource collection
|
+ 355162 Allow creating an empty resource collection
|
||||||
|
+ JETTY-1410 HTTP client handles CONTINUE 100 response correctly
|
||||||
+ JETTY-1414 HashLoginService doesn't refresh realm if specified config filename is not an absolute platform specific value
|
+ JETTY-1414 HashLoginService doesn't refresh realm if specified config filename is not an absolute platform specific value
|
||||||
|
|
||||||
jetty-7.5.0.RC0 - 15 August 2011
|
jetty-7.5.0.RC0 - 15 August 2011
|
||||||
|
|
|
@ -70,7 +70,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
||||||
HttpConnection(Buffers requestBuffers, Buffers responseBuffers, EndPoint endp)
|
HttpConnection(Buffers requestBuffers, Buffers responseBuffers, EndPoint endp)
|
||||||
{
|
{
|
||||||
super(endp);
|
super(endp);
|
||||||
|
|
||||||
_generator = new HttpGenerator(requestBuffers,endp);
|
_generator = new HttpGenerator(requestBuffers,endp);
|
||||||
_parser = new HttpParser(responseBuffers,endp,new Handler());
|
_parser = new HttpParser(responseBuffers,endp,new Handler());
|
||||||
}
|
}
|
||||||
|
@ -571,14 +571,24 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
||||||
@Override
|
@Override
|
||||||
public void startResponse(Buffer version, int status, Buffer reason) throws IOException
|
public void startResponse(Buffer version, int status, Buffer reason) throws IOException
|
||||||
{
|
{
|
||||||
|
|
||||||
HttpExchange exchange = _exchange;
|
HttpExchange exchange = _exchange;
|
||||||
if (exchange!=null)
|
if (exchange!=null)
|
||||||
{
|
{
|
||||||
// handle special case for CONNECT 200 responses
|
switch(status)
|
||||||
if (status==HttpStatus.OK_200 && HttpMethods.CONNECT.equalsIgnoreCase(exchange.getMethod()))
|
{
|
||||||
_parser.setHeadResponse(true);
|
case HttpStatus.CONTINUE_100:
|
||||||
|
case HttpStatus.PROCESSING_102:
|
||||||
|
// TODO check if appropriate expect was sent in the request.
|
||||||
|
exchange.setEventListener(new NonFinalResponseListener(exchange));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HttpStatus.OK_200:
|
||||||
|
// handle special case for CONNECT 200 responses
|
||||||
|
if (HttpMethods.CONNECT.equalsIgnoreCase(exchange.getMethod()))
|
||||||
|
_parser.setHeadResponse(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
_http11 = HttpVersions.HTTP_1_1_BUFFER.equals(version);
|
_http11 = HttpVersions.HTTP_1_1_BUFFER.equals(version);
|
||||||
_status=status;
|
_status=status;
|
||||||
exchange.getEventListener().onResponseStatus(version,status,reason);
|
exchange.getEventListener().onResponseStatus(version,status,reason);
|
||||||
|
@ -734,8 +744,10 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
private class ConnectionIdleTask extends Timeout.Task
|
private class ConnectionIdleTask extends Timeout.Task
|
||||||
{
|
{
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Override
|
||||||
public void expired()
|
public void expired()
|
||||||
{
|
{
|
||||||
|
@ -746,4 +758,87 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
private class NonFinalResponseListener implements HttpEventListener
|
||||||
|
{
|
||||||
|
final HttpExchange _exchange;
|
||||||
|
final HttpEventListener _next;
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public NonFinalResponseListener(HttpExchange exchange)
|
||||||
|
{
|
||||||
|
_exchange=exchange;
|
||||||
|
_next=exchange.getEventListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void onRequestCommitted() throws IOException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void onRequestComplete() throws IOException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void onResponseHeader(Buffer name, Buffer value) throws IOException
|
||||||
|
{
|
||||||
|
_next.onResponseHeader(name,value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void onResponseHeaderComplete() throws IOException
|
||||||
|
{
|
||||||
|
_next.onResponseHeaderComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void onResponseContent(Buffer content) throws IOException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void onResponseComplete() throws IOException
|
||||||
|
{
|
||||||
|
_exchange.setEventListener(_next);
|
||||||
|
_exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_RESPONSE);
|
||||||
|
_parser.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void onConnectionFailed(Throwable ex)
|
||||||
|
{
|
||||||
|
_exchange.setEventListener(_next);
|
||||||
|
_next.onConnectionFailed(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void onException(Throwable ex)
|
||||||
|
{
|
||||||
|
_exchange.setEventListener(_next);
|
||||||
|
_next.onException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void onExpire()
|
||||||
|
{
|
||||||
|
_exchange.setEventListener(_next);
|
||||||
|
_next.onExpire();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void onRetry()
|
||||||
|
{
|
||||||
|
_exchange.setEventListener(_next);
|
||||||
|
_next.onRetry();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -302,6 +302,7 @@ public class HttpExchange
|
||||||
{
|
{
|
||||||
case STATUS_START:
|
case STATUS_START:
|
||||||
case STATUS_EXCEPTED:
|
case STATUS_EXCEPTED:
|
||||||
|
case STATUS_WAITING_FOR_RESPONSE:
|
||||||
set=_status.compareAndSet(oldStatus,newStatus);
|
set=_status.compareAndSet(oldStatus,newStatus);
|
||||||
break;
|
break;
|
||||||
case STATUS_CANCELLING:
|
case STATUS_CANCELLING:
|
||||||
|
@ -344,7 +345,7 @@ public class HttpExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!set)
|
if (!set)
|
||||||
throw new IllegalStateException(oldStatus + " => " + newStatus);
|
throw new IllegalStateException(toState(oldStatus) + " => " + toState(newStatus));
|
||||||
}
|
}
|
||||||
catch (IOException x)
|
catch (IOException x)
|
||||||
{
|
{
|
||||||
|
@ -726,11 +727,10 @@ public class HttpExchange
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static String toState(int s)
|
||||||
public String toString()
|
|
||||||
{
|
{
|
||||||
String state;
|
String state;
|
||||||
switch(getStatus())
|
switch(s)
|
||||||
{
|
{
|
||||||
case STATUS_START: state="START"; break;
|
case STATUS_START: state="START"; break;
|
||||||
case STATUS_WAITING_FOR_CONNECTION: state="CONNECTING"; break;
|
case STATUS_WAITING_FOR_CONNECTION: state="CONNECTING"; break;
|
||||||
|
@ -746,6 +746,13 @@ public class HttpExchange
|
||||||
case STATUS_CANCELLED: state="CANCELLED"; break;
|
case STATUS_CANCELLED: state="CANCELLED"; break;
|
||||||
default: state="UNKNOWN";
|
default: state="UNKNOWN";
|
||||||
}
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String state=toState(getStatus());
|
||||||
long now=System.currentTimeMillis();
|
long now=System.currentTimeMillis();
|
||||||
long forMs = now -_lastStateChange;
|
long forMs = now -_lastStateChange;
|
||||||
String s= String.format("%s@%x=%s//%s%s#%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,state,forMs);
|
String s= String.format("%s@%x=%s//%s%s#%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,state,forMs);
|
||||||
|
|
|
@ -0,0 +1,240 @@
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) Webtide LLC
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// 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 static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.http.HttpMethods;
|
||||||
|
import org.eclipse.jetty.http.HttpStatus;
|
||||||
|
import org.eclipse.jetty.server.Connector;
|
||||||
|
import org.eclipse.jetty.server.Request;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
|
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public class Http100ContinueTest
|
||||||
|
{
|
||||||
|
private static final int TIMEOUT = 500;
|
||||||
|
|
||||||
|
private static final String CONTENT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. "
|
||||||
|
+ "Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque "
|
||||||
|
+ "habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. "
|
||||||
|
+ "Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam "
|
||||||
|
+ "at faucibus. Etiam in urna turpis, sed congue mi. Morbi et lorem eros. Donec vulputate "
|
||||||
|
+ "velit in risus suscipit lobortis. Aliquam id urna orci, nec sollicitudin ipsum. "
|
||||||
|
+ "Cras a orci turpis. Donec suscipit vulputate cursus. Mauris nunc tellus, fermentum "
|
||||||
|
+ "eu auctor ut, mollis at diam. Quisque porttitor ultrices metus, vitae tincidunt massa "
|
||||||
|
+ "sollicitudin a. Vivamus porttitor libero eget purus hendrerit cursus. Integer aliquam "
|
||||||
|
+ "consequat mauris quis luctus. Cras enim nibh, dignissim eu faucibus ac, mollis nec neque. "
|
||||||
|
+ "Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse "
|
||||||
|
+ "et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque.";
|
||||||
|
|
||||||
|
private static TestFeature _feature;
|
||||||
|
|
||||||
|
private static Server _server;
|
||||||
|
private static TestHandler _handler;
|
||||||
|
private static HttpClient _client;
|
||||||
|
private static String _requestUrl;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void init() throws Exception
|
||||||
|
{
|
||||||
|
File docRoot = new File("target/test-output/docroot/");
|
||||||
|
if (!docRoot.exists())
|
||||||
|
assertTrue(docRoot.mkdirs());
|
||||||
|
docRoot.deleteOnExit();
|
||||||
|
|
||||||
|
_server = new Server();
|
||||||
|
Connector connector = new SelectChannelConnector();
|
||||||
|
_server.addConnector(connector);
|
||||||
|
|
||||||
|
_handler = new TestHandler();
|
||||||
|
_server.setHandler(_handler);
|
||||||
|
|
||||||
|
_server.start();
|
||||||
|
|
||||||
|
_client = new HttpClient();
|
||||||
|
_client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||||
|
_client.setTimeout(TIMEOUT);
|
||||||
|
_client.setMaxRetries(0);
|
||||||
|
_client.start();
|
||||||
|
|
||||||
|
_requestUrl = "http://localhost:" + connector.getLocalPort() + "/";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void destroy() throws Exception
|
||||||
|
{
|
||||||
|
_client.stop();
|
||||||
|
|
||||||
|
_server.stop();
|
||||||
|
_server.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSuccess() throws Exception
|
||||||
|
{
|
||||||
|
// Handler to send CONTINUE 100
|
||||||
|
_feature = TestFeature.CONTINUE;
|
||||||
|
|
||||||
|
ContentExchange exchange = sendExchange();
|
||||||
|
|
||||||
|
int state = exchange.waitForDone();
|
||||||
|
assertEquals(HttpExchange.STATUS_COMPLETED, state);
|
||||||
|
|
||||||
|
int responseStatus = exchange.getResponseStatus();
|
||||||
|
assertEquals(HttpStatus.OK_200,responseStatus);
|
||||||
|
|
||||||
|
String content = exchange.getResponseContent();
|
||||||
|
assertEquals(Http100ContinueTest.CONTENT,content);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMissingContinue() throws Exception
|
||||||
|
{
|
||||||
|
// Handler does not send CONTINUE 100
|
||||||
|
_feature = TestFeature.NORMAL;
|
||||||
|
|
||||||
|
ContentExchange exchange = sendExchange();
|
||||||
|
|
||||||
|
int state = exchange.waitForDone();
|
||||||
|
assertEquals(HttpExchange.STATUS_COMPLETED, state);
|
||||||
|
|
||||||
|
int responseStatus = exchange.getResponseStatus();
|
||||||
|
assertEquals(HttpStatus.OK_200,responseStatus);
|
||||||
|
|
||||||
|
String content = exchange.getResponseContent();
|
||||||
|
assertEquals(Http100ContinueTest.CONTENT,content);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testError() throws Exception
|
||||||
|
{
|
||||||
|
// Handler sends NOT FOUND 404 response
|
||||||
|
_feature = TestFeature.NOTFOUND;
|
||||||
|
|
||||||
|
ContentExchange exchange = sendExchange();
|
||||||
|
|
||||||
|
int state = exchange.waitForDone();
|
||||||
|
assertEquals(HttpExchange.STATUS_COMPLETED, state);
|
||||||
|
|
||||||
|
int responseStatus = exchange.getResponseStatus();
|
||||||
|
assertEquals(HttpStatus.NOT_FOUND_404,responseStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTimeout() throws Exception
|
||||||
|
{
|
||||||
|
// Handler delays response till client times out
|
||||||
|
_feature = TestFeature.TIMEOUT;
|
||||||
|
|
||||||
|
final CountDownLatch expires = new CountDownLatch(1);
|
||||||
|
ContentExchange exchange = new ContentExchange()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected void onExpire()
|
||||||
|
{
|
||||||
|
expires.countDown();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
configureExchange(exchange);
|
||||||
|
_client.send(exchange);
|
||||||
|
|
||||||
|
assertTrue(expires.await(TIMEOUT*10,TimeUnit.MILLISECONDS));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContentExchange sendExchange() throws Exception
|
||||||
|
{
|
||||||
|
ContentExchange exchange = new ContentExchange();
|
||||||
|
|
||||||
|
configureExchange(exchange);
|
||||||
|
_client.send(exchange);
|
||||||
|
|
||||||
|
return exchange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void configureExchange(ContentExchange exchange)
|
||||||
|
{
|
||||||
|
exchange.setURL(_requestUrl);
|
||||||
|
exchange.setMethod(HttpMethods.GET);
|
||||||
|
exchange.addRequestHeader("User-Agent","Jetty-Client/7.0");
|
||||||
|
exchange.addRequestHeader("Expect","100-continue"); //server to send CONTINUE 100
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TestHandler extends AbstractHandler
|
||||||
|
{
|
||||||
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
if (baseRequest.isHandled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
baseRequest.setHandled(true);
|
||||||
|
|
||||||
|
switch (_feature)
|
||||||
|
{
|
||||||
|
case CONTINUE:
|
||||||
|
// force 100 Continue response to be sent
|
||||||
|
request.getInputStream();
|
||||||
|
// next send data
|
||||||
|
|
||||||
|
case NORMAL:
|
||||||
|
response.setContentType("text/plain");
|
||||||
|
response.setStatus(HttpServletResponse.SC_OK);
|
||||||
|
response.getWriter().print(CONTENT);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NOTFOUND:
|
||||||
|
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TIMEOUT:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(TIMEOUT*4);
|
||||||
|
}
|
||||||
|
catch (InterruptedException ex)
|
||||||
|
{
|
||||||
|
Log.ignore(ex);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TestFeature {
|
||||||
|
CONTINUE,
|
||||||
|
NORMAL,
|
||||||
|
NOTFOUND,
|
||||||
|
TIMEOUT
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue