Merged branch 'master' into '431642'.
This commit is contained in:
commit
43454ebd0a
|
@ -246,14 +246,12 @@ public class GZIPContentDecoder implements ContentDecoder
|
||||||
if (output == null)
|
if (output == null)
|
||||||
{
|
{
|
||||||
// Save the inflated bytes and loop to see if we have finished
|
// Save the inflated bytes and loop to see if we have finished
|
||||||
output = new byte[decoded];
|
output = Arrays.copyOf(bytes, decoded);
|
||||||
System.arraycopy(bytes, 0, output, 0, decoded);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Accumulate inflated bytes and loop to see if we have finished
|
// Accumulate inflated bytes and loop to see if we have finished
|
||||||
byte[] newOutput = new byte[output.length + decoded];
|
byte[] newOutput = Arrays.copyOf(output, output.length+decoded);
|
||||||
System.arraycopy(output, 0, newOutput, 0, output.length);
|
|
||||||
System.arraycopy(bytes, 0, newOutput, output.length, decoded);
|
System.arraycopy(bytes, 0, newOutput, output.length, decoded);
|
||||||
output = newOutput;
|
output = newOutput;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,14 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.client.util;
|
package org.eclipse.jetty.client.util;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.charset.UnsupportedCharsetException;
|
import java.nio.charset.UnsupportedCharsetException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.eclipse.jetty.client.api.Response;
|
import org.eclipse.jetty.client.api.Response;
|
||||||
|
@ -30,6 +33,7 @@ import org.eclipse.jetty.client.api.Response.Listener;
|
||||||
import org.eclipse.jetty.client.api.Result;
|
import org.eclipse.jetty.client.api.Result;
|
||||||
import org.eclipse.jetty.http.HttpFields;
|
import org.eclipse.jetty.http.HttpFields;
|
||||||
import org.eclipse.jetty.http.HttpHeader;
|
import org.eclipse.jetty.http.HttpHeader;
|
||||||
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Implementation of {@link Listener} that buffers the content up to a maximum length
|
* <p>Implementation of {@link Listener} that buffers the content up to a maximum length
|
||||||
|
@ -40,7 +44,7 @@ import org.eclipse.jetty.http.HttpHeader;
|
||||||
public abstract class BufferingResponseListener extends Listener.Adapter
|
public abstract class BufferingResponseListener extends Listener.Adapter
|
||||||
{
|
{
|
||||||
private final int maxLength;
|
private final int maxLength;
|
||||||
private volatile byte[] buffer = new byte[0];
|
private volatile ByteBuffer buffer;
|
||||||
private volatile String encoding;
|
private volatile String encoding;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -58,53 +62,57 @@ public abstract class BufferingResponseListener extends Listener.Adapter
|
||||||
*/
|
*/
|
||||||
public BufferingResponseListener(int maxLength)
|
public BufferingResponseListener(int maxLength)
|
||||||
{
|
{
|
||||||
this.maxLength = maxLength;
|
this.maxLength=maxLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onHeaders(Response response)
|
public void onHeaders(Response response)
|
||||||
{
|
{
|
||||||
|
super.onHeaders(response);
|
||||||
|
|
||||||
HttpFields headers = response.getHeaders();
|
HttpFields headers = response.getHeaders();
|
||||||
long length = headers.getLongField(HttpHeader.CONTENT_LENGTH.asString());
|
long length = headers.getLongField(HttpHeader.CONTENT_LENGTH.asString());
|
||||||
if (length > maxLength)
|
if (length > maxLength)
|
||||||
{
|
{
|
||||||
response.abort(new IllegalArgumentException("Buffering capacity exceeded"));
|
response.abort(new IllegalArgumentException("Buffering capacity exceeded"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
buffer=BufferUtil.allocate((length > 0)?(int)length:1024);
|
||||||
|
|
||||||
|
String contentType = headers.get(HttpHeader.CONTENT_TYPE);
|
||||||
|
if (contentType != null)
|
||||||
{
|
{
|
||||||
String contentType = headers.get(HttpHeader.CONTENT_TYPE);
|
String charset = "charset=";
|
||||||
if (contentType != null)
|
int index = contentType.toLowerCase(Locale.ENGLISH).indexOf(charset);
|
||||||
|
if (index > 0)
|
||||||
{
|
{
|
||||||
String charset = "charset=";
|
String encoding = contentType.substring(index + charset.length());
|
||||||
int index = contentType.toLowerCase(Locale.ENGLISH).indexOf(charset);
|
// Sometimes charsets arrive with an ending semicolon
|
||||||
|
index = encoding.indexOf(';');
|
||||||
if (index > 0)
|
if (index > 0)
|
||||||
{
|
encoding = encoding.substring(0, index);
|
||||||
String encoding = contentType.substring(index + charset.length());
|
this.encoding = encoding;
|
||||||
// Sometimes charsets arrive with an ending semicolon
|
|
||||||
index = encoding.indexOf(';');
|
|
||||||
if (index > 0)
|
|
||||||
encoding = encoding.substring(0, index);
|
|
||||||
this.encoding = encoding;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onContent(Response response, ByteBuffer content)
|
public void onContent(Response response, ByteBuffer content)
|
||||||
{
|
{
|
||||||
long newLength = buffer.length + content.remaining();
|
int length = content.remaining();
|
||||||
if (newLength > maxLength)
|
if (length>BufferUtil.space(buffer))
|
||||||
{
|
{
|
||||||
response.abort(new IllegalArgumentException("Buffering capacity exceeded"));
|
int requiredCapacity = buffer==null?0:buffer.capacity()+length;
|
||||||
}
|
if (requiredCapacity>maxLength)
|
||||||
else
|
response.abort(new IllegalArgumentException("Buffering capacity exceeded"));
|
||||||
{
|
|
||||||
byte[] newBuffer = new byte[(int)newLength];
|
int newCapacity = Math.min(Integer.highestOneBit(requiredCapacity) << 1, maxLength);
|
||||||
System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
|
buffer = BufferUtil.ensureCapacity(buffer,newCapacity);
|
||||||
content.get(newBuffer, buffer.length, content.remaining());
|
|
||||||
buffer = newBuffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BufferUtil.append(buffer, content);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -121,7 +129,9 @@ public abstract class BufferingResponseListener extends Listener.Adapter
|
||||||
*/
|
*/
|
||||||
public byte[] getContent()
|
public byte[] getContent()
|
||||||
{
|
{
|
||||||
return buffer;
|
if (buffer==null)
|
||||||
|
return new byte[0];
|
||||||
|
return BufferUtil.toArray(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -144,14 +154,9 @@ public abstract class BufferingResponseListener extends Listener.Adapter
|
||||||
*/
|
*/
|
||||||
public String getContentAsString(String encoding)
|
public String getContentAsString(String encoding)
|
||||||
{
|
{
|
||||||
try
|
if (buffer==null)
|
||||||
{
|
return null;
|
||||||
return new String(getContent(), encoding);
|
return BufferUtil.toString(buffer, Charset.forName(encoding));
|
||||||
}
|
|
||||||
catch (UnsupportedEncodingException x)
|
|
||||||
{
|
|
||||||
throw new UnsupportedCharsetException(encoding);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -161,6 +166,19 @@ public abstract class BufferingResponseListener extends Listener.Adapter
|
||||||
*/
|
*/
|
||||||
public String getContentAsString(Charset encoding)
|
public String getContentAsString(Charset encoding)
|
||||||
{
|
{
|
||||||
return new String(getContent(), encoding);
|
if (buffer==null)
|
||||||
|
return null;
|
||||||
|
return BufferUtil.toString(buffer, encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @return Content as InputStream
|
||||||
|
*/
|
||||||
|
public InputStream getContentAsInputStream()
|
||||||
|
{
|
||||||
|
if (buffer==null)
|
||||||
|
return new ByteArrayInputStream(new byte[]{});
|
||||||
|
return new ByteArrayInputStream(buffer.array(), buffer.arrayOffset(), buffer.remaining());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,12 +37,14 @@ import java.util.List;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.Exchanger;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.zip.GZIPOutputStream;
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletOutputStream;
|
import javax.servlet.ServletOutputStream;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
@ -1047,26 +1049,33 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
final AtomicInteger complete = new AtomicInteger();
|
final Exchanger<Response> ex = new Exchanger<Response>();
|
||||||
BufferingResponseListener listener = new BufferingResponseListener()
|
BufferingResponseListener listener = new BufferingResponseListener()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void onComplete(Result result)
|
public void onComplete(Result result)
|
||||||
{
|
{
|
||||||
complete.incrementAndGet();
|
try
|
||||||
|
{
|
||||||
|
ex.exchange(result.getResponse());
|
||||||
|
}
|
||||||
|
catch (InterruptedException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
|
|
||||||
|
client.newRequest("localhost", connector.getLocalPort())
|
||||||
.scheme(scheme)
|
.scheme(scheme)
|
||||||
.onResponseContent(listener)
|
.send(listener);
|
||||||
.onComplete(listener)
|
|
||||||
.send();
|
Response response = ex.exchange(null);
|
||||||
|
|
||||||
Assert.assertEquals(200, response.getStatus());
|
Assert.assertEquals(200, response.getStatus());
|
||||||
Assert.assertEquals(1, complete.get());
|
|
||||||
Assert.assertArrayEquals(content, listener.getContent());
|
Assert.assertArrayEquals(content, listener.getContent());
|
||||||
Assert.assertArrayEquals(content, response.getContent());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.io.IOException;
|
||||||
import java.nio.BufferOverflowException;
|
import java.nio.BufferOverflowException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.HttpTokens.EndOfContent;
|
import org.eclipse.jetty.http.HttpTokens.EndOfContent;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
@ -916,10 +917,8 @@ public class HttpGenerator
|
||||||
line[versionLength+6+reason.length()]=HttpTokens.LINE_FEED;
|
line[versionLength+6+reason.length()]=HttpTokens.LINE_FEED;
|
||||||
|
|
||||||
__preprepared[i] = new PreparedResponse();
|
__preprepared[i] = new PreparedResponse();
|
||||||
__preprepared[i]._reason=new byte[line.length-versionLength-7] ;
|
__preprepared[i]._schemeCode = Arrays.copyOfRange(line, 0,versionLength+5);
|
||||||
System.arraycopy(line,versionLength+5,__preprepared[i]._reason,0,line.length-versionLength-7);
|
__preprepared[i]._reason = Arrays.copyOfRange(line, versionLength+5, line.length-2);
|
||||||
__preprepared[i]._schemeCode=new byte[versionLength+5];
|
|
||||||
System.arraycopy(line,0,__preprepared[i]._schemeCode,0,versionLength+5);
|
|
||||||
__preprepared[i]._responseLine=line;
|
__preprepared[i]._responseLine=line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1091,8 +1090,7 @@ public class HttpGenerator
|
||||||
{
|
{
|
||||||
super(header,value);
|
super(header,value);
|
||||||
int cbl=header.getBytesColonSpace().length;
|
int cbl=header.getBytesColonSpace().length;
|
||||||
_bytes=new byte[cbl+value.length()+2];
|
_bytes=Arrays.copyOf(header.getBytesColonSpace(), cbl+value.length()+2);
|
||||||
System.arraycopy(header.getBytesColonSpace(),0,_bytes,0,cbl);
|
|
||||||
System.arraycopy(value.getBytes(StandardCharsets.ISO_8859_1),0,_bytes,cbl,value.length());
|
System.arraycopy(value.getBytes(StandardCharsets.ISO_8859_1),0,_bytes,cbl,value.length());
|
||||||
_bytes[_bytes.length-2]=(byte)'\r';
|
_bytes[_bytes.length-2]=(byte)'\r';
|
||||||
_bytes[_bytes.length-1]=(byte)'\n';
|
_bytes[_bytes.length-1]=(byte)'\n';
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.ClosedChannelException;
|
import java.nio.channels.ClosedChannelException;
|
||||||
import java.nio.channels.WritePendingException;
|
import java.nio.channels.WritePendingException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -301,10 +302,7 @@ abstract public class WriteFlusher
|
||||||
if (consumed == length)
|
if (consumed == length)
|
||||||
return EMPTY_BUFFERS;
|
return EMPTY_BUFFERS;
|
||||||
|
|
||||||
int newLength = length - consumed;
|
return Arrays.copyOfRange(buffers,consumed,length);
|
||||||
ByteBuffer[] result = new ByteBuffer[newLength];
|
|
||||||
System.arraycopy(buffers, consumed, result, 0, newLength);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,6 +112,7 @@
|
||||||
javax.servlet.http;version="[3.1,3.2)",
|
javax.servlet.http;version="[3.1,3.2)",
|
||||||
javax.transaction;version="1.1.0";resolution:=optional,
|
javax.transaction;version="1.1.0";resolution:=optional,
|
||||||
javax.transaction.xa;version="1.1.0";resolution:=optional,
|
javax.transaction.xa;version="1.1.0";resolution:=optional,
|
||||||
|
org.objectweb.asm;version=4;resolution:=optional,
|
||||||
org.eclipse.jetty.annotations;version="9.0.0";resolution:=optional,
|
org.eclipse.jetty.annotations;version="9.0.0";resolution:=optional,
|
||||||
org.osgi.framework,
|
org.osgi.framework,
|
||||||
org.osgi.service.cm;version="1.2.0",
|
org.osgi.service.cm;version="1.2.0",
|
||||||
|
|
|
@ -35,21 +35,6 @@ import org.eclipse.jetty.util.thread.Scheduler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of AsyncContext interface that holds the state of request-response cycle.
|
* Implementation of AsyncContext interface that holds the state of request-response cycle.
|
||||||
*
|
|
||||||
* <table>
|
|
||||||
* <tr><th>STATE</th><th colspan=6>ACTION</th></tr>
|
|
||||||
* <tr><th></th> <th>handling()</th> <th>startAsync()</th><th>unhandle()</th> <th>dispatch()</th> <th>complete()</th> <th>completed()</th></tr>
|
|
||||||
* <tr><th align=right>IDLE:</th> <td>DISPATCHED</td> <td></td> <td></td> <td></td> <td>COMPLETECALLED??</td><td></td></tr>
|
|
||||||
* <tr><th align=right>DISPATCHED:</th> <td></td> <td>ASYNCSTARTED</td><td>COMPLETING</td> <td></td> <td></td> <td></td></tr>
|
|
||||||
* <tr><th align=right>ASYNCSTARTED:</th> <td></td> <td></td> <td>ASYNCWAIT</td> <td>REDISPATCHING</td><td>COMPLETECALLED</td> <td></td></tr>
|
|
||||||
* <tr><th align=right>REDISPATCHING:</th> <td></td> <td></td> <td>REDISPATCHED</td><td></td> <td></td> <td></td></tr>
|
|
||||||
* <tr><th align=right>ASYNCWAIT:</th> <td></td> <td></td> <td></td> <td>REDISPATCH</td> <td>COMPLETECALLED</td> <td></td></tr>
|
|
||||||
* <tr><th align=right>REDISPATCH:</th> <td>REDISPATCHED</td><td></td> <td></td> <td></td> <td></td> <td></td></tr>
|
|
||||||
* <tr><th align=right>REDISPATCHED:</th> <td></td> <td>ASYNCSTARTED</td><td>COMPLETING</td> <td></td> <td></td> <td></td></tr>
|
|
||||||
* <tr><th align=right>COMPLETECALLED:</th><td>COMPLETING</td> <td></td> <td>COMPLETING</td> <td></td> <td></td> <td></td></tr>
|
|
||||||
* <tr><th align=right>COMPLETING:</th> <td>COMPLETING</td> <td></td> <td></td> <td></td> <td></td> <td>COMPLETED</td></tr>
|
|
||||||
* <tr><th align=right>COMPLETED:</th> <td></td> <td></td> <td></td> <td></td> <td></td> <td></td></tr>
|
|
||||||
* </table>
|
|
||||||
*/
|
*/
|
||||||
public class HttpChannelState
|
public class HttpChannelState
|
||||||
{
|
{
|
||||||
|
@ -57,16 +42,22 @@ public class HttpChannelState
|
||||||
|
|
||||||
private final static long DEFAULT_TIMEOUT=30000L;
|
private final static long DEFAULT_TIMEOUT=30000L;
|
||||||
|
|
||||||
|
/** The dispatched state of the HttpChannel, used to control the overall livecycle
|
||||||
|
*/
|
||||||
public enum State
|
public enum State
|
||||||
{
|
{
|
||||||
IDLE, // Idle request
|
IDLE, // Idle request
|
||||||
DISPATCHED, // Request dispatched to filter/servlet
|
DISPATCHED, // Request dispatched to filter/servlet
|
||||||
ASYNCWAIT, // Suspended and parked
|
ASYNC_WAIT, // Suspended and parked
|
||||||
ASYNCIO, // Has been dispatched for async IO
|
ASYNC_WOKEN, // A thread has been dispatch to handle from ASYNCWAIT
|
||||||
COMPLETING, // Request is completable
|
ASYNC_IO, // Has been dispatched for async IO
|
||||||
COMPLETED // Request is complete
|
COMPLETING, // Request is completable
|
||||||
|
COMPLETED // Request is complete
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The actions to take as the channel moves from state to state.
|
||||||
|
*/
|
||||||
public enum Action
|
public enum Action
|
||||||
{
|
{
|
||||||
REQUEST_DISPATCH, // handle a normal request dispatch
|
REQUEST_DISPATCH, // handle a normal request dispatch
|
||||||
|
@ -78,6 +69,11 @@ public class HttpChannelState
|
||||||
COMPLETE // Complete the channel
|
COMPLETE // Complete the channel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The state of the servlet async API. This can lead or follow the
|
||||||
|
* channel dispatch state and also includes reasons such as expired,
|
||||||
|
* dispatched or completed.
|
||||||
|
*/
|
||||||
public enum Async
|
public enum Async
|
||||||
{
|
{
|
||||||
STARTED,
|
STARTED,
|
||||||
|
@ -188,16 +184,18 @@ public class HttpChannelState
|
||||||
case COMPLETED:
|
case COMPLETED:
|
||||||
return Action.WAIT;
|
return Action.WAIT;
|
||||||
|
|
||||||
case ASYNCWAIT:
|
case ASYNC_WAIT:
|
||||||
|
LOG.warn("How did I get here?", new Throwable());
|
||||||
|
case ASYNC_WOKEN:
|
||||||
if (_asyncRead)
|
if (_asyncRead)
|
||||||
{
|
{
|
||||||
_state=State.ASYNCIO;
|
_state=State.ASYNC_IO;
|
||||||
_asyncRead=false;
|
_asyncRead=false;
|
||||||
return Action.READ_CALLBACK;
|
return Action.READ_CALLBACK;
|
||||||
}
|
}
|
||||||
if (_asyncWrite)
|
if (_asyncWrite)
|
||||||
{
|
{
|
||||||
_state=State.ASYNCIO;
|
_state=State.ASYNC_IO;
|
||||||
_asyncWrite=false;
|
_asyncWrite=false;
|
||||||
return Action.WRITE_CALLBACK;
|
return Action.WRITE_CALLBACK;
|
||||||
}
|
}
|
||||||
|
@ -293,7 +291,7 @@ public class HttpChannelState
|
||||||
switch(_state)
|
switch(_state)
|
||||||
{
|
{
|
||||||
case DISPATCHED:
|
case DISPATCHED:
|
||||||
case ASYNCIO:
|
case ASYNC_IO:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException(this.getStatusString());
|
throw new IllegalStateException(this.getStatusString());
|
||||||
|
@ -301,7 +299,7 @@ public class HttpChannelState
|
||||||
|
|
||||||
if (_asyncRead)
|
if (_asyncRead)
|
||||||
{
|
{
|
||||||
_state=State.ASYNCIO;
|
_state=State.ASYNC_IO;
|
||||||
_asyncRead=false;
|
_asyncRead=false;
|
||||||
return Action.READ_CALLBACK;
|
return Action.READ_CALLBACK;
|
||||||
}
|
}
|
||||||
|
@ -309,7 +307,7 @@ public class HttpChannelState
|
||||||
if (_asyncWrite)
|
if (_asyncWrite)
|
||||||
{
|
{
|
||||||
_asyncWrite=false;
|
_asyncWrite=false;
|
||||||
_state=State.ASYNCIO;
|
_state=State.ASYNC_IO;
|
||||||
return Action.WRITE_CALLBACK;
|
return Action.WRITE_CALLBACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,7 +331,7 @@ public class HttpChannelState
|
||||||
case EXPIRING:
|
case EXPIRING:
|
||||||
case STARTED:
|
case STARTED:
|
||||||
scheduleTimeout();
|
scheduleTimeout();
|
||||||
_state=State.ASYNCWAIT;
|
_state=State.ASYNC_WAIT;
|
||||||
return Action.WAIT;
|
return Action.WAIT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,7 +358,7 @@ public class HttpChannelState
|
||||||
switch(_state)
|
switch(_state)
|
||||||
{
|
{
|
||||||
case DISPATCHED:
|
case DISPATCHED:
|
||||||
case ASYNCIO:
|
case ASYNC_IO:
|
||||||
dispatch=false;
|
dispatch=false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -411,8 +409,11 @@ public class HttpChannelState
|
||||||
if (_async==Async.EXPIRING)
|
if (_async==Async.EXPIRING)
|
||||||
{
|
{
|
||||||
_async=Async.EXPIRED;
|
_async=Async.EXPIRED;
|
||||||
if (_state==State.ASYNCWAIT)
|
if (_state==State.ASYNC_WAIT)
|
||||||
|
{
|
||||||
|
_state=State.ASYNC_WOKEN;
|
||||||
dispatch=true;
|
dispatch=true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,13 +424,17 @@ public class HttpChannelState
|
||||||
public void complete()
|
public void complete()
|
||||||
{
|
{
|
||||||
// just like resume, except don't set _dispatched=true;
|
// just like resume, except don't set _dispatched=true;
|
||||||
boolean handle;
|
boolean handle=false;
|
||||||
synchronized (this)
|
synchronized (this)
|
||||||
{
|
{
|
||||||
if (_async!=Async.STARTED && _async!=Async.EXPIRING)
|
if (_async!=Async.STARTED && _async!=Async.EXPIRING)
|
||||||
throw new IllegalStateException(this.getStatusString());
|
throw new IllegalStateException(this.getStatusString());
|
||||||
_async=Async.COMPLETE;
|
_async=Async.COMPLETE;
|
||||||
handle=_state==State.ASYNCWAIT;
|
if (_state==State.ASYNC_WAIT)
|
||||||
|
{
|
||||||
|
handle=true;
|
||||||
|
_state=State.ASYNC_WOKEN;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelTimeout();
|
cancelTimeout();
|
||||||
|
@ -511,7 +516,7 @@ public class HttpChannelState
|
||||||
switch(_state)
|
switch(_state)
|
||||||
{
|
{
|
||||||
case DISPATCHED:
|
case DISPATCHED:
|
||||||
case ASYNCIO:
|
case ASYNC_IO:
|
||||||
throw new IllegalStateException(getStatusString());
|
throw new IllegalStateException(getStatusString());
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -571,7 +576,7 @@ public class HttpChannelState
|
||||||
{
|
{
|
||||||
synchronized(this)
|
synchronized(this)
|
||||||
{
|
{
|
||||||
return _state==State.ASYNCWAIT || _state==State.DISPATCHED && _async==Async.STARTED;
|
return _state==State.ASYNC_WAIT || _state==State.DISPATCHED && _async==Async.STARTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -665,12 +670,16 @@ public class HttpChannelState
|
||||||
|
|
||||||
public void onReadPossible()
|
public void onReadPossible()
|
||||||
{
|
{
|
||||||
boolean handle;
|
boolean handle=false;
|
||||||
|
|
||||||
synchronized (this)
|
synchronized (this)
|
||||||
{
|
{
|
||||||
_asyncRead=true;
|
_asyncRead=true;
|
||||||
handle=_state==State.ASYNCWAIT;
|
if (_state==State.ASYNC_WAIT)
|
||||||
|
{
|
||||||
|
_state=State.ASYNC_WOKEN;
|
||||||
|
handle=true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handle)
|
if (handle)
|
||||||
|
@ -679,12 +688,16 @@ public class HttpChannelState
|
||||||
|
|
||||||
public void onWritePossible()
|
public void onWritePossible()
|
||||||
{
|
{
|
||||||
boolean handle;
|
boolean handle=false;
|
||||||
|
|
||||||
synchronized (this)
|
synchronized (this)
|
||||||
{
|
{
|
||||||
_asyncWrite=true;
|
_asyncWrite=true;
|
||||||
handle=_state==State.ASYNCWAIT;
|
if (_state==State.ASYNC_WAIT)
|
||||||
|
{
|
||||||
|
_state=State.ASYNC_WOKEN;
|
||||||
|
handle=true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handle)
|
if (handle)
|
||||||
|
|
|
@ -1214,20 +1214,17 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
||||||
_protectedTargets = null;
|
_protectedTargets = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_protectedTargets = new String[targets.length];
|
_protectedTargets = Arrays.copyOf(targets, targets.length);
|
||||||
System.arraycopy(targets, 0, _protectedTargets, 0, targets.length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public String[] getProtectedTargets ()
|
public String[] getProtectedTargets()
|
||||||
{
|
{
|
||||||
if (_protectedTargets == null)
|
if (_protectedTargets == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
String[] tmp = new String[_protectedTargets.length];
|
return Arrays.copyOf(_protectedTargets, _protectedTargets.length);
|
||||||
System.arraycopy(_protectedTargets, 0, tmp, 0, _protectedTargets.length);
|
|
||||||
return tmp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.server.handler;
|
package org.eclipse.jetty.server.handler;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
@ -25,6 +26,8 @@ import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
|
||||||
import org.eclipse.jetty.server.Connector;
|
import org.eclipse.jetty.server.Connector;
|
||||||
import org.eclipse.jetty.server.HttpConfiguration;
|
import org.eclipse.jetty.server.HttpConfiguration;
|
||||||
|
@ -43,12 +46,12 @@ import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resource Handler test
|
* Resource Handler test
|
||||||
*
|
*
|
||||||
* TODO: increase the testing going on here
|
* TODO: increase the testing going on here
|
||||||
*/
|
*/
|
||||||
public class ResourceHandlerTest
|
public class ResourceHandlerTest
|
||||||
{
|
{
|
||||||
private static final String LN = System.getProperty("line.separator");
|
private static String LN = System.getProperty("line.separator");
|
||||||
private static Server _server;
|
private static Server _server;
|
||||||
private static HttpConfiguration _config;
|
private static HttpConfiguration _config;
|
||||||
private static ServerConnector _connector;
|
private static ServerConnector _connector;
|
||||||
|
@ -60,29 +63,56 @@ public class ResourceHandlerTest
|
||||||
{
|
{
|
||||||
File dir = MavenTestingUtils.getTargetFile("test-classes/simple");
|
File dir = MavenTestingUtils.getTargetFile("test-classes/simple");
|
||||||
File huge = new File(dir,"huge.txt");
|
File huge = new File(dir,"huge.txt");
|
||||||
File big=new File(dir,"big.txt");
|
File big = new File(dir,"big.txt");
|
||||||
try (OutputStream out = new FileOutputStream(huge)) {
|
try (OutputStream out = new FileOutputStream(huge))
|
||||||
for (int i=0;i<100;i++)
|
{
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
{
|
{
|
||||||
try (InputStream in=new FileInputStream(big))
|
try (InputStream in = new FileInputStream(big))
|
||||||
{
|
{
|
||||||
IO.copy(in,out);
|
IO.copy(in,out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
huge.deleteOnExit();
|
huge.deleteOnExit();
|
||||||
|
|
||||||
|
// determine how the SCM of choice checked out the big.txt EOL
|
||||||
|
// we can't just use whatever is the OS default.
|
||||||
|
// because, for example, a windows system using git can be configured for EOL handling using
|
||||||
|
// local, remote, file lists, patterns, etc, rendering assumptions about the OS EOL choice
|
||||||
|
// wrong for unit tests.
|
||||||
|
LN = System.getProperty("line.separator");
|
||||||
|
try (BufferedReader reader = Files.newBufferedReader(big.toPath(),StandardCharsets.UTF_8))
|
||||||
|
{
|
||||||
|
// a buffer large enough to capture at least 1 EOL
|
||||||
|
char cbuf[] = new char[128];
|
||||||
|
reader.read(cbuf);
|
||||||
|
String sample = new String(cbuf);
|
||||||
|
if (sample.contains("\r\n"))
|
||||||
|
{
|
||||||
|
LN = "\r\n";
|
||||||
|
}
|
||||||
|
else if (sample.contains("\n\r"))
|
||||||
|
{
|
||||||
|
LN = "\n\r";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LN = "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_server = new Server();
|
_server = new Server();
|
||||||
_config=new HttpConfiguration();
|
_config = new HttpConfiguration();
|
||||||
_config.setOutputBufferSize(2048);
|
_config.setOutputBufferSize(2048);
|
||||||
_connector = new ServerConnector(_server,new HttpConnectionFactory(_config));
|
_connector = new ServerConnector(_server,new HttpConnectionFactory(_config));
|
||||||
|
|
||||||
_server.setConnectors(new Connector[] { _connector });
|
_server.setConnectors(new Connector[] { _connector });
|
||||||
|
|
||||||
_resourceHandler = new ResourceHandler();
|
_resourceHandler = new ResourceHandler();
|
||||||
_resourceHandler.setMinAsyncContentLength(4096);
|
_resourceHandler.setMinAsyncContentLength(4096);
|
||||||
_resourceHandler.setMinMemoryMappedContentLength(8192);
|
_resourceHandler.setMinMemoryMappedContentLength(8192);
|
||||||
|
|
||||||
_resourceHandler.setResourceBase(MavenTestingUtils.getTargetFile("test-classes/simple").getAbsolutePath());
|
_resourceHandler.setResourceBase(MavenTestingUtils.getTargetFile("test-classes/simple").getAbsolutePath());
|
||||||
|
|
||||||
_contextHandler = new ContextHandler("/resource");
|
_contextHandler = new ContextHandler("/resource");
|
||||||
|
@ -96,7 +126,7 @@ public class ResourceHandlerTest
|
||||||
{
|
{
|
||||||
_server.stop();
|
_server.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void before()
|
public void before()
|
||||||
{
|
{
|
||||||
|
@ -107,45 +137,44 @@ public class ResourceHandlerTest
|
||||||
public void testMissing() throws Exception
|
public void testMissing() throws Exception
|
||||||
{
|
{
|
||||||
SimpleRequest sr = new SimpleRequest(new URI("http://localhost:" + _connector.getLocalPort()));
|
SimpleRequest sr = new SimpleRequest(new URI("http://localhost:" + _connector.getLocalPort()));
|
||||||
Assert.assertNotNull("missing jetty.css" , sr.getString("/resource/jetty-dir.css"));
|
Assert.assertNotNull("missing jetty.css",sr.getString("/resource/jetty-dir.css"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSimple() throws Exception
|
public void testSimple() throws Exception
|
||||||
{
|
{
|
||||||
SimpleRequest sr = new SimpleRequest(new URI("http://localhost:" + _connector.getLocalPort()));
|
SimpleRequest sr = new SimpleRequest(new URI("http://localhost:" + _connector.getLocalPort()));
|
||||||
Assert.assertEquals("simple text", sr.getString("/resource/simple.txt"));
|
Assert.assertEquals("simple text",sr.getString("/resource/simple.txt"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBigFile() throws Exception
|
public void testBigFile() throws Exception
|
||||||
{
|
{
|
||||||
_config.setOutputBufferSize(2048);
|
_config.setOutputBufferSize(2048);
|
||||||
SimpleRequest sr = new SimpleRequest(new URI("http://localhost:" + _connector.getLocalPort()));
|
SimpleRequest sr = new SimpleRequest(new URI("http://localhost:" + _connector.getLocalPort()));
|
||||||
String response=sr.getString("/resource/big.txt");
|
String response = sr.getString("/resource/big.txt");
|
||||||
Assert.assertThat(response,Matchers.startsWith(" 1\tThis is a big file"));
|
Assert.assertThat(response,Matchers.startsWith(" 1\tThis is a big file"));
|
||||||
Assert.assertThat(response,Matchers.endsWith(" 400\tThis is a big file"+LN));
|
Assert.assertThat(response,Matchers.endsWith(" 400\tThis is a big file" + LN));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBigFileBigBuffer() throws Exception
|
public void testBigFileBigBuffer() throws Exception
|
||||||
{
|
{
|
||||||
_config.setOutputBufferSize(16*1024);
|
_config.setOutputBufferSize(16 * 1024);
|
||||||
SimpleRequest sr = new SimpleRequest(new URI("http://localhost:" + _connector.getLocalPort()));
|
SimpleRequest sr = new SimpleRequest(new URI("http://localhost:" + _connector.getLocalPort()));
|
||||||
String response=sr.getString("/resource/big.txt");
|
String response = sr.getString("/resource/big.txt");
|
||||||
Assert.assertThat(response,Matchers.startsWith(" 1\tThis is a big file"));
|
Assert.assertThat(response,Matchers.startsWith(" 1\tThis is a big file"));
|
||||||
Assert.assertThat(response,Matchers.endsWith(" 400\tThis is a big file"+LN));
|
Assert.assertThat(response,Matchers.endsWith(" 400\tThis is a big file" + LN));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBigFileLittleBuffer() throws Exception
|
public void testBigFileLittleBuffer() throws Exception
|
||||||
{
|
{
|
||||||
_config.setOutputBufferSize(8);
|
_config.setOutputBufferSize(8);
|
||||||
SimpleRequest sr = new SimpleRequest(new URI("http://localhost:" + _connector.getLocalPort()));
|
SimpleRequest sr = new SimpleRequest(new URI("http://localhost:" + _connector.getLocalPort()));
|
||||||
String response=sr.getString("/resource/big.txt");
|
String response = sr.getString("/resource/big.txt");
|
||||||
Assert.assertThat(response,Matchers.startsWith(" 1\tThis is a big file"));
|
Assert.assertThat(response,Matchers.startsWith(" 1\tThis is a big file"));
|
||||||
Assert.assertThat(response,Matchers.endsWith(" 400\tThis is a big file"+LN));
|
Assert.assertThat(response,Matchers.endsWith(" 400\tThis is a big file" + LN));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -157,8 +186,8 @@ public class ResourceHandlerTest
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
String response = IO.toString(socket.getInputStream());
|
String response = IO.toString(socket.getInputStream());
|
||||||
Assert.assertThat(response,Matchers.startsWith("HTTP/1.1 200 OK"));
|
Assert.assertThat(response,Matchers.startsWith("HTTP/1.1 200 OK"));
|
||||||
Assert.assertThat(response,Matchers.containsString(" 400\tThis is a big file"+LN+" 1\tThis is a big file"));
|
Assert.assertThat(response,Matchers.containsString(" 400\tThis is a big file" + LN + " 1\tThis is a big file"));
|
||||||
Assert.assertThat(response,Matchers.endsWith(" 400\tThis is a big file"+LN));
|
Assert.assertThat(response,Matchers.endsWith(" 400\tThis is a big file" + LN));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.io.ByteArrayOutputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
@ -62,8 +63,7 @@ public class HeadersBlockGenerator
|
||||||
for (int i = 1; i < values.size(); ++i)
|
for (int i = 1; i < values.size(); ++i)
|
||||||
{
|
{
|
||||||
byte[] moreValueBytes = values.get(i).getBytes(iso1);
|
byte[] moreValueBytes = values.get(i).getBytes(iso1);
|
||||||
byte[] newValueBytes = new byte[valueBytes.length + 1 + moreValueBytes.length];
|
byte[] newValueBytes = Arrays.copyOf(valueBytes,valueBytes.length + 1 + moreValueBytes.length);
|
||||||
System.arraycopy(valueBytes, 0, newValueBytes, 0, valueBytes.length);
|
|
||||||
newValueBytes[valueBytes.length] = 0;
|
newValueBytes[valueBytes.length] = 0;
|
||||||
System.arraycopy(moreValueBytes, 0, newValueBytes, valueBytes.length + 1, moreValueBytes.length);
|
System.arraycopy(moreValueBytes, 0, newValueBytes, valueBytes.length + 1, moreValueBytes.length);
|
||||||
valueBytes = newValueBytes;
|
valueBytes = newValueBytes;
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.spdy.parser;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.zip.ZipException;
|
import java.util.zip.ZipException;
|
||||||
|
|
||||||
import org.eclipse.jetty.spdy.CompressionDictionary;
|
import org.eclipse.jetty.spdy.CompressionDictionary;
|
||||||
|
@ -114,16 +115,14 @@ public abstract class HeadersBlockParser
|
||||||
int needed = length - accumulated;
|
int needed = length - accumulated;
|
||||||
if (remaining < needed)
|
if (remaining < needed)
|
||||||
{
|
{
|
||||||
byte[] local = new byte[accumulated + remaining];
|
byte[] local = Arrays.copyOf(data,accumulated + remaining);
|
||||||
System.arraycopy(data, 0, local, 0, accumulated);
|
|
||||||
buffer.get(local, accumulated, remaining);
|
buffer.get(local, accumulated, remaining);
|
||||||
data = local;
|
data = local;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
byte[] local = new byte[length];
|
byte[] local = Arrays.copyOf(data,length);
|
||||||
System.arraycopy(data, 0, local, 0, accumulated);
|
|
||||||
buffer.get(local, accumulated, needed);
|
buffer.get(local, accumulated, needed);
|
||||||
data = local;
|
data = local;
|
||||||
return true;
|
return true;
|
||||||
|
@ -199,8 +198,7 @@ public abstract class HeadersBlockParser
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Last pass needed to decompress, merge decompressed bytes
|
// Last pass needed to decompress, merge decompressed bytes
|
||||||
byte[] result = new byte[decompressed.length + count];
|
byte[] result = Arrays.copyOf(decompressed,decompressed.length+count);
|
||||||
System.arraycopy(decompressed, 0, result, 0, decompressed.length);
|
|
||||||
System.arraycopy(buffer, 0, result, decompressed.length, count);
|
System.arraycopy(buffer, 0, result, decompressed.length, count);
|
||||||
return ByteBuffer.wrap(result);
|
return ByteBuffer.wrap(result);
|
||||||
}
|
}
|
||||||
|
@ -214,8 +212,7 @@ public abstract class HeadersBlockParser
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
byte[] result = new byte[decompressed.length + buffer.length];
|
byte[] result = Arrays.copyOf(decompressed,decompressed.length+buffer.length);
|
||||||
System.arraycopy(decompressed, 0, result, 0, decompressed.length);
|
|
||||||
System.arraycopy(buffer, 0, result, decompressed.length, buffer.length);
|
System.arraycopy(buffer, 0, result, decompressed.length, buffer.length);
|
||||||
decompressed = result;
|
decompressed = result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ public class PathMatchers
|
||||||
* the raw pattern (can contain "glob:" or "regex:" syntax indicator)
|
* the raw pattern (can contain "glob:" or "regex:" syntax indicator)
|
||||||
* @return the Path version of the pattern provided.
|
* @return the Path version of the pattern provided.
|
||||||
*/
|
*/
|
||||||
private static Path asPath(String pattern)
|
private static Path asPath(final String pattern)
|
||||||
{
|
{
|
||||||
String test = pattern;
|
String test = pattern;
|
||||||
if (test.startsWith("glob:"))
|
if (test.startsWith("glob:"))
|
||||||
|
@ -119,43 +119,89 @@ public class PathMatchers
|
||||||
*/
|
*/
|
||||||
public static Path getSearchRoot(final String pattern)
|
public static Path getSearchRoot(final String pattern)
|
||||||
{
|
{
|
||||||
Path path = asPath(pattern);
|
StringBuilder root = new StringBuilder();
|
||||||
Path test = path.getRoot();
|
|
||||||
|
|
||||||
boolean isSyntaxed = pattern.startsWith("glob:") || pattern.startsWith("regex:");
|
int start = 0;
|
||||||
|
boolean syntaxed = false;
|
||||||
int len = path.getNameCount();
|
if (pattern.startsWith("glob:"))
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
{
|
||||||
Path part = path.getName(i);
|
start = "glob:".length();
|
||||||
if (isGlob(part.toString(),isSyntaxed))
|
syntaxed = true;
|
||||||
|
}
|
||||||
|
else if (pattern.startsWith("regex:"))
|
||||||
|
{
|
||||||
|
start = "regex:".length();
|
||||||
|
syntaxed = true;
|
||||||
|
}
|
||||||
|
int len = pattern.length();
|
||||||
|
int lastSep = 0;
|
||||||
|
for (int i = start; i < len; i++)
|
||||||
|
{
|
||||||
|
int cp = pattern.codePointAt(i);
|
||||||
|
if (cp < 127)
|
||||||
{
|
{
|
||||||
// found a glob part, return prior parts now
|
char c = (char)cp;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// is this the last entry?
|
// unix path case
|
||||||
if (i == (len - 1))
|
if (c == '/')
|
||||||
{
|
{
|
||||||
// always return prior entries
|
root.append(c);
|
||||||
break;
|
lastSep = root.length();
|
||||||
}
|
}
|
||||||
|
else if (c == '\\')
|
||||||
|
{
|
||||||
|
root.append("\\");
|
||||||
|
lastSep = root.length();
|
||||||
|
|
||||||
if (test == null)
|
// possible escaped sequence.
|
||||||
{
|
// only really interested in windows escape sequences "\\"
|
||||||
test = part;
|
int count = countChars(pattern,i+1,'\\');
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
// skip extra slashes
|
||||||
|
i += count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (isGlob(c,syntaxed))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
root.append(c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
test = test.resolve(part);
|
root.appendCodePoint(cp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (test == null)
|
String rootPath = root.substring(0,lastSep);
|
||||||
|
if (rootPath.length() <= 0)
|
||||||
{
|
{
|
||||||
return EMPTY_PATH;
|
return EMPTY_PATH;
|
||||||
}
|
}
|
||||||
return test;
|
|
||||||
|
return asPath(rootPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int countChars(String pattern, int offset, char c)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
int len = pattern.length();
|
||||||
|
for (int i = offset; i < len; i++)
|
||||||
|
{
|
||||||
|
if (pattern.charAt(i) == c)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -184,29 +230,24 @@ public class PathMatchers
|
||||||
* true if overall pattern is syntaxed with <code>"glob:"</code> or <code>"regex:"</code>
|
* true if overall pattern is syntaxed with <code>"glob:"</code> or <code>"regex:"</code>
|
||||||
* @return true if part has glob characters
|
* @return true if part has glob characters
|
||||||
*/
|
*/
|
||||||
private static boolean isGlob(String part, boolean syntaxed)
|
private static boolean isGlob(char c, boolean syntaxed)
|
||||||
{
|
{
|
||||||
int len = part.length();
|
for (char g : GLOB_CHARS)
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
{
|
||||||
char c = part.charAt(i);
|
if (c == g)
|
||||||
for (char g : GLOB_CHARS)
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (syntaxed)
|
||||||
|
{
|
||||||
|
for (char g : SYNTAXED_GLOB_CHARS)
|
||||||
{
|
{
|
||||||
if (c == g)
|
if (c == g)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (syntaxed)
|
|
||||||
{
|
|
||||||
for (char g : SYNTAXED_GLOB_CHARS)
|
|
||||||
{
|
|
||||||
if (c == g)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -361,7 +361,10 @@ public class StartArgs
|
||||||
StartLog.debug("rawlibref = " + rawlibref);
|
StartLog.debug("rawlibref = " + rawlibref);
|
||||||
String libref = properties.expand(rawlibref);
|
String libref = properties.expand(rawlibref);
|
||||||
StartLog.debug("expanded = " + libref);
|
StartLog.debug("expanded = " + libref);
|
||||||
|
|
||||||
|
// perform path escaping (needed by windows)
|
||||||
|
libref = libref.replaceAll("\\\\([^\\\\])","\\\\\\\\$1");
|
||||||
|
|
||||||
for (Path libpath : baseHome.getPaths(libref))
|
for (Path libpath : baseHome.getPaths(libref))
|
||||||
{
|
{
|
||||||
classpath.addComponent(libpath.toFile());
|
classpath.addComponent(libpath.toFile());
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.start;
|
package org.eclipse.jetty.start;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.is;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -38,7 +38,7 @@ public class MainTest
|
||||||
System.setProperty("jetty.home","");
|
System.setProperty("jetty.home","");
|
||||||
System.setProperty("jetty.base","");
|
System.setProperty("jetty.base","");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBasicProcessing() throws Exception
|
public void testBasicProcessing() throws Exception
|
||||||
{
|
{
|
||||||
|
@ -69,12 +69,12 @@ public class MainTest
|
||||||
StartArgs args = main.processCommandLine(cmdLineArgs.toArray(new String[cmdLineArgs.size()]));
|
StartArgs args = main.processCommandLine(cmdLineArgs.toArray(new String[cmdLineArgs.size()]));
|
||||||
System.err.println(args);
|
System.err.println(args);
|
||||||
|
|
||||||
//Assert.assertEquals("--stop should not build module tree", 0, args.getEnabledModules().size());
|
// Assert.assertEquals("--stop should not build module tree", 0, args.getEnabledModules().size());
|
||||||
Assert.assertEquals("--stop missing port","10000",args.getProperties().getString("STOP.PORT"));
|
Assert.assertEquals("--stop missing port","10000",args.getProperties().getString("STOP.PORT"));
|
||||||
Assert.assertEquals("--stop missing key","foo",args.getProperties().getString("STOP.KEY"));
|
Assert.assertEquals("--stop missing key","foo",args.getProperties().getString("STOP.KEY"));
|
||||||
Assert.assertEquals("--stop missing wait","300",args.getProperties().getString("STOP.WAIT"));
|
Assert.assertEquals("--stop missing wait","300",args.getProperties().getString("STOP.WAIT"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore("Just a bit noisy for general testing")
|
@Ignore("Just a bit noisy for general testing")
|
||||||
public void testListConfig() throws Exception
|
public void testListConfig() throws Exception
|
||||||
|
@ -90,7 +90,7 @@ public class MainTest
|
||||||
StartArgs args = main.processCommandLine(cmdLineArgs.toArray(new String[cmdLineArgs.size()]));
|
StartArgs args = main.processCommandLine(cmdLineArgs.toArray(new String[cmdLineArgs.size()]));
|
||||||
main.listConfig(args);
|
main.listConfig(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore("Just a bit noisy for general testing")
|
@Ignore("Just a bit noisy for general testing")
|
||||||
public void testHelp() throws Exception
|
public void testHelp() throws Exception
|
||||||
|
@ -107,12 +107,12 @@ public class MainTest
|
||||||
File homePath = MavenTestingUtils.getTestResourceDir("usecases/home").getAbsoluteFile();
|
File homePath = MavenTestingUtils.getTestResourceDir("usecases/home").getAbsoluteFile();
|
||||||
cmdLineArgs.add("jetty.home=" + homePath);
|
cmdLineArgs.add("jetty.home=" + homePath);
|
||||||
cmdLineArgs.add("user.dir=" + homePath);
|
cmdLineArgs.add("user.dir=" + homePath);
|
||||||
|
|
||||||
// JVM args
|
// JVM args
|
||||||
cmdLineArgs.add("--exec");
|
cmdLineArgs.add("--exec");
|
||||||
cmdLineArgs.add("-Xms1024m");
|
cmdLineArgs.add("-Xms1024m");
|
||||||
cmdLineArgs.add("-Xmx1024m");
|
cmdLineArgs.add("-Xmx1024m");
|
||||||
|
|
||||||
// Arbitrary Libs
|
// Arbitrary Libs
|
||||||
File extraJar = MavenTestingUtils.getTestResourceFile("extra-libs/example.jar");
|
File extraJar = MavenTestingUtils.getTestResourceFile("extra-libs/example.jar");
|
||||||
File extraDir = MavenTestingUtils.getTestResourceDir("extra-resources");
|
File extraDir = MavenTestingUtils.getTestResourceDir("extra-resources");
|
||||||
|
@ -127,9 +127,9 @@ public class MainTest
|
||||||
|
|
||||||
StartArgs args = main.processCommandLine(cmdLineArgs.toArray(new String[cmdLineArgs.size()]));
|
StartArgs args = main.processCommandLine(cmdLineArgs.toArray(new String[cmdLineArgs.size()]));
|
||||||
BaseHome baseHome = main.getBaseHome();
|
BaseHome baseHome = main.getBaseHome();
|
||||||
|
|
||||||
Assert.assertThat("jetty.home", baseHome.getHome(), is(homePath.getAbsolutePath()));
|
Assert.assertThat("jetty.home",baseHome.getHome(),is(homePath.getAbsolutePath()));
|
||||||
Assert.assertThat("jetty.base", baseHome.getBase(), is(homePath.getAbsolutePath()));
|
Assert.assertThat("jetty.base",baseHome.getBase(),is(homePath.getAbsolutePath()));
|
||||||
|
|
||||||
ConfigurationAssert.assertConfiguration(baseHome,args,"assert-home-with-jvm.txt");
|
ConfigurationAssert.assertConfiguration(baseHome,args,"assert-home-with-jvm.txt");
|
||||||
}
|
}
|
||||||
|
@ -146,10 +146,10 @@ public class MainTest
|
||||||
Main main = new Main();
|
Main main = new Main();
|
||||||
StartArgs args = main.processCommandLine(cmdLineArgs.toArray(new String[cmdLineArgs.size()]));
|
StartArgs args = main.processCommandLine(cmdLineArgs.toArray(new String[cmdLineArgs.size()]));
|
||||||
BaseHome baseHome = main.getBaseHome();
|
BaseHome baseHome = main.getBaseHome();
|
||||||
|
|
||||||
Assert.assertThat("jetty.home", baseHome.getHome(), is(homePath.getAbsolutePath()));
|
Assert.assertThat("jetty.home",baseHome.getHome(),is(homePath.getAbsolutePath()));
|
||||||
Assert.assertThat("jetty.base", baseHome.getBase(), is(homePath.getAbsolutePath()));
|
Assert.assertThat("jetty.base",baseHome.getBase(),is(homePath.getAbsolutePath()));
|
||||||
|
|
||||||
ConfigurationAssert.assertConfiguration(baseHome,args,"assert-home-with-spaces.txt");
|
ConfigurationAssert.assertConfiguration(baseHome,args,"assert-home-with-spaces.txt");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2014 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 static org.hamcrest.Matchers.is;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.toolchain.test.OS;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.Parameterized;
|
||||||
|
import org.junit.runners.Parameterized.Parameter;
|
||||||
|
import org.junit.runners.Parameterized.Parameters;
|
||||||
|
|
||||||
|
@RunWith(Parameterized.class)
|
||||||
|
public class PathMatchersAbsoluteTest
|
||||||
|
{
|
||||||
|
@Parameters(name="{0} -> {1}")
|
||||||
|
public static List<Object[]> data()
|
||||||
|
{
|
||||||
|
List<Object[]> cases = new ArrayList<>();
|
||||||
|
|
||||||
|
if(OS.IS_UNIX)
|
||||||
|
{
|
||||||
|
cases.add(new Object[]{"/opt/app",true});
|
||||||
|
cases.add(new Object[]{"/opt/app",true});
|
||||||
|
cases.add(new Object[]{"/opt/florb",true});
|
||||||
|
cases.add(new Object[]{"/home/user/benfranklin",true});
|
||||||
|
cases.add(new Object[]{"glob:/home/user/benfranklin/*.jar",true});
|
||||||
|
cases.add(new Object[]{"glob:/**/*.jar",true});
|
||||||
|
cases.add(new Object[]{"regex:/*-[^dev].ini",true});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(OS.IS_WINDOWS)
|
||||||
|
{
|
||||||
|
// normal declaration
|
||||||
|
cases.add(new Object[]{"D:\\code\\jetty\\jetty-start\\src\\test\\resources\\extra-libs\\example.jar",true});
|
||||||
|
// escaped declaration
|
||||||
|
cases.add(new Object[]{"C:\\\\System32",true});
|
||||||
|
cases.add(new Object[]{"C:\\\\Program Files",true});
|
||||||
|
}
|
||||||
|
|
||||||
|
cases.add(new Object[]{"etc",false});
|
||||||
|
cases.add(new Object[]{"lib",false});
|
||||||
|
cases.add(new Object[]{"${user.dir}",false});
|
||||||
|
cases.add(new Object[]{"**/*.jar",false});
|
||||||
|
cases.add(new Object[]{"glob:*.ini",false});
|
||||||
|
cases.add(new Object[]{"regex:*-[^dev].ini",false});
|
||||||
|
|
||||||
|
return cases;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Parameter(value=0)
|
||||||
|
public String pattern;
|
||||||
|
@Parameter(value=1)
|
||||||
|
public boolean expected;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAbsolute()
|
||||||
|
{
|
||||||
|
Assert.assertThat("isAbsolute(\""+pattern+"\")",PathMatchers.isAbsolute(pattern),is(expected));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2014 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 static org.hamcrest.Matchers.is;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.toolchain.test.OS;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.Parameterized;
|
||||||
|
import org.junit.runners.Parameterized.Parameter;
|
||||||
|
import org.junit.runners.Parameterized.Parameters;
|
||||||
|
|
||||||
|
@RunWith(Parameterized.class)
|
||||||
|
public class PathMatchersSearchRootTest
|
||||||
|
{
|
||||||
|
@Parameters(name="{0}")
|
||||||
|
public static List<String[]> data()
|
||||||
|
{
|
||||||
|
List<String[]> cases = new ArrayList<>();
|
||||||
|
|
||||||
|
if (OS.IS_UNIX)
|
||||||
|
{
|
||||||
|
// absolute first
|
||||||
|
cases.add(new String[]{"/opt/app/*.jar","/opt/app"});
|
||||||
|
cases.add(new String[]{"/lib/jvm/**/jre/lib/*.jar","/lib/jvm"});
|
||||||
|
cases.add(new String[]{"glob:/var/lib/*.xml","/var/lib"});
|
||||||
|
cases.add(new String[]{"glob:/var/lib/*.{xml,java}","/var/lib"});
|
||||||
|
cases.add(new String[]{"glob:/opt/corporate/lib-{dev,prod}/*.ini","/opt/corporate"});
|
||||||
|
cases.add(new String[]{"regex:/opt/jetty/.*/lib-(dev|prod)/*.ini","/opt/jetty"});
|
||||||
|
|
||||||
|
cases.add(new String[]{"/*.ini","/"});
|
||||||
|
cases.add(new String[]{"/etc/jetty.conf","/etc"});
|
||||||
|
cases.add(new String[]{"/common.conf","/"});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OS.IS_WINDOWS)
|
||||||
|
{
|
||||||
|
// absolute declaration
|
||||||
|
cases.add(new String[]{"D:\\code\\jetty\\jetty-start\\src\\test\\resources\\extra-libs\\example.jar",
|
||||||
|
"D:\\code\\jetty\\jetty-start\\src\\test\\resources\\extra-libs"});
|
||||||
|
// escaped declaration
|
||||||
|
// absolute patterns (complete with required windows slash escaping)
|
||||||
|
cases.add(new String[]{"C:\\\\corp\\\\lib\\\\*.jar","C:\\corp\\lib"});
|
||||||
|
cases.add(new String[]{"D:\\\\lib\\\\**\\\\jre\\\\lib\\\\*.jar","D:\\lib"});
|
||||||
|
}
|
||||||
|
|
||||||
|
// some relative paths
|
||||||
|
cases.add(new String[]{"lib/*.jar","lib"});
|
||||||
|
cases.add(new String[]{"etc/jetty.xml","etc"});
|
||||||
|
cases.add(new String[]{"start.ini","."});
|
||||||
|
cases.add(new String[]{"start.d/","start.d"});
|
||||||
|
return cases;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Parameter(value=0)
|
||||||
|
public String pattern;
|
||||||
|
@Parameter(value=1)
|
||||||
|
public String expectedSearchRoot;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchRoot()
|
||||||
|
{
|
||||||
|
Path actual = PathMatchers.getSearchRoot(pattern);
|
||||||
|
String expectedNormal = FS.separators(expectedSearchRoot);
|
||||||
|
Assert.assertThat(".getSearchRoot(\"" + pattern + "\")",actual.toString(),is(expectedNormal));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,105 +0,0 @@
|
||||||
//
|
|
||||||
// ========================================================================
|
|
||||||
// Copyright (c) 1995-2014 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 static org.hamcrest.Matchers.*;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.toolchain.test.OS;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
public class PathMatchersTest
|
|
||||||
{
|
|
||||||
private void assertIsAbsolute(String pattern, boolean expected)
|
|
||||||
{
|
|
||||||
Assert.assertThat("isAbsolute(\"" + pattern + "\")",PathMatchers.isAbsolute(pattern),is(expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIsAbsolute()
|
|
||||||
{
|
|
||||||
if (OS.IS_UNIX)
|
|
||||||
{
|
|
||||||
assertIsAbsolute("/opt/app",true);
|
|
||||||
assertIsAbsolute("/opt/florb",true);
|
|
||||||
assertIsAbsolute("/home/user/benfranklin",true);
|
|
||||||
assertIsAbsolute("glob:/home/user/benfranklin/*.jar",true);
|
|
||||||
assertIsAbsolute("glob:/**/*.jar",true);
|
|
||||||
assertIsAbsolute("regex:/*-[^dev].ini",true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OS.IS_WINDOWS)
|
|
||||||
{
|
|
||||||
assertIsAbsolute("C:\\\\System32",true);
|
|
||||||
assertIsAbsolute("C:\\\\Program Files",true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIsNotAbsolute()
|
|
||||||
{
|
|
||||||
assertIsAbsolute("etc",false);
|
|
||||||
assertIsAbsolute("lib",false);
|
|
||||||
assertIsAbsolute("${user.dir}",false);
|
|
||||||
assertIsAbsolute("**/*.jar",false);
|
|
||||||
assertIsAbsolute("glob:*.ini",false);
|
|
||||||
assertIsAbsolute("regex:*-[^dev].ini",false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertSearchRoot(String pattern, String expectedSearchRoot)
|
|
||||||
{
|
|
||||||
Path actual = PathMatchers.getSearchRoot(pattern);
|
|
||||||
String expectedNormal = FS.separators(expectedSearchRoot);
|
|
||||||
Assert.assertThat(".getSearchRoot(\"" + pattern + "\")",actual.toString(),is(expectedNormal));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetSearchRoot()
|
|
||||||
{
|
|
||||||
if (OS.IS_UNIX)
|
|
||||||
{
|
|
||||||
// absolute first
|
|
||||||
assertSearchRoot("/opt/app/*.jar","/opt/app");
|
|
||||||
assertSearchRoot("/lib/jvm/**/jre/lib/*.jar","/lib/jvm");
|
|
||||||
assertSearchRoot("glob:/var/lib/*.xml","/var/lib");
|
|
||||||
assertSearchRoot("glob:/var/lib/*.{xml,java}","/var/lib");
|
|
||||||
assertSearchRoot("glob:/opt/corporate/lib-{dev,prod}/*.ini","/opt/corporate");
|
|
||||||
assertSearchRoot("regex:/opt/jetty/.*/lib-(dev|prod)/*.ini","/opt/jetty");
|
|
||||||
|
|
||||||
assertSearchRoot("/*.ini","/");
|
|
||||||
assertSearchRoot("/etc/jetty.conf","/etc");
|
|
||||||
assertSearchRoot("/common.conf","/");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OS.IS_WINDOWS)
|
|
||||||
{
|
|
||||||
// absolute patterns (complete with required windows slash escaping)
|
|
||||||
assertSearchRoot("C:\\\\corp\\\\lib\\\\*.jar","C:\\corp\\lib");
|
|
||||||
assertSearchRoot("D:\\\\lib\\\\**\\\\jre\\\\lib\\\\*.jar","C:\\lib");
|
|
||||||
}
|
|
||||||
|
|
||||||
// some relative paths
|
|
||||||
assertSearchRoot("lib/*.jar","lib");
|
|
||||||
assertSearchRoot("etc/jetty.xml","etc");
|
|
||||||
assertSearchRoot("start.ini",".");
|
|
||||||
assertSearchRoot("start.d/",".");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -19,6 +19,7 @@
|
||||||
package org.eclipse.jetty.util;
|
package org.eclipse.jetty.util;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -107,11 +108,12 @@ public class ArrayTernaryTrie<V> extends AbstractTrie<V>
|
||||||
*/
|
*/
|
||||||
public ArrayTernaryTrie(ArrayTernaryTrie<V> trie, double factor)
|
public ArrayTernaryTrie(ArrayTernaryTrie<V> trie, double factor)
|
||||||
{
|
{
|
||||||
this(trie.isCaseInsensitive(),(int)(trie._value.length*factor));
|
super(trie.isCaseInsensitive());
|
||||||
|
int capacity=(int)(trie._value.length*factor);
|
||||||
_rows=trie._rows;
|
_rows=trie._rows;
|
||||||
System.arraycopy(trie._value,0,_value,0,trie._value.length);
|
_value=Arrays.copyOf(trie._value, capacity);
|
||||||
System.arraycopy(trie._tree,0,_tree,0,trie._tree.length);
|
_tree=Arrays.copyOf(trie._tree, capacity*ROW_SIZE);
|
||||||
System.arraycopy(trie._key,0,_key,0,trie._key.length);
|
_key=Arrays.copyOf(trie._key, capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
|
|
@ -30,6 +30,7 @@ import java.nio.channels.FileChannel;
|
||||||
import java.nio.channels.FileChannel.MapMode;
|
import java.nio.channels.FileChannel.MapMode;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.resource.Resource;
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
|
|
||||||
|
@ -215,15 +216,18 @@ public class BufferUtil
|
||||||
*/
|
*/
|
||||||
public static byte[] toArray(ByteBuffer buffer)
|
public static byte[] toArray(ByteBuffer buffer)
|
||||||
{
|
{
|
||||||
byte[] to = new byte[buffer.remaining()];
|
|
||||||
if (buffer.hasArray())
|
if (buffer.hasArray())
|
||||||
{
|
{
|
||||||
byte[] array = buffer.array();
|
byte[] array = buffer.array();
|
||||||
System.arraycopy(array, buffer.arrayOffset() + buffer.position(), to, 0, to.length);
|
int from=buffer.arrayOffset() + buffer.position();
|
||||||
|
return Arrays.copyOfRange(array,from,from+buffer.remaining());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
byte[] to = new byte[buffer.remaining()];
|
||||||
buffer.slice().get(to);
|
buffer.slice().get(to);
|
||||||
return to;
|
return to;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -1022,6 +1026,20 @@ public class BufferUtil
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ByteBuffer ensureCapacity(ByteBuffer buffer, int capacity)
|
||||||
|
{
|
||||||
|
if (buffer==null)
|
||||||
|
return allocate(capacity);
|
||||||
|
|
||||||
|
if (buffer.capacity()>=capacity)
|
||||||
|
return buffer;
|
||||||
|
|
||||||
|
if (buffer.hasArray())
|
||||||
|
return ByteBuffer.wrap(Arrays.copyOfRange(buffer.array(), buffer.arrayOffset(), buffer.arrayOffset()+capacity),buffer.position(),buffer.remaining());
|
||||||
|
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.io.OutputStream;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -253,19 +254,14 @@ public class ByteArrayISO8859Writer extends Writer
|
||||||
{
|
{
|
||||||
if (_fixed)
|
if (_fixed)
|
||||||
throw new IOException("Buffer overflow: "+_buf.length);
|
throw new IOException("Buffer overflow: "+_buf.length);
|
||||||
byte[] buf = new byte[(_buf.length+n)*4/3];
|
_buf=Arrays.copyOf(_buf,(_buf.length+n)*4/3);
|
||||||
System.arraycopy(_buf,0,buf,0,_size);
|
|
||||||
_buf=buf;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public byte[] getByteArray()
|
public byte[] getByteArray()
|
||||||
{
|
{
|
||||||
byte[] data=new byte[_size];
|
return Arrays.copyOf(_buf,_size);
|
||||||
System.arraycopy(_buf,0,data,0,_size);
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -289,6 +289,41 @@ public class BufferUtilTest
|
||||||
int capacity = BufferUtil.TEMP_BUFFER_SIZE*2+1024;
|
int capacity = BufferUtil.TEMP_BUFFER_SIZE*2+1024;
|
||||||
testWriteToWithBufferThatDoesNotExposeArray(capacity);
|
testWriteToWithBufferThatDoesNotExposeArray(capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnsureCapacity() throws Exception
|
||||||
|
{
|
||||||
|
ByteBuffer b = BufferUtil.toBuffer("Goodbye Cruel World");
|
||||||
|
assertTrue(b==BufferUtil.ensureCapacity(b, 0));
|
||||||
|
assertTrue(b==BufferUtil.ensureCapacity(b, 10));
|
||||||
|
assertTrue(b==BufferUtil.ensureCapacity(b, b.capacity()));
|
||||||
|
|
||||||
|
|
||||||
|
ByteBuffer b1 = BufferUtil.ensureCapacity(b, 64);
|
||||||
|
assertTrue(b!=b1);
|
||||||
|
assertEquals(64, b1.capacity());
|
||||||
|
assertEquals("Goodbye Cruel World", BufferUtil.toString(b1));
|
||||||
|
|
||||||
|
b1.position(8);
|
||||||
|
b1.limit(13);
|
||||||
|
assertEquals("Cruel", BufferUtil.toString(b1));
|
||||||
|
ByteBuffer b2 = b1.slice();
|
||||||
|
assertEquals("Cruel", BufferUtil.toString(b2));
|
||||||
|
System.err.println(BufferUtil.toDetailString(b2));
|
||||||
|
assertEquals(8, b2.arrayOffset());
|
||||||
|
assertEquals(5, b2.capacity());
|
||||||
|
|
||||||
|
assertTrue(b2==BufferUtil.ensureCapacity(b2, 5));
|
||||||
|
|
||||||
|
ByteBuffer b3 = BufferUtil.ensureCapacity(b2, 64);
|
||||||
|
assertTrue(b2!=b3);
|
||||||
|
assertEquals(64, b3.capacity());
|
||||||
|
assertEquals("Cruel", BufferUtil.toString(b3));
|
||||||
|
assertEquals(0, b3.arrayOffset());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void testWriteToWithBufferThatDoesNotExposeArray(int capacity) throws IOException
|
private void testWriteToWithBufferThatDoesNotExposeArray(int capacity) throws IOException
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
<instructions>
|
<instructions>
|
||||||
<Bundle-Description>javax.websocket.server Implementation</Bundle-Description>
|
<Bundle-Description>javax.websocket.server Implementation</Bundle-Description>
|
||||||
<Export-Package>org.eclipse.jetty.websocket.jsr356.server.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"</Export-Package>
|
<Export-Package>org.eclipse.jetty.websocket.jsr356.server.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"</Export-Package>
|
||||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
|
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
|
||||||
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=javax.servlet.ServletContainerInitializer</Provide-Capability>
|
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=javax.servlet.ServletContainerInitializer</Provide-Capability>
|
||||||
</instructions>
|
</instructions>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.websocket.client.masks;
|
package org.eclipse.jetty.websocket.client.masks;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||||
|
|
||||||
public class FixedMasker implements Masker
|
public class FixedMasker implements Masker
|
||||||
|
@ -32,10 +34,9 @@ public class FixedMasker implements Masker
|
||||||
|
|
||||||
public FixedMasker(byte[] mask)
|
public FixedMasker(byte[] mask)
|
||||||
{
|
{
|
||||||
this.mask = new byte[4];
|
|
||||||
// Copy to avoid that external code keeps a reference
|
// Copy to avoid that external code keeps a reference
|
||||||
// to the array parameter to modify masking on-the-fly
|
// to the array parameter to modify masking on-the-fly
|
||||||
System.arraycopy(mask,0,mask,0,4);
|
this.mask=Arrays.copyOf(mask, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -154,10 +154,7 @@ public abstract class WebSocketFrame implements Frame
|
||||||
masked = copy.masked;
|
masked = copy.masked;
|
||||||
mask = null;
|
mask = null;
|
||||||
if (copy.mask != null)
|
if (copy.mask != null)
|
||||||
{
|
mask = Arrays.copyOf(copy.mask, copy.mask.length);
|
||||||
mask = new byte[copy.mask.length];
|
|
||||||
System.arraycopy(copy.mask,0,mask,0,mask.length);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.websocket.server.ab;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
@ -113,9 +114,7 @@ public abstract class AbstractABCase implements Fuzzed
|
||||||
*/
|
*/
|
||||||
protected ByteBuffer copyOf(byte[] payload)
|
protected ByteBuffer copyOf(byte[] payload)
|
||||||
{
|
{
|
||||||
byte copy[] = new byte[payload.length];
|
return ByteBuffer.wrap(Arrays.copyOf(payload,payload.length));
|
||||||
System.arraycopy(payload,0,copy,0,payload.length);
|
|
||||||
return ByteBuffer.wrap(copy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue