Merge from master to release-9
This commit is contained in:
commit
ef472ed01b
|
@ -29,7 +29,6 @@ import java.util.List;
|
|||
import org.apache.tools.ant.BuildException;
|
||||
import org.eclipse.jetty.ant.types.Connector;
|
||||
import org.eclipse.jetty.ant.types.ContextHandlers;
|
||||
import org.eclipse.jetty.ant.utils.Monitor;
|
||||
import org.eclipse.jetty.ant.utils.ServerProxy;
|
||||
import org.eclipse.jetty.ant.utils.TaskLog;
|
||||
import org.eclipse.jetty.security.LoginService;
|
||||
|
@ -37,6 +36,7 @@ import org.eclipse.jetty.server.Handler;
|
|||
import org.eclipse.jetty.server.RequestLog;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.ShutdownMonitor;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
|
@ -95,7 +95,6 @@ public class ServerProxyImpl implements ServerProxy
|
|||
/** wait for all jetty threads to exit or continue */
|
||||
private boolean daemon;
|
||||
|
||||
private Monitor monitor;
|
||||
|
||||
private boolean configured = false;
|
||||
|
||||
|
@ -267,8 +266,6 @@ public class ServerProxyImpl implements ServerProxy
|
|||
System.setProperty("jetty.ant.server.host", host);
|
||||
}
|
||||
|
||||
startMonitor();
|
||||
|
||||
startScanners();
|
||||
|
||||
TaskLog.log("Jetty AntTask Started");
|
||||
|
@ -356,6 +353,11 @@ public class ServerProxyImpl implements ServerProxy
|
|||
|
||||
configured = true;
|
||||
|
||||
ShutdownMonitor monitor = ShutdownMonitor.getInstance();
|
||||
monitor.setPort(stopPort);
|
||||
monitor.setKey(stopKey);
|
||||
monitor.setExitVm(false);
|
||||
|
||||
if (tempDirectory != null && !tempDirectory.exists())
|
||||
tempDirectory.mkdirs();
|
||||
|
||||
|
@ -430,17 +432,7 @@ public class ServerProxyImpl implements ServerProxy
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
private void startMonitor() throws Exception
|
||||
{
|
||||
if (stopPort > 0 && stopKey != null && monitor == null)
|
||||
{
|
||||
monitor = new Monitor(stopPort, stopKey, new Server[] {server});
|
||||
monitor.start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,143 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 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.ant.utils;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.LineNumberReader;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
|
||||
|
||||
/**
|
||||
* Monitor
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class Monitor extends Thread
|
||||
{
|
||||
private String stopKey;
|
||||
|
||||
private Server[] servers;
|
||||
|
||||
private ServerSocket serverSocket;
|
||||
|
||||
public Monitor(int port, String key, Server[] servers)
|
||||
throws Exception
|
||||
{
|
||||
if (port <= 0) throw new IllegalStateException("Bad stop port");
|
||||
if (key == null) throw new IllegalStateException("Bad stop key");
|
||||
if (servers == null) throw new IllegalStateException("No servers");
|
||||
|
||||
this.stopKey = key;
|
||||
this.servers = servers;
|
||||
setName("JettyStopTaskMonitor");
|
||||
setDaemon(true);
|
||||
InetSocketAddress address = new InetSocketAddress("127.0.0.1", port);
|
||||
serverSocket = new ServerSocket();
|
||||
serverSocket.setReuseAddress(true);
|
||||
try
|
||||
{
|
||||
serverSocket.bind(address, 1);
|
||||
TaskLog.log("Jetty monitoring port 127.0.0.1:" + port);
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
TaskLog.log("Error binding to stop port 127.0.0.1:" + port);
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Thread#run()
|
||||
*/
|
||||
public void run()
|
||||
{
|
||||
while (serverSocket != null)
|
||||
{
|
||||
Socket socket = null;
|
||||
try
|
||||
{
|
||||
socket = serverSocket.accept();
|
||||
socket.setSoLinger(false, 0);
|
||||
LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
|
||||
|
||||
String key = lin.readLine();
|
||||
System.err.println("Monitor: " + key);
|
||||
if (!stopKey.equals(key)) continue;
|
||||
String cmd = lin.readLine();
|
||||
if ("stop".equals(cmd))
|
||||
{
|
||||
close(serverSocket);
|
||||
serverSocket = null;
|
||||
for (Server s : servers)
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskLog.log("Stopping server: " + s);
|
||||
s.stop();
|
||||
TaskLog.log("Stopped server: " + s);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
TaskLog.log(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// confirm the stop
|
||||
socket.getOutputStream().write("Stopped\r\n".getBytes());
|
||||
}
|
||||
else
|
||||
TaskLog.log("Unsupported monitor operation: " + cmd);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
TaskLog.log(e.getMessage());
|
||||
}
|
||||
finally
|
||||
{
|
||||
close(socket);
|
||||
socket = null;
|
||||
close(serverSocket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param c
|
||||
*/
|
||||
private void close(Closeable c)
|
||||
{
|
||||
if (c == null) return;
|
||||
|
||||
try
|
||||
{
|
||||
c.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
TaskLog.log(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -505,13 +505,6 @@
|
|||
<type>war</type>
|
||||
</dependency>
|
||||
<!-- NOT READY YET
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-all</artifactId>
|
||||
<classifier>javadoc</classifier>
|
||||
<type>jar</type>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
-->
|
||||
<!-- <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-jndi</artifactId>
|
||||
<version>${project.version}</version> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId>
|
||||
|
|
|
@ -29,8 +29,8 @@ The project is 100% <a href="http://en.wikipedia.org/wiki/Open_source">Open Sour
|
|||
<ul>
|
||||
<li><a href="/test/">Test Jetty Webapp</a></li>
|
||||
<li><a href="/async-rest/">Async Rest</a></li>
|
||||
<li><a href="/javadoc/">Javadoc context</a></li>
|
||||
<li><a href="/xref/">Proxy to xref</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="/oldContextPath/">Redirected Context</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
|
|
|
@ -78,7 +78,7 @@ public class HttpParser
|
|||
private HttpMethod _method;
|
||||
private String _methodString;
|
||||
private HttpVersion _version;
|
||||
private String _uri;
|
||||
private ByteBuffer _uri=ByteBuffer.allocate(128); // Tune?
|
||||
private byte _eol;
|
||||
private EndOfContent _endOfContent;
|
||||
private long _contentLength;
|
||||
|
@ -87,12 +87,10 @@ public class HttpParser
|
|||
private int _chunkPosition;
|
||||
private boolean _headResponse;
|
||||
private ByteBuffer _contentChunk;
|
||||
// private final Trie<HttpField> _connectionFields=(Trie<HttpField>)HttpField.CONNECTION.clone();
|
||||
private final Trie<HttpField> _connectionFields=new Trie(512);
|
||||
private final Trie<HttpField> _connectionFields=new Trie<>(512);
|
||||
|
||||
private int _length;
|
||||
private final StringBuilder _string=new StringBuilder();
|
||||
private final Utf8StringBuilder _utf8=new Utf8StringBuilder();
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public HttpParser(RequestHandler<ByteBuffer> handler)
|
||||
|
@ -360,9 +358,39 @@ public class HttpParser
|
|||
}
|
||||
else
|
||||
{
|
||||
_uri.clear();
|
||||
setState(State.URI);
|
||||
_utf8.reset();
|
||||
_utf8.append(ch);
|
||||
// quick scan for space or EoBuffer
|
||||
if (buffer.hasArray())
|
||||
{
|
||||
byte[] array=buffer.array();
|
||||
int p=buffer.arrayOffset()+buffer.position();
|
||||
int l=buffer.arrayOffset()+buffer.limit();
|
||||
int i=p;
|
||||
while (i<l && array[i]>HttpTokens.SPACE)
|
||||
i++;
|
||||
|
||||
int len=i-p;
|
||||
_headerBytes+=len;
|
||||
|
||||
if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
|
||||
{
|
||||
LOG.warn("URI is too large >"+_maxHeaderBytes);
|
||||
badMessage(buffer,HttpStatus.REQUEST_URI_TOO_LONG_414,null);
|
||||
return true;
|
||||
}
|
||||
if (_uri.remaining()<len)
|
||||
{
|
||||
ByteBuffer uri = ByteBuffer.allocate(_uri.capacity()+2*len);
|
||||
_uri.flip();
|
||||
uri.put(_uri);
|
||||
_uri=uri;
|
||||
}
|
||||
_uri.put(array,p-1,len+1);
|
||||
buffer.position(i-buffer.arrayOffset());
|
||||
}
|
||||
else
|
||||
_uri.put(ch);
|
||||
}
|
||||
}
|
||||
else if (ch < HttpTokens.SPACE)
|
||||
|
@ -396,15 +424,12 @@ public class HttpParser
|
|||
case URI:
|
||||
if (ch == HttpTokens.SPACE)
|
||||
{
|
||||
_uri=_utf8.toString();
|
||||
_utf8.reset();
|
||||
setState(State.SPACE2);
|
||||
}
|
||||
else if (ch < HttpTokens.SPACE && ch>=0)
|
||||
{
|
||||
// HTTP/0.9
|
||||
_uri=_utf8.toString();
|
||||
_utf8.reset();
|
||||
_uri.flip();
|
||||
return_from_parse|=_requestHandler.startRequest(_method,_methodString,_uri,null);
|
||||
setState(State.END);
|
||||
BufferUtil.clear(buffer);
|
||||
|
@ -412,7 +437,16 @@ public class HttpParser
|
|||
return_from_parse|=_handler.messageComplete();
|
||||
}
|
||||
else
|
||||
_utf8.append(ch);
|
||||
{
|
||||
if (!_uri.hasRemaining())
|
||||
{
|
||||
ByteBuffer uri = ByteBuffer.allocate(_uri.capacity()*2);
|
||||
_uri.flip();
|
||||
uri.put(_uri);
|
||||
_uri=uri;
|
||||
}
|
||||
_uri.put(ch);
|
||||
}
|
||||
break;
|
||||
|
||||
case SPACE2:
|
||||
|
@ -439,6 +473,7 @@ public class HttpParser
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
@ -455,6 +490,7 @@ public class HttpParser
|
|||
else
|
||||
{
|
||||
// HTTP/0.9
|
||||
_uri.flip();
|
||||
return_from_parse|=_requestHandler.startRequest(_method,_methodString,_uri, null);
|
||||
setState(State.END);
|
||||
BufferUtil.clear(buffer);
|
||||
|
@ -477,6 +513,7 @@ public class HttpParser
|
|||
|
||||
_eol=ch;
|
||||
setState(State.HEADER);
|
||||
_uri.flip();
|
||||
return_from_parse|=_requestHandler.startRequest(_method,_methodString,_uri, _version);
|
||||
continue;
|
||||
}
|
||||
|
@ -1001,7 +1038,6 @@ public class HttpParser
|
|||
_version=null;
|
||||
_method=null;
|
||||
_methodString=null;
|
||||
_uri=null;
|
||||
_endOfContent=EndOfContent.UNKNOWN_CONTENT;
|
||||
_header=null;
|
||||
quickStart(buffer);
|
||||
|
@ -1214,7 +1250,6 @@ public class HttpParser
|
|||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
BufferUtil.clear(buffer);
|
||||
if (isClosed())
|
||||
{
|
||||
|
@ -1360,8 +1395,13 @@ public class HttpParser
|
|||
{
|
||||
/**
|
||||
* This is the method called by parser when the HTTP request line is parsed
|
||||
* @param method The method as enum if of a known type
|
||||
* @param methodString The method as a string
|
||||
* @param uri The raw bytes of the URI. These are copied into a ByteBuffer that will not be changed until this parser is reset and reused.
|
||||
* @param version
|
||||
* @return true if handling parsing should return.
|
||||
*/
|
||||
public abstract boolean startRequest(HttpMethod method, String methodString, String uri, HttpVersion version);
|
||||
public abstract boolean startRequest(HttpMethod method, String methodString, ByteBuffer uri, HttpVersion version);
|
||||
|
||||
/**
|
||||
* This is the method called by the parser after it has parsed the host header (and checked it's format). This is
|
||||
|
|
|
@ -237,10 +237,10 @@ public class HttpTester
|
|||
private String _uri;
|
||||
|
||||
@Override
|
||||
public boolean startRequest(HttpMethod method, String methodString, String uri, HttpVersion version)
|
||||
public boolean startRequest(HttpMethod method, String methodString, ByteBuffer uri, HttpVersion version)
|
||||
{
|
||||
_method=methodString;
|
||||
_uri=uri;
|
||||
_uri=BufferUtil.toUTF8String(uri);
|
||||
_version=version;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ public class HttpURI
|
|||
|
||||
public void parse(String raw)
|
||||
{
|
||||
byte[] b = StringUtil.getBytes(raw);
|
||||
byte[] b = StringUtil.getUtf8Bytes(raw);
|
||||
parse2(b,0,b.length);
|
||||
_rawString=raw;
|
||||
}
|
||||
|
@ -566,9 +566,7 @@ public class HttpURI
|
|||
if (_path==_param)
|
||||
return null;
|
||||
|
||||
int length = _param-_path;
|
||||
byte[] bytes=null;
|
||||
int n=0;
|
||||
Utf8StringBuilder utf8b=null;
|
||||
|
||||
for (int i=_path;i<_param;i++)
|
||||
{
|
||||
|
@ -576,32 +574,48 @@ public class HttpURI
|
|||
|
||||
if (b=='%')
|
||||
{
|
||||
if (utf8b==null)
|
||||
{
|
||||
utf8b=new Utf8StringBuilder();
|
||||
utf8b.append(_raw,_path,i-_path);
|
||||
}
|
||||
|
||||
if ((i+2)>=_param)
|
||||
throw new IllegalArgumentException("Bad % encoding: "+this);
|
||||
if (_raw[i+1]=='u')
|
||||
{
|
||||
if ((i+5)>=_param)
|
||||
throw new IllegalArgumentException("Bad %u encoding: "+this);
|
||||
try
|
||||
{
|
||||
String unicode = new String(Character.toChars(TypeUtil.parseInt(_raw,i+2,4,16)));
|
||||
utf8b.getStringBuilder().append(unicode);
|
||||
i+=5;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
b=(byte)(0xff&TypeUtil.parseInt(_raw,i+1,2,16));
|
||||
utf8b.append(b);
|
||||
i+=2;
|
||||
}
|
||||
else if (bytes==null)
|
||||
{
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bytes==null)
|
||||
else if (utf8b!=null)
|
||||
{
|
||||
bytes=new byte[length];
|
||||
System.arraycopy(_raw,_path,bytes,0,n);
|
||||
utf8b.append(b);
|
||||
}
|
||||
}
|
||||
|
||||
bytes[n++]=b;
|
||||
if (utf8b==null)
|
||||
return StringUtil.toUTF8String(_raw, _path, _param-_path);
|
||||
return utf8b.toString();
|
||||
}
|
||||
|
||||
if (bytes==null)
|
||||
return new String(_raw,_path,length,_charset);
|
||||
return new String(bytes,0,n,_charset);
|
||||
}
|
||||
|
||||
|
||||
public String getDecodedPath(String encoding)
|
||||
{
|
||||
if (_path==_param)
|
||||
|
@ -617,23 +631,46 @@ public class HttpURI
|
|||
|
||||
if (b=='%')
|
||||
{
|
||||
if (bytes==null)
|
||||
{
|
||||
bytes=new byte[length];
|
||||
System.arraycopy(_raw,_path,bytes,0,n);
|
||||
}
|
||||
|
||||
if ((i+2)>=_param)
|
||||
throw new IllegalArgumentException("Bad % encoding: "+this);
|
||||
if (_raw[i+1]=='u')
|
||||
{
|
||||
if ((i+5)>=_param)
|
||||
throw new IllegalArgumentException("Bad %u encoding: "+this);
|
||||
|
||||
try
|
||||
{
|
||||
String unicode = new String(Character.toChars(TypeUtil.parseInt(_raw,i+2,4,16)));
|
||||
byte[] encoded = unicode.getBytes(encoding);
|
||||
System.arraycopy(encoded,0,bytes,n,encoded.length);
|
||||
n+=encoded.length;
|
||||
i+=5;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
b=(byte)(0xff&TypeUtil.parseInt(_raw,i+1,2,16));
|
||||
bytes[n++]=b;
|
||||
i+=2;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (bytes==null)
|
||||
{
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bytes==null)
|
||||
{
|
||||
bytes=new byte[length];
|
||||
System.arraycopy(_raw,_path,bytes,0,n);
|
||||
}
|
||||
|
||||
bytes[n++]=b;
|
||||
}
|
||||
|
||||
|
@ -644,12 +681,6 @@ public class HttpURI
|
|||
return StringUtil.toString(bytes,0,n,encoding);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public String getPathAndParam()
|
||||
{
|
||||
if (_path==_query)
|
||||
|
@ -697,17 +728,17 @@ public class HttpURI
|
|||
return new String(_raw,_fragment+1,_end-_fragment-1,_charset);
|
||||
}
|
||||
|
||||
public void decodeQueryTo(MultiMap parameters)
|
||||
public void decodeQueryTo(MultiMap<String> parameters)
|
||||
{
|
||||
if (_query==_fragment)
|
||||
return;
|
||||
if (_charset==StringUtil.__UTF8_CHARSET)
|
||||
UrlEncoded.decodeUtf8To(_raw,_query+1,_fragment-_query-1,parameters);
|
||||
else
|
||||
UrlEncoded.decodeTo(StringUtil.toString(_raw,_query+1,_fragment-_query-1,_charset.toString()),parameters,_charset.toString());
|
||||
UrlEncoded.decodeTo(StringUtil.toString(_raw,_query+1,_fragment-_query-1,_charset.toString()),parameters,_charset.toString(),-1);
|
||||
}
|
||||
|
||||
public void decodeQueryTo(MultiMap parameters, String encoding) throws UnsupportedEncodingException
|
||||
public void decodeQueryTo(MultiMap<String> parameters, String encoding) throws UnsupportedEncodingException
|
||||
{
|
||||
if (_query==_fragment)
|
||||
return;
|
||||
|
@ -715,7 +746,7 @@ public class HttpURI
|
|||
if (encoding==null || StringUtil.isUTF8(encoding))
|
||||
UrlEncoded.decodeUtf8To(_raw,_query+1,_fragment-_query-1,parameters);
|
||||
else
|
||||
UrlEncoded.decodeTo(StringUtil.toString(_raw,_query+1,_fragment-_query-1,encoding),parameters,encoding);
|
||||
UrlEncoded.decodeTo(StringUtil.toString(_raw,_query+1,_fragment-_query-1,encoding),parameters,encoding,-1);
|
||||
}
|
||||
|
||||
public void clear()
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
*=application/octet-stream
|
||||
ai=application/postscript
|
||||
aif=audio/x-aiff
|
||||
aifc=audio/x-aiff
|
||||
|
|
|
@ -843,14 +843,14 @@ public class HttpParserTest
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean startRequest(HttpMethod httpMethod, String method, String uri, HttpVersion version)
|
||||
public boolean startRequest(HttpMethod httpMethod, String method, ByteBuffer uri, HttpVersion version)
|
||||
{
|
||||
request=true;
|
||||
_h= -1;
|
||||
_hdr= new String[10];
|
||||
_val= new String[10];
|
||||
_methodOrVersion= method;
|
||||
_uriOrStatus= uri;
|
||||
_uriOrStatus= BufferUtil.toUTF8String(uri);
|
||||
_versionOrReason= version==null?null:version.asString();
|
||||
|
||||
fields=new HttpFields();
|
||||
|
|
|
@ -18,10 +18,11 @@
|
|||
|
||||
package org.eclipse.jetty.http;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class MimeTypesTest
|
||||
{
|
||||
|
@ -61,13 +62,9 @@ public class MimeTypesTest
|
|||
@Test
|
||||
public void testGetMimeByExtension_NoExtension()
|
||||
{
|
||||
assertMimeTypeByExtension("application/octet-stream", "README");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMimeByExtensionWithoutExistingMimeMapping()
|
||||
{
|
||||
assertMimeTypeByExtension("application/octet-stream", "awesome-font.ttf");
|
||||
MimeTypes mimetypes = new MimeTypes();
|
||||
String contentType = mimetypes.getMimeByExtension("README");
|
||||
assertNull(contentType);
|
||||
}
|
||||
|
||||
private void assertMimeTypeByExtension(String expectedMimeType, String filename)
|
||||
|
|
|
@ -42,6 +42,7 @@ import org.eclipse.jetty.security.LoginService;
|
|||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.RequestLog;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ShutdownMonitor;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
|
@ -470,6 +471,14 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
{
|
||||
getLog().debug("Starting Jetty Server ...");
|
||||
|
||||
if(stopPort>0 && stopKey!=null)
|
||||
{
|
||||
ShutdownMonitor monitor = ShutdownMonitor.getInstance();
|
||||
monitor.setPort(stopPort);
|
||||
monitor.setKey(stopKey);
|
||||
monitor.setExitVm(!daemon);
|
||||
}
|
||||
|
||||
printSystemProperties();
|
||||
|
||||
//apply any config from a jetty.xml file first which is able to
|
||||
|
@ -530,11 +539,6 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
|||
|
||||
getLog().info("Started Jetty Server");
|
||||
|
||||
if(stopPort>0 && stopKey!=null)
|
||||
{
|
||||
Monitor monitor = new Monitor(stopPort, stopKey, new Server[]{server}, !daemon);
|
||||
monitor.start();
|
||||
}
|
||||
|
||||
// start the scanner thread (if necessary) on the main webapp
|
||||
configureScanner ();
|
||||
|
|
|
@ -1,148 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 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.maven.plugin;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.LineNumberReader;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Monitor
|
||||
*
|
||||
* Listens for stop commands eg via mvn jetty:stop and
|
||||
* causes jetty to stop either by exiting the jvm, or
|
||||
* by stopping the Server instances. The choice of
|
||||
* behaviour is controlled by either passing true
|
||||
* (exit jvm) or false (stop Servers) in the constructor.
|
||||
*
|
||||
*/
|
||||
public class Monitor extends Thread
|
||||
{
|
||||
private String _key;
|
||||
private Server[] _servers;
|
||||
|
||||
ServerSocket _serverSocket;
|
||||
boolean _kill;
|
||||
|
||||
public Monitor(int port, String key, Server[] servers, boolean kill)
|
||||
throws UnknownHostException, IOException
|
||||
{
|
||||
if (port <= 0)
|
||||
throw new IllegalStateException ("Bad stop port");
|
||||
if (key==null)
|
||||
throw new IllegalStateException("Bad stop key");
|
||||
|
||||
_key = key;
|
||||
_servers = servers;
|
||||
_kill = kill;
|
||||
setDaemon(true);
|
||||
setName("StopJettyPluginMonitor");
|
||||
InetSocketAddress address = new InetSocketAddress("127.0.0.1", port);
|
||||
_serverSocket=new ServerSocket();
|
||||
_serverSocket.setReuseAddress(true);
|
||||
try
|
||||
{
|
||||
_serverSocket.bind(address,1);
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
System.out.println("Error binding to stop port 127.0.0.1:"+port);
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
while (_serverSocket != null)
|
||||
{
|
||||
Socket socket = null;
|
||||
try
|
||||
{
|
||||
socket = _serverSocket.accept();
|
||||
socket.setSoLinger(false, 0);
|
||||
LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
|
||||
|
||||
String key = lin.readLine();
|
||||
if (!_key.equals(key)) continue;
|
||||
String cmd = lin.readLine();
|
||||
if ("stop".equals(cmd))
|
||||
{
|
||||
try{socket.close();}catch (Exception e){e.printStackTrace();}
|
||||
try{socket.close();}catch (Exception e){e.printStackTrace();}
|
||||
try{_serverSocket.close();}catch (Exception e){e.printStackTrace();}
|
||||
|
||||
_serverSocket = null;
|
||||
|
||||
if (_kill)
|
||||
{
|
||||
System.out.println("Killing Jetty");
|
||||
System.exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i=0; _servers != null && i < _servers.length; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
System.out.println("Stopping server "+i);
|
||||
_servers[i].stop();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
System.out.println("Unsupported monitor operation");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (socket != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
socket.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
socket = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,6 +33,7 @@ import java.util.TreeMap;
|
|||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ShutdownMonitor;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -57,7 +58,7 @@ public class Starter
|
|||
|
||||
private JettyServer server;
|
||||
private JettyWebAppContext webApp;
|
||||
private Monitor monitor;
|
||||
|
||||
|
||||
private int stopPort=0;
|
||||
private String stopKey=null;
|
||||
|
@ -172,7 +173,10 @@ public class Starter
|
|||
System.err.println("STOP PORT="+stopPort+", STOP KEY="+stopKey);
|
||||
if(stopPort>0 && stopKey!=null)
|
||||
{
|
||||
monitor = new Monitor(stopPort, stopKey, new Server[]{server}, true);
|
||||
ShutdownMonitor monitor = ShutdownMonitor.getInstance();
|
||||
monitor.setPort(stopPort);
|
||||
monitor.setKey(stopKey);
|
||||
monitor.setExitVm(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -375,9 +379,6 @@ public class Starter
|
|||
*/
|
||||
public void run() throws Exception
|
||||
{
|
||||
if (monitor != null)
|
||||
monitor.start();
|
||||
|
||||
LOG.info("Started Jetty Server");
|
||||
server.start();
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ public class RewriteRegexRuleTest extends AbstractRuleTestCase
|
|||
if (test[5]!=null)
|
||||
{
|
||||
MultiMap<String> params=new MultiMap<String>();
|
||||
UrlEncoded.decodeTo(test[5],params,StringUtil.__UTF8);
|
||||
UrlEncoded.decodeTo(test[5],params,StringUtil.__UTF8_CHARSET,-1);
|
||||
|
||||
for (String n:params.keySet())
|
||||
assertEquals(params.getString(n),_request.getParameter(n));
|
||||
|
|
|
@ -1,131 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 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.runner;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Monitor
|
||||
*
|
||||
* Listens for stop commands eg via mvn jetty:stop and
|
||||
* causes jetty to stop by exiting the virtual machine
|
||||
*
|
||||
*/
|
||||
public class Monitor extends Thread
|
||||
{
|
||||
private String _key;
|
||||
|
||||
private ServerSocket _serverSocket;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Monitor(int port, String key)
|
||||
throws UnknownHostException, IOException
|
||||
{
|
||||
if (port <= 0)
|
||||
throw new IllegalStateException ("Bad stop port");
|
||||
if (key==null)
|
||||
throw new IllegalStateException("Bad stop key");
|
||||
|
||||
_key = key;
|
||||
|
||||
setDaemon(true);
|
||||
setName("JettyRunnerMonitor");
|
||||
|
||||
_serverSocket=new ServerSocket(port,1,InetAddress.getByName("127.0.0.1"));
|
||||
_serverSocket.setReuseAddress(true);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void run()
|
||||
{
|
||||
while (_serverSocket != null)
|
||||
{
|
||||
Socket socket = null;
|
||||
try
|
||||
{
|
||||
socket = _serverSocket.accept();
|
||||
socket.setSoLinger(false, 0);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
|
||||
String key = reader.readLine();
|
||||
if (!_key.equals(key)) continue;
|
||||
String cmd = reader.readLine();
|
||||
if ("stop".equals(cmd))
|
||||
{
|
||||
closeSocket(socket);
|
||||
closeServerSocket(_serverSocket);
|
||||
|
||||
System.err.println("Stopping Jetty");
|
||||
System.exit(0);
|
||||
}
|
||||
else
|
||||
System.err.println("Unsupported monitor operation: "+cmd);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
closeSocket(socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void closeSocket(Socket socket)
|
||||
{
|
||||
if (socket != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
socket.close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
socket = null;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void closeServerSocket(ServerSocket socket)
|
||||
{
|
||||
if (socket != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
socket.close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
socket = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,6 +38,7 @@ import org.eclipse.jetty.server.Handler;
|
|||
import org.eclipse.jetty.server.NCSARequestLog;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.ShutdownMonitor;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
|
@ -84,7 +85,6 @@ public class Runner
|
|||
public static final int __defaultPort = 8080;
|
||||
|
||||
protected Server _server;
|
||||
protected Monitor _monitor;
|
||||
protected URLClassLoader _classLoader;
|
||||
protected Classpath _classpath = new Classpath();
|
||||
protected ContextHandlerCollection _contexts;
|
||||
|
@ -461,7 +461,10 @@ public class Runner
|
|||
break;
|
||||
|
||||
case 3:
|
||||
_monitor = new Monitor(stopPort, stopKey);
|
||||
ShutdownMonitor monitor = ShutdownMonitor.getInstance();
|
||||
monitor.setPort(stopPort);
|
||||
monitor.setKey(stopKey);
|
||||
monitor.setExitVm(true);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -498,11 +501,6 @@ public class Runner
|
|||
*/
|
||||
public void run() throws Exception
|
||||
{
|
||||
if (_monitor != null)
|
||||
{
|
||||
_monitor.start();
|
||||
}
|
||||
|
||||
_server.start();
|
||||
_server.join();
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ public class Dispatcher implements RequestDispatcher
|
|||
}
|
||||
|
||||
MultiMap<String> parameters=new MultiMap<>();
|
||||
UrlEncoded.decodeTo(query,parameters,baseRequest.getCharacterEncoding());
|
||||
UrlEncoded.decodeTo(query,parameters,baseRequest.getCharacterEncoding(),-1);
|
||||
|
||||
if(old_params != null) {
|
||||
// Merge parameters.
|
||||
|
|
|
@ -373,7 +373,7 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean startRequest(HttpMethod httpMethod, String method, String uri, HttpVersion version)
|
||||
public boolean startRequest(HttpMethod httpMethod, String method, ByteBuffer uri, HttpVersion version)
|
||||
{
|
||||
_expect = false;
|
||||
_expect100Continue = false;
|
||||
|
@ -384,9 +384,9 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
|
|||
_request.setMethod(httpMethod, method);
|
||||
|
||||
if (httpMethod == HttpMethod.CONNECT)
|
||||
_uri.parseConnect(uri);
|
||||
_uri.parseConnect(uri.array(),uri.arrayOffset()+uri.position(),uri.remaining());
|
||||
else
|
||||
_uri.parse(uri);
|
||||
_uri.parse(uri.array(),uri.arrayOffset()+uri.position(),uri.remaining());
|
||||
_request.setUri(_uri);
|
||||
|
||||
String path;
|
||||
|
@ -403,7 +403,10 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
|
|||
String info = URIUtil.canonicalPath(path);
|
||||
|
||||
if (info == null)
|
||||
{
|
||||
info = "/";
|
||||
_request.setRequestURI("");
|
||||
}
|
||||
_request.setPathInfo(info);
|
||||
_version = version == null ? HttpVersion.HTTP_0_9 : version;
|
||||
_request.setHttpVersion(_version);
|
||||
|
|
|
@ -2102,7 +2102,7 @@ public class Request implements HttpServletRequest
|
|||
{
|
||||
// extract parameters from dispatch query
|
||||
MultiMap<String> parameters = new MultiMap<>();
|
||||
UrlEncoded.decodeTo(query,parameters, StringUtil.__UTF8); //have to assume UTF-8 because we can't know otherwise
|
||||
UrlEncoded.decodeTo(query,parameters, StringUtil.__UTF8_CHARSET,-1); //have to assume UTF-8 because we can't know otherwise
|
||||
|
||||
boolean merge_old_query = false;
|
||||
|
||||
|
@ -2123,11 +2123,11 @@ public class Request implements HttpServletRequest
|
|||
{
|
||||
StringBuilder overridden_query_string = new StringBuilder();
|
||||
MultiMap<String> overridden_old_query = new MultiMap<>();
|
||||
UrlEncoded.decodeTo(_queryString,overridden_old_query,getQueryEncoding());//decode using any queryencoding set for the request
|
||||
UrlEncoded.decodeTo(_queryString,overridden_old_query,getQueryEncoding(),-1);//decode using any queryencoding set for the request
|
||||
|
||||
|
||||
MultiMap<String> overridden_new_query = new MultiMap<>();
|
||||
UrlEncoded.decodeTo(query,overridden_new_query,StringUtil.__UTF8); //have to assume utf8 as we cannot know otherwise
|
||||
UrlEncoded.decodeTo(query,overridden_new_query,StringUtil.__UTF8_CHARSET,-1); //have to assume utf8 as we cannot know otherwise
|
||||
|
||||
for(String name: overridden_old_query.keySet())
|
||||
{
|
||||
|
|
|
@ -383,7 +383,7 @@ public class ResourceCache
|
|||
_resource=resource;
|
||||
|
||||
String mimeType = _mimeTypes.getMimeByExtension(_resource.toString());
|
||||
_contentType=BufferUtil.toBuffer(mimeType);
|
||||
_contentType=(mimeType==null?null:BufferUtil.toBuffer(mimeType));
|
||||
boolean exists=resource.exists();
|
||||
_lastModified=exists?resource.lastModified():-1;
|
||||
_lastModifiedBytes=_lastModified<0?null:BufferUtil.toBuffer(HttpFields.formatDate(_lastModified));
|
||||
|
|
|
@ -270,8 +270,10 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
if (getStopAtShutdown())
|
||||
if (getStopAtShutdown()) {
|
||||
ShutdownThread.register(this);
|
||||
ShutdownMonitor.getInstance().start(); // initialize
|
||||
}
|
||||
|
||||
LOG.info("jetty-"+getVersion());
|
||||
HttpGenerator.setServerVersion(getVersion());
|
||||
|
|
|
@ -0,0 +1,317 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 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 java.io.InputStreamReader;
|
||||
import java.io.LineNumberReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.thread.ShutdownThread;
|
||||
|
||||
/**
|
||||
* Shutdown/Stop Monitor thread.
|
||||
* <p>
|
||||
* This thread listens on the port specified by the STOP.PORT system parameter (defaults to -1 for not listening) for request authenticated with the key given
|
||||
* by the STOP.KEY system parameter (defaults to "eclipse") for admin requests.
|
||||
* <p>
|
||||
* If the stop port is set to zero, then a random port is assigned and the port number is printed to stdout.
|
||||
* <p>
|
||||
* Commands "stop" and "status" are currently supported.
|
||||
*/
|
||||
public class ShutdownMonitor extends Thread
|
||||
{
|
||||
// Implementation of safe lazy init, using Initialization on Demand Holder technique.
|
||||
static class Holder
|
||||
{
|
||||
static ShutdownMonitor instance = new ShutdownMonitor();
|
||||
}
|
||||
|
||||
public static ShutdownMonitor getInstance()
|
||||
{
|
||||
return Holder.instance;
|
||||
}
|
||||
|
||||
private boolean DEBUG;
|
||||
private int port;
|
||||
private String key;
|
||||
private boolean exitVm;
|
||||
private ServerSocket serverSocket;
|
||||
|
||||
/**
|
||||
* Create a ShutdownMonitor using configuration from the System properties.
|
||||
* <p>
|
||||
* <code>STOP.PORT</code> = the port to listen on (empty, null, or values less than 0 disable the stop ability)<br>
|
||||
* <code>STOP.KEY</code> = the magic key/passphrase to allow the stop (defaults to "eclipse")<br>
|
||||
* <p>
|
||||
* Note: server socket will only listen on localhost, and a successful stop will issue a System.exit() call.
|
||||
*/
|
||||
private ShutdownMonitor()
|
||||
{
|
||||
Properties props = System.getProperties();
|
||||
|
||||
this.DEBUG = props.containsKey("DEBUG");
|
||||
|
||||
// Use values passed thru via /jetty-start/
|
||||
this.port = Integer.parseInt(props.getProperty("STOP.PORT","-1"));
|
||||
this.key = props.getProperty("STOP.KEY","eclipse");
|
||||
this.exitVm = true;
|
||||
}
|
||||
|
||||
private void close(ServerSocket server)
|
||||
{
|
||||
if (server == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
server.close();
|
||||
}
|
||||
catch (IOException ignore)
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
|
||||
private void close(Socket socket)
|
||||
{
|
||||
if (socket == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
socket.close();
|
||||
}
|
||||
catch (IOException ignore)
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
|
||||
private void debug(String format, Object... args)
|
||||
{
|
||||
if (DEBUG)
|
||||
{
|
||||
System.err.printf("[ShutdownMonitor] " + format + "%n",args);
|
||||
}
|
||||
}
|
||||
|
||||
private void debug(Throwable t)
|
||||
{
|
||||
if (DEBUG)
|
||||
{
|
||||
t.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
public String getKey()
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
public int getPort()
|
||||
{
|
||||
return port;
|
||||
}
|
||||
|
||||
public ServerSocket getServerSocket()
|
||||
{
|
||||
return serverSocket;
|
||||
}
|
||||
|
||||
public boolean isExitVm()
|
||||
{
|
||||
return exitVm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (serverSocket == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
Socket socket = null;
|
||||
try
|
||||
{
|
||||
socket = serverSocket.accept();
|
||||
|
||||
LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
|
||||
String key = lin.readLine();
|
||||
if (!this.key.equals(key))
|
||||
{
|
||||
System.err.println("Ignoring command with incorrect key");
|
||||
continue;
|
||||
}
|
||||
|
||||
OutputStream out = socket.getOutputStream();
|
||||
|
||||
String cmd = lin.readLine();
|
||||
debug("command=%s",cmd);
|
||||
if ("stop".equals(cmd))
|
||||
{
|
||||
// Graceful Shutdown
|
||||
debug("Issuing graceful shutdown..");
|
||||
ShutdownThread.getInstance().run();
|
||||
|
||||
// Reply to client
|
||||
debug("Informing client that we are stopped.");
|
||||
out.write("Stopped\r\n".getBytes(StringUtil.__UTF8));
|
||||
out.flush();
|
||||
|
||||
// Shutdown Monitor
|
||||
debug("Shutting down monitor");
|
||||
close(socket);
|
||||
close(serverSocket);
|
||||
|
||||
if (exitVm)
|
||||
{
|
||||
// Kill JVM
|
||||
debug("Killing JVM");
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
else if ("status".equals(cmd))
|
||||
{
|
||||
// Reply to client
|
||||
out.write("OK\r\n".getBytes(StringUtil.__UTF8));
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
debug(e);
|
||||
System.err.println(e.toString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
close(socket);
|
||||
socket = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setDebug(boolean flag)
|
||||
{
|
||||
this.DEBUG = flag;
|
||||
}
|
||||
|
||||
public void setExitVm(boolean exitVm)
|
||||
{
|
||||
if (isAlive())
|
||||
{
|
||||
throw new IllegalStateException("ShutdownMonitor already started");
|
||||
}
|
||||
this.exitVm = exitVm;
|
||||
}
|
||||
|
||||
public void setKey(String key)
|
||||
{
|
||||
if (isAlive())
|
||||
{
|
||||
throw new IllegalStateException("ShutdownMonitor already started");
|
||||
}
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public void setPort(int port)
|
||||
{
|
||||
if (isAlive())
|
||||
{
|
||||
throw new IllegalStateException("ShutdownMonitor already started");
|
||||
}
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public void start()
|
||||
{
|
||||
if (isAlive())
|
||||
{
|
||||
System.out.printf("ShutdownMonitor already started");
|
||||
return; // cannot start it again
|
||||
}
|
||||
startListenSocket();
|
||||
if (serverSocket == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
super.start();
|
||||
}
|
||||
|
||||
private void startListenSocket()
|
||||
{
|
||||
if (this.port < 0)
|
||||
{
|
||||
System.out.println("ShutdownMonitor not in use (port < 0): " + port);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
setDaemon(true);
|
||||
setName("ShutdownMonitor");
|
||||
|
||||
this.serverSocket = new ServerSocket(this.port,1,InetAddress.getByName("127.0.0.1"));
|
||||
if (this.port == 0)
|
||||
{
|
||||
// server assigned port in use
|
||||
this.port = serverSocket.getLocalPort();
|
||||
System.out.printf("STOP.PORT=%d%n",this.port);
|
||||
}
|
||||
|
||||
if (this.key == null)
|
||||
{
|
||||
// create random key
|
||||
this.key = Long.toString((long)(Long.MAX_VALUE * Math.random() + this.hashCode() + System.currentTimeMillis()),36);
|
||||
System.out.printf("STOP.KEY=%s%n",this.key);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
debug(e);
|
||||
System.err.println("Error binding monitor port " + this.port + ": " + e.toString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
// establish the port and key that are in use
|
||||
debug("STOP.PORT=%d",this.port);
|
||||
debug("STOP.KEY=%s",this.key);
|
||||
debug("%s",serverSocket);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s[port=%d]",this.getClass().getName(),port);
|
||||
}
|
||||
}
|
|
@ -192,7 +192,8 @@ public class HttpURITest
|
|||
/* 1*/ {"/path/%69nfo","/path/info", "UTF-8"},
|
||||
/* 2*/ {"http://host/path/%69nfo","/path/info", "UTF-8"},
|
||||
/* 3*/ {"http://host/path/%69nf%c2%a4","/path/inf\u00a4", "UTF-8"},
|
||||
/* 4*/ {"http://host/path/%E5", "/path/\u00e5", "ISO-8859-1"}
|
||||
/* 4*/ {"http://host/path/%E5", "/path/\u00e5", "ISO-8859-1"},
|
||||
/* 5*/ {"/foo/%u30ED/bar%3Fabc%3D123%26xyz%3D456","/foo/\u30ed/bar?abc=123&xyz=456","UTF-8"}
|
||||
};
|
||||
|
||||
@Test
|
||||
|
@ -205,10 +206,11 @@ public class HttpURITest
|
|||
uri.parse(encoding_tests[t][0]);
|
||||
assertEquals(""+t,encoding_tests[t][1],uri.getDecodedPath(encoding_tests[t][2]));
|
||||
|
||||
if ("UTF-8".equalsIgnoreCase(encoding_tests[t][2]))
|
||||
assertEquals(""+t,encoding_tests[t][1],uri.getDecodedPath());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNoPercentEncodingOfQueryUsingNonUTF8() throws Exception
|
||||
{
|
||||
|
@ -310,7 +312,7 @@ public class HttpURITest
|
|||
@Test
|
||||
public void testUnicodeErrors() throws UnsupportedEncodingException
|
||||
{
|
||||
String uri="http://server/path?invalid=data%u2021here";
|
||||
String uri="http://server/path?invalid=data%uXXXXhere%u000";
|
||||
try
|
||||
{
|
||||
URLDecoder.decode(uri,"UTF-8");
|
||||
|
|
|
@ -53,6 +53,7 @@ import org.eclipse.jetty.util.IO;
|
|||
import org.eclipse.jetty.util.MultiPartInputStreamParser;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.StdErrLog;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
|
@ -935,6 +936,7 @@ public class RequestTest
|
|||
@Test
|
||||
public void testHashDOS() throws Exception
|
||||
{
|
||||
((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(true);
|
||||
LOG.info("Expecting maxFormKeys limit and Closing HttpParser exceptions...");
|
||||
_server.setAttribute("org.eclipse.jetty.server.Request.maxFormContentSize",-1);
|
||||
_server.setAttribute("org.eclipse.jetty.server.Request.maxFormKeys",1000);
|
||||
|
@ -979,12 +981,19 @@ public class RequestTest
|
|||
"\r\n"+
|
||||
buf;
|
||||
|
||||
try
|
||||
{
|
||||
long start=System.currentTimeMillis();
|
||||
String response = _connector.getResponses(request);
|
||||
assertTrue(response.contains("200 OK"));
|
||||
assertTrue(response.contains("Form too many keys"));
|
||||
long now=System.currentTimeMillis();
|
||||
assertTrue((now-start)<5000);
|
||||
}
|
||||
finally
|
||||
{
|
||||
((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface RequestTester
|
||||
|
|
|
@ -966,7 +966,9 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
// content-length header
|
||||
//
|
||||
writeHeaders(response,content,-1);
|
||||
String mimetype=content.getContentType().toString();
|
||||
String mimetype=(content.getContentType()==null?null:content.getContentType().toString());
|
||||
if (mimetype==null)
|
||||
LOG.warn("Unknown mimetype for "+request.getRequestURI());
|
||||
MultiPartOutputStream multi = new MultiPartOutputStream(out);
|
||||
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
|
||||
|
||||
|
@ -993,7 +995,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
length+=
|
||||
((i>0)?2:0)+
|
||||
2+multi.getBoundary().length()+2+
|
||||
HttpHeader.CONTENT_TYPE.asString().length()+2+mimetype.length()+2+
|
||||
(mimetype==null?0:HttpHeader.CONTENT_TYPE.asString().length()+2+mimetype.length())+2+
|
||||
HttpHeader.CONTENT_RANGE.asString().length()+2+header[i].length()+2+
|
||||
2+
|
||||
(ibr.getLast(content_length)-ibr.getFirst(content_length))+1;
|
||||
|
|
|
@ -23,6 +23,8 @@ import java.io.FileOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.util.EnumSet;
|
||||
import javax.servlet.DispatcherType;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.servlet.Filter;
|
||||
|
@ -462,6 +464,153 @@ public class DefaultServletTest
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRangeRequests() throws Exception
|
||||
{
|
||||
testdir.ensureEmpty();
|
||||
File resBase = testdir.getFile("docroot");
|
||||
FS.ensureDirExists(resBase);
|
||||
File data = new File(resBase, "data.txt");
|
||||
createFile(data, "01234567890123456789012345678901234567890123456789012345678901234567890123456789");
|
||||
String resBasePath = resBase.getAbsolutePath();
|
||||
|
||||
ServletHolder defholder = context.addServlet(DefaultServlet.class, "/");
|
||||
defholder.setInitParameter("dirAllowed", "false");
|
||||
defholder.setInitParameter("redirectWelcome", "false");
|
||||
defholder.setInitParameter("welcomeServlets", "false");
|
||||
defholder.setInitParameter("gzip", "false");
|
||||
defholder.setInitParameter("acceptRanges", "true");
|
||||
defholder.setInitParameter("resourceBase", resBasePath);
|
||||
|
||||
String response = connector.getResponses("GET /context/data.txt HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n\r\n");
|
||||
assertResponseContains("200 OK", response);
|
||||
assertResponseContains("Accept-Ranges: bytes", response);
|
||||
|
||||
|
||||
|
||||
response = connector.getResponses("GET /context/data.txt HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n"+
|
||||
"Range: bytes=0-9\r\n" +
|
||||
"\r\n");
|
||||
assertResponseContains("206 Partial", response);
|
||||
assertResponseContains("Content-Type: text/plain", response);
|
||||
assertResponseContains("Content-Length: 10", response);
|
||||
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
||||
|
||||
|
||||
response = connector.getResponses("GET /context/data.txt HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n"+
|
||||
"Range: bytes=0-9,20-29,40-49\r\n" +
|
||||
"\r\n");
|
||||
int start = response.indexOf("--jetty");
|
||||
String body = response.substring(start);
|
||||
String boundary = body.substring(0, body.indexOf("\r\n"));
|
||||
assertResponseContains("206 Partial", response);
|
||||
assertResponseContains("Content-Type: multipart/byteranges; boundary=", response);
|
||||
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
||||
assertResponseContains("Content-Range: bytes 20-29/80", response);
|
||||
assertResponseContains("Content-Length: " + body.length(), response);
|
||||
assertTrue(body.endsWith(boundary + "--\r\n"));
|
||||
|
||||
response = connector.getResponses("GET /context/data.txt HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n"+
|
||||
"Range: bytes=0-9,20-29,40-49,70-79\r\n" +
|
||||
"\r\n");
|
||||
start = response.indexOf("--jetty");
|
||||
body = response.substring(start);
|
||||
boundary = body.substring(0, body.indexOf("\r\n"));
|
||||
assertResponseContains("206 Partial", response);
|
||||
assertResponseContains("Content-Type: multipart/byteranges; boundary=", response);
|
||||
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
||||
assertResponseContains("Content-Range: bytes 20-29/80", response);
|
||||
assertResponseContains("Content-Range: bytes 70-79/80", response);
|
||||
assertResponseContains("Content-Length: " + body.length(), response);
|
||||
assertTrue(body.endsWith(boundary + "--\r\n"));
|
||||
|
||||
response = connector.getResponses("GET /context/data.txt HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n"+
|
||||
"Range: bytes=0-9,20-29,40-49,60-60,70-79\r\n" +
|
||||
"\r\n");
|
||||
start = response.indexOf("--jetty");
|
||||
body = response.substring(start);
|
||||
boundary = body.substring(0, body.indexOf("\r\n"));
|
||||
assertResponseContains("206 Partial", response);
|
||||
assertResponseContains("Content-Type: multipart/byteranges; boundary=", response);
|
||||
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
||||
assertResponseContains("Content-Range: bytes 20-29/80", response);
|
||||
assertResponseContains("Content-Range: bytes 60-60/80", response);
|
||||
assertResponseContains("Content-Range: bytes 70-79/80", response);
|
||||
assertResponseContains("Content-Length: " + body.length(), response);
|
||||
assertTrue(body.endsWith(boundary + "--\r\n"));
|
||||
|
||||
//test a range request with a file with no suffix, therefore no mimetype
|
||||
|
||||
File nofilesuffix = new File(resBase, "nofilesuffix");
|
||||
createFile(nofilesuffix, "01234567890123456789012345678901234567890123456789012345678901234567890123456789");
|
||||
|
||||
response = connector.getResponses("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n"+
|
||||
"\r\n");
|
||||
assertResponseContains("200 OK", response);
|
||||
assertResponseContains("Accept-Ranges: bytes", response);
|
||||
|
||||
|
||||
|
||||
response = connector.getResponses("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n"+
|
||||
"Range: bytes=0-9\r\n" +
|
||||
"\r\n");
|
||||
assertResponseContains("206 Partial", response);
|
||||
assertResponseContains("Content-Length: 10", response);
|
||||
assertTrue(!response.contains("Content-Type:"));
|
||||
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
||||
|
||||
response = connector.getResponses("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n"+
|
||||
"Range: bytes=0-9,20-29,40-49\r\n" +
|
||||
"\r\n");
|
||||
start = response.indexOf("--jetty");
|
||||
body = response.substring(start);
|
||||
boundary = body.substring(0, body.indexOf("\r\n"));
|
||||
assertResponseContains("206 Partial", response);
|
||||
assertResponseContains("Content-Type: multipart/byteranges; boundary=", response);
|
||||
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
||||
assertResponseContains("Content-Range: bytes 20-29/80", response);
|
||||
assertResponseContains("Content-Length: " + body.length(), response);
|
||||
assertTrue(body.endsWith(boundary + "--\r\n"));
|
||||
|
||||
|
||||
|
||||
response = connector.getResponses("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n"+
|
||||
"Range: bytes=0-9,20-29,40-49,60-60,70-79\r\n" +
|
||||
"\r\n");
|
||||
start = response.indexOf("--jetty");
|
||||
body = response.substring(start);
|
||||
boundary = body.substring(0, body.indexOf("\r\n"));
|
||||
assertResponseContains("206 Partial", response);
|
||||
assertResponseContains("Content-Type: multipart/byteranges; boundary=", response);
|
||||
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
||||
assertResponseContains("Content-Range: bytes 20-29/80", response);
|
||||
assertResponseContains("Content-Range: bytes 60-60/80", response);
|
||||
assertResponseContains("Content-Range: bytes 70-79/80", response);
|
||||
assertResponseContains("Content-Length: " + body.length(), response);
|
||||
assertTrue(body.endsWith(boundary + "--\r\n"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testFiltered() throws Exception
|
||||
{
|
||||
|
|
|
@ -50,6 +50,9 @@ import org.eclipse.jetty.util.LazyList;
|
|||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.eclipse.jetty.util.MultiPartInputStreamParser;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -77,6 +80,7 @@ import org.eclipse.jetty.util.StringUtil;
|
|||
*/
|
||||
public class MultiPartFilter implements Filter
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(MultiPartFilter.class);
|
||||
public final static String CONTENT_TYPE_SUFFIX=".org.eclipse.jetty.servlet.contentType";
|
||||
private final static String MULTIPART = "org.eclipse.jetty.servlet.MultiPartFile.multiPartInputStream";
|
||||
private File tempdir;
|
||||
|
@ -275,11 +279,13 @@ public class MultiPartFilter implements Filter
|
|||
@Override
|
||||
public Map<String, String[]> getParameterMap()
|
||||
{
|
||||
Map<String, String[]> cmap = new HashMap<>();
|
||||
Map<String, String[]> cmap = new HashMap<String,String[]>();
|
||||
|
||||
for ( String key : _params.keySet() )
|
||||
for ( Object key : _params.keySet() )
|
||||
{
|
||||
cmap.put(key,getParameterValues(key));
|
||||
String[] a = LazyList.toStringArray(getParameter((String)key));
|
||||
cmap.put((String)key,a);
|
||||
|
||||
}
|
||||
|
||||
return Collections.unmodifiableMap(cmap);
|
||||
|
|
|
@ -18,10 +18,23 @@
|
|||
|
||||
package org.eclipse.jetty.servlets;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.Socket;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
|
@ -68,6 +81,7 @@ public class MultipartFilterTest
|
|||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
System.err.println(req.getParameter("field1"));
|
||||
assertNotNull(req.getParameter("fileup"));
|
||||
assertNotNull(req.getParameter("fileup"+MultiPartFilter.CONTENT_TYPE_SUFFIX));
|
||||
assertEquals(req.getParameter("fileup"+MultiPartFilter.CONTENT_TYPE_SUFFIX), "application/octet-stream");
|
||||
|
@ -194,6 +208,104 @@ public class MultipartFilterTest
|
|||
assertTrue(response.getContent().indexOf("brown cow")>=0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadlyEncodedFilename() throws Exception
|
||||
{
|
||||
// generated and parsed test
|
||||
HttpTester.Request request = HttpTester.newRequest();
|
||||
HttpTester.Response response;
|
||||
// test GET
|
||||
request.setMethod("POST");
|
||||
request.setVersion("HTTP/1.0");
|
||||
request.setHeader("Host","tester");
|
||||
request.setURI("/context/dump");
|
||||
|
||||
String boundary="XyXyXy";
|
||||
request.setHeader("Content-Type","multipart/form-data; boundary="+boundary);
|
||||
|
||||
|
||||
String content = "--" + boundary + "\r\n"+
|
||||
"Content-Disposition: form-data; name=\"fileup\"; filename=\"Taken on Aug 22 \\ 2012.jpg\"\r\n"+
|
||||
"Content-Type: application/octet-stream\r\n\r\n"+
|
||||
"How now brown cow."+
|
||||
"\r\n--" + boundary + "--\r\n\r\n";
|
||||
|
||||
request.setContent(content);
|
||||
|
||||
response = HttpTester.parseResponse(tester.getResponses(request.generate()));
|
||||
|
||||
//System.out.printf("Content: [%s]%n", response.getContent());
|
||||
assertThat(response.getStatus(), is(HttpServletResponse.SC_OK));
|
||||
assertThat(response.getContent(), containsString("Filename [Taken on Aug 22 \\ 2012.jpg]"));
|
||||
assertThat(response.getContent(), containsString("How now brown cow."));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadlyEncodedMSFilename() throws Exception
|
||||
{
|
||||
// generated and parsed test
|
||||
HttpTester.Request request = HttpTester.newRequest();
|
||||
HttpTester.Response response;
|
||||
// test GET
|
||||
request.setMethod("POST");
|
||||
request.setVersion("HTTP/1.0");
|
||||
request.setHeader("Host","tester");
|
||||
request.setURI("/context/dump");
|
||||
|
||||
String boundary="XyXyXy";
|
||||
request.setHeader("Content-Type","multipart/form-data; boundary="+boundary);
|
||||
|
||||
|
||||
String content = "--" + boundary + "\r\n"+
|
||||
"Content-Disposition: form-data; name=\"fileup\"; filename=\"c:\\this\\really\\is\\some\\path\\to\\a\\file.txt\"\r\n"+
|
||||
"Content-Type: application/octet-stream\r\n\r\n"+
|
||||
"How now brown cow."+
|
||||
"\r\n--" + boundary + "--\r\n\r\n";
|
||||
|
||||
request.setContent(content);
|
||||
|
||||
response = HttpTester.parseResponse(tester.getResponses(request.generate()));
|
||||
|
||||
//System.out.printf("Content: [%s]%n", response.getContent());
|
||||
|
||||
assertThat(response.getStatus(), is(HttpServletResponse.SC_OK));
|
||||
assertThat(response.getContent(), containsString("Filename [c:\\this\\really\\is\\some\\path\\to\\a\\file.txt]"));
|
||||
assertThat(response.getContent(), containsString("How now brown cow."));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCorrectlyEncodedMSFilename() throws Exception
|
||||
{
|
||||
// generated and parsed test
|
||||
HttpTester.Request request = HttpTester.newRequest();
|
||||
HttpTester.Response response;
|
||||
// test GET
|
||||
request.setMethod("POST");
|
||||
request.setVersion("HTTP/1.0");
|
||||
request.setHeader("Host","tester");
|
||||
request.setURI("/context/dump");
|
||||
|
||||
String boundary="XyXyXy";
|
||||
request.setHeader("Content-Type","multipart/form-data; boundary="+boundary);
|
||||
|
||||
|
||||
String content = "--" + boundary + "\r\n"+
|
||||
"Content-Disposition: form-data; name=\"fileup\"; filename=\"c:\\\\this\\\\really\\\\is\\\\some\\\\path\\\\to\\\\a\\\\file.txt\"\r\n"+
|
||||
"Content-Type: application/octet-stream\r\n\r\n"+
|
||||
"How now brown cow."+
|
||||
"\r\n--" + boundary + "--\r\n\r\n";
|
||||
|
||||
request.setContent(content);
|
||||
|
||||
response = HttpTester.parseResponse(tester.getResponses(request.generate()));
|
||||
|
||||
//System.out.printf("Content: [%s]%n", response.getContent());
|
||||
assertThat(response.getStatus(), is(HttpServletResponse.SC_OK));
|
||||
assertThat(response.getContent(), containsString("Filename [c:\\this\\really\\is\\some\\path\\to\\a\\file.txt]"));
|
||||
assertThat(response.getContent(), containsString("How now brown cow."));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Test multipart with parts encoded in base64 (RFC1521 section 5)
|
||||
*/
|
||||
|
@ -467,20 +579,149 @@ public class MultipartFilterTest
|
|||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testNoBody()
|
||||
throws Exception
|
||||
{
|
||||
String boundary="XyXyXy";
|
||||
// generated and parsed test
|
||||
HttpTester.Request request = HttpTester.newRequest();
|
||||
HttpTester.Response response;
|
||||
|
||||
request.setMethod("POST");
|
||||
request.setVersion("HTTP/1.0");
|
||||
request.setHeader("Host","tester");
|
||||
request.setURI("/context/dump");
|
||||
request.setHeader("Content-Type","multipart/form-data; boundary="+boundary);
|
||||
|
||||
response = HttpTester.parseResponse(tester.getResponses(request.generate()));
|
||||
assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, response.getStatus());
|
||||
assertTrue(response.getReason().startsWith("Missing content"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWhitespaceBodyWithCRLF()
|
||||
throws Exception
|
||||
{
|
||||
String whitespace = " \n\n\n\r\n\r\n\r\n\r\n";
|
||||
|
||||
String boundary="XyXyXy";
|
||||
// generated and parsed test
|
||||
HttpTester.Request request = HttpTester.newRequest();
|
||||
HttpTester.Response response;
|
||||
request.setMethod("POST");
|
||||
request.setVersion("HTTP/1.0");
|
||||
request.setHeader("Host","tester");
|
||||
request.setURI("/context/dump");
|
||||
request.setHeader("Content-Type","multipart/form-data; boundary="+boundary);
|
||||
request.setContent(whitespace);
|
||||
|
||||
response = HttpTester.parseResponse(tester.getResponses(request.generate()));
|
||||
assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, response.getStatus());
|
||||
assertTrue(response.getReason().startsWith("Missing initial"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testWhitespaceBody()
|
||||
throws Exception
|
||||
{
|
||||
String whitespace = " ";
|
||||
|
||||
String boundary="XyXyXy";
|
||||
// generated and parsed test
|
||||
HttpTester.Request request = HttpTester.newRequest();
|
||||
HttpTester.Response response;
|
||||
request.setMethod("POST");
|
||||
request.setVersion("HTTP/1.0");
|
||||
request.setHeader("Host","tester");
|
||||
request.setURI("/context/dump");
|
||||
request.setHeader("Content-Type","multipart/form-data; boundary="+boundary);
|
||||
request.setContent(whitespace);
|
||||
|
||||
response = HttpTester.parseResponse(tester.getResponses(request.generate()));
|
||||
assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, response.getStatus());
|
||||
assertTrue(response.getReason().startsWith("Missing initial"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLeadingWhitespaceBodyWithCRLF()
|
||||
throws Exception
|
||||
{
|
||||
String boundary = "AaB03x";
|
||||
|
||||
String body = " \n\n\n\r\n\r\n\r\n\r\n"+
|
||||
"--AaB03x\r\n"+
|
||||
"content-disposition: form-data; name=\"field1\"\r\n"+
|
||||
"\r\n"+
|
||||
"Joe Blow\r\n"+
|
||||
"--AaB03x\r\n"+
|
||||
"Content-Disposition: form-data; name=\"fileup\"; filename=\"test.upload\"\r\n"+
|
||||
"Content-Type: application/octet-stream\r\n"+
|
||||
"\r\n" +
|
||||
"aaaa,bbbbb"+"\r\n" +
|
||||
"--AaB03x--\r\n";
|
||||
|
||||
// generated and parsed test
|
||||
HttpTester.Request request = HttpTester.newRequest();
|
||||
HttpTester.Response response;
|
||||
request.setMethod("POST");
|
||||
request.setVersion("HTTP/1.0");
|
||||
request.setHeader("Host","tester");
|
||||
request.setURI("/context/dump");
|
||||
request.setHeader("Content-Type","multipart/form-data; boundary="+boundary);
|
||||
request.setContent(body);
|
||||
|
||||
response = HttpTester.parseResponse(tester.getResponses(request.generate()));
|
||||
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
|
||||
assertTrue(response.getContent().contains("aaaa,bbbbb"));
|
||||
}
|
||||
@Test
|
||||
public void testLeadingWhitespaceBodyWithoutCRLF()
|
||||
throws Exception
|
||||
{
|
||||
String boundary = "AaB03x";
|
||||
|
||||
String body = " "+
|
||||
"--AaB03x\r\n"+
|
||||
"content-disposition: form-data; name=\"field1\"\r\n"+
|
||||
"\r\n"+
|
||||
"Joe Blow\r\n"+
|
||||
"--AaB03x\r\n"+
|
||||
"Content-Disposition: form-data; name=\"fileup\"; filename=\"test.upload\"\r\n"+
|
||||
"Content-Type: application/octet-stream\r\n"+
|
||||
"\r\n" +
|
||||
"aaaa,bbbbb"+"\r\n" +
|
||||
"--AaB03x--\r\n";
|
||||
|
||||
// generated and parsed test
|
||||
HttpTester.Request request = HttpTester.newRequest();
|
||||
HttpTester.Response response;
|
||||
request.setMethod("POST");
|
||||
request.setVersion("HTTP/1.0");
|
||||
request.setHeader("Host","tester");
|
||||
request.setURI("/context/dump");
|
||||
request.setHeader("Content-Type","multipart/form-data; boundary="+boundary);
|
||||
request.setContent(body);
|
||||
|
||||
response = HttpTester.parseResponse(tester.getResponses(request.generate()));
|
||||
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
|
||||
assertTrue(response.getContent().contains("aaaa,bbbbb"));
|
||||
}
|
||||
/*
|
||||
* see the testParameterMap test
|
||||
*
|
||||
*/
|
||||
public static class TestServletParameterMap extends DumpServlet
|
||||
{
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
assertEquals("How now brown cow.", req.getParameterMap().get("strupContent-Type:"));
|
||||
String[] content = req.getParameterMap().get("\"strup\"Content-Type: application/octet-stream");
|
||||
assertThat (content[0], containsString("How now brown cow."));
|
||||
super.doPost(req, resp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -535,8 +776,17 @@ public class MultipartFilterTest
|
|||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
resp.getWriter().println((IO.toString(new FileInputStream((File)req.getAttribute("fileup")))));
|
||||
}
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
File file = (File)req.getAttribute("fileup");
|
||||
in = new FileInputStream(file);
|
||||
|
||||
PrintWriter out = resp.getWriter();
|
||||
out.printf("Filename [%s]\r\n", req.getParameter("fileup"));
|
||||
out.println(IO.toString(in));
|
||||
} finally {
|
||||
IO.close(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -167,11 +167,6 @@ public class ClientUsageTest
|
|||
{
|
||||
StringBuilder builder = (StringBuilder)stream.getAttribute("builder");
|
||||
builder.append(dataInfo.asString("UTF-8", true));
|
||||
if (dataInfo.isClose())
|
||||
{
|
||||
int receivedLength = builder.toString().getBytes(Charset.forName("UTF-8")).length;
|
||||
assert receivedLength == stream.getAttribute("content-length");
|
||||
}
|
||||
|
||||
}
|
||||
}, new Promise.Adapter<Stream>()
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.eclipse.jetty.server.HttpTransport;
|
|||
import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
|
||||
import org.eclipse.jetty.spdy.api.DataInfo;
|
||||
import org.eclipse.jetty.spdy.api.Stream;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Fields;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -170,10 +171,13 @@ public class HttpChannelOverSPDY extends HttpChannel<DataInfo>
|
|||
|
||||
HttpMethod httpMethod = HttpMethod.fromString(methodHeader.value());
|
||||
HttpVersion httpVersion = HttpVersion.fromString(versionHeader.value());
|
||||
String uriString = uriHeader.value();
|
||||
|
||||
LOG.debug("HTTP > {} {} {}", httpMethod, uriString, httpVersion);
|
||||
startRequest(httpMethod, httpMethod.asString(), uriString, httpVersion);
|
||||
// TODO should handle URI as byte buffer as some bad clients send WRONG encodings in query string
|
||||
// that we have to deal with
|
||||
ByteBuffer uri = BufferUtil.toBuffer(uriHeader.value());
|
||||
|
||||
LOG.debug("HTTP > {} {} {}", httpMethod, uriHeader.value(), httpVersion);
|
||||
startRequest(httpMethod, httpMethod.asString(), uri, httpVersion);
|
||||
|
||||
Fields.Field schemeHeader = headers.get(HTTPSPDYHeader.SCHEME.name(version));
|
||||
if (schemeHeader != null)
|
||||
|
|
|
@ -52,6 +52,7 @@ import org.eclipse.jetty.spdy.api.Stream;
|
|||
import org.eclipse.jetty.spdy.api.StreamFrameListener;
|
||||
import org.eclipse.jetty.spdy.api.SynInfo;
|
||||
import org.eclipse.jetty.spdy.server.http.HTTPSPDYHeader;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.Fields;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
|
@ -80,13 +81,13 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean startRequest(HttpMethod method, String methodString, String uri, HttpVersion httpVersion)
|
||||
public boolean startRequest(HttpMethod method, String methodString, ByteBuffer uri, HttpVersion httpVersion)
|
||||
{
|
||||
Connector connector = getConnector();
|
||||
String scheme = connector.getConnectionFactory(SslConnectionFactory.class) != null ? "https" : "http";
|
||||
headers.put(HTTPSPDYHeader.SCHEME.name(version), scheme);
|
||||
headers.put(HTTPSPDYHeader.METHOD.name(version), methodString);
|
||||
headers.put(HTTPSPDYHeader.URI.name(version), uri);
|
||||
headers.put(HTTPSPDYHeader.URI.name(version), BufferUtil.toUTF8String(uri)); // TODO handle bad encodings
|
||||
headers.put(HTTPSPDYHeader.VERSION.name(version), httpVersion.asString());
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -53,12 +53,13 @@ import java.util.Set;
|
|||
/*-------------------------------------------*/
|
||||
/**
|
||||
* <p>
|
||||
* Main start class. This class is intended to be the main class listed in the MANIFEST.MF of the start.jar archive. It allows an application to be started with
|
||||
* the command "java -jar start.jar".
|
||||
* Main start class. This class is intended to be the main class listed in the MANIFEST.MF of the start.jar archive. It
|
||||
* allows an application to be started with the command "java -jar start.jar".
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The behaviour of Main is controlled by the parsing of the {@link Config} "org/eclipse/start/start.config" file obtained as a resource or file.
|
||||
* The behaviour of Main is controlled by the parsing of the {@link Config} "org/eclipse/start/start.config" file
|
||||
* obtained as a resource or file.
|
||||
* </p>
|
||||
*/
|
||||
public class Main
|
||||
|
@ -472,11 +473,6 @@ public class Main
|
|||
/* ------------------------------------------------------------ */
|
||||
public void start(List<String> xmls) throws IOException, InterruptedException
|
||||
{
|
||||
// Setup Start / Stop Monitoring
|
||||
int port = Integer.parseInt(Config.getProperty("STOP.PORT","-1"));
|
||||
String key = Config.getProperty("STOP.KEY",null);
|
||||
Monitor monitor = new Monitor(port,key);
|
||||
|
||||
// Load potential Config (start.config)
|
||||
List<String> configuredXmls = loadConfig(xmls);
|
||||
|
||||
|
@ -561,9 +557,8 @@ public class Main
|
|||
copyInThread(process.getErrorStream(),System.err);
|
||||
copyInThread(process.getInputStream(),System.out);
|
||||
copyInThread(System.in,process.getOutputStream());
|
||||
monitor.setProcess(process);
|
||||
process.waitFor();
|
||||
|
||||
System.exit(0); // exit JVM when child process ends.
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -668,11 +663,18 @@ public class Main
|
|||
cmd.addArg(x);
|
||||
}
|
||||
cmd.addRawArg("-Djetty.home=" + _jettyHome);
|
||||
|
||||
// Special Stop/Shutdown properties
|
||||
ensureSystemPropertySet("STOP.PORT");
|
||||
ensureSystemPropertySet("STOP.KEY");
|
||||
|
||||
// System Properties
|
||||
for (String p : _sysProps)
|
||||
{
|
||||
String v = System.getProperty(p);
|
||||
cmd.addEqualsArg("-D" + p,v);
|
||||
}
|
||||
|
||||
cmd.addArg("-cp");
|
||||
cmd.addRawArg(classpath.toString());
|
||||
cmd.addRawArg(_config.getMainClassname());
|
||||
|
@ -695,6 +697,34 @@ public class Main
|
|||
return cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the System Properties are set (if defined as a System property, or start.config property, or
|
||||
* start.ini property)
|
||||
*
|
||||
* @param key
|
||||
* the key to be sure of
|
||||
*/
|
||||
private void ensureSystemPropertySet(String key)
|
||||
{
|
||||
if (_sysProps.contains(key))
|
||||
{
|
||||
return; // done
|
||||
}
|
||||
|
||||
Properties props = Config.getProperties();
|
||||
if (props.containsKey(key))
|
||||
{
|
||||
String val = props.getProperty(key,null);
|
||||
if (val == null)
|
||||
{
|
||||
return; // no value to set
|
||||
}
|
||||
// setup system property
|
||||
_sysProps.add(key);
|
||||
System.setProperty(key,val);
|
||||
}
|
||||
}
|
||||
|
||||
private String findJavaBin()
|
||||
{
|
||||
File javaHome = new File(System.getProperty("java.home"));
|
||||
|
@ -897,8 +927,8 @@ public class Main
|
|||
/**
|
||||
* Load Configuration.
|
||||
*
|
||||
* No specific configuration is real until a {@link Config#getCombinedClasspath(java.util.Collection)} is used to execute the {@link Class} specified by
|
||||
* {@link Config#getMainClassname()} is executed.
|
||||
* No specific configuration is real until a {@link Config#getCombinedClasspath(java.util.Collection)} is used to
|
||||
* execute the {@link Class} specified by {@link Config#getMainClassname()} is executed.
|
||||
*
|
||||
* @param xmls
|
||||
* the command line specified xml configuration options.
|
||||
|
@ -979,7 +1009,6 @@ public class Main
|
|||
stop(port,key,0);
|
||||
}
|
||||
|
||||
|
||||
public void stop(int port, String key, int timeout)
|
||||
{
|
||||
int _port = port;
|
||||
|
@ -1009,11 +1038,15 @@ public class Main
|
|||
|
||||
if (timeout > 0)
|
||||
{
|
||||
System.err.println("Waiting"+(timeout > 0 ? (" "+timeout+"sec") : "")+" for jetty to stop");
|
||||
System.err.printf("Waiting %,d seconds for jetty to stop%n",timeout);
|
||||
LineNumberReader lin = new LineNumberReader(new InputStreamReader(s.getInputStream()));
|
||||
String response=lin.readLine();
|
||||
String response;
|
||||
while ((response = lin.readLine()) != null)
|
||||
{
|
||||
Config.debug("Received \"" + response + "\"");
|
||||
if ("Stopped".equals(response))
|
||||
System.err.println("Stopped");
|
||||
System.err.println("Server reports itself as Stopped");
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
|
|
@ -1,158 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 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.start;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.LineNumberReader;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
/*-------------------------------------------*/
|
||||
/** Monitor thread.
|
||||
* This thread listens on the port specified by the STOP.PORT system parameter
|
||||
* (defaults to -1 for not listening) for request authenticated with the key given by the STOP.KEY
|
||||
* system parameter (defaults to "eclipse") for admin requests.
|
||||
* <p>
|
||||
* If the stop port is set to zero, then a random port is assigned and the port number
|
||||
* is printed to stdout.
|
||||
* <p>
|
||||
* Commands "stop" and * "status" are currently supported.
|
||||
*
|
||||
*/
|
||||
public class Monitor extends Thread
|
||||
{
|
||||
private Process _process;
|
||||
private final int _port;
|
||||
private final String _key;
|
||||
|
||||
ServerSocket _socket;
|
||||
|
||||
public Monitor(int port,String key)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(port<0)
|
||||
return;
|
||||
setDaemon(true);
|
||||
setName("StopMonitor");
|
||||
_socket=new ServerSocket(port,1,InetAddress.getByName("127.0.0.1"));
|
||||
if (port==0)
|
||||
{
|
||||
port=_socket.getLocalPort();
|
||||
System.out.println(port);
|
||||
}
|
||||
|
||||
if (key==null)
|
||||
{
|
||||
key=Long.toString((long)(Long.MAX_VALUE*Math.random()+this.hashCode()+System.currentTimeMillis()),36);
|
||||
System.out.println("STOP.KEY="+key);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Config.debug(e);
|
||||
System.err.println("Error binding monitor port "+port+": "+e.toString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
_port=port;
|
||||
_key=key;
|
||||
}
|
||||
|
||||
if (_socket!=null)
|
||||
this.start();
|
||||
else
|
||||
System.err.println("WARN: Not listening on monitor port: "+_port);
|
||||
}
|
||||
|
||||
public Process getProcess()
|
||||
{
|
||||
return _process;
|
||||
}
|
||||
|
||||
public void setProcess(Process process)
|
||||
{
|
||||
_process = process;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Socket socket=null;
|
||||
try{
|
||||
socket=_socket.accept();
|
||||
|
||||
LineNumberReader lin=
|
||||
new LineNumberReader(new InputStreamReader(socket.getInputStream()));
|
||||
String key=lin.readLine();
|
||||
if (!_key.equals(key))
|
||||
{
|
||||
System.err.println("Ignoring command with incorrect key");
|
||||
continue;
|
||||
}
|
||||
|
||||
String cmd=lin.readLine();
|
||||
Config.debug("command=" + cmd);
|
||||
if ("stop".equals(cmd))
|
||||
{
|
||||
if (_process!=null)
|
||||
{
|
||||
//if we have a child process, wait for it to finish before we stop
|
||||
try
|
||||
{
|
||||
_process.destroy();
|
||||
_process.waitFor();
|
||||
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
System.err.println("Interrupted waiting for child to terminate");
|
||||
}
|
||||
}
|
||||
socket.getOutputStream().write("Stopped\r\n".getBytes());
|
||||
try {socket.close();}catch(Exception e){e.printStackTrace();}
|
||||
try {_socket.close();}catch(Exception e){e.printStackTrace();}
|
||||
System.exit(0);
|
||||
}
|
||||
else if ("status".equals(cmd))
|
||||
{
|
||||
socket.getOutputStream().write("OK\r\n".getBytes());
|
||||
socket.getOutputStream().flush();
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Config.debug(e);
|
||||
System.err.println(e.toString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (socket!=null)
|
||||
{
|
||||
try{socket.close();}catch(Exception e){}
|
||||
}
|
||||
socket=null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.eclipse.jetty.util;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** ByteArrayOutputStream with public internals
|
||||
|
@ -46,4 +47,8 @@ public class ByteArrayOutputStream2 extends ByteArrayOutputStream
|
|||
buf[count++]=(byte)b;
|
||||
}
|
||||
|
||||
public String toString(Charset charset)
|
||||
{
|
||||
return new String(buf, 0, count, charset);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,9 @@ import javax.servlet.MultipartConfigElement;
|
|||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.Part;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
@ -49,6 +52,7 @@ import javax.servlet.http.Part;
|
|||
*/
|
||||
public class MultiPartInputStreamParser
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(MultiPartInputStreamParser.class);
|
||||
public static final MultipartConfigElement __DEFAULT_MULTIPART_CONFIG = new MultipartConfigElement(System.getProperty("java.io.tmpdir"));
|
||||
protected InputStream _in;
|
||||
protected MultipartConfigElement _config;
|
||||
|
@ -464,7 +468,7 @@ public class MultiPartInputStreamParser
|
|||
|
||||
String contentTypeBoundary = "";
|
||||
if (_contentType.indexOf("boundary=") >= 0)
|
||||
contentTypeBoundary = QuotedStringTokenizer.unquote(value(_contentType.substring(_contentType.indexOf("boundary=")), true).trim());
|
||||
contentTypeBoundary = QuotedStringTokenizer.unquote(value(_contentType.substring(_contentType.indexOf("boundary="))).trim());
|
||||
|
||||
String boundary="--"+contentTypeBoundary;
|
||||
byte[] byteBoundary=(boundary+"--").getBytes(StringUtil.__ISO_8859_1);
|
||||
|
@ -475,7 +479,20 @@ public class MultiPartInputStreamParser
|
|||
if (line == null || line.length() == 0)
|
||||
throw new IOException("Missing content for multipart request");
|
||||
|
||||
if (!line.equals(boundary))
|
||||
boolean badFormatLogged = false;
|
||||
line=line.trim();
|
||||
while (line != null && !line.equals(boundary))
|
||||
{
|
||||
if (!badFormatLogged)
|
||||
{
|
||||
LOG.warn("Badly formatted multipart request");
|
||||
badFormatLogged = true;
|
||||
}
|
||||
line=((ReadLineInputStream)_in).readLine();
|
||||
line=(line==null?line:line.trim());
|
||||
}
|
||||
|
||||
if (line == null || line.length() == 0)
|
||||
throw new IOException("Missing initial multi part boundary");
|
||||
|
||||
// Read each part
|
||||
|
@ -525,7 +542,7 @@ public class MultiPartInputStreamParser
|
|||
throw new IOException("Missing content-disposition");
|
||||
}
|
||||
|
||||
QuotedStringTokenizer tok=new QuotedStringTokenizer(contentDisposition,";");
|
||||
QuotedStringTokenizer tok=new QuotedStringTokenizer(contentDisposition,";", false, true);
|
||||
String name=null;
|
||||
String filename=null;
|
||||
while(tok.hasMoreTokens())
|
||||
|
@ -535,9 +552,9 @@ public class MultiPartInputStreamParser
|
|||
if(t.startsWith("form-data"))
|
||||
form_data=true;
|
||||
else if(tl.startsWith("name="))
|
||||
name=value(t, true);
|
||||
name=value(t);
|
||||
else if(tl.startsWith("filename="))
|
||||
filename=value(t, false);
|
||||
filename=filenameValue(t);
|
||||
}
|
||||
|
||||
// Check disposition
|
||||
|
@ -703,24 +720,42 @@ public class MultiPartInputStreamParser
|
|||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private String value(String nameEqualsValue, boolean splitAfterSpace)
|
||||
private String value(String nameEqualsValue)
|
||||
{
|
||||
String value=nameEqualsValue.substring(nameEqualsValue.indexOf('=')+1).trim();
|
||||
int i=value.indexOf(';');
|
||||
if(i>0)
|
||||
value=value.substring(0,i);
|
||||
if(value.startsWith("\""))
|
||||
{
|
||||
value=value.substring(1,value.indexOf('"',1));
|
||||
int idx = nameEqualsValue.indexOf('=');
|
||||
String value = nameEqualsValue.substring(idx+1).trim();
|
||||
return QuotedStringTokenizer.unquoteOnly(value);
|
||||
}
|
||||
else if (splitAfterSpace)
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private String filenameValue(String nameEqualsValue)
|
||||
{
|
||||
i=value.indexOf(' ');
|
||||
if(i>0)
|
||||
value=value.substring(0,i);
|
||||
}
|
||||
int idx = nameEqualsValue.indexOf('=');
|
||||
String value = nameEqualsValue.substring(idx+1).trim();
|
||||
|
||||
if (value.matches(".??[a-z,A-Z]\\:\\\\[^\\\\].*"))
|
||||
{
|
||||
//incorrectly escaped IE filenames that have the whole path
|
||||
//we just strip any leading & trailing quotes and leave it as is
|
||||
char first=value.charAt(0);
|
||||
if (first=='"' || first=='\'')
|
||||
value=value.substring(1);
|
||||
char last=value.charAt(value.length()-1);
|
||||
if (last=='"' || last=='\'')
|
||||
value = value.substring(0,value.length()-1);
|
||||
|
||||
return value;
|
||||
}
|
||||
else
|
||||
//unquote the string, but allow any backslashes that don't
|
||||
//form a valid escape sequence to remain as many browsers
|
||||
//even on *nix systems will not escape a filename containing
|
||||
//backslashes
|
||||
return QuotedStringTokenizer.unquoteOnly(value, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static class Base64InputStream extends InputStream
|
||||
{
|
||||
|
|
|
@ -96,6 +96,7 @@ public class MultiPartOutputStream extends FilterOutputStream
|
|||
out.write(__DASHDASH);
|
||||
out.write(boundaryBytes);
|
||||
out.write(__CRLF);
|
||||
if (contentType != null)
|
||||
out.write(("Content-Type: "+contentType).getBytes(StringUtil.__ISO_8859_1));
|
||||
out.write(__CRLF);
|
||||
out.write(__CRLF);
|
||||
|
@ -113,6 +114,7 @@ public class MultiPartOutputStream extends FilterOutputStream
|
|||
out.write(__DASHDASH);
|
||||
out.write(boundaryBytes);
|
||||
out.write(__CRLF);
|
||||
if (contentType != null)
|
||||
out.write(("Content-Type: "+contentType).getBytes(StringUtil.__ISO_8859_1));
|
||||
out.write(__CRLF);
|
||||
for (int i=0;headers!=null && i<headers.length;i++)
|
||||
|
|
|
@ -409,12 +409,21 @@ public class QuotedStringTokenizer
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static String unquoteOnly(String s)
|
||||
{
|
||||
return unquoteOnly(s, false);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Unquote a string, NOT converting unicode sequences
|
||||
* @param s The string to unquote.
|
||||
* @param lenient if true, will leave in backslashes that aren't valid escapes
|
||||
* @return quoted string
|
||||
*/
|
||||
public static String unquoteOnly(String s)
|
||||
public static String unquoteOnly(String s, boolean lenient)
|
||||
{
|
||||
if (s==null)
|
||||
return null;
|
||||
|
@ -435,6 +444,10 @@ public class QuotedStringTokenizer
|
|||
if (escape)
|
||||
{
|
||||
escape=false;
|
||||
if (lenient && !isValidEscaping(c))
|
||||
{
|
||||
b.append('\\');
|
||||
}
|
||||
b.append(c);
|
||||
}
|
||||
else if (c=='\\')
|
||||
|
@ -450,12 +463,18 @@ public class QuotedStringTokenizer
|
|||
return b.toString();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static String unquote(String s)
|
||||
{
|
||||
return unquote(s,false);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Unquote a string.
|
||||
* @param s The string to unquote.
|
||||
* @return quoted string
|
||||
*/
|
||||
public static String unquote(String s)
|
||||
public static String unquote(String s, boolean lenient)
|
||||
{
|
||||
if (s==null)
|
||||
return null;
|
||||
|
@ -512,6 +531,10 @@ public class QuotedStringTokenizer
|
|||
);
|
||||
break;
|
||||
default:
|
||||
if (lenient && !isValidEscaping(c))
|
||||
{
|
||||
b.append('\\');
|
||||
}
|
||||
b.append(c);
|
||||
}
|
||||
}
|
||||
|
@ -528,6 +551,20 @@ public class QuotedStringTokenizer
|
|||
return b.toString();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Check that char c (which is preceded by a backslash) is a valid
|
||||
* escape sequence.
|
||||
* @param c
|
||||
* @return
|
||||
*/
|
||||
private static boolean isValidEscaping(char c)
|
||||
{
|
||||
return ((c == 'n') || (c == 'r') || (c == 't') ||
|
||||
(c == 'f') || (c == 'b') || (c == '\\') ||
|
||||
(c == '/') || (c == '"') || (c == 'u'));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return handle double quotes if true
|
||||
|
|
|
@ -52,11 +52,13 @@ public class StringUtil
|
|||
|
||||
public final static Charset __UTF8_CHARSET;
|
||||
public final static Charset __ISO_8859_1_CHARSET;
|
||||
public final static Charset __UTF16_CHARSET;
|
||||
|
||||
static
|
||||
{
|
||||
__UTF8_CHARSET=Charset.forName(__UTF8);
|
||||
__ISO_8859_1_CHARSET=Charset.forName(__ISO_8859_1);
|
||||
__UTF16_CHARSET=Charset.forName(__UTF16);
|
||||
|
||||
CHARSETS.put("UTF-8",__UTF8);
|
||||
CHARSETS.put("UTF8",__UTF8);
|
||||
|
|
|
@ -273,13 +273,7 @@ public class TypeUtil
|
|||
{
|
||||
char c=s.charAt(offset+i);
|
||||
|
||||
int digit=c-'0';
|
||||
if (digit<0 || digit>=base || digit>=10)
|
||||
{
|
||||
digit=10+c-'A';
|
||||
if (digit<10 || digit>=base)
|
||||
digit=10+c-'a';
|
||||
}
|
||||
int digit=convertHexDigit((int)c);
|
||||
if (digit<0 || digit>=base)
|
||||
throw new NumberFormatException(s.substring(offset,offset+length));
|
||||
value=value*base+digit;
|
||||
|
@ -353,15 +347,28 @@ public class TypeUtil
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param b An ASCII encoded character 0-9 a-f A-F
|
||||
* @param c An ASCII encoded character 0-9 a-f A-F
|
||||
* @return The byte value of the character 0-16.
|
||||
*/
|
||||
public static byte convertHexDigit( byte b )
|
||||
public static byte convertHexDigit( byte c )
|
||||
{
|
||||
if ((b >= '0') && (b <= '9')) return (byte)(b - '0');
|
||||
if ((b >= 'a') && (b <= 'f')) return (byte)(b - 'a' + 10);
|
||||
if ((b >= 'A') && (b <= 'F')) return (byte)(b - 'A' + 10);
|
||||
throw new IllegalArgumentException("!hex:"+Integer.toHexString(0xff&b));
|
||||
byte b = (byte)((c & 0x1f) + ((c >> 6) * 0x19) - 0x10);
|
||||
if (b<0 || b>15)
|
||||
throw new IllegalArgumentException("!hex "+c);
|
||||
return b;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param c An ASCII encoded character 0-9 a-f A-F
|
||||
* @return The byte value of the character 0-16.
|
||||
*/
|
||||
public static int convertHexDigit( int c )
|
||||
{
|
||||
int d= ((c & 0x1f) + ((c >> 6) * 0x19) - 0x10);
|
||||
if (d<0 || d>15)
|
||||
throw new NumberFormatException("!hex "+c);
|
||||
return d;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -18,11 +18,14 @@
|
|||
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
import static org.eclipse.jetty.util.TypeUtil.convertHexDigit;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -54,7 +57,21 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
{
|
||||
static final Logger LOG = Log.getLogger(UrlEncoded.class);
|
||||
|
||||
public static final String ENCODING = System.getProperty("org.eclipse.jetty.util.UrlEncoding.charset",StringUtil.__UTF8);
|
||||
public static final Charset ENCODING;
|
||||
static
|
||||
{
|
||||
Charset encoding=null;
|
||||
try
|
||||
{
|
||||
encoding=Charset.forName(System.getProperty("org.eclipse.jetty.util.UrlEncoding.charset",StringUtil.__UTF8));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
encoding=StringUtil.__UTF8_CHARSET;
|
||||
}
|
||||
ENCODING=encoding;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
public UrlEncoded(UrlEncoded url)
|
||||
|
@ -67,20 +84,6 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
{
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
public UrlEncoded(String s)
|
||||
{
|
||||
this();
|
||||
decode(s,ENCODING);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
public UrlEncoded(String s, String charset)
|
||||
{
|
||||
this();
|
||||
decode(s,charset);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
public void decode(String query)
|
||||
{
|
||||
|
@ -88,7 +91,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
public void decode(String query,String charset)
|
||||
public void decode(String query,Charset charset)
|
||||
{
|
||||
decodeTo(query,this,charset,-1);
|
||||
}
|
||||
|
@ -104,7 +107,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
/* -------------------------------------------------------------- */
|
||||
/** Encode Hashtable with % encoding.
|
||||
*/
|
||||
public String encode(String charset)
|
||||
public String encode(Charset charset)
|
||||
{
|
||||
return encode(charset,false);
|
||||
}
|
||||
|
@ -114,7 +117,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
* @param equalsForNullValue if True, then an '=' is always used, even
|
||||
* for parameters without a value. e.g. "blah?a=&b=&c=".
|
||||
*/
|
||||
public synchronized String encode(String charset, boolean equalsForNullValue)
|
||||
public synchronized String encode(Charset charset, boolean equalsForNullValue)
|
||||
{
|
||||
return encode(this,charset,equalsForNullValue);
|
||||
}
|
||||
|
@ -124,7 +127,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
* @param equalsForNullValue if True, then an '=' is always used, even
|
||||
* for parameters without a value. e.g. "blah?a=&b=&c=".
|
||||
*/
|
||||
public static String encode(MultiMap<String> map, String charset, boolean equalsForNullValue)
|
||||
public static String encode(MultiMap<String> map, Charset charset, boolean equalsForNullValue)
|
||||
{
|
||||
if (charset==null)
|
||||
charset=ENCODING;
|
||||
|
@ -178,22 +181,20 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
return result.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
/** Decoded parameters to Map.
|
||||
* @param content the string containing the encoded parameters
|
||||
*/
|
||||
public static void decodeTo(String content, MultiMap<String> map, String charset)
|
||||
public static void decodeTo(String content, MultiMap<String> map, String charset, int maxKeys)
|
||||
{
|
||||
decodeTo(content,map,charset,-1);
|
||||
decodeTo(content,map,charset==null?null:Charset.forName(charset),maxKeys);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
/** Decoded parameters to Map.
|
||||
* @param content the string containing the encoded parameters
|
||||
*/
|
||||
public static void decodeTo(String content, MultiMap<String> map, String charset, int maxKeys)
|
||||
public static void decodeTo(String content, MultiMap<String> map, Charset charset, int maxKeys)
|
||||
{
|
||||
if (charset==null)
|
||||
charset=ENCODING;
|
||||
|
@ -226,10 +227,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
key = null;
|
||||
value=null;
|
||||
if (maxKeys>0 && map.size()>maxKeys)
|
||||
{
|
||||
LOG.warn("maxFormKeys limit exceeded keys>{}",maxKeys);
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException("Form too many keys");
|
||||
break;
|
||||
case '=':
|
||||
if (key!=null)
|
||||
|
@ -321,7 +319,16 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
|
||||
case '%':
|
||||
if (i+2<end)
|
||||
buffer.append((byte)((TypeUtil.convertHexDigit(raw[++i])<<4) + TypeUtil.convertHexDigit(raw[++i])));
|
||||
{
|
||||
if ('u'==raw[i+1])
|
||||
{
|
||||
i++;
|
||||
if (i+4<end)
|
||||
buffer.getStringBuilder().append(Character.toChars((convertHexDigit(raw[++i])<<12) +(convertHexDigit(raw[++i])<<8) + (convertHexDigit(raw[++i])<<4) +convertHexDigit(raw[++i])));
|
||||
}
|
||||
else
|
||||
buffer.append((byte)((convertHexDigit(raw[++i])<<4) + convertHexDigit(raw[++i])));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -385,10 +392,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
key = null;
|
||||
value=null;
|
||||
if (maxKeys>0 && map.size()>maxKeys)
|
||||
{
|
||||
LOG.warn("maxFormKeys limit exceeded keys>{}",maxKeys);
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException("Form too many keys");
|
||||
break;
|
||||
|
||||
case '=':
|
||||
|
@ -406,12 +410,29 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
break;
|
||||
|
||||
case '%':
|
||||
int dh=in.read();
|
||||
int dl=in.read();
|
||||
if (dh<0||dl<0)
|
||||
break;
|
||||
buffer.append((char)((TypeUtil.convertHexDigit((byte)dh)<<4) + TypeUtil.convertHexDigit((byte)dl)));
|
||||
int code0=in.read();
|
||||
if ('u'==code0)
|
||||
{
|
||||
int code1=in.read();
|
||||
if (code1>=0)
|
||||
{
|
||||
int code2=in.read();
|
||||
if (code2>=0)
|
||||
{
|
||||
int code3=in.read();
|
||||
if (code3>=0)
|
||||
buffer.append(Character.toChars((convertHexDigit(code0)<<12)+(convertHexDigit(code1)<<8)+(convertHexDigit(code2)<<4)+convertHexDigit(code3)));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (code0>=0)
|
||||
{
|
||||
int code1=in.read();
|
||||
if (code1>=0)
|
||||
buffer.append((char)((convertHexDigit(code0)<<4)+convertHexDigit(code1)));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
buffer.append((char)b);
|
||||
break;
|
||||
|
@ -471,10 +492,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
key = null;
|
||||
value=null;
|
||||
if (maxKeys>0 && map.size()>maxKeys)
|
||||
{
|
||||
LOG.warn("maxFormKeys limit exceeded keys>{}",maxKeys);
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException("Form too many keys");
|
||||
break;
|
||||
|
||||
case '=':
|
||||
|
@ -492,12 +510,29 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
break;
|
||||
|
||||
case '%':
|
||||
int dh=in.read();
|
||||
int dl=in.read();
|
||||
if (dh<0||dl<0)
|
||||
break;
|
||||
buffer.append((byte)((TypeUtil.convertHexDigit((byte)dh)<<4) + TypeUtil.convertHexDigit((byte)dl)));
|
||||
int code0=in.read();
|
||||
if ('u'==code0)
|
||||
{
|
||||
int code1=in.read();
|
||||
if (code1>=0)
|
||||
{
|
||||
int code2=in.read();
|
||||
if (code2>=0)
|
||||
{
|
||||
int code3=in.read();
|
||||
if (code3>=0)
|
||||
buffer.getStringBuilder().append(Character.toChars((convertHexDigit(code0)<<12)+(convertHexDigit(code1)<<8)+(convertHexDigit(code2)<<4)+convertHexDigit(code3)));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (code0>=0)
|
||||
{
|
||||
int code1=in.read();
|
||||
if (code1>=0)
|
||||
buffer.append((byte)((convertHexDigit(code0)<<4)+convertHexDigit(code1)));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
buffer.append((byte)b);
|
||||
break;
|
||||
|
@ -542,39 +577,58 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
public static void decodeTo(InputStream in, MultiMap<String> map, String charset, int maxLength, int maxKeys)
|
||||
throws IOException
|
||||
{
|
||||
//no charset present, use the configured default
|
||||
if (charset==null)
|
||||
{
|
||||
charset=ENCODING;
|
||||
if (ENCODING==StringUtil.__UTF8_CHARSET)
|
||||
decodeUtf8To(in,map,maxLength,maxKeys);
|
||||
else
|
||||
decodeTo(in,map,ENCODING,maxLength,maxKeys);
|
||||
}
|
||||
else if (StringUtil.__UTF8.equalsIgnoreCase(charset))
|
||||
decodeUtf8To(in,map,maxLength,maxKeys);
|
||||
else if (StringUtil.__ISO_8859_1.equalsIgnoreCase(charset))
|
||||
decode88591To(in,map,maxLength,maxKeys);
|
||||
else if (StringUtil.__UTF16.equalsIgnoreCase(charset))
|
||||
decodeUtf16To(in,map,maxLength,maxKeys);
|
||||
else
|
||||
decodeTo(in,map,Charset.forName(charset),maxLength,maxKeys);
|
||||
}
|
||||
|
||||
if (StringUtil.__UTF8.equalsIgnoreCase(charset))
|
||||
/* -------------------------------------------------------------- */
|
||||
/** Decoded parameters to Map.
|
||||
* @param in the stream containing the encoded parameters
|
||||
*/
|
||||
public static void decodeTo(InputStream in, MultiMap<String> map, Charset charset, int maxLength, int maxKeys)
|
||||
throws IOException
|
||||
{
|
||||
//no charset present, use the configured default
|
||||
if (charset==null)
|
||||
charset=ENCODING;
|
||||
|
||||
if (StringUtil.__UTF8_CHARSET.equals(charset))
|
||||
{
|
||||
decodeUtf8To(in,map,maxLength,maxKeys);
|
||||
return;
|
||||
}
|
||||
|
||||
if (StringUtil.__ISO_8859_1.equals(charset))
|
||||
if (StringUtil.__ISO_8859_1_CHARSET.equals(charset))
|
||||
{
|
||||
decode88591To(in,map,maxLength,maxKeys);
|
||||
return;
|
||||
}
|
||||
|
||||
if (StringUtil.__UTF16.equalsIgnoreCase(charset)) // Should be all 2 byte encodings
|
||||
if (StringUtil.__UTF16_CHARSET.equals(charset)) // Should be all 2 byte encodings
|
||||
{
|
||||
decodeUtf16To(in,map,maxLength,maxKeys);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
synchronized(map)
|
||||
{
|
||||
String key = null;
|
||||
String value = null;
|
||||
|
||||
int c;
|
||||
int digit=0;
|
||||
int digits=0;
|
||||
|
||||
int totalLength = 0;
|
||||
ByteArrayOutputStream2 output = new ByteArrayOutputStream2();
|
||||
|
@ -599,6 +653,8 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
}
|
||||
key = null;
|
||||
value=null;
|
||||
if (maxKeys>0 && map.size()>maxKeys)
|
||||
throw new IllegalStateException("Form too many keys");
|
||||
break;
|
||||
case '=':
|
||||
if (key!=null)
|
||||
|
@ -614,20 +670,30 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
output.write(' ');
|
||||
break;
|
||||
case '%':
|
||||
digits=2;
|
||||
int code0=in.read();
|
||||
if ('u'==code0)
|
||||
{
|
||||
int code1=in.read();
|
||||
if (code1>=0)
|
||||
{
|
||||
int code2=in.read();
|
||||
if (code2>=0)
|
||||
{
|
||||
int code3=in.read();
|
||||
if (code3>=0)
|
||||
output.write(new String(Character.toChars((convertHexDigit(code0)<<12)+(convertHexDigit(code1)<<8)+(convertHexDigit(code2)<<4)+convertHexDigit(code3))).getBytes(charset));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (code0>=0)
|
||||
{
|
||||
int code1=in.read();
|
||||
if (code1>=0)
|
||||
output.write((convertHexDigit(code0)<<4)+convertHexDigit(code1));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (digits==2)
|
||||
{
|
||||
digit=TypeUtil.convertHexDigit((byte)c);
|
||||
digits=1;
|
||||
}
|
||||
else if (digits==1)
|
||||
{
|
||||
output.write((digit<<4) + TypeUtil.convertHexDigit((byte)c));
|
||||
digits=0;
|
||||
}
|
||||
else
|
||||
output.write(c);
|
||||
break;
|
||||
}
|
||||
|
@ -654,9 +720,9 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
* This method makes the assumption that the majority of calls
|
||||
* will need no decoding.
|
||||
*/
|
||||
public static String decodeString(String encoded,int offset,int length,String charset)
|
||||
public static String decodeString(String encoded,int offset,int length,Charset charset)
|
||||
{
|
||||
if (charset==null || StringUtil.isUTF8(charset))
|
||||
if (charset==null || StringUtil.__UTF8_CHARSET.equals(charset))
|
||||
{
|
||||
Utf8StringBuffer buffer=null;
|
||||
|
||||
|
@ -683,7 +749,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
|
||||
buffer.getStringBuffer().append(' ');
|
||||
}
|
||||
else if (c=='%' && (i+2)<length)
|
||||
else if (c=='%')
|
||||
{
|
||||
if (buffer==null)
|
||||
{
|
||||
|
@ -691,17 +757,38 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
buffer.getStringBuffer().append(encoded,offset,offset+i);
|
||||
}
|
||||
|
||||
if ((i+2)<length)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte b=(byte)TypeUtil.parseInt(encoded,offset+i+1,2,16);
|
||||
buffer.append(b);
|
||||
if ('u'==encoded.charAt(offset+i+1))
|
||||
{
|
||||
if((i+5)<length)
|
||||
{
|
||||
int o=offset+i+2;
|
||||
i+=5;
|
||||
String unicode = new String(Character.toChars(TypeUtil.parseInt(encoded,o,4,16)));
|
||||
buffer.getStringBuffer().append(unicode);
|
||||
}
|
||||
else
|
||||
i=length;
|
||||
}
|
||||
else
|
||||
{
|
||||
int o=offset+i+1;
|
||||
i+=2;
|
||||
byte b=(byte)TypeUtil.parseInt(encoded,o,2,16);
|
||||
buffer.append(b);
|
||||
}
|
||||
}
|
||||
catch(NumberFormatException nfe)
|
||||
{
|
||||
buffer.getStringBuffer().append('%');
|
||||
buffer.getStringBuffer().append(Utf8Appendable.REPLACEMENT);
|
||||
}
|
||||
}
|
||||
else
|
||||
i=length;
|
||||
}
|
||||
else if (buffer!=null)
|
||||
buffer.getStringBuffer().append(c);
|
||||
}
|
||||
|
@ -719,8 +806,6 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
{
|
||||
StringBuffer buffer=null;
|
||||
|
||||
try
|
||||
{
|
||||
for (int i=0;i<length;i++)
|
||||
{
|
||||
char c = encoded.charAt(offset+i);
|
||||
|
@ -744,7 +829,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
|
||||
buffer.append(' ');
|
||||
}
|
||||
else if (c=='%' && (i+2)<length)
|
||||
else if (c=='%')
|
||||
{
|
||||
if (buffer==null)
|
||||
{
|
||||
|
@ -762,15 +847,27 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
{
|
||||
try
|
||||
{
|
||||
ba[n]=(byte)TypeUtil.parseInt(encoded,offset+i+1,2,16);
|
||||
n++;
|
||||
if ('u'==encoded.charAt(offset+i+1))
|
||||
{
|
||||
int o=offset+i+2;
|
||||
i+=6;
|
||||
String unicode = new String(Character.toChars(TypeUtil.parseInt(encoded,o,4,16)));
|
||||
byte[] reencoded = unicode.getBytes(charset);
|
||||
System.arraycopy(reencoded,0,ba,n,reencoded.length);
|
||||
n+=reencoded.length;
|
||||
}
|
||||
else
|
||||
{
|
||||
int o=offset+i+1;
|
||||
i+=3;
|
||||
ba[n]=(byte)TypeUtil.parseInt(encoded,o,2,16);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
catch(NumberFormatException nfe)
|
||||
{
|
||||
LOG.ignore(nfe);
|
||||
ba[n++] = (byte)'%';
|
||||
i++;
|
||||
ba[n++] = (byte)'?';
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -812,11 +909,6 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
|
||||
return buffer.toString();
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -835,20 +927,12 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
* @param string
|
||||
* @return encoded string.
|
||||
*/
|
||||
public static String encodeString(String string,String charset)
|
||||
public static String encodeString(String string,Charset charset)
|
||||
{
|
||||
if (charset==null)
|
||||
charset=ENCODING;
|
||||
byte[] bytes=null;
|
||||
try
|
||||
{
|
||||
bytes=string.getBytes(charset);
|
||||
}
|
||||
catch(UnsupportedEncodingException e)
|
||||
{
|
||||
// LOG.warn(LogSupport.EXCEPTION,e);
|
||||
bytes=string.getBytes();
|
||||
}
|
||||
|
||||
int len=bytes.length;
|
||||
byte[] encoded= new byte[bytes.length*3];
|
||||
|
@ -890,16 +974,8 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
|||
if (noEncode)
|
||||
return string;
|
||||
|
||||
try
|
||||
{
|
||||
return new String(encoded,0,n,charset);
|
||||
}
|
||||
catch(UnsupportedEncodingException e)
|
||||
{
|
||||
// LOG.warn(LogSupport.EXCEPTION,e);
|
||||
return new String(encoded,0,n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -46,6 +46,7 @@ import javax.servlet.http.Part;
|
|||
import org.eclipse.jetty.util.MultiPartInputStreamParser.MultiPart;
|
||||
import org.hamcrest.core.IsNot;
|
||||
import org.junit.Test;
|
||||
import org.hamcrest.core.IsNot;
|
||||
|
||||
/**
|
||||
* MultiPartInputStreamTest
|
||||
|
@ -236,6 +237,92 @@ public class MultiPartInputStreamTest
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLeadingWhitespaceBodyWithCRLF()
|
||||
throws Exception
|
||||
{
|
||||
String body = " \n\n\n\r\n\r\n\r\n\r\n"+
|
||||
"--AaB03x\r\n"+
|
||||
"content-disposition: form-data; name=\"field1\"\r\n"+
|
||||
"\r\n"+
|
||||
"Joe Blow\r\n"+
|
||||
"--AaB03x\r\n"+
|
||||
"content-disposition: form-data; name=\"stuff\"; filename=\"" + "foo.txt" + "\"\r\n"+
|
||||
"Content-Type: text/plain\r\n"+
|
||||
"\r\n"+"aaaa"+
|
||||
"bbbbb"+"\r\n" +
|
||||
"--AaB03x--\r\n";
|
||||
|
||||
|
||||
MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
|
||||
MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(body.getBytes()),
|
||||
_contentType,
|
||||
config,
|
||||
_tmpDir);
|
||||
mpis.setDeleteOnExit(true);
|
||||
|
||||
Collection<Part> parts = mpis.getParts();
|
||||
assertThat(parts, notNullValue());
|
||||
assertThat(parts.size(), is(2));
|
||||
Part field1 = mpis.getPart("field1");
|
||||
assertThat(field1, notNullValue());
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
IO.copy(field1.getInputStream(), baos);
|
||||
assertThat(baos.toString("US-ASCII"), is("Joe Blow"));
|
||||
|
||||
Part stuff = mpis.getPart("stuff");
|
||||
assertThat(stuff, notNullValue());
|
||||
baos = new ByteArrayOutputStream();
|
||||
IO.copy(stuff.getInputStream(), baos);
|
||||
assertTrue(baos.toString("US-ASCII").contains("aaaa"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testLeadingWhitespaceBodyWithoutCRLF()
|
||||
throws Exception
|
||||
{
|
||||
String body = " "+
|
||||
"--AaB03x\r\n"+
|
||||
"content-disposition: form-data; name=\"field1\"\r\n"+
|
||||
"\r\n"+
|
||||
"Joe Blow\r\n"+
|
||||
"--AaB03x\r\n"+
|
||||
"content-disposition: form-data; name=\"stuff\"; filename=\"" + "foo.txt" + "\"\r\n"+
|
||||
"Content-Type: text/plain\r\n"+
|
||||
"\r\n"+"aaaa"+
|
||||
"bbbbb"+"\r\n" +
|
||||
"--AaB03x--\r\n";
|
||||
|
||||
MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
|
||||
MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(body.getBytes()),
|
||||
_contentType,
|
||||
config,
|
||||
_tmpDir);
|
||||
mpis.setDeleteOnExit(true);
|
||||
|
||||
Collection<Part> parts = mpis.getParts();
|
||||
assertThat(parts, notNullValue());
|
||||
assertThat(parts.size(), is(2));
|
||||
Part field1 = mpis.getPart("field1");
|
||||
assertThat(field1, notNullValue());
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
IO.copy(field1.getInputStream(), baos);
|
||||
assertThat(baos.toString("US-ASCII"), is("Joe Blow"));
|
||||
|
||||
Part stuff = mpis.getPart("stuff");
|
||||
assertThat(stuff, notNullValue());
|
||||
baos = new ByteArrayOutputStream();
|
||||
IO.copy(stuff.getInputStream(), baos);
|
||||
assertTrue(baos.toString("US-ASCII").contains("bbbbb"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testNoLimits()
|
||||
throws Exception
|
||||
|
@ -446,6 +533,71 @@ public class MultiPartInputStreamTest
|
|||
assertThat(baos.toString("UTF-8"), is("Other"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadlyEncodedFilename() throws Exception
|
||||
{
|
||||
|
||||
String contents = "--AaB03x\r\n"+
|
||||
"content-disposition: form-data; name=\"stuff\"; filename=\"" +"Taken on Aug 22 \\ 2012.jpg" + "\"\r\n"+
|
||||
"Content-Type: text/plain\r\n"+
|
||||
"\r\n"+"stuff"+
|
||||
"aaa"+"\r\n" +
|
||||
"--AaB03x--\r\n";
|
||||
|
||||
MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
|
||||
MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(contents.getBytes()),
|
||||
_contentType,
|
||||
config,
|
||||
_tmpDir);
|
||||
mpis.setDeleteOnExit(true);
|
||||
Collection<Part> parts = mpis.getParts();
|
||||
assertThat(parts.size(), is(1));
|
||||
assertThat(((MultiPartInputStreamParser.MultiPart)parts.iterator().next()).getContentDispositionFilename(), is("Taken on Aug 22 \\ 2012.jpg"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadlyEncodedMSFilename() throws Exception
|
||||
{
|
||||
|
||||
String contents = "--AaB03x\r\n"+
|
||||
"content-disposition: form-data; name=\"stuff\"; filename=\"" +"c:\\this\\really\\is\\some\\path\\to\\a\\file.txt" + "\"\r\n"+
|
||||
"Content-Type: text/plain\r\n"+
|
||||
"\r\n"+"stuff"+
|
||||
"aaa"+"\r\n" +
|
||||
"--AaB03x--\r\n";
|
||||
|
||||
MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
|
||||
MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(contents.getBytes()),
|
||||
_contentType,
|
||||
config,
|
||||
_tmpDir);
|
||||
mpis.setDeleteOnExit(true);
|
||||
Collection<Part> parts = mpis.getParts();
|
||||
assertThat(parts.size(), is(1));
|
||||
assertThat(((MultiPartInputStreamParser.MultiPart)parts.iterator().next()).getContentDispositionFilename(), is("c:\\this\\really\\is\\some\\path\\to\\a\\file.txt"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCorrectlyEncodedMSFilename() throws Exception
|
||||
{
|
||||
String contents = "--AaB03x\r\n"+
|
||||
"content-disposition: form-data; name=\"stuff\"; filename=\"" +"c:\\\\this\\\\really\\\\is\\\\some\\\\path\\\\to\\\\a\\\\file.txt" + "\"\r\n"+
|
||||
"Content-Type: text/plain\r\n"+
|
||||
"\r\n"+"stuff"+
|
||||
"aaa"+"\r\n" +
|
||||
"--AaB03x--\r\n";
|
||||
|
||||
MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
|
||||
MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(contents.getBytes()),
|
||||
_contentType,
|
||||
config,
|
||||
_tmpDir);
|
||||
mpis.setDeleteOnExit(true);
|
||||
Collection<Part> parts = mpis.getParts();
|
||||
assertThat(parts.size(), is(1));
|
||||
assertThat(((MultiPartInputStreamParser.MultiPart)parts.iterator().next()).getContentDispositionFilename(), is("c:\\this\\really\\is\\some\\path\\to\\a\\file.txt"));
|
||||
}
|
||||
|
||||
public void testMulti ()
|
||||
throws Exception
|
||||
{
|
||||
|
@ -458,6 +610,9 @@ public class MultiPartInputStreamTest
|
|||
testMulti("stuff with spaces.txt");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void testMulti(String filename) throws IOException, ServletException
|
||||
{
|
||||
MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
|
||||
|
|
|
@ -18,9 +18,7 @@
|
|||
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -190,4 +188,21 @@ public class QuotedStringTokenizerTest
|
|||
assertEquals("ba\\uXXXXaaa", QuotedStringTokenizer.unquoteOnly("\"ba\\\\uXXXXaaa\""));
|
||||
}
|
||||
|
||||
/**
|
||||
* When encountering a Content-Disposition line during a multi-part mime file
|
||||
* upload, the filename="..." field can contain '\' characters that do not
|
||||
* belong to a proper escaping sequence, this tests QuotedStringTokenizer to
|
||||
* ensure that it preserves those slashes for where they cannot be escaped.
|
||||
*/
|
||||
@Test
|
||||
public void testNextTokenOnContentDisposition()
|
||||
{
|
||||
String content_disposition = "form-data; name=\"fileup\"; filename=\"Taken on Aug 22 \\ 2012.jpg\"";
|
||||
|
||||
QuotedStringTokenizer tok=new QuotedStringTokenizer(content_disposition,";",false,true);
|
||||
|
||||
assertEquals("form-data", tok.nextToken().trim());
|
||||
assertEquals("name=\"fileup\"", tok.nextToken().trim());
|
||||
assertEquals("filename=\"Taken on Aug 22 \\ 2012.jpg\"", tok.nextToken().trim());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,23 @@ import org.junit.Test;
|
|||
|
||||
public class TypeUtilTest
|
||||
{
|
||||
@Test
|
||||
public void convertHexDigitTest()
|
||||
{
|
||||
Assert.assertEquals((byte)0,TypeUtil.convertHexDigit((byte)'0'));
|
||||
Assert.assertEquals((byte)9,TypeUtil.convertHexDigit((byte)'9'));
|
||||
Assert.assertEquals((byte)10,TypeUtil.convertHexDigit((byte)'a'));
|
||||
Assert.assertEquals((byte)10,TypeUtil.convertHexDigit((byte)'A'));
|
||||
Assert.assertEquals((byte)15,TypeUtil.convertHexDigit((byte)'f'));
|
||||
Assert.assertEquals((byte)15,TypeUtil.convertHexDigit((byte)'F'));
|
||||
|
||||
Assert.assertEquals((int)0,TypeUtil.convertHexDigit((int)'0'));
|
||||
Assert.assertEquals((int)9,TypeUtil.convertHexDigit((int)'9'));
|
||||
Assert.assertEquals((int)10,TypeUtil.convertHexDigit((int)'a'));
|
||||
Assert.assertEquals((int)10,TypeUtil.convertHexDigit((int)'A'));
|
||||
Assert.assertEquals((int)15,TypeUtil.convertHexDigit((int)'f'));
|
||||
Assert.assertEquals((int)15,TypeUtil.convertHexDigit((int)'F'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToHexInt() throws Exception
|
||||
|
|
|
@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals;
|
|||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
@ -120,33 +121,34 @@ public class URLEncodedTest
|
|||
assertEquals("encoded get", url_encoded.getString("Name8"),"xx, yy ,zz");
|
||||
|
||||
url_encoded.clear();
|
||||
url_encoded.decode("Name11=xxVerdi+%C6+og+2zz", "ISO-8859-1");
|
||||
url_encoded.decode("Name11=%u30EDxxVerdi+%C6+og+2zz", StringUtil.__ISO_8859_1_CHARSET);
|
||||
assertEquals("encoded param size",1, url_encoded.size());
|
||||
assertEquals("encoded get", url_encoded.getString("Name11"),"xxVerdi \u00c6 og 2zz");
|
||||
assertEquals("encoded get", "?xxVerdi \u00c6 og 2zz",url_encoded.getString("Name11"));
|
||||
|
||||
url_encoded.clear();
|
||||
url_encoded.decode("Name12=xxVerdi+%2F+og+2zz", "UTF-8");
|
||||
url_encoded.decode("Name12=%u30EDxxVerdi+%2F+og+2zz", StringUtil.__UTF8_CHARSET);
|
||||
assertEquals("encoded param size",1, url_encoded.size());
|
||||
assertEquals("encoded get", url_encoded.getString("Name12"),"xxVerdi / og 2zz");
|
||||
assertEquals("encoded get", url_encoded.getString("Name12"),"\u30edxxVerdi / og 2zz");
|
||||
|
||||
url_encoded.clear();
|
||||
url_encoded.decode("Name14=%GG%+%%+%", "ISO-8859-1");
|
||||
url_encoded.decode("Name14=%uXXXXa%GGb%+%c%+%d", StringUtil.__ISO_8859_1_CHARSET);
|
||||
assertEquals("encoded param size",1, url_encoded.size());
|
||||
assertEquals("encoded get", url_encoded.getString("Name14"),"%GG% %% %");
|
||||
assertEquals("encoded get","?a?b?c?d", url_encoded.getString("Name14"));
|
||||
|
||||
url_encoded.clear();
|
||||
url_encoded.decode("Name14=%GG%+%%+%", "UTF-8");
|
||||
url_encoded.decode("Name14=%uXXXX%GG%+%%+%", StringUtil.__UTF8_CHARSET);
|
||||
assertEquals("encoded param size",1, url_encoded.size());
|
||||
assertEquals("encoded get", url_encoded.getString("Name14"),"%GG% %% %");
|
||||
assertEquals("encoded get", "\ufffd\ufffd\ufffd\ufffd",url_encoded.getString("Name14"));
|
||||
|
||||
|
||||
/* Not every jvm supports this encoding */
|
||||
|
||||
if (java.nio.charset.Charset.isSupported("SJIS"))
|
||||
{
|
||||
url_encoded.clear();
|
||||
url_encoded.decode("Name9=%83e%83X%83g", "SJIS"); // "Test" in Japanese Katakana
|
||||
url_encoded.decode("Name9=%u30ED%83e%83X%83g", Charset.forName("SJIS")); // "Test" in Japanese Katakana
|
||||
assertEquals("encoded param size",1, url_encoded.size());
|
||||
assertEquals("encoded get", "\u30c6\u30b9\u30c8", url_encoded.getString("Name9"));
|
||||
assertEquals("encoded get", "\u30ed\u30c6\u30b9\u30c8", url_encoded.getString("Name9"));
|
||||
}
|
||||
else
|
||||
assertTrue("Charset SJIS not supported by jvm", true);
|
||||
|
@ -158,11 +160,11 @@ public class URLEncodedTest
|
|||
public void testBadEncoding()
|
||||
{
|
||||
UrlEncoded url_encoded = new UrlEncoded();
|
||||
url_encoded.decode("Name15=xx%zz", "UTF-8");
|
||||
url_encoded.decode("Name15=xx%zz", StringUtil.__UTF8_CHARSET);
|
||||
assertEquals("encoded param size",1, url_encoded.size());
|
||||
assertEquals("encoded get", "xx%zz", url_encoded.getString("Name15"));
|
||||
assertEquals("encoded get", "xx\ufffd", url_encoded.getString("Name15"));
|
||||
|
||||
assertEquals("%u123",UrlEncoded.decodeString("%u123",0,5,"UTF-8"));
|
||||
assertEquals("xxx",UrlEncoded.decodeString("xxx%u123",0,5,StringUtil.__UTF8_CHARSET));
|
||||
}
|
||||
|
||||
|
||||
|
@ -184,20 +186,20 @@ public class URLEncodedTest
|
|||
{
|
||||
ByteArrayInputStream in = new ByteArrayInputStream("name\n=value+%30&name1=&name2&n\u00e3me3=value+3".getBytes(charsets[i][0]));
|
||||
MultiMap<String> m = new MultiMap<>();
|
||||
UrlEncoded.decodeTo(in, m, charsets[i][1], -1,-1);
|
||||
assertEquals(i+" stream length",4,m.size());
|
||||
assertEquals(i+" stream name\\n","value 0",m.getString("name\n"));
|
||||
assertEquals(i+" stream name1","",m.getString("name1"));
|
||||
assertEquals(i+" stream name2","",m.getString("name2"));
|
||||
assertEquals(i+" stream n\u00e3me3","value 3",m.getString("n\u00e3me3"));
|
||||
UrlEncoded.decodeTo(in, m, charsets[i][1]==null?null:Charset.forName(charsets[i][1]), -1,-1);
|
||||
assertEquals(charsets[i][1]+" stream length",4,m.size());
|
||||
assertEquals(charsets[i][1]+" stream name\\n","value 0",m.getString("name\n"));
|
||||
assertEquals(charsets[i][1]+" stream name1","",m.getString("name1"));
|
||||
assertEquals(charsets[i][1]+" stream name2","",m.getString("name2"));
|
||||
assertEquals(charsets[i][1]+" stream n\u00e3me3","value 3",m.getString("n\u00e3me3"));
|
||||
}
|
||||
|
||||
|
||||
if (java.nio.charset.Charset.isSupported("Shift_JIS"))
|
||||
{
|
||||
ByteArrayInputStream in2 = new ByteArrayInputStream ("name=%83e%83X%83g".getBytes());
|
||||
ByteArrayInputStream in2 = new ByteArrayInputStream ("name=%83e%83X%83g".getBytes(StringUtil.__ISO_8859_1));
|
||||
MultiMap<String> m2 = new MultiMap<>();
|
||||
UrlEncoded.decodeTo(in2, m2, "Shift_JIS", -1,-1);
|
||||
UrlEncoded.decodeTo(in2, m2, Charset.forName("Shift_JIS"), -1,-1);
|
||||
assertEquals("stream length",1,m2.size());
|
||||
assertEquals("stream name","\u30c6\u30b9\u30c8",m2.getString("name"));
|
||||
}
|
||||
|
|
|
@ -27,11 +27,16 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.HandlerList;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceCollection;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
@ -183,6 +188,36 @@ public class WebAppContextTest
|
|||
assertFalse(context.isProtectedTarget("/something-else/web-inf"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNullPath() throws Exception
|
||||
{
|
||||
Server server = new Server(0);
|
||||
HandlerList handlers = new HandlerList();
|
||||
ContextHandlerCollection contexts = new ContextHandlerCollection();
|
||||
WebAppContext context = new WebAppContext();
|
||||
context.setBaseResource(Resource.newResource("./src/test/webapp"));
|
||||
context.setContextPath("/");
|
||||
server.setHandler(handlers);
|
||||
handlers.addHandler(contexts);
|
||||
contexts.addHandler(context);
|
||||
|
||||
LocalConnector connector = new LocalConnector(server);
|
||||
server.addConnector(connector);
|
||||
|
||||
server.start();
|
||||
try
|
||||
{
|
||||
String response = connector.getResponses("GET http://localhost:8080 HTTP/1.1\r\nHost: localhost:8080\r\nConnection: close\r\n\r\n");
|
||||
Assert.assertTrue(response.indexOf("200 OK")>=0);
|
||||
}
|
||||
finally
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ServletA extends GenericServlet
|
||||
{
|
||||
@Override
|
||||
|
|
|
@ -88,7 +88,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web
|
|||
String query = requestURI.getQuery();
|
||||
if (StringUtil.isNotBlank(query))
|
||||
{
|
||||
UrlEncoded.decodeTo(query,params,StringUtil.__UTF8);
|
||||
UrlEncoded.decodeTo(query,params,StringUtil.__UTF8_CHARSET,-1);
|
||||
}
|
||||
|
||||
for (String name : params.keySet())
|
||||
|
|
|
@ -41,6 +41,7 @@ public class LocalWebSocketConnection implements WebSocketConnection, LogicalCon
|
|||
private WebSocketPolicy policy = WebSocketPolicy.newServerPolicy();
|
||||
private boolean open = false;
|
||||
private IncomingFrames incoming;
|
||||
private IOState ioState = new IOState();
|
||||
|
||||
public LocalWebSocketConnection()
|
||||
{
|
||||
|
@ -83,8 +84,7 @@ public class LocalWebSocketConnection implements WebSocketConnection, LogicalCon
|
|||
@Override
|
||||
public IOState getIOState()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
return ioState;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.eclipse.jetty.http.HttpVersion;
|
|||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.common.extensions.mux.MuxChannel;
|
||||
|
@ -89,7 +90,7 @@ public class MuxAddHandler implements MuxAddServer
|
|||
|
||||
HttpMethod method = HttpMethod.fromString(request.getMethod());
|
||||
HttpVersion version = HttpVersion.fromString(request.getHttpVersion());
|
||||
httpChannel.startRequest(method,request.getMethod(),request.getRequestURI().toASCIIString(),version);
|
||||
httpChannel.startRequest(method,request.getMethod(),BufferUtil.toBuffer(request.getRequestURI().toASCIIString()),version);
|
||||
|
||||
for (String headerName : request.getHeaders().keySet())
|
||||
{
|
||||
|
|
|
@ -25,13 +25,16 @@ import java.nio.ByteBuffer;
|
|||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
|
||||
import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception;
|
||||
import org.eclipse.jetty.util.Utf8StringBuilder;
|
||||
import org.eclipse.jetty.util.log.StdErrLog;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.Generator;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.Parser;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.server.blockhead.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.server.helper.IncomingFramesCapture;
|
||||
|
@ -42,12 +45,14 @@ import org.junit.Assert;
|
|||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Test various <a href="http://tools.ietf.org/html/rfc6455">RFC 6455</a> specified requirements placed on {@link WebSocketServlet}
|
||||
* <p>
|
||||
* This test serves a different purpose than than the {@link WebSocketMessageRFC6455Test}, and {@link WebSocketParserRFC6455Test} tests.
|
||||
*/
|
||||
@RunWith(AdvancedRunner.class)
|
||||
public class WebSocketServletRFCTest
|
||||
{
|
||||
private static Generator generator = new UnitGenerator();
|
||||
|
@ -66,6 +71,12 @@ public class WebSocketServletRFCTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
private void enableStacks(Class<?> clazz, boolean enabled)
|
||||
{
|
||||
StdErrLog log = StdErrLog.getLogger(clazz);
|
||||
log.setHideStacks(!enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that aggregation of binary frames into a single message occurs
|
||||
*/
|
||||
|
@ -324,6 +335,9 @@ public class WebSocketServletRFCTest
|
|||
@Test
|
||||
public void testTextNotUTF8() throws Exception
|
||||
{
|
||||
// Disable Long Stacks from Parser (we know this test will throw an exception)
|
||||
enableStacks(Parser.class,false);
|
||||
|
||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
||||
client.setProtocols("other");
|
||||
try
|
||||
|
@ -347,8 +361,9 @@ public class WebSocketServletRFCTest
|
|||
}
|
||||
finally
|
||||
{
|
||||
// Reenable Long Stacks from Parser
|
||||
enableStacks(Parser.class,true);
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.nio.ByteBuffer;
|
|||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.StdErrLog;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.Generator;
|
||||
import org.eclipse.jetty.websocket.server.SimpleServletServer;
|
||||
|
@ -88,6 +89,12 @@ public abstract class AbstractABCase
|
|||
@Rule
|
||||
public TestName testname = new TestName();
|
||||
|
||||
protected void enableStacks(Class<?> clazz, boolean enabled)
|
||||
{
|
||||
StdErrLog log = StdErrLog.getLogger(clazz);
|
||||
log.setHideStacks(!enabled);
|
||||
}
|
||||
|
||||
public Generator getLaxGenerator()
|
||||
{
|
||||
return laxGenerator;
|
||||
|
|
|
@ -190,6 +190,7 @@ public class Fuzzer
|
|||
// we expect that the close handshake to have occurred and the server should have closed the connection
|
||||
try
|
||||
{
|
||||
@SuppressWarnings("unused")
|
||||
int val = client.read();
|
||||
|
||||
Assert.fail("Server has not closed socket");
|
||||
|
|
|
@ -22,13 +22,17 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.Parser;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AdvancedRunner.class)
|
||||
public class TestABCase2 extends AbstractABCase
|
||||
{
|
||||
/**
|
||||
|
@ -232,6 +236,9 @@ public class TestABCase2 extends AbstractABCase
|
|||
@Test
|
||||
public void testCase2_5() throws Exception
|
||||
{
|
||||
// Disable Long Stacks from Parser (we know this test will throw an exception)
|
||||
enableStacks(Parser.class,false);
|
||||
|
||||
byte payload[] = new byte[126]; // intentionally too big
|
||||
Arrays.fill(payload,(byte)'5');
|
||||
|
||||
|
@ -253,6 +260,7 @@ public class TestABCase2 extends AbstractABCase
|
|||
}
|
||||
finally
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
fuzzer.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,13 +22,34 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.Parser;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Test various RSV violations
|
||||
*/
|
||||
@RunWith(AdvancedRunner.class)
|
||||
public class TestABCase3 extends AbstractABCase
|
||||
{
|
||||
@After
|
||||
public void enableParserStacks()
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void quietParserStacks()
|
||||
{
|
||||
enableStacks(Parser.class,false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send small text frame, with RSV1 == true, with no extensions defined.
|
||||
*/
|
||||
|
|
|
@ -21,12 +21,21 @@ package org.eclipse.jetty.websocket.server.ab;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.Parser;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Test various bad / forbidden opcodes (per spec)
|
||||
*/
|
||||
@RunWith(AdvancedRunner.class)
|
||||
public class TestABCase4 extends AbstractABCase
|
||||
{
|
||||
// Allow Fuzzer / Generator to create bad frames for testing frame validation
|
||||
|
@ -40,6 +49,18 @@ public class TestABCase4 extends AbstractABCase
|
|||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void enableParserStacks()
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void quietParserStacks()
|
||||
{
|
||||
enableStacks(Parser.class,false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send opcode 3 (reserved)
|
||||
*/
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.eclipse.jetty.toolchain.test.annotation.Slow;
|
|||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.Parser;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
@ -43,6 +44,9 @@ public class TestABCase5 extends AbstractABCase
|
|||
@Test
|
||||
public void testCase5_1() throws Exception
|
||||
{
|
||||
// Disable Long Stacks from Parser (we know this test will throw an exception)
|
||||
enableStacks(Parser.class,false);
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
send.add(new WebSocketFrame(OpCode.PING).setPayload("hello, ").setFin(false));
|
||||
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("world"));
|
||||
|
@ -62,6 +66,7 @@ public class TestABCase5 extends AbstractABCase
|
|||
finally
|
||||
{
|
||||
fuzzer.close();
|
||||
enableStacks(Parser.class,true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,6 +76,9 @@ public class TestABCase5 extends AbstractABCase
|
|||
@Test
|
||||
public void testCase5_10() throws Exception
|
||||
{
|
||||
// Disable Long Stacks from Parser (we know this test will throw an exception)
|
||||
enableStacks(Parser.class,false);
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("sorry").setFin(true));
|
||||
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("hello, world"));
|
||||
|
@ -89,6 +97,7 @@ public class TestABCase5 extends AbstractABCase
|
|||
}
|
||||
finally
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
fuzzer.close();
|
||||
}
|
||||
}
|
||||
|
@ -99,6 +108,9 @@ public class TestABCase5 extends AbstractABCase
|
|||
@Test
|
||||
public void testCase5_11() throws Exception
|
||||
{
|
||||
// Disable Long Stacks from Parser (we know this test will throw an exception)
|
||||
enableStacks(Parser.class,false);
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("sorry").setFin(true));
|
||||
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("hello, world"));
|
||||
|
@ -118,6 +130,7 @@ public class TestABCase5 extends AbstractABCase
|
|||
}
|
||||
finally
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
fuzzer.close();
|
||||
}
|
||||
}
|
||||
|
@ -128,6 +141,9 @@ public class TestABCase5 extends AbstractABCase
|
|||
@Test
|
||||
public void testCase5_12() throws Exception
|
||||
{
|
||||
// Disable Long Stacks from Parser (we know this test will throw an exception)
|
||||
enableStacks(Parser.class,false);
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("sorry").setFin(false));
|
||||
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("hello, world"));
|
||||
|
@ -146,6 +162,7 @@ public class TestABCase5 extends AbstractABCase
|
|||
}
|
||||
finally
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
fuzzer.close();
|
||||
}
|
||||
}
|
||||
|
@ -156,6 +173,8 @@ public class TestABCase5 extends AbstractABCase
|
|||
@Test
|
||||
public void testCase5_13() throws Exception
|
||||
{
|
||||
// Disable Long Stacks from Parser (we know this test will throw an exception)
|
||||
enableStacks(Parser.class,false);
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("sorry").setFin(false));
|
||||
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("hello, world"));
|
||||
|
@ -174,6 +193,7 @@ public class TestABCase5 extends AbstractABCase
|
|||
}
|
||||
finally
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
fuzzer.close();
|
||||
}
|
||||
}
|
||||
|
@ -184,6 +204,9 @@ public class TestABCase5 extends AbstractABCase
|
|||
@Test
|
||||
public void testCase5_14() throws Exception
|
||||
{
|
||||
// Disable Long Stacks from Parser (we know this test will throw an exception)
|
||||
enableStacks(Parser.class,false);
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("sorry").setFin(false));
|
||||
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("hello, world"));
|
||||
|
@ -203,6 +226,7 @@ public class TestABCase5 extends AbstractABCase
|
|||
}
|
||||
finally
|
||||
{
|
||||
enableStacks(Parser.class,false);
|
||||
fuzzer.close();
|
||||
}
|
||||
}
|
||||
|
@ -213,6 +237,9 @@ public class TestABCase5 extends AbstractABCase
|
|||
@Test
|
||||
public void testCase5_15() throws Exception
|
||||
{
|
||||
// Disable Long Stacks from Parser (we know this test will throw an exception)
|
||||
enableStacks(Parser.class,false);
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("fragment1").setFin(false));
|
||||
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("fragment2").setFin(true));
|
||||
|
@ -234,6 +261,7 @@ public class TestABCase5 extends AbstractABCase
|
|||
}
|
||||
finally
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
fuzzer.close();
|
||||
}
|
||||
}
|
||||
|
@ -244,6 +272,9 @@ public class TestABCase5 extends AbstractABCase
|
|||
@Test
|
||||
public void testCase5_16() throws Exception
|
||||
{
|
||||
// Disable Long Stacks from Parser (we know this test will throw an exception)
|
||||
enableStacks(Parser.class,false);
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("fragment1").setFin(false)); // bad frame
|
||||
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("fragment2").setFin(false));
|
||||
|
@ -266,6 +297,7 @@ public class TestABCase5 extends AbstractABCase
|
|||
}
|
||||
finally
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
fuzzer.close();
|
||||
}
|
||||
}
|
||||
|
@ -276,6 +308,9 @@ public class TestABCase5 extends AbstractABCase
|
|||
@Test
|
||||
public void testCase5_17() throws Exception
|
||||
{
|
||||
// Disable Long Stacks from Parser (we know this test will throw an exception)
|
||||
enableStacks(Parser.class,false);
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("fragment1").setFin(true)); // nothing to continue
|
||||
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("fragment2").setFin(false));
|
||||
|
@ -298,6 +333,7 @@ public class TestABCase5 extends AbstractABCase
|
|||
}
|
||||
finally
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
fuzzer.close();
|
||||
}
|
||||
}
|
||||
|
@ -308,6 +344,9 @@ public class TestABCase5 extends AbstractABCase
|
|||
@Test
|
||||
public void testCase5_18() throws Exception
|
||||
{
|
||||
// Disable Long Stacks from Parser (we know this test will throw an exception)
|
||||
enableStacks(Parser.class,false);
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("fragment1").setFin(false));
|
||||
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("fragment2").setFin(true)); // bad frame, must be continuation
|
||||
|
@ -326,6 +365,7 @@ public class TestABCase5 extends AbstractABCase
|
|||
}
|
||||
finally
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
fuzzer.close();
|
||||
}
|
||||
}
|
||||
|
@ -388,6 +428,9 @@ public class TestABCase5 extends AbstractABCase
|
|||
@Test
|
||||
public void testCase5_2() throws Exception
|
||||
{
|
||||
// Disable Long Stacks from Parser (we know this test will throw an exception)
|
||||
enableStacks(Parser.class,false);
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
send.add(new WebSocketFrame(OpCode.PONG).setPayload("hello, ").setFin(false));
|
||||
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("world"));
|
||||
|
@ -406,6 +449,7 @@ public class TestABCase5 extends AbstractABCase
|
|||
}
|
||||
finally
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
fuzzer.close();
|
||||
}
|
||||
}
|
||||
|
@ -691,6 +735,9 @@ public class TestABCase5 extends AbstractABCase
|
|||
@Test
|
||||
public void testCase5_9() throws Exception
|
||||
{
|
||||
// Disable Long Stacks from Parser (we know this test will throw an exception)
|
||||
enableStacks(Parser.class,false);
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("sorry").setFin(true));
|
||||
send.add(new WebSocketFrame(OpCode.TEXT).setPayload("hello, world"));
|
||||
|
@ -709,6 +756,7 @@ public class TestABCase5 extends AbstractABCase
|
|||
}
|
||||
finally
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
fuzzer.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.eclipse.jetty.util.TypeUtil;
|
|||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.Parser;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.server.helper.Hex;
|
||||
import org.junit.Test;
|
||||
|
@ -356,6 +357,9 @@ public class TestABCase6 extends AbstractABCase
|
|||
@Slow
|
||||
public void testCase6_4_3() throws Exception
|
||||
{
|
||||
// Disable Long Stacks from Parser (we know this test will throw an exception)
|
||||
enableStacks(Parser.class,false);
|
||||
|
||||
ByteBuffer payload = ByteBuffer.allocate(64);
|
||||
BufferUtil.clearToFill(payload);
|
||||
payload.put(TypeUtil.fromHexString("cebae1bdb9cf83cebcceb5")); // good
|
||||
|
@ -400,6 +404,7 @@ public class TestABCase6 extends AbstractABCase
|
|||
}
|
||||
finally
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
fuzzer.close();
|
||||
}
|
||||
}
|
||||
|
@ -411,6 +416,9 @@ public class TestABCase6 extends AbstractABCase
|
|||
@Slow
|
||||
public void testCase6_4_4() throws Exception
|
||||
{
|
||||
// Disable Long Stacks from Parser (we know this test will throw an exception)
|
||||
enableStacks(Parser.class,false);
|
||||
|
||||
byte invalid[] = Hex.asByteArray("CEBAE1BDB9CF83CEBCCEB5F49080808080656469746564");
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
|
@ -437,6 +445,7 @@ public class TestABCase6 extends AbstractABCase
|
|||
}
|
||||
finally
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
fuzzer.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import java.util.List;
|
|||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.log.StdErrLog;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
|
@ -177,10 +176,4 @@ public class TestABCase6_BadUTF extends AbstractABCase
|
|||
enableStacks(Parser.class,true);
|
||||
}
|
||||
}
|
||||
|
||||
private void enableStacks(Class<?> clazz, boolean enabled)
|
||||
{
|
||||
StdErrLog log = StdErrLog.getLogger(clazz);
|
||||
log.setHideStacks(!enabled);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ import java.util.List;
|
|||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.StdErrLog;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
|
@ -41,12 +40,6 @@ import org.junit.Test;
|
|||
*/
|
||||
public class TestABCase7 extends AbstractABCase
|
||||
{
|
||||
private static void enableStacks(Class<?> clazz, boolean enabled)
|
||||
{
|
||||
StdErrLog log = StdErrLog.getLogger(clazz);
|
||||
log.setHideStacks(!enabled);
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
# org.eclipse.jetty.LEVEL=WARN
|
||||
org.eclipse.jetty.LEVEL=WARN
|
||||
|
||||
# org.eclipse.jetty.websocket.LEVEL=DEBUG
|
||||
org.eclipse.jetty.websocket.LEVEL=WARN
|
||||
# org.eclipse.jetty.websocket.LEVEL=WARN
|
||||
# org.eclipse.jetty.websocket.common.io.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.server.ab.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.common.io.LEVEL=DEBUG
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -567,7 +567,7 @@
|
|||
-->
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<id>eclipse-release</id>
|
||||
<!-- Not ready yet
|
||||
<modules>
|
||||
<module>aggregates/jetty-all</module>
|
||||
|
|
|
@ -20,6 +20,8 @@ package com.acme;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
|
@ -120,4 +122,21 @@ public class CookieDump extends HttpServlet
|
|||
return string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
// For testing --stop with STOP.WAIT handling of the jetty-start behavior.
|
||||
if (Boolean.getBoolean("test.slow.destroy"))
|
||||
{
|
||||
try
|
||||
{
|
||||
TimeUnit.SECONDS.sleep(10);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
This is the Test webapp for the Jetty 9 HTTP Server and Servlet Container.
|
||||
For more information about Jetty, please visit our
|
||||
<a href="http://www.eclipse.org/jetty">website</a>
|
||||
or <a href="http://www.eclipse.org/jetty/documentation/current/">documentation</a> or see the bundled <a href="javadoc/">javadoc</a>.<br/>
|
||||
or <a href="http://www.eclipse.org/jetty/documentation/current/">documentation</a> hub.<br/>
|
||||
Commercial support for Jetty is available via <a href="http://www.webtide.com">Webtide</a> and <a href="http://www.intalio.com">Intalio</a>.
|
||||
</p>
|
||||
<p>
|
||||
|
|
|
@ -22,10 +22,14 @@ import com.acme.DispatchServlet;
|
|||
import org.eclipse.jetty.servlet.DefaultServlet;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.servlet.ServletTester;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.StdErrLog;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Simple tests against DispatchServlet.
|
||||
|
@ -136,8 +140,7 @@ public class DispatchServletTest
|
|||
response.startsWith("HTTP/1.1 413 "));
|
||||
|
||||
assertFalse(msg + " should not be code 500.", response.startsWith("HTTP/1.1 500 "));
|
||||
|
||||
assertTrue(msg + " should return error code 403 (Forbidden)", response.startsWith("HTTP/1.1 403 "));
|
||||
assertThat(response,Matchers.startsWith("HTTP/1.1 403 "));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
|
||||
|
||||
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
|
||||
<Set name="contextPath">/xref</Set>
|
||||
<Set name="contextPath">/proxy</Set>
|
||||
</Configure>
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
<display-name>Transparent Proxy WebApp</display-name>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>TransparentProxy</servlet-name>
|
||||
<servlet-name>XrefTransparentProxy</servlet-name>
|
||||
<servlet-class>org.eclipse.jetty.proxy.ProxyServlet$Transparent</servlet-class>
|
||||
<init-param>
|
||||
<param-name>proxyTo</param-name><param-value>http://download.eclipse.org/jetty/stable-9/xref</param-value>
|
||||
<param-name>proxyTo</param-name><param-value>http://download.eclipse.org/jetty/stable-9</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>hostHeader</param-name><param-value>download.eclipse.org</param-value>
|
||||
|
@ -22,8 +22,26 @@
|
|||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>TransparentProxy</servlet-name>
|
||||
<url-pattern>/</url-pattern>
|
||||
<servlet-name>XrefTransparentProxy</servlet-name>
|
||||
<url-pattern>/xref/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>JavadocTransparentProxy</servlet-name>
|
||||
<servlet-class>org.eclipse.jetty.proxy.ProxyServlet$Transparent</servlet-class>
|
||||
<init-param>
|
||||
<param-name>proxyTo</param-name><param-value>http://download.eclipse.org/jetty/stable-9</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>hostHeader</param-name><param-value>download.eclipse.org</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
<async-supported>true</async-supported>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>JavadocTransparentProxy</servlet-name>
|
||||
<url-pattern>/apidocs/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
</web-app>
|
||||
|
|
Loading…
Reference in New Issue