297104 suppot HTTP/1.0 CONNECT
git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@1554 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
parent
3be6db58f8
commit
ae344afe78
|
@ -115,6 +115,19 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
super(buffers, io);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public boolean isRequest()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public boolean isResponse()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void reset(boolean returnBuffers)
|
||||
|
@ -142,8 +155,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
_last = false;
|
||||
_head = false;
|
||||
_noContent = false;
|
||||
_close = false;
|
||||
|
||||
_persistent = true;
|
||||
|
||||
|
||||
|
||||
|
@ -342,8 +354,8 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
_last = _last | allContentAdded;
|
||||
|
||||
boolean has_server = false;
|
||||
if (_version == HttpVersions.HTTP_1_0_ORDINAL)
|
||||
_close = true;
|
||||
if (_persistent==null)
|
||||
_persistent=(_version > HttpVersions.HTTP_1_0_ORDINAL);
|
||||
|
||||
// get a header buffer
|
||||
if (_header == null)
|
||||
|
|
|
@ -62,8 +62,7 @@ public abstract class AbstractGenerator implements Generator
|
|||
protected boolean _last = false;
|
||||
protected boolean _head = false;
|
||||
protected boolean _noContent = false;
|
||||
protected boolean _close = false;
|
||||
|
||||
protected Boolean _persistent = null;
|
||||
|
||||
protected Buffer _header; // Buffer for HTTP header (and maybe small _content)
|
||||
protected Buffer _buffer; // Buffer for copy of passed _content
|
||||
|
@ -88,6 +87,12 @@ public abstract class AbstractGenerator implements Generator
|
|||
this._endp = io;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public abstract boolean isRequest();
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public abstract boolean isResponse();
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public boolean isOpen()
|
||||
{
|
||||
|
@ -104,7 +109,7 @@ public abstract class AbstractGenerator implements Generator
|
|||
_last = false;
|
||||
_head = false;
|
||||
_noContent=false;
|
||||
_close = false;
|
||||
_persistent = true;
|
||||
_contentWritten = 0;
|
||||
_contentLength = HttpTokens.UNKNOWN_CONTENT;
|
||||
_date = null;
|
||||
|
@ -134,7 +139,7 @@ public abstract class AbstractGenerator implements Generator
|
|||
throw new IllegalStateException("Flushed");
|
||||
|
||||
_last = false;
|
||||
_close = false;
|
||||
_persistent=null;
|
||||
_contentWritten = 0;
|
||||
_contentLength = HttpTokens.UNKNOWN_CONTENT;
|
||||
_content=null;
|
||||
|
@ -252,13 +257,15 @@ public abstract class AbstractGenerator implements Generator
|
|||
*/
|
||||
public boolean isPersistent()
|
||||
{
|
||||
return !_close;
|
||||
return _persistent!=null
|
||||
?_persistent.booleanValue()
|
||||
:(isRequest()?true:_version>HttpVersions.HTTP_1_0_ORDINAL);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setPersistent(boolean persistent)
|
||||
{
|
||||
_close=!persistent;
|
||||
_persistent=persistent;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -402,7 +409,7 @@ public abstract class AbstractGenerator implements Generator
|
|||
{
|
||||
if (Log.isDebugEnabled())
|
||||
Log.debug("ContentLength written=="+_contentWritten+" != contentLength=="+_contentLength);
|
||||
_close = true;
|
||||
_persistent = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -441,7 +448,8 @@ public abstract class AbstractGenerator implements Generator
|
|||
if (!isCommitted())
|
||||
{
|
||||
setResponse(code, reason);
|
||||
_close = close;
|
||||
if (close)
|
||||
_persistent=false;
|
||||
completeHeader(null, false);
|
||||
if (content != null)
|
||||
addContent(new View(new ByteArrayBuffer(content)), Generator.LAST);
|
||||
|
|
|
@ -351,7 +351,20 @@ public class HttpGenerator extends AbstractGenerator
|
|||
Log.debug(e);
|
||||
throw new InterruptedIOException(e.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public boolean isRequest()
|
||||
{
|
||||
return _method!=null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public boolean isResponse()
|
||||
{
|
||||
return _method==null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -362,7 +375,7 @@ public class HttpGenerator extends AbstractGenerator
|
|||
return;
|
||||
|
||||
// handle a reset
|
||||
if (_method==null && _status==0)
|
||||
if (isResponse() && _status==0)
|
||||
throw new EofException();
|
||||
|
||||
if (_last && !allContentAdded)
|
||||
|
@ -375,10 +388,10 @@ public class HttpGenerator extends AbstractGenerator
|
|||
|
||||
boolean has_server = false;
|
||||
|
||||
if (_method!=null)
|
||||
if (isRequest())
|
||||
{
|
||||
_close = false;
|
||||
// Request
|
||||
_persistent=true;
|
||||
|
||||
if (_version == HttpVersions.HTTP_0_9_ORDINAL)
|
||||
{
|
||||
_contentLength = HttpTokens.NO_CONTENT;
|
||||
|
@ -402,18 +415,19 @@ public class HttpGenerator extends AbstractGenerator
|
|||
}
|
||||
else
|
||||
{
|
||||
// Response
|
||||
// Responses
|
||||
|
||||
if (_version == HttpVersions.HTTP_0_9_ORDINAL)
|
||||
{
|
||||
_close = true;
|
||||
_persistent = false;
|
||||
_contentLength = HttpTokens.EOF_CONTENT;
|
||||
_state = STATE_CONTENT;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_version == HttpVersions.HTTP_1_0_ORDINAL)
|
||||
_close = true;
|
||||
if (_persistent==null)
|
||||
_persistent= (_version > HttpVersions.HTTP_1_0_ORDINAL);
|
||||
|
||||
// add response line
|
||||
Status status = _status<__status.length?__status[_status]:null;
|
||||
|
@ -528,7 +542,7 @@ public class HttpGenerator extends AbstractGenerator
|
|||
break;
|
||||
|
||||
case HttpHeaders.CONNECTION_ORDINAL:
|
||||
if (_method!=null)
|
||||
if (isRequest())
|
||||
field.put(_header);
|
||||
|
||||
int connection_value = field.getValueOrdinal();
|
||||
|
@ -547,10 +561,10 @@ public class HttpGenerator extends AbstractGenerator
|
|||
{
|
||||
case HttpHeaderValues.CLOSE_ORDINAL:
|
||||
close=true;
|
||||
if (_method==null)
|
||||
_close=true;
|
||||
if (isResponse())
|
||||
_persistent=false;
|
||||
keep_alive=false;
|
||||
if (_close && _method==null && _contentLength == HttpTokens.UNKNOWN_CONTENT)
|
||||
if (!_persistent && isResponse() && _contentLength == HttpTokens.UNKNOWN_CONTENT)
|
||||
_contentLength = HttpTokens.EOF_CONTENT;
|
||||
break;
|
||||
|
||||
|
@ -558,8 +572,8 @@ public class HttpGenerator extends AbstractGenerator
|
|||
if (_version == HttpVersions.HTTP_1_0_ORDINAL)
|
||||
{
|
||||
keep_alive = true;
|
||||
if (_method==null)
|
||||
_close = false;
|
||||
if (isResponse())
|
||||
_persistent = true;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -586,7 +600,7 @@ public class HttpGenerator extends AbstractGenerator
|
|||
case HttpHeaderValues.UPGRADE_ORDINAL:
|
||||
{
|
||||
// special case for websocket connection ordering
|
||||
if (_method==null)
|
||||
if (isResponse())
|
||||
{
|
||||
field.put(_header);
|
||||
continue;
|
||||
|
@ -595,9 +609,9 @@ public class HttpGenerator extends AbstractGenerator
|
|||
case HttpHeaderValues.CLOSE_ORDINAL:
|
||||
{
|
||||
close=true;
|
||||
if (_method==null)
|
||||
_close=true;
|
||||
if (_close && _method==null && _contentLength == HttpTokens.UNKNOWN_CONTENT)
|
||||
if (isResponse())
|
||||
_persistent=false;
|
||||
if (!_persistent && isResponse() && _contentLength == HttpTokens.UNKNOWN_CONTENT)
|
||||
_contentLength = HttpTokens.EOF_CONTENT;
|
||||
break;
|
||||
}
|
||||
|
@ -606,8 +620,8 @@ public class HttpGenerator extends AbstractGenerator
|
|||
if (_version == HttpVersions.HTTP_1_0_ORDINAL)
|
||||
{
|
||||
keep_alive = true;
|
||||
if (_method==null)
|
||||
_close = false;
|
||||
if (isResponse())
|
||||
_persistent=true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -655,13 +669,13 @@ public class HttpGenerator extends AbstractGenerator
|
|||
// written yet?
|
||||
|
||||
// Response known not to have a body
|
||||
if (_contentWritten == 0 && _method==null && (_status < 200 || _status == 204 || _status == 304))
|
||||
if (_contentWritten == 0 && isResponse() && (_status < 200 || _status == 204 || _status == 304))
|
||||
_contentLength = HttpTokens.NO_CONTENT;
|
||||
else if (_last)
|
||||
{
|
||||
// we have seen all the _content there is
|
||||
_contentLength = _contentWritten;
|
||||
if (content_length == null && (_method==null || _contentLength>0 || content_type ))
|
||||
if (content_length == null && (isResponse() || _contentLength>0 || content_type ))
|
||||
{
|
||||
// known length but not actually set.
|
||||
_header.put(HttpHeaders.CONTENT_LENGTH_BUFFER);
|
||||
|
@ -674,8 +688,8 @@ public class HttpGenerator extends AbstractGenerator
|
|||
else
|
||||
{
|
||||
// No idea, so we must assume that a body is coming
|
||||
_contentLength = (_close || _version < HttpVersions.HTTP_1_1_ORDINAL ) ? HttpTokens.EOF_CONTENT : HttpTokens.CHUNKED_CONTENT;
|
||||
if (_method!=null && _contentLength==HttpTokens.EOF_CONTENT)
|
||||
_contentLength = (!_persistent || _version < HttpVersions.HTTP_1_1_ORDINAL ) ? HttpTokens.EOF_CONTENT : HttpTokens.CHUNKED_CONTENT;
|
||||
if (isRequest() && _contentLength==HttpTokens.EOF_CONTENT)
|
||||
{
|
||||
_contentLength=HttpTokens.NO_CONTENT;
|
||||
_noContent=true;
|
||||
|
@ -684,12 +698,12 @@ public class HttpGenerator extends AbstractGenerator
|
|||
break;
|
||||
|
||||
case HttpTokens.NO_CONTENT:
|
||||
if (content_length == null && _method==null && _status >= 200 && _status != 204 && _status != 304)
|
||||
if (content_length == null && isResponse() && _status >= 200 && _status != 204 && _status != 304)
|
||||
_header.put(CONTENT_LENGTH_0);
|
||||
break;
|
||||
|
||||
case HttpTokens.EOF_CONTENT:
|
||||
_close = _method==null;
|
||||
_persistent = isRequest();
|
||||
break;
|
||||
|
||||
case HttpTokens.CHUNKED_CONTENT:
|
||||
|
@ -720,12 +734,12 @@ public class HttpGenerator extends AbstractGenerator
|
|||
if (_contentLength==HttpTokens.EOF_CONTENT)
|
||||
{
|
||||
keep_alive=false;
|
||||
_close=true;
|
||||
_persistent=false;
|
||||
}
|
||||
|
||||
if (_method==null)
|
||||
if (isResponse())
|
||||
{
|
||||
if (_close && (close || _version > HttpVersions.HTTP_1_0_ORDINAL))
|
||||
if (!_persistent && (close || _version > HttpVersions.HTTP_1_0_ORDINAL))
|
||||
{
|
||||
_header.put(CONNECTION_CLOSE);
|
||||
if (connection!=null)
|
||||
|
@ -872,7 +886,7 @@ public class HttpGenerator extends AbstractGenerator
|
|||
{
|
||||
if (_state == STATE_FLUSHING)
|
||||
_state = STATE_END;
|
||||
if (_state==STATE_END && _close && _status!=100)
|
||||
if (_state==STATE_END && !_persistent && _status!=100)
|
||||
_endp.close();
|
||||
}
|
||||
else
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.eclipse.jetty.server.handler;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
@ -10,6 +11,7 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpGenerator;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.http.HttpParser;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
|
@ -171,7 +173,7 @@ public class ProxyHandler extends HandlerWrapper
|
|||
if (HttpMethods.CONNECT.equalsIgnoreCase(request.getMethod()))
|
||||
{
|
||||
_logger.debug("CONNECT request for {}", request.getRequestURI(), null);
|
||||
handleConnect(request, response, request.getRequestURI());
|
||||
handleConnect(baseRequest,request, response, request.getRequestURI());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -190,7 +192,7 @@ public class ProxyHandler extends HandlerWrapper
|
|||
* @throws ServletException if an application error occurs
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
protected void handleConnect(HttpServletRequest request, HttpServletResponse response, String serverAddress) throws ServletException, IOException
|
||||
protected void handleConnect(Request baseRequest, HttpServletRequest request, HttpServletResponse response, String serverAddress) throws ServletException, IOException
|
||||
{
|
||||
boolean proceed = handleAuthentication(request, response, serverAddress);
|
||||
if (!proceed)
|
||||
|
@ -237,8 +239,12 @@ public class ProxyHandler extends HandlerWrapper
|
|||
|
||||
// CONNECT expects a 200 response
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
// Flush it so that the client receives it
|
||||
response.flushBuffer();
|
||||
|
||||
// Prevent close
|
||||
((HttpGenerator)baseRequest.getConnection().getGenerator()).setPersistent(true);
|
||||
|
||||
// close to force last flush it so that the client receives it
|
||||
response.getOutputStream().close();
|
||||
|
||||
upgradeConnection(request, response, clientToProxy);
|
||||
}
|
||||
|
@ -608,15 +614,21 @@ public class ProxyHandler extends HandlerWrapper
|
|||
}
|
||||
return this;
|
||||
}
|
||||
catch (ClosedChannelException x)
|
||||
{
|
||||
_logger.debug("ClientToProxy",x);
|
||||
closeServer();
|
||||
throw x;
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
_logger.warn("ClientToProxy: Unexpected exception", x);
|
||||
_logger.warn("ClientToProxy", x);
|
||||
close();
|
||||
throw x;
|
||||
}
|
||||
catch (RuntimeException x)
|
||||
{
|
||||
_logger.warn("ClientToProxy: Unexpected exception", x);
|
||||
_logger.warn("ClientToProxy", x);
|
||||
close();
|
||||
throw x;
|
||||
}
|
||||
|
|
|
@ -400,11 +400,19 @@ public class HttpServerTestBase extends TestCase
|
|||
for (int c=0;c<1;c++)
|
||||
{
|
||||
String test=encoding[e]+"x"+b+"x"+w+"x"+c;
|
||||
URL url=new URL("http://"+HOST+":"+port+"/?writes="+w+"&block="+b+ (e==0?"":("&encoding="+encoding[e]))+(c==0?"&chars=true":""));
|
||||
InputStream in = (InputStream)url.getContent();
|
||||
String response=IO.toString(in,e==0?null:encoding[e]);
|
||||
|
||||
assertEquals(test,b*w,response.length());
|
||||
try
|
||||
{
|
||||
URL url=new URL("http://"+HOST+":"+port+"/?writes="+w+"&block="+b+ (e==0?"":("&encoding="+encoding[e]))+(c==0?"&chars=true":""));
|
||||
InputStream in = (InputStream)url.getContent();
|
||||
String response=IO.toString(in,e==0?null:encoding[e]);
|
||||
|
||||
assertEquals(test,b*w,response.length());
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
System.err.println(test);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,18 @@ public class HttpWriterTest extends TestCase
|
|||
ByteArrayEndPoint endp = new ByteArrayEndPoint();
|
||||
AbstractGenerator generator = new AbstractGenerator(buffers,endp)
|
||||
{
|
||||
@Override
|
||||
public boolean isRequest()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResponse()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException
|
||||
{
|
||||
|
|
|
@ -23,4 +23,10 @@ public class SocketServerTest extends HttpServerTestBase
|
|||
{
|
||||
super(new SocketConnector());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testFlush() throws Exception
|
||||
{
|
||||
super.testFlush();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ public abstract class AbstractProxyHandlerTest extends TestCase
|
|||
protected Socket newSocket() throws IOException
|
||||
{
|
||||
Socket socket = new Socket("localhost", proxyConnector.getLocalPort());
|
||||
socket.setSoTimeout(5000);
|
||||
socket.setSoTimeout(500000);
|
||||
return socket;
|
||||
}
|
||||
|
||||
|
|
|
@ -89,6 +89,43 @@ public class ProxyHandlerConnectTest extends AbstractProxyHandlerTest
|
|||
}
|
||||
}
|
||||
|
||||
public void testCONNECT10AndGET() throws Exception
|
||||
{
|
||||
String hostPort = "localhost:" + serverConnector.getLocalPort();
|
||||
String request = "" +
|
||||
"CONNECT " + hostPort + " HTTP/1.0\r\n" +
|
||||
"Host: " + hostPort + "\r\n" +
|
||||
"\r\n";
|
||||
Socket socket = newSocket();
|
||||
try
|
||||
{
|
||||
OutputStream output = socket.getOutputStream();
|
||||
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
|
||||
output.write(request.getBytes("UTF-8"));
|
||||
output.flush();
|
||||
|
||||
// Expect 200 OK from the CONNECT request
|
||||
Response response = readResponse(input);
|
||||
assertEquals("200", response.getCode());
|
||||
|
||||
request = "" +
|
||||
"GET /echo" + " HTTP/1.1\r\n" +
|
||||
"Host: " + hostPort + "\r\n" +
|
||||
"\r\n";
|
||||
output.write(request.getBytes("UTF-8"));
|
||||
output.flush();
|
||||
|
||||
response = readResponse(input);
|
||||
assertEquals("200", response.getCode());
|
||||
assertEquals("GET /echo", response.getBody());
|
||||
}
|
||||
finally
|
||||
{
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void testCONNECTAndGETPipelined() throws Exception
|
||||
{
|
||||
String hostPort = "localhost:" + serverConnector.getLocalPort();
|
||||
|
|
Loading…
Reference in New Issue