Merge branch 'jetty-8' into release-8
This commit is contained in:
commit
8024831fec
|
@ -1,14 +1,33 @@
|
|||
target/
|
||||
# eclipse
|
||||
.classpath
|
||||
.project
|
||||
.settings
|
||||
|
||||
# maven
|
||||
target/
|
||||
*/src/main/java/META-INF/
|
||||
.pmd
|
||||
|
||||
# common junk
|
||||
*.log
|
||||
*.swp
|
||||
*.diff
|
||||
*.patch
|
||||
|
||||
# intellij
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# Mac filesystem dust
|
||||
/.DS_Store
|
||||
|
||||
# pmd
|
||||
.pmdruleset
|
||||
.pmd
|
||||
|
||||
# netbeans
|
||||
/nbproject
|
||||
|
||||
# vim
|
||||
.*.sw[a-p]
|
||||
|
|
19
VERSION.txt
19
VERSION.txt
|
@ -1,5 +1,11 @@
|
|||
jetty-8.0.2-SNAPSHOT
|
||||
|
||||
|
||||
jetty-7.5.2-SNAPSHOT
|
||||
+ 358121 Implement new UTF8 Algorithm to UTF8Appendable.java
|
||||
+ 353839 ajp component error when upload file
|
||||
+ JETTY-1378 new system property to for the use of the JDTCompiler when using the latest jsp-impl
|
||||
|
||||
jetty-8.0.1.v20110908 - 08 September 2011
|
||||
+ 350634 Added Resource.newResource(File)
|
||||
+ 356190 fix monodb tests for changed test api
|
||||
|
@ -12,12 +18,25 @@ jetty-8.0.1.v20110908 - 08 September 2011
|
|||
+ 356823 correctly decode close codes. Send not utf-8 close code.
|
||||
+ 357058 Acceptor thread blocking
|
||||
|
||||
jetty-7.5.1.v20110908 - 08 September 2011
|
||||
+ 350634 Added Resource.newResource(File)
|
||||
+ 356190 fix monodb tests for changed test api
|
||||
+ 356428 removed timed waits from test
|
||||
+ 356693 reduce visibility to webapp of websocket implementations
|
||||
+ 356695 jetty server jars are provided for websockets
|
||||
+ 356726 Instead of the sessionDestroyed called sessionCreated after
|
||||
invalidate session
|
||||
+ 356751 Add null protection to ServletContextHandler.doStop
|
||||
+ 356823 correctly decode close codes. Send not utf-8 close code.
|
||||
+ 357058 Acceptor thread blocking
|
||||
|
||||
jetty-8.0.0.v20110901 - 01 September 2011
|
||||
+ 352565 cookie httponly flag ignored
|
||||
+ 353073 better warnings
|
||||
+ 353285 ServletSecurity annotation ignored
|
||||
+ 356421 Upgraded websocket to draft 13 support
|
||||
|
||||
|
||||
jetty-7.5.0.v20110901 - 01 September 2011
|
||||
+ 356421 Upgraded websocket to draft 13 support
|
||||
+ 353073 better warnings
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.eclipse.jetty.server.handler.RequestLogHandler;
|
|||
import org.eclipse.jetty.server.handler.StatisticsHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
|
||||
import org.eclipse.jetty.server.ssl.SslSocketConnector;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
|
||||
|
@ -87,9 +88,15 @@ public class LikeJettyXml
|
|||
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
|
||||
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"
|
||||
});
|
||||
cf.setProtocol("TLSv1.1");
|
||||
cf.addExcludeProtocols(new String[]{"TLSv1","SSLv3"});
|
||||
ssl_connector.setStatsOn(true);
|
||||
server.addConnector(ssl_connector);
|
||||
ssl_connector.open();
|
||||
|
||||
|
||||
|
||||
|
||||
Ajp13SocketConnector ajp = new Ajp13SocketConnector();
|
||||
ajp.setPort(8009);
|
||||
server.addConnector(ajp);
|
||||
|
|
|
@ -29,7 +29,7 @@ public class SecuredHelloHandler
|
|||
{
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
Server server = new Server(0);
|
||||
Server server = new Server(8080);
|
||||
|
||||
LoginService loginService = new HashLoginService("MyRealm","src/test/resources/realm.properties");
|
||||
server.addBean(loginService);
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<goal>unpack-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includes>META-INF/**,org/eclipse/**</includes>
|
||||
<includes>META-INF/**,org/eclipse/**,org/apache/jasper/compiler/**</includes>
|
||||
<excludes>**/MANIFEST.MF,javax/**</excludes>
|
||||
<outputDirectory>${project.build.directory}/classes</outputDirectory>
|
||||
<overWriteReleases>false</overWriteReleases>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<goal>unpack-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includes>META-INF/**,org/eclipse/**</includes>
|
||||
<includes>META-INF/**,org/eclipse/**,org/apache/jasper/compiler/*</includes>
|
||||
<excludes>**/MANIFEST.MF,javax/**</excludes>
|
||||
<outputDirectory>${project.build.directory}/classes</outputDirectory>
|
||||
<overWriteReleases>false</overWriteReleases>
|
||||
|
@ -75,6 +75,19 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>javadoc-jar</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<goal>unpack-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includes>META-INF/**,org/eclipse/**</includes>
|
||||
<includes>META-INF/**,org/eclipse/**,org/apache/jasper/compiler/**</includes>
|
||||
<excludes>**/MANIFEST.MF,javax/**</excludes>
|
||||
<outputDirectory>${project.build.directory}/classes</outputDirectory>
|
||||
<overWriteReleases>false</overWriteReleases>
|
||||
|
|
|
@ -44,38 +44,38 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
static
|
||||
{
|
||||
byte[] xA001 =
|
||||
{ (byte) 0xA0, (byte) 0x01 };
|
||||
{ (byte)0xA0, (byte)0x01 };
|
||||
byte[] xA002 =
|
||||
{ (byte) 0xA0, (byte) 0x02 };
|
||||
{ (byte)0xA0, (byte)0x02 };
|
||||
byte[] xA003 =
|
||||
{ (byte) 0xA0, (byte) 0x03 };
|
||||
{ (byte)0xA0, (byte)0x03 };
|
||||
byte[] xA004 =
|
||||
{ (byte) 0xA0, (byte) 0x04 };
|
||||
{ (byte)0xA0, (byte)0x04 };
|
||||
byte[] xA005 =
|
||||
{ (byte) 0xA0, (byte) 0x05 };
|
||||
{ (byte)0xA0, (byte)0x05 };
|
||||
byte[] xA006 =
|
||||
{ (byte) 0xA0, (byte) 0x06 };
|
||||
{ (byte)0xA0, (byte)0x06 };
|
||||
byte[] xA007 =
|
||||
{ (byte) 0xA0, (byte) 0x07 };
|
||||
{ (byte)0xA0, (byte)0x07 };
|
||||
byte[] xA008 =
|
||||
{ (byte) 0xA0, (byte) 0x08 };
|
||||
{ (byte)0xA0, (byte)0x08 };
|
||||
byte[] xA009 =
|
||||
{ (byte) 0xA0, (byte) 0x09 };
|
||||
{ (byte)0xA0, (byte)0x09 };
|
||||
byte[] xA00A =
|
||||
{ (byte) 0xA0, (byte) 0x0A };
|
||||
{ (byte)0xA0, (byte)0x0A };
|
||||
byte[] xA00B =
|
||||
{ (byte) 0xA0, (byte) 0x0B };
|
||||
__headerHash.put("Content-Type", xA001);
|
||||
__headerHash.put("Content-Language", xA002);
|
||||
__headerHash.put("Content-Length", xA003);
|
||||
__headerHash.put("Date", xA004);
|
||||
__headerHash.put("Last-Modified", xA005);
|
||||
__headerHash.put("Location", xA006);
|
||||
__headerHash.put("Set-Cookie", xA007);
|
||||
__headerHash.put("Set-Cookie2", xA008);
|
||||
__headerHash.put("Servlet-Engine", xA009);
|
||||
__headerHash.put("Status", xA00A);
|
||||
__headerHash.put("WWW-Authenticate", xA00B);
|
||||
{ (byte)0xA0, (byte)0x0B };
|
||||
__headerHash.put("Content-Type",xA001);
|
||||
__headerHash.put("Content-Language",xA002);
|
||||
__headerHash.put("Content-Length",xA003);
|
||||
__headerHash.put("Date",xA004);
|
||||
__headerHash.put("Last-Modified",xA005);
|
||||
__headerHash.put("Location",xA006);
|
||||
__headerHash.put("Set-Cookie",xA007);
|
||||
__headerHash.put("Set-Cookie2",xA008);
|
||||
__headerHash.put("Servlet-Engine",xA009);
|
||||
__headerHash.put("Status",xA00A);
|
||||
__headerHash.put("WWW-Authenticate",xA00B);
|
||||
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
// 0, 1 ajp int 1 packet length
|
||||
// 9 CPONG response Code
|
||||
private static final byte[] AJP13_CPONG_RESPONSE =
|
||||
{ 'A', 'B', 0, 1, 9};
|
||||
{ 'A', 'B', 0, 1, 9 };
|
||||
|
||||
private static final byte[] AJP13_END_RESPONSE =
|
||||
{ 'A', 'B', 0, 2, 5, 1 };
|
||||
|
@ -114,7 +114,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
/* ------------------------------------------------------------ */
|
||||
public Ajp13Generator(Buffers buffers, EndPoint io)
|
||||
{
|
||||
super(buffers, io);
|
||||
super(buffers,io);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -130,6 +130,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void reset(boolean returnBuffers)
|
||||
|
@ -140,9 +141,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
_needMore = false;
|
||||
_expectMore = false;
|
||||
_bufferPrepared = false;
|
||||
_last=false;
|
||||
|
||||
|
||||
_last = false;
|
||||
|
||||
_state = STATE_HEADER;
|
||||
|
||||
|
@ -159,11 +158,9 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
_noContent = false;
|
||||
_persistent = true;
|
||||
|
||||
|
||||
|
||||
_header = null; // Buffer for HTTP header (and maybe small _content)
|
||||
_buffer = null; // Buffer for copy of passed _content
|
||||
_content = null; // Buffer passed to addContent
|
||||
_header = null; // Buffer for HTTP header (and maybe small _content)
|
||||
_buffer = null; // Buffer for copy of passed _content
|
||||
_content = null; // Buffer passed to addContent
|
||||
|
||||
}
|
||||
|
||||
|
@ -175,13 +172,13 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
{
|
||||
initContent();
|
||||
}
|
||||
catch(IOException e)
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return super.getContentBufferSize()-7;
|
||||
return super.getContentBufferSize() - 7;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void increaseContentBufferSize(int contentBufferSize)
|
||||
|
@ -196,11 +193,9 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
* @param content
|
||||
* @param last
|
||||
* @throws IllegalArgumentException
|
||||
* if <code>content</code> is
|
||||
* {@link Buffer#isImmutable immutable}.
|
||||
* if <code>content</code> is {@link Buffer#isImmutable immutable}.
|
||||
* @throws IllegalStateException
|
||||
* If the request is not expecting any more content, or if the
|
||||
* buffers are full and cannot be flushed.
|
||||
* If the request is not expecting any more content, or if the buffers are full and cannot be flushed.
|
||||
* @throws IOException
|
||||
* if there is a problem flushing the buffers.
|
||||
*/
|
||||
|
@ -217,13 +212,13 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
|
||||
if (_last || _state == STATE_END)
|
||||
{
|
||||
LOG.debug("Ignoring extra content {}", content);
|
||||
LOG.debug("Ignoring extra content {}",content);
|
||||
content.clear();
|
||||
return;
|
||||
}
|
||||
_last = last;
|
||||
|
||||
if(!_endp.isOpen())
|
||||
if (!_endp.isOpen())
|
||||
{
|
||||
_state = STATE_END;
|
||||
return;
|
||||
|
@ -289,8 +284,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
if (_last || _state == STATE_END)
|
||||
throw new IllegalStateException("Closed");
|
||||
|
||||
|
||||
if(!_endp.isOpen())
|
||||
if (!_endp.isOpen())
|
||||
{
|
||||
_state = STATE_END;
|
||||
return false;
|
||||
|
@ -322,8 +316,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Prepare buffer for unchecked writes. Prepare the generator buffer to
|
||||
* receive unchecked writes
|
||||
* Prepare buffer for unchecked writes. Prepare the generator buffer to receive unchecked writes
|
||||
*
|
||||
* @return the available space in the buffer.
|
||||
* @throws IOException
|
||||
|
@ -337,8 +330,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
if (_last || _state == STATE_END)
|
||||
throw new IllegalStateException("Closed");
|
||||
|
||||
|
||||
if(!_endp.isOpen())
|
||||
if (!_endp.isOpen())
|
||||
{
|
||||
_state = STATE_END;
|
||||
return -1;
|
||||
|
@ -377,8 +369,8 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
_last = _last | allContentAdded;
|
||||
|
||||
boolean has_server = false;
|
||||
if (_persistent==null)
|
||||
_persistent=(_version > HttpVersions.HTTP_1_0_ORDINAL);
|
||||
if (_persistent == null)
|
||||
_persistent = (_version > HttpVersions.HTTP_1_0_ORDINAL);
|
||||
|
||||
// get a header buffer
|
||||
if (_header == null)
|
||||
|
@ -390,13 +382,13 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
try
|
||||
{
|
||||
// start the header
|
||||
_buffer.put((byte) 'A');
|
||||
_buffer.put((byte) 'B');
|
||||
_buffer.put((byte)'A');
|
||||
_buffer.put((byte)'B');
|
||||
addInt(0);
|
||||
_buffer.put((byte) 0x4);
|
||||
_buffer.put((byte)0x4);
|
||||
addInt(_status);
|
||||
if (_reason == null)
|
||||
_reason=HttpGenerator.getReasonBuffer(_status);
|
||||
_reason = HttpGenerator.getReasonBuffer(_status);
|
||||
if (_reason == null)
|
||||
_reason = new ByteArrayBuffer(Integer.toString(_status));
|
||||
addBuffer(_reason);
|
||||
|
@ -407,7 +399,6 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
_content = null;
|
||||
}
|
||||
|
||||
|
||||
// allocate 2 bytes for number of headers
|
||||
int field_index = _buffer.putIndex();
|
||||
addInt(0);
|
||||
|
@ -417,15 +408,15 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
if (fields != null)
|
||||
{
|
||||
// Add headers
|
||||
int s=fields.size();
|
||||
for (int f=0;f<s;f++)
|
||||
int s = fields.size();
|
||||
for (int f = 0; f < s; f++)
|
||||
{
|
||||
HttpFields.Field field = fields.getField(f);
|
||||
if (field==null)
|
||||
if (field == null)
|
||||
continue;
|
||||
num_fields++;
|
||||
|
||||
byte[] codes = (byte[]) __headerHash.get(field.getName());
|
||||
byte[] codes = (byte[])__headerHash.get(field.getName());
|
||||
if (codes != null)
|
||||
{
|
||||
_buffer.put(codes);
|
||||
|
@ -460,14 +451,13 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
// insert the total packet size on 2nd and 3rd byte that
|
||||
// was previously
|
||||
// allocated
|
||||
addInt(2, payloadSize);
|
||||
addInt(2,payloadSize);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_buffer = tmpbuf;
|
||||
}
|
||||
|
||||
|
||||
_state = STATE_CONTENT;
|
||||
|
||||
}
|
||||
|
@ -501,7 +491,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
{
|
||||
try
|
||||
{
|
||||
if (_state == STATE_HEADER && !_expectMore)
|
||||
if (_state == STATE_HEADER && !_expectMore)
|
||||
throw new IllegalStateException("State==HEADER");
|
||||
prepareBuffers();
|
||||
|
||||
|
@ -528,90 +518,87 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
Flushing: while (true)
|
||||
{
|
||||
int len = -1;
|
||||
int to_flush = ((_header != null && _header.length() > 0) ? 4 : 0) | ((_buffer != null && _buffer.length() > 0) ? 2 : 0);
|
||||
|
||||
int to_flush = ((_header != null && _header.length() > 0)?4:0) | ((_buffer != null && _buffer.length() > 0)?2:0);
|
||||
|
||||
switch (to_flush)
|
||||
{
|
||||
case 7:
|
||||
throw new IllegalStateException(); // should
|
||||
// never
|
||||
// happen!
|
||||
case 6:
|
||||
len = _endp.flush(_header, _buffer, null);
|
||||
case 7:
|
||||
throw new IllegalStateException(); // should
|
||||
// never
|
||||
// happen!
|
||||
case 6:
|
||||
len = _endp.flush(_header,_buffer,null);
|
||||
|
||||
break;
|
||||
case 5:
|
||||
throw new IllegalStateException(); // should
|
||||
// never
|
||||
// happen!
|
||||
case 4:
|
||||
len = _endp.flush(_header);
|
||||
break;
|
||||
case 3:
|
||||
throw new IllegalStateException(); // should
|
||||
// never
|
||||
// happen!
|
||||
case 2:
|
||||
len = _endp.flush(_buffer);
|
||||
break;
|
||||
case 5:
|
||||
throw new IllegalStateException(); // should
|
||||
// never
|
||||
// happen!
|
||||
case 4:
|
||||
len = _endp.flush(_header);
|
||||
break;
|
||||
case 3:
|
||||
throw new IllegalStateException(); // should
|
||||
// never
|
||||
// happen!
|
||||
case 2:
|
||||
len = _endp.flush(_buffer);
|
||||
|
||||
break;
|
||||
case 1:
|
||||
throw new IllegalStateException(); // should
|
||||
// never
|
||||
// happen!
|
||||
case 0:
|
||||
{
|
||||
// Nothing more we can write now.
|
||||
if (_header != null)
|
||||
_header.clear();
|
||||
|
||||
_bufferPrepared = false;
|
||||
|
||||
if (_buffer != null)
|
||||
break;
|
||||
case 1:
|
||||
throw new IllegalStateException(); // should
|
||||
// never
|
||||
// happen!
|
||||
case 0:
|
||||
{
|
||||
_buffer.clear();
|
||||
// Nothing more we can write now.
|
||||
if (_header != null)
|
||||
_header.clear();
|
||||
|
||||
// reserve some space for the
|
||||
// header
|
||||
_buffer.setPutIndex(7);
|
||||
_buffer.setGetIndex(7);
|
||||
_bufferPrepared = false;
|
||||
|
||||
// Special case handling for
|
||||
// small left over buffer from
|
||||
// an addContent that caused a
|
||||
// buffer flush.
|
||||
if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
|
||||
if (_buffer != null)
|
||||
{
|
||||
_buffer.clear();
|
||||
|
||||
// reserve some space for the
|
||||
// header
|
||||
_buffer.setPutIndex(7);
|
||||
_buffer.setGetIndex(7);
|
||||
|
||||
// Special case handling for
|
||||
// small left over buffer from
|
||||
// an addContent that caused a
|
||||
// buffer flush.
|
||||
if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
|
||||
{
|
||||
|
||||
_buffer.put(_content);
|
||||
_content.clear();
|
||||
_content = null;
|
||||
break Flushing;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Are we completely finished for now?
|
||||
if (!_expectMore && !_needEOC && (_content == null || _content.length() == 0))
|
||||
{
|
||||
if (_state == STATE_FLUSHING)
|
||||
_state = STATE_END;
|
||||
|
||||
// if (_state == STATE_END)
|
||||
// {
|
||||
// _endp.close();
|
||||
// }
|
||||
//
|
||||
|
||||
_buffer.put(_content);
|
||||
_content.clear();
|
||||
_content = null;
|
||||
break Flushing;
|
||||
}
|
||||
|
||||
// Try to prepare more to write.
|
||||
prepareBuffers();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Are we completely finished for now?
|
||||
if (!_expectMore && !_needEOC && (_content == null || _content.length() == 0))
|
||||
{
|
||||
if (_state == STATE_FLUSHING)
|
||||
_state = STATE_END;
|
||||
|
||||
// if (_state == STATE_END)
|
||||
// {
|
||||
// _endp.close();
|
||||
// }
|
||||
//
|
||||
|
||||
break Flushing;
|
||||
}
|
||||
|
||||
// Try to prepare more to write.
|
||||
prepareBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
// If we failed to flush anything twice in a row
|
||||
|
@ -631,7 +618,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
catch (IOException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
throw (e instanceof EofException) ? e : new EofException(e);
|
||||
throw (e instanceof EofException)?e:new EofException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -680,14 +667,14 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
{
|
||||
_bufferPrepared = true;
|
||||
|
||||
_buffer.put((byte) 0);
|
||||
_buffer.put((byte)0);
|
||||
int put = _buffer.putIndex();
|
||||
_buffer.setGetIndex(0);
|
||||
_buffer.setPutIndex(0);
|
||||
_buffer.put((byte) 'A');
|
||||
_buffer.put((byte) 'B');
|
||||
_buffer.put((byte)'A');
|
||||
_buffer.put((byte)'B');
|
||||
addInt(payloadSize + 4);
|
||||
_buffer.put((byte) 3);
|
||||
_buffer.put((byte)3);
|
||||
addInt(payloadSize);
|
||||
_buffer.setPutIndex(put);
|
||||
}
|
||||
|
@ -759,15 +746,15 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
/* ------------------------------------------------------------ */
|
||||
private void addInt(int i)
|
||||
{
|
||||
_buffer.put((byte) ((i >> 8) & 0xFF));
|
||||
_buffer.put((byte) (i & 0xFF));
|
||||
_buffer.put((byte)((i >> 8) & 0xFF));
|
||||
_buffer.put((byte)(i & 0xFF));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void addInt(int startIndex, int i)
|
||||
{
|
||||
_buffer.poke(startIndex, (byte) ((i >> 8) & 0xFF));
|
||||
_buffer.poke((startIndex + 1), (byte) (i & 0xFF));
|
||||
_buffer.poke(startIndex,(byte)((i >> 8) & 0xFF));
|
||||
_buffer.poke((startIndex + 1),(byte)(i & 0xFF));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -786,7 +773,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
addInt(b.length);
|
||||
|
||||
_buffer.put(b);
|
||||
_buffer.put((byte) 0);
|
||||
_buffer.put((byte)0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -800,15 +787,14 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
|
||||
addInt(b.length());
|
||||
_buffer.put(b);
|
||||
_buffer.put((byte) 0);
|
||||
_buffer.put((byte)0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void getBodyChunk() throws IOException
|
||||
{
|
||||
_needMore = true;
|
||||
_expectMore = true;
|
||||
flushBuffer();
|
||||
ByteArrayBuffer bf = new ByteArrayBuffer(AJP13_MORE_CONTENT);
|
||||
_endp.flush(bf);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -818,7 +804,6 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
_expectMore = false;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void sendCPong() throws IOException
|
||||
{
|
||||
|
@ -831,13 +816,11 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
{
|
||||
_endp.flush(buff);
|
||||
}
|
||||
while(buff.length() >0);
|
||||
while (buff.length() > 0);
|
||||
_buffers.returnBuffer(buff);
|
||||
|
||||
reset(true);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
<Item>org.eclipse.jetty.webapp.FragmentConfiguration</Item>
|
||||
<Item>org.eclipse.jetty.annotations.AnnotationConfiguration</Item>
|
||||
<Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item>
|
||||
<Item>org.eclipse.jetty.annotations.ContainerInitializerConfiguration</Item>
|
||||
</Array>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
|
|
@ -18,9 +18,11 @@ import java.util.ArrayList;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletContainerInitializer;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.annotation.HandlesTypes;
|
||||
|
||||
|
||||
|
@ -47,6 +49,8 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(AnnotationConfiguration.class);
|
||||
public static final String CLASS_INHERITANCE_MAP = "org.eclipse.jetty.classInheritanceMap";
|
||||
public static final String CONTAINER_INITIALIZERS = "org.eclipse.jetty.containerInitializers";
|
||||
|
||||
|
||||
public void preConfigure(final WebAppContext context) throws Exception
|
||||
{
|
||||
|
@ -58,45 +62,46 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
boolean metadataComplete = context.getMetaData().isMetaDataComplete();
|
||||
context.addDecorator(new AnnotationDecorator(context));
|
||||
|
||||
if (metadataComplete)
|
||||
{
|
||||
//Never scan any jars or classes for annotations if metadata is complete
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Metadata-complete==true, not processing annotations for context "+context);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Only scan jars and classes if metadata is not complete and the web app is version 3.0, or
|
||||
//a 2.5 version webapp that has specifically asked to discover annotations
|
||||
if (LOG.isDebugEnabled()) LOG.debug("parsing annotations");
|
||||
|
||||
AnnotationParser parser = createAnnotationParser();
|
||||
//Discoverable annotations - those that you have to look for without loading a class
|
||||
parser.registerAnnotationHandler("javax.servlet.annotation.WebServlet", new WebServletAnnotationHandler(context));
|
||||
parser.registerAnnotationHandler("javax.servlet.annotation.WebFilter", new WebFilterAnnotationHandler(context));
|
||||
parser.registerAnnotationHandler("javax.servlet.annotation.WebListener", new WebListenerAnnotationHandler(context));
|
||||
ClassInheritanceHandler classHandler = new ClassInheritanceHandler();
|
||||
parser.registerClassHandler(classHandler);
|
||||
registerServletContainerInitializerAnnotationHandlers(context, parser);
|
||||
|
||||
if (context.getServletContext().getEffectiveMajorVersion() >= 3 || context.isConfigurationDiscovered())
|
||||
{
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Scanning all classses for annotations: webxmlVersion="+context.getServletContext().getEffectiveMajorVersion()+" configurationDiscovered="+context.isConfigurationDiscovered());
|
||||
parseContainerPath(context, parser);
|
||||
//email from Rajiv Mordani jsrs 315 7 April 2010
|
||||
// If there is a <others/> then the ordering should be
|
||||
// WEB-INF/classes the order of the declared elements + others.
|
||||
// In case there is no others then it is
|
||||
// WEB-INF/classes + order of the elements.
|
||||
parseWebInfClasses(context, parser);
|
||||
parseWebInfLib (context, parser);
|
||||
}
|
||||
|
||||
//save the type inheritance map created by the parser for later reference
|
||||
context.setAttribute(CLASS_INHERITANCE_MAP, classHandler.getMap());
|
||||
}
|
||||
|
||||
//Even if metadata is complete, we still need to scan for ServletContainerInitializers - if there are any
|
||||
AnnotationParser parser = null;
|
||||
if (!metadataComplete)
|
||||
{
|
||||
//If metadata isn't complete, if this is a servlet 3 webapp or isConfigDiscovered is true, we need to search for annotations
|
||||
if (context.getServletContext().getEffectiveMajorVersion() >= 3 || context.isConfigurationDiscovered())
|
||||
{
|
||||
parser = createAnnotationParser();
|
||||
parser.registerAnnotationHandler("javax.servlet.annotation.WebServlet", new WebServletAnnotationHandler(context));
|
||||
parser.registerAnnotationHandler("javax.servlet.annotation.WebFilter", new WebFilterAnnotationHandler(context));
|
||||
parser.registerAnnotationHandler("javax.servlet.annotation.WebListener", new WebListenerAnnotationHandler(context));
|
||||
}
|
||||
}
|
||||
else
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Metadata-complete==true, not processing discoverable servlet annotations for context "+context);
|
||||
|
||||
|
||||
|
||||
//Regardless of metadata, if there are any ServletContainerInitializers with @HandlesTypes, then we need to scan all the
|
||||
//classes so we can call their onStartup() methods correctly
|
||||
List<ServletContainerInitializer> nonExcludedInitializers = getNonExcludedInitializers(context);
|
||||
parser = registerServletContainerInitializerAnnotationHandlers(context, parser, nonExcludedInitializers);
|
||||
|
||||
if (parser != null)
|
||||
{
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Scanning all classses for annotations: webxmlVersion="+context.getServletContext().getEffectiveMajorVersion()+" configurationDiscovered="+context.isConfigurationDiscovered());
|
||||
parseContainerPath(context, parser);
|
||||
//email from Rajiv Mordani jsrs 315 7 April 2010
|
||||
// If there is a <others/> then the ordering should be
|
||||
// WEB-INF/classes the order of the declared elements + others.
|
||||
// In case there is no others then it is
|
||||
// WEB-INF/classes + order of the elements.
|
||||
parseWebInfClasses(context, parser);
|
||||
parseWebInfLib (context, parser);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return a new AnnotationParser. This method can be overridden to use a different impleemntation of
|
||||
* the AnnotationParser. Note that this is considered internal API.
|
||||
|
@ -112,10 +117,13 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
context.addDecorator(new AnnotationDecorator(context));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void registerServletContainerInitializerAnnotationHandlers (WebAppContext context, AnnotationParser parser)
|
||||
|
||||
public AnnotationParser registerServletContainerInitializerAnnotationHandlers (WebAppContext context, AnnotationParser parser, List<ServletContainerInitializer> scis)
|
||||
throws Exception
|
||||
{
|
||||
|
||||
//TODO verify my interpretation of the spec. That is, that metadata-complete has nothing
|
||||
//to do with finding the ServletContainerInitializers, classes designated to be of interest to them,
|
||||
//or even calling them on startup.
|
||||
|
@ -125,46 +133,73 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
//that will record the classes that have that annotation.
|
||||
//If it is NOT an annotation, then we will interrogate the type hierarchy discovered during
|
||||
//parsing later on to find the applicable classes.
|
||||
ArrayList<ContainerInitializer> initializers = new ArrayList<ContainerInitializer>();
|
||||
context.setAttribute(ContainerInitializerConfiguration.CONTAINER_INITIALIZERS, initializers);
|
||||
|
||||
//We use the ServiceLoader mechanism to find the ServletContainerInitializer classes to inspect
|
||||
ServiceLoader<ServletContainerInitializer> loadedInitializers = ServiceLoader.load(ServletContainerInitializer.class, context.getClassLoader());
|
||||
|
||||
if (loadedInitializers != null)
|
||||
if (scis == null || scis.isEmpty())
|
||||
return parser; // nothing to do
|
||||
|
||||
ServletContainerInitializerListener listener = new ServletContainerInitializerListener();
|
||||
listener.setWebAppContext(context);
|
||||
context.addEventListener(listener);
|
||||
|
||||
//may need to add a listener
|
||||
|
||||
ArrayList<ContainerInitializer> initializers = new ArrayList<ContainerInitializer>();
|
||||
context.setAttribute(CONTAINER_INITIALIZERS, initializers);
|
||||
|
||||
for (ServletContainerInitializer service : scis)
|
||||
{
|
||||
for (ServletContainerInitializer service : loadedInitializers)
|
||||
HandlesTypes annotation = service.getClass().getAnnotation(HandlesTypes.class);
|
||||
ContainerInitializer initializer = new ContainerInitializer();
|
||||
initializer.setTarget(service);
|
||||
initializers.add(initializer);
|
||||
if (annotation != null)
|
||||
{
|
||||
if (!isFromExcludedJar(context, service))
|
||||
{
|
||||
HandlesTypes annotation = service.getClass().getAnnotation(HandlesTypes.class);
|
||||
ContainerInitializer initializer = new ContainerInitializer();
|
||||
initializer.setTarget(service);
|
||||
initializers.add(initializer);
|
||||
if (annotation != null)
|
||||
//There is a HandlesTypes annotation on the on the ServletContainerInitializer
|
||||
Class[] classes = annotation.value();
|
||||
if (classes != null)
|
||||
{
|
||||
initializer.setInterestedTypes(classes);
|
||||
|
||||
//We need to create a parser if we haven't already
|
||||
if (parser == null)
|
||||
parser = createAnnotationParser();
|
||||
|
||||
//If we haven't already done so, we need to register a handler that will
|
||||
//process the whole class hierarchy
|
||||
if (context.getAttribute(CLASS_INHERITANCE_MAP) == null)
|
||||
{
|
||||
Class[] classes = annotation.value();
|
||||
if (classes != null)
|
||||
{
|
||||
initializer.setInterestedTypes(classes);
|
||||
for (Class c: classes)
|
||||
{
|
||||
if (c.isAnnotation())
|
||||
{
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Registering annotation handler for "+c.getName());
|
||||
parser.registerAnnotationHandler(c.getName(), new ContainerInitializerAnnotationHandler(initializer, c));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if (LOG.isDebugEnabled()) LOG.debug("No classes in HandlesTypes on initializer "+service.getClass());
|
||||
ClassInheritanceHandler classHandler = new ClassInheritanceHandler();
|
||||
context.setAttribute(CLASS_INHERITANCE_MAP, classHandler.getMap());
|
||||
parser.registerClassHandler(classHandler);
|
||||
}
|
||||
|
||||
for (Class c: classes)
|
||||
{
|
||||
//The value of one of the HandlesTypes classes is actually an Annotation itself so
|
||||
//register a handler for it
|
||||
if (c.isAnnotation())
|
||||
{
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Registering annotation handler for "+c.getName());
|
||||
|
||||
parser.registerAnnotationHandler(c.getName(), new ContainerInitializerAnnotationHandler(initializer, c));
|
||||
}
|
||||
}
|
||||
else
|
||||
if (LOG.isDebugEnabled()) LOG.debug("No annotation on initializer "+service.getClass());
|
||||
}
|
||||
else
|
||||
if (LOG.isDebugEnabled()) LOG.debug("No classes in HandlesTypes on initializer "+service.getClass());
|
||||
}
|
||||
else
|
||||
if (LOG.isDebugEnabled()) LOG.debug("No annotation on initializer "+service.getClass());
|
||||
}
|
||||
|
||||
//return the parser in case we lazily created it
|
||||
return parser;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check to see if the ServletContainerIntializer loaded via the ServiceLoader came
|
||||
|
@ -206,6 +241,30 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
return !found;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public List<ServletContainerInitializer> getNonExcludedInitializers (WebAppContext context)
|
||||
throws Exception
|
||||
{
|
||||
List<ServletContainerInitializer> nonExcludedInitializers = new ArrayList<ServletContainerInitializer>();
|
||||
|
||||
//We use the ServiceLoader mechanism to find the ServletContainerInitializer classes to inspect
|
||||
ServiceLoader<ServletContainerInitializer> loadedInitializers = ServiceLoader.load(ServletContainerInitializer.class, context.getClassLoader());
|
||||
|
||||
if (loadedInitializers != null)
|
||||
{
|
||||
for (ServletContainerInitializer service : loadedInitializers)
|
||||
{
|
||||
if (!isFromExcludedJar(context, service))
|
||||
nonExcludedInitializers.add(service);
|
||||
}
|
||||
}
|
||||
return nonExcludedInitializers;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void parseContainerPath (final WebAppContext context, final AnnotationParser parser)
|
||||
throws Exception
|
||||
{
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
package org.eclipse.jetty.annotations;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
|
||||
import org.eclipse.jetty.annotations.AnnotationConfiguration;
|
||||
import org.eclipse.jetty.plus.annotation.ContainerInitializer;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
// ========================================================================
|
||||
// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -11,37 +25,28 @@
|
|||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
|
||||
|
||||
package org.eclipse.jetty.annotations;
|
||||
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.plus.annotation.ContainerInitializer;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.eclipse.jetty.webapp.AbstractConfiguration;
|
||||
import org.eclipse.jetty.webapp.Configuration;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
/**
|
||||
* ContainerInitializerConfiguration
|
||||
* ServletContainerInitializerListener
|
||||
*
|
||||
*
|
||||
* Apply the ServletContainerInitializers.
|
||||
*/
|
||||
public class ContainerInitializerConfiguration extends AbstractConfiguration
|
||||
public class ServletContainerInitializerListener implements ServletContextListener
|
||||
{
|
||||
public static final String CONTAINER_INITIALIZERS = "org.eclipse.jetty.containerInitializers";
|
||||
|
||||
public void preConfigure(WebAppContext context) throws Exception
|
||||
{
|
||||
WebAppContext _context = null;
|
||||
|
||||
|
||||
public void setWebAppContext (WebAppContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public void configure(WebAppContext context) throws Exception
|
||||
/**
|
||||
* @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
|
||||
*/
|
||||
public void contextInitialized(ServletContextEvent sce)
|
||||
{
|
||||
List<ContainerInitializer> initializers = (List<ContainerInitializer>)context.getAttribute(CONTAINER_INITIALIZERS);
|
||||
MultiMap classMap = (MultiMap)context.getAttribute(AnnotationConfiguration.CLASS_INHERITANCE_MAP);
|
||||
List<ContainerInitializer> initializers = (List<ContainerInitializer>)_context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS);
|
||||
MultiMap classMap = (MultiMap)_context.getAttribute(AnnotationConfiguration.CLASS_INHERITANCE_MAP);
|
||||
|
||||
if (initializers != null)
|
||||
{
|
||||
|
@ -58,9 +63,12 @@ public class ContainerInitializerConfiguration extends AbstractConfiguration
|
|||
//add the class with the annotation
|
||||
i.addApplicableTypeName(name);
|
||||
//add the classes that inherit the annotation
|
||||
List<String> implementsOrExtends = (List<String>)classMap.getValues(name);
|
||||
if (implementsOrExtends != null && !implementsOrExtends.isEmpty())
|
||||
addInheritedTypes(classMap, i, implementsOrExtends);
|
||||
if (classMap != null)
|
||||
{
|
||||
List<String> implementsOrExtends = (List<String>)classMap.getValues(name);
|
||||
if (implementsOrExtends != null && !implementsOrExtends.isEmpty())
|
||||
addInheritedTypes(classMap, i, implementsOrExtends);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,29 +83,33 @@ public class ContainerInitializerConfiguration extends AbstractConfiguration
|
|||
{
|
||||
//add the classes that implement or extend the class.
|
||||
//TODO but not including the class itself?
|
||||
List<String> implementsOrExtends = (List<String>)classMap.getValues(c.getName());
|
||||
if (implementsOrExtends != null && !implementsOrExtends.isEmpty())
|
||||
addInheritedTypes(classMap, i, implementsOrExtends);
|
||||
if (classMap != null)
|
||||
{
|
||||
List<String> implementsOrExtends = (List<String>)classMap.getValues(c.getName());
|
||||
if (implementsOrExtends != null && !implementsOrExtends.isEmpty())
|
||||
addInheritedTypes(classMap, i, implementsOrExtends);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//instantiate ServletContainerInitializers, call doStart
|
||||
i.callStartup(context);
|
||||
try
|
||||
{
|
||||
i.callStartup(_context);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//OK, how do I throw an exception such that it really stops the startup sequence?
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
//TODO Email from Jan Luehe 18 August: after all ServletContainerInitializers have been
|
||||
//called, need to check to see if there are any ServletRegistrations remaining
|
||||
//that are "preliminary" and fail the deployment if so.
|
||||
}
|
||||
}
|
||||
|
||||
public void postConfigure(WebAppContext context) throws Exception
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void deconfigure(WebAppContext context) throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -114,5 +126,15 @@ public class ContainerInitializerConfiguration extends AbstractConfiguration
|
|||
addInheritedTypes (classMap, initializer, implementsOrExtends);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
|
||||
*/
|
||||
public void contextDestroyed(ServletContextEvent sce)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -178,10 +178,19 @@ public class HttpClient extends HttpBuffers implements Attributes, Dumpable
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return the threadPool
|
||||
* @return the threadpool
|
||||
*/
|
||||
public ThreadPool getThreadPool()
|
||||
{
|
||||
if (_threadPool==null)
|
||||
{
|
||||
QueuedThreadPool pool = new QueuedThreadPool();
|
||||
pool.setMaxThreads(16);
|
||||
pool.setDaemon(true);
|
||||
pool.setName("HttpClient");
|
||||
_threadPool = pool;
|
||||
}
|
||||
|
||||
return _threadPool;
|
||||
}
|
||||
|
||||
|
@ -420,13 +429,7 @@ public class HttpClient extends HttpBuffers implements Attributes, Dumpable
|
|||
_idleTimeoutQ.setNow();
|
||||
|
||||
if (_threadPool == null)
|
||||
{
|
||||
QueuedThreadPool pool = new QueuedThreadPool();
|
||||
pool.setMaxThreads(16);
|
||||
pool.setDaemon(true);
|
||||
pool.setName("HttpClient");
|
||||
_threadPool = pool;
|
||||
}
|
||||
getThreadPool();
|
||||
|
||||
if (_threadPool instanceof LifeCycle)
|
||||
{
|
||||
|
|
|
@ -73,7 +73,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
HttpConnection(Buffers requestBuffers, Buffers responseBuffers, EndPoint endp)
|
||||
{
|
||||
super(endp);
|
||||
|
||||
|
||||
_generator = new HttpGenerator(requestBuffers,endp);
|
||||
_parser = new HttpParser(responseBuffers,endp,new Handler());
|
||||
}
|
||||
|
@ -277,6 +277,9 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
{
|
||||
long filled = _parser.parseAvailable();
|
||||
io += filled;
|
||||
|
||||
if (_parser.isIdle() && (_endp.isInputShutdown() || !_endp.isOpen()))
|
||||
throw new EOFException();
|
||||
}
|
||||
|
||||
if (io > 0)
|
||||
|
@ -353,16 +356,34 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
complete = true;
|
||||
}
|
||||
}
|
||||
|
||||
// if the endpoint is closed, but the parser incomplete
|
||||
if (!_endp.isOpen() && !(_parser.isComplete()||_parser.isIdle()))
|
||||
{
|
||||
// we wont be called again so let the parser see the close
|
||||
complete=true;
|
||||
_parser.parseAvailable();
|
||||
// TODO should not need this
|
||||
if (!(_parser.isComplete()||_parser.isIdle()))
|
||||
{
|
||||
LOG.warn("Incomplete {} {}",_parser,_endp);
|
||||
if (_exchange!=null && !_exchange.isDone())
|
||||
{
|
||||
_exchange.setStatus(HttpExchange.STATUS_EXCEPTED);
|
||||
_exchange.getEventListener().onException(new EOFException("Incomplete"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_generator.isComplete() && !_parser.isComplete())
|
||||
if (_endp.isInputShutdown() && !_parser.isComplete() && !_parser.isIdle())
|
||||
{
|
||||
if (!_endp.isOpen() || _endp.isInputShutdown())
|
||||
if (_exchange!=null && !_exchange.isDone())
|
||||
{
|
||||
complete=true;
|
||||
close=true;
|
||||
close();
|
||||
_exchange.setStatus(HttpExchange.STATUS_EXCEPTED);
|
||||
_exchange.getEventListener().onException(new EOFException("Incomplete"));
|
||||
}
|
||||
_endp.close();
|
||||
}
|
||||
|
||||
if (complete || failed)
|
||||
|
@ -431,9 +452,9 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
finally
|
||||
{
|
||||
_parser.returnBuffers();
|
||||
|
||||
|
||||
// Do we have more stuff to write?
|
||||
if (!_generator.isComplete() && _generator.getBytesBuffered()>0 && _endp instanceof AsyncEndPoint)
|
||||
if (!_generator.isComplete() && _generator.getBytesBuffered()>0 && _endp.isOpen() && _endp instanceof AsyncEndPoint)
|
||||
{
|
||||
// Assume we are write blocked!
|
||||
((AsyncEndPoint)_endp).scheduleWrite();
|
||||
|
@ -549,6 +570,8 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
|
||||
private boolean shouldClose()
|
||||
{
|
||||
if (_endp.isInputShutdown())
|
||||
return true;
|
||||
if (_connectionHeader!=null)
|
||||
{
|
||||
if (HttpHeaderValues.CLOSE_BUFFER.equals(_connectionHeader))
|
||||
|
@ -669,6 +692,9 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
case HttpExchange.STATUS_EXCEPTED:
|
||||
case HttpExchange.STATUS_EXPIRED:
|
||||
break;
|
||||
case HttpExchange.STATUS_PARSING_CONTENT:
|
||||
if (_endp.isInputShutdown() && _parser.isState(HttpParser.STATE_EOF_CONTENT))
|
||||
break;
|
||||
default:
|
||||
String exch= exchange.toString();
|
||||
String reason = _endp.isOpen()?(_endp.isInputShutdown()?"half closed: ":"local close: "):"closed: ";
|
||||
|
@ -724,7 +750,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.util.component.Dumpable#dump()
|
||||
|
@ -746,7 +772,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
AggregateLifeCycle.dump(out,indent,Collections.singletonList(_endp));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private class ConnectionIdleTask extends Timeout.Task
|
||||
{
|
||||
|
@ -761,14 +787,14 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private class NonFinalResponseListener implements HttpEventListener
|
||||
{
|
||||
final HttpExchange _exchange;
|
||||
final HttpEventListener _next;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public NonFinalResponseListener(HttpExchange exchange)
|
||||
{
|
||||
|
@ -813,7 +839,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
{
|
||||
_exchange.setEventListener(_next);
|
||||
_exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_RESPONSE);
|
||||
_parser.reset();
|
||||
_parser.reset();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -584,7 +584,7 @@ public class HttpDestination implements Dumpable
|
|||
@Override
|
||||
public synchronized String toString()
|
||||
{
|
||||
return "HttpDestination@" + hashCode() + "//" + _address.getHost() + ":" + _address.getPort() + "(" + _connections.size() + "," + _idle.size() + "," + _queue.size() + ")";
|
||||
return String.format("HttpDestination@%x//%s:%d(%d/%d,%d,%d/%d)%n",hashCode(),_address.getHost(),_address.getPort(),_connections.size(),_maxConnections,_idle.size(),_queue.size(),_maxQueueSize);
|
||||
}
|
||||
|
||||
public synchronized String toDetailString()
|
||||
|
|
|
@ -35,7 +35,9 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
import org.eclipse.jetty.util.thread.Timeout;
|
||||
|
||||
/**
|
||||
* <p>An HTTP client API that encapsulates an exchange (a request and its response) with a HTTP server.</p>
|
||||
* <p>
|
||||
* An HTTP client API that encapsulates an exchange (a request and its response) with a HTTP server.
|
||||
* </p>
|
||||
*
|
||||
* This object encapsulates:
|
||||
* <ul>
|
||||
|
@ -48,23 +50,25 @@ import org.eclipse.jetty.util.thread.Timeout;
|
|||
* <li>The ability to intercept callbacks (see {@link #setEventListener(HttpEventListener)}
|
||||
* </ul>
|
||||
*
|
||||
* <p>The HttpExchange class is intended to be used by a developer wishing to have close asynchronous
|
||||
* interaction with the the exchange.<br />
|
||||
* Typically a developer will extend the HttpExchange class with a derived
|
||||
* class that overrides some or all of the onXxx callbacks. <br />
|
||||
* There are also some predefined HttpExchange subtypes that can be used as a basis,
|
||||
* see {@link org.eclipse.jetty.client.ContentExchange} and {@link org.eclipse.jetty.client.CachedExchange}.</p>
|
||||
* <p>
|
||||
* The HttpExchange class is intended to be used by a developer wishing to have close asynchronous interaction with the the exchange.<br />
|
||||
* Typically a developer will extend the HttpExchange class with a derived class that overrides some or all of the onXxx callbacks. <br />
|
||||
* There are also some predefined HttpExchange subtypes that can be used as a basis, see {@link org.eclipse.jetty.client.ContentExchange} and
|
||||
* {@link org.eclipse.jetty.client.CachedExchange}.
|
||||
* </p>
|
||||
*
|
||||
* <p>Typically the HttpExchange is passed to the {@link HttpClient#send(HttpExchange)} method, which in
|
||||
* turn selects a {@link HttpDestination} and calls its {@link HttpDestination#send(HttpExchange)}, which
|
||||
* then creates or selects a {@link HttpConnection} and calls its {@link HttpConnection#send(HttpExchange)}.
|
||||
* A developer may wish to directly call send on the destination or connection if they wish to bypass
|
||||
* some handling provided (eg Cookie handling in the HttpDestination).</p>
|
||||
* <p>
|
||||
* Typically the HttpExchange is passed to the {@link HttpClient#send(HttpExchange)} method, which in turn selects a {@link HttpDestination} and calls its
|
||||
* {@link HttpDestination#send(HttpExchange)}, which then creates or selects a {@link HttpConnection} and calls its {@link HttpConnection#send(HttpExchange)}. A
|
||||
* developer may wish to directly call send on the destination or connection if they wish to bypass some handling provided (eg Cookie handling in the
|
||||
* HttpDestination).
|
||||
* </p>
|
||||
*
|
||||
* <p>In some circumstances, the HttpClient or HttpDestination may wish to retry a HttpExchange (eg. failed
|
||||
* pipeline request, authentication retry or redirection). In such cases, the HttpClient and/or HttpDestination
|
||||
* may insert their own HttpExchangeListener to intercept and filter the call backs intended for the
|
||||
* HttpExchange.</p>
|
||||
* <p>
|
||||
* In some circumstances, the HttpClient or HttpDestination may wish to retry a HttpExchange (eg. failed pipeline request, authentication retry or redirection).
|
||||
* In such cases, the HttpClient and/or HttpDestination may insert their own HttpExchangeListener to intercept and filter the call backs intended for the
|
||||
* HttpExchange.
|
||||
* </p>
|
||||
*/
|
||||
public class HttpExchange
|
||||
{
|
||||
|
@ -106,9 +110,10 @@ public class HttpExchange
|
|||
// a timeout for this exchange
|
||||
private long _timeout = -1;
|
||||
private volatile Timeout.Task _timeoutTask;
|
||||
|
||||
private long _lastStateChange=-1;
|
||||
private long _lastStateChange=System.currentTimeMillis();
|
||||
private long _sent=-1;
|
||||
private int _lastState=-1;
|
||||
private int _lastStatePeriod=-1;
|
||||
|
||||
boolean _onRequestCompleteDone;
|
||||
boolean _onResponseCompleteDone;
|
||||
|
@ -131,8 +136,10 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param status the status to wait for
|
||||
* @throws InterruptedException if the waiting thread is interrupted
|
||||
* @param status
|
||||
* the status to wait for
|
||||
* @throws InterruptedException
|
||||
* if the waiting thread is interrupted
|
||||
* @deprecated Use {@link #waitForDone()} instead
|
||||
*/
|
||||
@Deprecated
|
||||
|
@ -142,21 +149,17 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* Wait until the exchange is "done".
|
||||
* Done is defined as when a final state has been passed to the
|
||||
* HttpExchange via the associated onXxx call. Note that an
|
||||
* exchange can transit a final state when being used as part
|
||||
* of a dialog (eg {@link SecurityListener}. Done status
|
||||
* is thus defined as:<pre>
|
||||
* done == onConnectionFailed
|
||||
* || onException
|
||||
* || onExpire
|
||||
* || onRequestComplete && onResponseComplete
|
||||
* Wait until the exchange is "done". Done is defined as when a final state has been passed to the HttpExchange via the associated onXxx call. Note that an
|
||||
* exchange can transit a final state when being used as part of a dialog (eg {@link SecurityListener}. Done status is thus defined as:
|
||||
*
|
||||
* <pre>
|
||||
* done == onConnectionFailed || onException || onExpire || onRequestComplete && onResponseComplete
|
||||
* </pre>
|
||||
*
|
||||
* @return the done status
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public int waitForDone () throws InterruptedException
|
||||
public int waitForDone() throws InterruptedException
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
|
@ -170,12 +173,12 @@ public class HttpExchange
|
|||
{
|
||||
// TODO - this should do a cancel and wakeup everybody that was waiting.
|
||||
// might need a version number concept
|
||||
synchronized(this)
|
||||
synchronized (this)
|
||||
{
|
||||
_timeoutTask=null;
|
||||
_onRequestCompleteDone=false;
|
||||
_onResponseCompleteDone=false;
|
||||
_onDone=false;
|
||||
_timeoutTask = null;
|
||||
_onRequestCompleteDone = false;
|
||||
_onResponseCompleteDone = false;
|
||||
_onDone = false;
|
||||
setStatus(STATUS_START);
|
||||
}
|
||||
}
|
||||
|
@ -186,13 +189,16 @@ public class HttpExchange
|
|||
{
|
||||
int oldStatus = _status.get();
|
||||
boolean set = false;
|
||||
if (oldStatus!=newStatus)
|
||||
if (oldStatus != newStatus)
|
||||
{
|
||||
_lastStateChange=System.currentTimeMillis();
|
||||
long now = System.currentTimeMillis();
|
||||
_lastStatePeriod=(int)(now-_lastStateChange);
|
||||
_lastState=oldStatus;
|
||||
_lastStateChange=now;
|
||||
if (newStatus==STATUS_SENDING_REQUEST)
|
||||
_sent=_lastStateChange;
|
||||
}
|
||||
|
||||
|
||||
// State machine: from which old status you can go into which new status
|
||||
switch (oldStatus)
|
||||
{
|
||||
|
@ -204,7 +210,10 @@ public class HttpExchange
|
|||
case STATUS_WAITING_FOR_COMMIT:
|
||||
case STATUS_CANCELLING:
|
||||
case STATUS_EXCEPTED:
|
||||
set=_status.compareAndSet(oldStatus,newStatus);
|
||||
set = _status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
case STATUS_EXPIRED:
|
||||
set = setStatusExpired(newStatus,oldStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -214,11 +223,10 @@ public class HttpExchange
|
|||
case STATUS_WAITING_FOR_COMMIT:
|
||||
case STATUS_CANCELLING:
|
||||
case STATUS_EXCEPTED:
|
||||
set=_status.compareAndSet(oldStatus,newStatus);
|
||||
set = _status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
case STATUS_EXPIRED:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
getEventListener().onExpire();
|
||||
set = setStatusExpired(newStatus,oldStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -228,11 +236,10 @@ public class HttpExchange
|
|||
case STATUS_SENDING_REQUEST:
|
||||
case STATUS_CANCELLING:
|
||||
case STATUS_EXCEPTED:
|
||||
set=_status.compareAndSet(oldStatus,newStatus);
|
||||
set = _status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
case STATUS_EXPIRED:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
getEventListener().onExpire();
|
||||
set = setStatusExpired(newStatus,oldStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -240,16 +247,15 @@ public class HttpExchange
|
|||
switch (newStatus)
|
||||
{
|
||||
case STATUS_WAITING_FOR_RESPONSE:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
if (set = _status.compareAndSet(oldStatus,newStatus))
|
||||
getEventListener().onRequestCommitted();
|
||||
break;
|
||||
case STATUS_CANCELLING:
|
||||
case STATUS_EXCEPTED:
|
||||
set=_status.compareAndSet(oldStatus,newStatus);
|
||||
set = _status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
case STATUS_EXPIRED:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
getEventListener().onExpire();
|
||||
set = setStatusExpired(newStatus,oldStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -259,11 +265,10 @@ public class HttpExchange
|
|||
case STATUS_PARSING_HEADERS:
|
||||
case STATUS_CANCELLING:
|
||||
case STATUS_EXCEPTED:
|
||||
set=_status.compareAndSet(oldStatus,newStatus);
|
||||
set = _status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
case STATUS_EXPIRED:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
getEventListener().onExpire();
|
||||
set = setStatusExpired(newStatus,oldStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -271,16 +276,15 @@ public class HttpExchange
|
|||
switch (newStatus)
|
||||
{
|
||||
case STATUS_PARSING_CONTENT:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
if (set = _status.compareAndSet(oldStatus,newStatus))
|
||||
getEventListener().onResponseHeaderComplete();
|
||||
break;
|
||||
case STATUS_CANCELLING:
|
||||
case STATUS_EXCEPTED:
|
||||
set=_status.compareAndSet(oldStatus,newStatus);
|
||||
set = _status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
case STATUS_EXPIRED:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
getEventListener().onExpire();
|
||||
set = setStatusExpired(newStatus,oldStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -288,16 +292,15 @@ public class HttpExchange
|
|||
switch (newStatus)
|
||||
{
|
||||
case STATUS_COMPLETED:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
if (set = _status.compareAndSet(oldStatus,newStatus))
|
||||
getEventListener().onResponseComplete();
|
||||
break;
|
||||
case STATUS_CANCELLING:
|
||||
case STATUS_EXCEPTED:
|
||||
set=_status.compareAndSet(oldStatus,newStatus);
|
||||
set = _status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
case STATUS_EXPIRED:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
getEventListener().onExpire();
|
||||
set = setStatusExpired(newStatus,oldStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -307,12 +310,12 @@ public class HttpExchange
|
|||
case STATUS_START:
|
||||
case STATUS_EXCEPTED:
|
||||
case STATUS_WAITING_FOR_RESPONSE:
|
||||
set=_status.compareAndSet(oldStatus,newStatus);
|
||||
set = _status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
case STATUS_CANCELLING:
|
||||
case STATUS_EXPIRED:
|
||||
// Don't change the status, it's too late
|
||||
set=true;
|
||||
set = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -321,12 +324,12 @@ public class HttpExchange
|
|||
{
|
||||
case STATUS_EXCEPTED:
|
||||
case STATUS_CANCELLED:
|
||||
if (set=_status.compareAndSet(oldStatus,newStatus))
|
||||
if (set = _status.compareAndSet(oldStatus,newStatus))
|
||||
done();
|
||||
break;
|
||||
default:
|
||||
// Ignore other statuses, we're cancelling
|
||||
set=true;
|
||||
set = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -336,10 +339,10 @@ public class HttpExchange
|
|||
switch (newStatus)
|
||||
{
|
||||
case STATUS_START:
|
||||
set=_status.compareAndSet(oldStatus,newStatus);
|
||||
set = _status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
default:
|
||||
set=true;
|
||||
set = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -357,6 +360,14 @@ public class HttpExchange
|
|||
}
|
||||
}
|
||||
|
||||
private boolean setStatusExpired(int newStatus, int oldStatus)
|
||||
{
|
||||
boolean set;
|
||||
if (set = _status.compareAndSet(oldStatus,newStatus))
|
||||
getEventListener().onExpire();
|
||||
return set;
|
||||
}
|
||||
|
||||
public boolean isDone()
|
||||
{
|
||||
synchronized (this)
|
||||
|
@ -369,7 +380,7 @@ public class HttpExchange
|
|||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isDone (int status)
|
||||
public boolean isDone(int status)
|
||||
{
|
||||
return isDone();
|
||||
}
|
||||
|
@ -381,10 +392,10 @@ public class HttpExchange
|
|||
|
||||
public void setEventListener(HttpEventListener listener)
|
||||
{
|
||||
_listener=listener;
|
||||
_listener = listener;
|
||||
}
|
||||
|
||||
public void setTimeout( long timeout )
|
||||
public void setTimeout(long timeout)
|
||||
{
|
||||
_timeout = timeout;
|
||||
}
|
||||
|
@ -395,7 +406,8 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param url an absolute URL (for example 'http://localhost/foo/bar?a=1')
|
||||
* @param url
|
||||
* an absolute URL (for example 'http://localhost/foo/bar?a=1')
|
||||
*/
|
||||
public void setURL(String url)
|
||||
{
|
||||
|
@ -403,7 +415,8 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param address the address of the server
|
||||
* @param address
|
||||
* the address of the server
|
||||
*/
|
||||
public void setAddress(Address address)
|
||||
{
|
||||
|
@ -421,8 +434,7 @@ public class HttpExchange
|
|||
/**
|
||||
* the local address used by the connection
|
||||
*
|
||||
* Note: this method will not be populated unless the exchange
|
||||
* has been executed by the HttpClient
|
||||
* Note: this method will not be populated unless the exchange has been executed by the HttpClient
|
||||
*
|
||||
* @return the local address used for the running of the exchange if available, null otherwise.
|
||||
*/
|
||||
|
@ -432,15 +444,17 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param scheme the scheme of the URL (for example 'http')
|
||||
* @param scheme
|
||||
* the scheme of the URL (for example 'http')
|
||||
*/
|
||||
public void setScheme(Buffer scheme)
|
||||
{
|
||||
_scheme = scheme;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param scheme the scheme of the URL (for example 'http')
|
||||
* @param scheme
|
||||
* the scheme of the URL (for example 'http')
|
||||
*/
|
||||
public void setScheme(String scheme)
|
||||
{
|
||||
|
@ -464,7 +478,8 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param version the HTTP protocol version as integer, 9, 10 or 11 for 0.9, 1.0 or 1.1
|
||||
* @param version
|
||||
* the HTTP protocol version as integer, 9, 10 or 11 for 0.9, 1.0 or 1.1
|
||||
*/
|
||||
public void setVersion(int version)
|
||||
{
|
||||
|
@ -472,7 +487,8 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param version the HTTP protocol version as string
|
||||
* @param version
|
||||
* the HTTP protocol version as string
|
||||
*/
|
||||
public void setVersion(String version)
|
||||
{
|
||||
|
@ -493,7 +509,8 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param method the HTTP method (for example 'GET')
|
||||
* @param method
|
||||
* the HTTP method (for example 'GET')
|
||||
*/
|
||||
public void setMethod(String method)
|
||||
{
|
||||
|
@ -528,9 +545,10 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the request URI
|
||||
* Set the request URI
|
||||
*
|
||||
* @param uri new request URI
|
||||
* @param uri
|
||||
* new request URI
|
||||
* @see #setRequestURI(String)
|
||||
* @deprecated
|
||||
*/
|
||||
|
@ -541,36 +559,41 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the request URI
|
||||
* Set the request URI
|
||||
*
|
||||
* Per RFC 2616 sec5, Request-URI = "*" | absoluteURI | abs_path | authority<br/>
|
||||
* where:<br/><br/>
|
||||
* "*" - request applies to server itself<br/>
|
||||
* where:<br/>
|
||||
* <br/>
|
||||
* "*" - request applies to server itself<br/>
|
||||
* absoluteURI - required for proxy requests, e.g. http://localhost:8080/context<br/>
|
||||
* (this form is generated automatically by HttpClient)<br/>
|
||||
* abs_path - used for most methods, e.g. /context<br/>
|
||||
* authority - used for CONNECT method only, e.g. localhost:8080<br/>
|
||||
* (this form is generated automatically by HttpClient)<br/>
|
||||
* abs_path - used for most methods, e.g. /context<br/>
|
||||
* authority - used for CONNECT method only, e.g. localhost:8080<br/>
|
||||
* <br/>
|
||||
* For complete definition of URI components, see RFC 2396 sec3.<br/>
|
||||
*
|
||||
* @param uri new request URI
|
||||
*
|
||||
* @param uri
|
||||
* new request URI
|
||||
*/
|
||||
public void setRequestURI(String uri)
|
||||
{
|
||||
_uri = uri;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param uri an absolute URI (for example 'http://localhost/foo/bar?a=1')
|
||||
* @param uri
|
||||
* an absolute URI (for example 'http://localhost/foo/bar?a=1')
|
||||
*/
|
||||
public void setURI(URI uri)
|
||||
{
|
||||
if (!uri.isAbsolute())
|
||||
throw new IllegalArgumentException("!Absolute URI: "+uri);
|
||||
|
||||
throw new IllegalArgumentException("!Absolute URI: " + uri);
|
||||
|
||||
if (uri.isOpaque())
|
||||
throw new IllegalArgumentException("Opaque URI: "+uri);
|
||||
throw new IllegalArgumentException("Opaque URI: " + uri);
|
||||
|
||||
LOG.debug("URI = {}",uri.toASCIIString());
|
||||
|
||||
String scheme = uri.getScheme();
|
||||
int port = uri.getPort();
|
||||
|
@ -582,13 +605,16 @@ public class HttpExchange
|
|||
|
||||
HttpURI httpUri = new HttpURI(uri);
|
||||
String completePath = httpUri.getCompletePath();
|
||||
setRequestURI(completePath==null ? "/" : completePath);
|
||||
setRequestURI(completePath == null?"/":completePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified request header
|
||||
* @param name the header name
|
||||
* @param value the header value
|
||||
*
|
||||
* @param name
|
||||
* the header name
|
||||
* @param value
|
||||
* the header value
|
||||
*/
|
||||
public void addRequestHeader(String name, String value)
|
||||
{
|
||||
|
@ -597,8 +623,11 @@ public class HttpExchange
|
|||
|
||||
/**
|
||||
* Adds the specified request header
|
||||
* @param name the header name
|
||||
* @param value the header value
|
||||
*
|
||||
* @param name
|
||||
* the header name
|
||||
* @param value
|
||||
* the header value
|
||||
*/
|
||||
public void addRequestHeader(Buffer name, Buffer value)
|
||||
{
|
||||
|
@ -607,30 +636,37 @@ public class HttpExchange
|
|||
|
||||
/**
|
||||
* Sets the specified request header
|
||||
* @param name the header name
|
||||
* @param value the header value
|
||||
*
|
||||
* @param name
|
||||
* the header name
|
||||
* @param value
|
||||
* the header value
|
||||
*/
|
||||
public void setRequestHeader(String name, String value)
|
||||
{
|
||||
getRequestFields().put(name, value);
|
||||
getRequestFields().put(name,value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the specified request header
|
||||
* @param name the header name
|
||||
* @param value the header value
|
||||
*
|
||||
* @param name
|
||||
* the header name
|
||||
* @param value
|
||||
* the header value
|
||||
*/
|
||||
public void setRequestHeader(Buffer name, Buffer value)
|
||||
{
|
||||
getRequestFields().put(name, value);
|
||||
getRequestFields().put(name,value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value the content type of the request
|
||||
* @param value
|
||||
* the content type of the request
|
||||
*/
|
||||
public void setRequestContentType(String value)
|
||||
{
|
||||
getRequestFields().put(HttpHeaders.CONTENT_TYPE_BUFFER, value);
|
||||
getRequestFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -642,7 +678,8 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param requestContent the request content
|
||||
* @param requestContent
|
||||
* the request content
|
||||
*/
|
||||
public void setRequestContent(Buffer requestContent)
|
||||
{
|
||||
|
@ -650,7 +687,8 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param stream the request content as a stream
|
||||
* @param stream
|
||||
* the request content as a stream
|
||||
*/
|
||||
public void setRequestContentSource(InputStream stream)
|
||||
{
|
||||
|
@ -708,7 +746,8 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param retryStatus whether a retry will be attempted or not
|
||||
* @param retryStatus
|
||||
* whether a retry will be attempted or not
|
||||
*/
|
||||
public void setRetryStatus(boolean retryStatus)
|
||||
{
|
||||
|
@ -716,13 +755,10 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* Initiates the cancelling of this exchange.
|
||||
* The status of the exchange is set to {@link #STATUS_CANCELLING}.
|
||||
* Cancelling the exchange is an asynchronous operation with respect to the request/response,
|
||||
* and as such checking the request/response status of a cancelled exchange may return undefined results
|
||||
* (for example it may have only some of the response headers being sent by the server).
|
||||
* The cancelling of the exchange is completed when the exchange status (see {@link #getStatus()}) is
|
||||
* {@link #STATUS_CANCELLED}, and this can be waited using {@link #waitForDone()}.
|
||||
* Initiates the cancelling of this exchange. The status of the exchange is set to {@link #STATUS_CANCELLING}. Cancelling the exchange is an asynchronous
|
||||
* operation with respect to the request/response, and as such checking the request/response status of a cancelled exchange may return undefined results
|
||||
* (for example it may have only some of the response headers being sent by the server). The cancelling of the exchange is completed when the exchange
|
||||
* status (see {@link #getStatus()}) is {@link #STATUS_CANCELLED}, and this can be waited using {@link #waitForDone()}.
|
||||
*/
|
||||
public void cancel()
|
||||
{
|
||||
|
@ -732,10 +768,10 @@ public class HttpExchange
|
|||
|
||||
private void done()
|
||||
{
|
||||
synchronized(this)
|
||||
synchronized (this)
|
||||
{
|
||||
disassociate();
|
||||
_onDone=true;
|
||||
_onDone = true;
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
@ -764,8 +800,8 @@ public class HttpExchange
|
|||
|
||||
void associate(HttpConnection connection)
|
||||
{
|
||||
if (connection.getEndPoint().getLocalHost() != null)
|
||||
_localAddress = new Address(connection.getEndPoint().getLocalHost(), connection.getEndPoint().getLocalPort());
|
||||
if (connection.getEndPoint().getLocalHost() != null)
|
||||
_localAddress = new Address(connection.getEndPoint().getLocalHost(),connection.getEndPoint().getLocalPort());
|
||||
|
||||
_connection = connection;
|
||||
if (getStatus() == STATUS_CANCELLING)
|
||||
|
@ -789,33 +825,60 @@ public class HttpExchange
|
|||
public static String toState(int s)
|
||||
{
|
||||
String state;
|
||||
switch(s)
|
||||
switch (s)
|
||||
{
|
||||
case STATUS_START: state="START"; break;
|
||||
case STATUS_WAITING_FOR_CONNECTION: state="CONNECTING"; break;
|
||||
case STATUS_WAITING_FOR_COMMIT: state="CONNECTED"; break;
|
||||
case STATUS_SENDING_REQUEST: state="SENDING"; break;
|
||||
case STATUS_WAITING_FOR_RESPONSE: state="WAITING"; break;
|
||||
case STATUS_PARSING_HEADERS: state="HEADERS"; break;
|
||||
case STATUS_PARSING_CONTENT: state="CONTENT"; break;
|
||||
case STATUS_COMPLETED: state="COMPLETED"; break;
|
||||
case STATUS_EXPIRED: state="EXPIRED"; break;
|
||||
case STATUS_EXCEPTED: state="EXCEPTED"; break;
|
||||
case STATUS_CANCELLING: state="CANCELLING"; break;
|
||||
case STATUS_CANCELLED: state="CANCELLED"; break;
|
||||
default: state="UNKNOWN";
|
||||
case STATUS_START:
|
||||
state = "START";
|
||||
break;
|
||||
case STATUS_WAITING_FOR_CONNECTION:
|
||||
state = "CONNECTING";
|
||||
break;
|
||||
case STATUS_WAITING_FOR_COMMIT:
|
||||
state = "CONNECTED";
|
||||
break;
|
||||
case STATUS_SENDING_REQUEST:
|
||||
state = "SENDING";
|
||||
break;
|
||||
case STATUS_WAITING_FOR_RESPONSE:
|
||||
state = "WAITING";
|
||||
break;
|
||||
case STATUS_PARSING_HEADERS:
|
||||
state = "HEADERS";
|
||||
break;
|
||||
case STATUS_PARSING_CONTENT:
|
||||
state = "CONTENT";
|
||||
break;
|
||||
case STATUS_COMPLETED:
|
||||
state = "COMPLETED";
|
||||
break;
|
||||
case STATUS_EXPIRED:
|
||||
state = "EXPIRED";
|
||||
break;
|
||||
case STATUS_EXCEPTED:
|
||||
state = "EXCEPTED";
|
||||
break;
|
||||
case STATUS_CANCELLING:
|
||||
state = "CANCELLING";
|
||||
break;
|
||||
case STATUS_CANCELLED:
|
||||
state = "CANCELLED";
|
||||
break;
|
||||
default:
|
||||
state = "UNKNOWN";
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
String state=toState(getStatus());
|
||||
long now=System.currentTimeMillis();
|
||||
long forMs = now -_lastStateChange;
|
||||
String s= String.format("%s@%x=%s//%s%s#%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,state,forMs);
|
||||
if (getStatus()>=STATUS_SENDING_REQUEST)
|
||||
String s= _lastState>=0
|
||||
?String.format("%s@%x=%s//%s%s#%s(%dms)->%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,toState(_lastState),_lastStatePeriod,state,forMs)
|
||||
:String.format("%s@%x=%s//%s%s#%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,state,forMs);
|
||||
if (getStatus()>=STATUS_SENDING_REQUEST && _sent>0)
|
||||
s+="sent="+(now-_sent)+"ms";
|
||||
return s;
|
||||
}
|
||||
|
@ -828,79 +891,93 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* Callback called when the request headers have been sent to the server.
|
||||
* This implementation does nothing.
|
||||
* @throws IOException allowed to be thrown by overriding code
|
||||
* Callback called when the request headers have been sent to the server. This implementation does nothing.
|
||||
*
|
||||
* @throws IOException
|
||||
* allowed to be thrown by overriding code
|
||||
*/
|
||||
protected void onRequestCommitted() throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback called when the request and its body have been sent to the server.
|
||||
* This implementation does nothing.
|
||||
* @throws IOException allowed to be thrown by overriding code
|
||||
* Callback called when the request and its body have been sent to the server. This implementation does nothing.
|
||||
*
|
||||
* @throws IOException
|
||||
* allowed to be thrown by overriding code
|
||||
*/
|
||||
protected void onRequestComplete() throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback called when a response status line has been received from the server.
|
||||
* This implementation does nothing.
|
||||
* @param version the HTTP version
|
||||
* @param status the HTTP status code
|
||||
* @param reason the HTTP status reason string
|
||||
* @throws IOException allowed to be thrown by overriding code
|
||||
* Callback called when a response status line has been received from the server. This implementation does nothing.
|
||||
*
|
||||
* @param version
|
||||
* the HTTP version
|
||||
* @param status
|
||||
* the HTTP status code
|
||||
* @param reason
|
||||
* the HTTP status reason string
|
||||
* @throws IOException
|
||||
* allowed to be thrown by overriding code
|
||||
*/
|
||||
protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback called for each response header received from the server.
|
||||
* This implementation does nothing.
|
||||
* @param name the header name
|
||||
* @param value the header value
|
||||
* @throws IOException allowed to be thrown by overriding code
|
||||
* Callback called for each response header received from the server. This implementation does nothing.
|
||||
*
|
||||
* @param name
|
||||
* the header name
|
||||
* @param value
|
||||
* the header value
|
||||
* @throws IOException
|
||||
* allowed to be thrown by overriding code
|
||||
*/
|
||||
protected void onResponseHeader(Buffer name, Buffer value) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback called when the response headers have been completely received from the server.
|
||||
* This implementation does nothing.
|
||||
* @throws IOException allowed to be thrown by overriding code
|
||||
* Callback called when the response headers have been completely received from the server. This implementation does nothing.
|
||||
*
|
||||
* @throws IOException
|
||||
* allowed to be thrown by overriding code
|
||||
*/
|
||||
protected void onResponseHeaderComplete() throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback called for each chunk of the response content received from the server.
|
||||
* This implementation does nothing.
|
||||
* @param content the buffer holding the content chunk
|
||||
* @throws IOException allowed to be thrown by overriding code
|
||||
* Callback called for each chunk of the response content received from the server. This implementation does nothing.
|
||||
*
|
||||
* @param content
|
||||
* the buffer holding the content chunk
|
||||
* @throws IOException
|
||||
* allowed to be thrown by overriding code
|
||||
*/
|
||||
protected void onResponseContent(Buffer content) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback called when the entire response has been received from the server
|
||||
* This implementation does nothing.
|
||||
* @throws IOException allowed to be thrown by overriding code
|
||||
* Callback called when the entire response has been received from the server This implementation does nothing.
|
||||
*
|
||||
* @throws IOException
|
||||
* allowed to be thrown by overriding code
|
||||
*/
|
||||
protected void onResponseComplete() throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback called when an exception was thrown during an attempt to establish the connection
|
||||
* with the server (for example the server is not listening).
|
||||
* Callback called when an exception was thrown during an attempt to establish the connection with the server (for example the server is not listening).
|
||||
* This implementation logs a warning.
|
||||
* @param x the exception thrown attempting to establish the connection with the server
|
||||
*
|
||||
* @param x
|
||||
* the exception thrown attempting to establish the connection with the server
|
||||
*/
|
||||
protected void onConnectionFailed(Throwable x)
|
||||
{
|
||||
|
@ -908,9 +985,10 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* Callback called when any other exception occurs during the handling of this exchange.
|
||||
* This implementation logs a warning.
|
||||
* @param x the exception thrown during the handling of this exchange
|
||||
* Callback called when any other exception occurs during the handling of this exchange. This implementation logs a warning.
|
||||
*
|
||||
* @param x
|
||||
* the exception thrown during the handling of this exchange
|
||||
*/
|
||||
protected void onException(Throwable x)
|
||||
{
|
||||
|
@ -918,8 +996,7 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* Callback called when no response has been received within the timeout.
|
||||
* This implementation logs a warning.
|
||||
* Callback called when no response has been received within the timeout. This implementation logs a warning.
|
||||
*/
|
||||
protected void onExpire()
|
||||
{
|
||||
|
@ -927,9 +1004,10 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* Callback called when the request is retried (due to failures or authentication).
|
||||
* Implementations must reset any consumable content that needs to be sent.
|
||||
* @throws IOException allowed to be thrown by overriding code
|
||||
* Callback called when the request is retried (due to failures or authentication). Implementations must reset any consumable content that needs to be sent.
|
||||
*
|
||||
* @throws IOException
|
||||
* allowed to be thrown by overriding code
|
||||
*/
|
||||
protected void onRetry() throws IOException
|
||||
{
|
||||
|
@ -948,8 +1026,7 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @return true if the exchange should have listeners configured for it by the destination,
|
||||
* false if this is being managed elsewhere
|
||||
* @return true if the exchange should have listeners configured for it by the destination, false if this is being managed elsewhere
|
||||
* @see #setConfigureListeners(boolean)
|
||||
*/
|
||||
public boolean configureListeners()
|
||||
|
@ -958,7 +1035,8 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
/**
|
||||
* @param autoConfigure whether the listeners are configured by the destination or elsewhere
|
||||
* @param autoConfigure
|
||||
* whether the listeners are configured by the destination or elsewhere
|
||||
*/
|
||||
public void setConfigureListeners(boolean autoConfigure)
|
||||
{
|
||||
|
@ -981,7 +1059,7 @@ public class HttpExchange
|
|||
HttpClient httpClient = destination.getHttpClient();
|
||||
long timeout = getTimeout();
|
||||
if (timeout > 0)
|
||||
httpClient.schedule(_timeoutTask, timeout);
|
||||
httpClient.schedule(_timeoutTask,timeout);
|
||||
else
|
||||
httpClient.schedule(_timeoutTask);
|
||||
}
|
||||
|
@ -1045,7 +1123,7 @@ public class HttpExchange
|
|||
}
|
||||
finally
|
||||
{
|
||||
synchronized(HttpExchange.this)
|
||||
synchronized (HttpExchange.this)
|
||||
{
|
||||
_onRequestCompleteDone = true;
|
||||
// Member _onDone may already be true, for example
|
||||
|
@ -1066,7 +1144,7 @@ public class HttpExchange
|
|||
}
|
||||
finally
|
||||
{
|
||||
synchronized(HttpExchange.this)
|
||||
synchronized (HttpExchange.this)
|
||||
{
|
||||
_onResponseCompleteDone = true;
|
||||
// Member _onDone may already be true, for example
|
||||
|
@ -1101,7 +1179,7 @@ public class HttpExchange
|
|||
|
||||
public void onRetry()
|
||||
{
|
||||
HttpExchange.this.setRetryStatus( true );
|
||||
HttpExchange.this.setRetryStatus(true);
|
||||
try
|
||||
{
|
||||
HttpExchange.this.onRetry();
|
||||
|
|
|
@ -110,25 +110,49 @@ public class RedirectListener extends HttpEventListenerWrapper
|
|||
if (_location != null)
|
||||
{
|
||||
if (_location.indexOf("://")>0)
|
||||
{
|
||||
_exchange.setURL(_location);
|
||||
}
|
||||
else
|
||||
{
|
||||
_exchange.setRequestURI(_location);
|
||||
}
|
||||
|
||||
// destination may have changed
|
||||
HttpDestination destination=_destination.getHttpClient().getDestination(_exchange.getAddress(),HttpSchemes.HTTPS.equals(String.valueOf(_exchange.getScheme())));
|
||||
|
||||
boolean isHttps = HttpSchemes.HTTPS.equals(String.valueOf(_exchange.getScheme()));
|
||||
HttpDestination destination=_destination.getHttpClient().getDestination(_exchange.getAddress(),isHttps);
|
||||
|
||||
if (_destination==destination)
|
||||
{
|
||||
_destination.resend(_exchange);
|
||||
}
|
||||
else
|
||||
{
|
||||
// unwrap to find ultimate listener.
|
||||
HttpEventListener listener=this;
|
||||
while(listener instanceof HttpEventListenerWrapper)
|
||||
{
|
||||
listener=((HttpEventListenerWrapper)listener).getEventListener();
|
||||
}
|
||||
|
||||
//reset the listener
|
||||
_exchange.getEventListener().onRetry();
|
||||
_exchange.reset();
|
||||
_exchange.setEventListener(listener);
|
||||
|
||||
// Set the new Host header
|
||||
Address address = _exchange.getAddress();
|
||||
int port = address.getPort();
|
||||
StringBuilder hostHeader = new StringBuilder( 64 );
|
||||
hostHeader.append( address.getHost() );
|
||||
if( !( ( port == 80 && !isHttps ) || ( port == 443 && isHttps ) ) )
|
||||
{
|
||||
hostHeader.append( ':' );
|
||||
hostHeader.append( port );
|
||||
}
|
||||
|
||||
_exchange.setRequestHeader( HttpHeaders.HOST, hostHeader.toString() );
|
||||
|
||||
destination.send(_exchange);
|
||||
}
|
||||
|
||||
|
@ -156,5 +180,28 @@ public class RedirectListener extends HttpEventListenerWrapper
|
|||
|
||||
super.onRetry();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate failed connection
|
||||
*/
|
||||
@Override
|
||||
public void onConnectionFailed( Throwable ex )
|
||||
{
|
||||
setDelegatingRequests(true);
|
||||
setDelegatingResponses(true);
|
||||
|
||||
super.onConnectionFailed( ex );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate onException
|
||||
*/
|
||||
@Override
|
||||
public void onException( Throwable ex )
|
||||
{
|
||||
setDelegatingRequests(true);
|
||||
setDelegatingResponses(true);
|
||||
|
||||
super.onException( ex );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,10 +15,13 @@ package org.eclipse.jetty.client;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.channels.UnresolvedAddressException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
@ -48,7 +51,6 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
private final HttpClient _httpClient;
|
||||
private final Manager _selectorManager=new Manager();
|
||||
private final Map<SocketChannel, Timeout.Task> _connectingChannels = new ConcurrentHashMap<SocketChannel, Timeout.Task>();
|
||||
private SSLContext _sslContext;
|
||||
private Buffers _sslBuffers;
|
||||
|
||||
/**
|
||||
|
@ -89,31 +91,34 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
public void startConnection( HttpDestination destination )
|
||||
throws IOException
|
||||
{
|
||||
SocketChannel channel = null;
|
||||
try
|
||||
{
|
||||
SocketChannel channel = SocketChannel.open();
|
||||
channel = SocketChannel.open();
|
||||
Address address = destination.isProxied() ? destination.getProxy() : destination.getAddress();
|
||||
channel.socket().setTcpNoDelay(true);
|
||||
|
||||
if (_httpClient.isConnectBlocking())
|
||||
{
|
||||
channel.socket().connect(address.toSocketAddress(), _httpClient.getConnectTimeout());
|
||||
channel.configureBlocking(false);
|
||||
_selectorManager.register( channel, destination );
|
||||
channel.socket().connect(address.toSocketAddress(), _httpClient.getConnectTimeout());
|
||||
channel.configureBlocking(false);
|
||||
_selectorManager.register( channel, destination );
|
||||
}
|
||||
else
|
||||
{
|
||||
channel.configureBlocking( false );
|
||||
channel.connect(address.toSocketAddress());
|
||||
_selectorManager.register( channel, destination );
|
||||
ConnectTimeout connectTimeout = new ConnectTimeout(channel, destination);
|
||||
channel.configureBlocking(false);
|
||||
channel.connect(address.toSocketAddress());
|
||||
_selectorManager.register(channel,destination);
|
||||
ConnectTimeout connectTimeout = new ConnectTimeout(channel,destination);
|
||||
_httpClient.schedule(connectTimeout,_httpClient.getConnectTimeout());
|
||||
_connectingChannels.put(channel, connectTimeout);
|
||||
_connectingChannels.put(channel,connectTimeout);
|
||||
}
|
||||
|
||||
}
|
||||
catch(IOException ex)
|
||||
{
|
||||
if (channel != null)
|
||||
channel.close();
|
||||
destination.onConnectionFailed(ex);
|
||||
}
|
||||
}
|
||||
|
@ -194,19 +199,16 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
private synchronized SSLEngine newSslEngine(SocketChannel channel) throws IOException
|
||||
{
|
||||
SslContextFactory sslContextFactory = _httpClient.getSslContextFactory();
|
||||
if (_sslContext == null)
|
||||
_sslContext = sslContextFactory.getSslContext();
|
||||
|
||||
SSLEngine sslEngine;
|
||||
if (channel != null && sslContextFactory.isSessionCachingEnabled())
|
||||
if (channel != null)
|
||||
{
|
||||
String peerHost = channel.socket().getInetAddress().getHostAddress();
|
||||
int peerPort = channel.socket().getPort();
|
||||
sslEngine = _sslContext.createSSLEngine(peerHost, peerPort);
|
||||
sslEngine = sslContextFactory.newSslEngine(peerHost, peerPort);
|
||||
}
|
||||
else
|
||||
{
|
||||
sslEngine = _sslContext.createSSLEngine();
|
||||
sslEngine = sslContextFactory.newSslEngine();
|
||||
}
|
||||
sslEngine.setUseClientMode(true);
|
||||
sslEngine.beginHandshake();
|
||||
|
|
|
@ -45,18 +45,9 @@ class SocketConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
|
||||
public void startConnection(final HttpDestination destination) throws IOException
|
||||
{
|
||||
Socket socket=null;
|
||||
|
||||
if ( destination.isSecure() )
|
||||
{
|
||||
SSLContext sslContext = _httpClient.getSSLContext();
|
||||
socket = sslContext.getSocketFactory().createSocket();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.debug("Using Regular Socket");
|
||||
socket = SocketFactory.getDefault().createSocket();
|
||||
}
|
||||
Socket socket= destination.isSecure()
|
||||
?_httpClient.getSslContextFactory().newSslSocket()
|
||||
:SocketFactory.getDefault().createSocket();
|
||||
|
||||
socket.setSoTimeout(0);
|
||||
socket.setTcpNoDelay(true);
|
||||
|
@ -97,6 +88,17 @@ class SocketConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
destination.onException(e);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
destination.returnConnection(connection,true);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
@ -25,6 +25,9 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
|
@ -37,7 +40,7 @@ public abstract class AbstractConnectionTest
|
|||
// httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET);
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testServerClosedConnection() throws Exception
|
||||
{
|
||||
|
@ -57,6 +60,19 @@ public abstract class AbstractConnectionTest
|
|||
httpClient.send(exchange);
|
||||
|
||||
Socket remote = serverSocket.accept();
|
||||
|
||||
// HttpClient.send() above is async, so if we write the response immediately
|
||||
// there is a chance that it arrives before the request is being sent, so we
|
||||
// read the request before sending the response to avoid the race
|
||||
InputStream input = remote.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
if (line.length() == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
OutputStream output = remote.getOutputStream();
|
||||
output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8"));
|
||||
output.write("Content-Length: 0\r\n".getBytes("UTF-8"));
|
||||
|
@ -80,6 +96,15 @@ public abstract class AbstractConnectionTest
|
|||
httpClient.send(exchange);
|
||||
|
||||
remote = serverSocket.accept();
|
||||
|
||||
input = remote.getInputStream();
|
||||
reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
if (line.length() == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
output = remote.getOutputStream();
|
||||
output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8"));
|
||||
output.write("Content-Length: 0\r\n".getBytes("UTF-8"));
|
||||
|
@ -94,6 +119,105 @@ public abstract class AbstractConnectionTest
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerClosedIncomplete() throws Exception
|
||||
{
|
||||
ServerSocket serverSocket = new ServerSocket();
|
||||
serverSocket.bind(null);
|
||||
int port=serverSocket.getLocalPort();
|
||||
|
||||
HttpClient httpClient = newHttpClient();
|
||||
httpClient.setMaxConnectionsPerAddress(1);
|
||||
httpClient.start();
|
||||
try
|
||||
{
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
HttpExchange exchange = new ConnectionExchange(latch);
|
||||
exchange.setAddress(new Address("localhost", port));
|
||||
exchange.setRequestURI("/");
|
||||
httpClient.send(exchange);
|
||||
|
||||
Socket remote = serverSocket.accept();
|
||||
|
||||
// HttpClient.send() above is async, so if we write the response immediately
|
||||
// there is a chance that it arrives before the request is being sent, so we
|
||||
// read the request before sending the response to avoid the race
|
||||
InputStream input = remote.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
if (line.length() == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
OutputStream output = remote.getOutputStream();
|
||||
output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8"));
|
||||
output.write("Content-Length: 10\r\n".getBytes("UTF-8"));
|
||||
output.write("\r\n".getBytes("UTF-8"));
|
||||
output.flush();
|
||||
|
||||
remote.close();
|
||||
|
||||
assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.waitForDone());
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerHalfClosedIncomplete() throws Exception
|
||||
{
|
||||
ServerSocket serverSocket = new ServerSocket();
|
||||
serverSocket.bind(null);
|
||||
int port=serverSocket.getLocalPort();
|
||||
|
||||
HttpClient httpClient = newHttpClient();
|
||||
httpClient.setIdleTimeout(10000);
|
||||
httpClient.setMaxConnectionsPerAddress(1);
|
||||
httpClient.start();
|
||||
try
|
||||
{
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
HttpExchange exchange = new ConnectionExchange(latch);
|
||||
exchange.setAddress(new Address("localhost", port));
|
||||
exchange.setRequestURI("/");
|
||||
httpClient.send(exchange);
|
||||
|
||||
Socket remote = serverSocket.accept();
|
||||
|
||||
// HttpClient.send() above is async, so if we write the response immediately
|
||||
// there is a chance that it arrives before the request is being sent, so we
|
||||
// read the request before sending the response to avoid the race
|
||||
InputStream input = remote.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
if (line.length() == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
OutputStream output = remote.getOutputStream();
|
||||
output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8"));
|
||||
output.write("Content-Length: 10\r\n".getBytes("UTF-8"));
|
||||
output.write("\r\n".getBytes("UTF-8"));
|
||||
output.flush();
|
||||
|
||||
remote.shutdownOutput();
|
||||
|
||||
assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.waitForDone());
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectionFailed() throws Exception
|
||||
{
|
||||
|
@ -262,16 +386,16 @@ public abstract class AbstractConnectionTest
|
|||
}
|
||||
}
|
||||
|
||||
private class ConnectionExchange extends HttpExchange
|
||||
protected class ConnectionExchange extends HttpExchange
|
||||
{
|
||||
private final CountDownLatch latch;
|
||||
|
||||
private ConnectionExchange()
|
||||
protected ConnectionExchange()
|
||||
{
|
||||
this.latch = null;
|
||||
}
|
||||
|
||||
private ConnectionExchange(CountDownLatch latch)
|
||||
protected ConnectionExchange(CountDownLatch latch)
|
||||
{
|
||||
this.latch = latch;
|
||||
}
|
||||
|
|
|
@ -14,9 +14,7 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.SocketTimeoutException;
|
||||
|
@ -34,7 +32,6 @@ import org.eclipse.jetty.server.Server;
|
|||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.log.StdErrLog;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
@ -45,8 +42,6 @@ import org.junit.Test;
|
|||
*/
|
||||
public abstract class AbstractHttpExchangeCancelTest
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AbstractHttpExchangeCancelTest.class);
|
||||
|
||||
private Server server;
|
||||
private Connector connector;
|
||||
|
||||
|
|
|
@ -22,4 +22,12 @@ public class AsyncSelectConnectionTest extends AbstractConnectionTest
|
|||
httpClient.setConnectBlocking(false);
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testServerHalfClosedIncomplete() throws Exception
|
||||
{
|
||||
super.testServerHalfClosedIncomplete();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -13,19 +13,23 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import org.eclipse.jetty.client.helperClasses.AsyncSslServerAndClientCreator;
|
||||
import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class AsyncSslHttpExchangeTest extends SslHttpExchangeTest
|
||||
{
|
||||
@Override
|
||||
public void setUp() throws Exception
|
||||
private static ServerAndClientCreator serverAndClientCreator = new AsyncSslServerAndClientCreator();
|
||||
|
||||
@Before
|
||||
public void setUpOnce() throws Exception
|
||||
{
|
||||
_scheme="https";
|
||||
startServer();
|
||||
_httpClient=new HttpClient();
|
||||
_httpClient.setIdleTimeout(2000);
|
||||
_httpClient.setTimeout(2500);
|
||||
_httpClient.setConnectTimeout(1000);
|
||||
_httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
_httpClient.setMaxConnectionsPerAddress(2);
|
||||
_httpClient.start();
|
||||
_server = serverAndClientCreator.createServer();
|
||||
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
|
||||
_port = _server.getConnectors()[0].getLocalPort();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,28 +13,23 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.client.helperClasses.ExternalKeyStoreAsyncSslServerAndClientCreator;
|
||||
import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ExternalKeyStoreAsyncSslHttpExchangeTest extends SslHttpExchangeTest
|
||||
{
|
||||
@Override
|
||||
public void setUp() throws Exception
|
||||
private static ServerAndClientCreator serverAndClientCreator = new ExternalKeyStoreAsyncSslServerAndClientCreator();
|
||||
|
||||
@Before
|
||||
public void setUpOnce() throws Exception
|
||||
{
|
||||
_scheme = "https";
|
||||
startServer();
|
||||
_httpClient = new HttpClient();
|
||||
_httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
_httpClient.setMaxConnectionsPerAddress(2);
|
||||
|
||||
String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
|
||||
|
||||
_httpClient.setKeyStoreInputStream(new FileInputStream(keystore));
|
||||
_httpClient.setKeyStorePassword("storepwd");
|
||||
_httpClient.setKeyManagerPassword("keypwd");
|
||||
_httpClient.start();
|
||||
_scheme="https";
|
||||
_server = serverAndClientCreator.createServer();
|
||||
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
|
||||
_port = _server.getConnectors()[0].getLocalPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.junit.Assert;
|
||||
|
||||
public final class HttpAsserts
|
||||
{
|
||||
public static void assertContainsHeaderKey(String expectedKey, HttpFields headers)
|
||||
{
|
||||
if (headers.containsKey(expectedKey))
|
||||
{
|
||||
return;
|
||||
}
|
||||
List<String> names = Collections.list(headers.getFieldNames());
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Missing expected header key [").append(expectedKey);
|
||||
err.append("] (of ").append(names.size()).append(" header fields)");
|
||||
for (int i = 0; i < names.size(); i++)
|
||||
{
|
||||
String value = headers.getStringField(names.get(i));
|
||||
err.append("\n").append(i).append("] ").append(names.get(i));
|
||||
err.append(": ").append(value);
|
||||
}
|
||||
Assert.fail(err.toString());
|
||||
}
|
||||
}
|
|
@ -13,14 +13,9 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.matchers.JUnitMatchers.containsString;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.matchers.JUnitMatchers.*;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
@ -30,13 +25,10 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.client.helperClasses.HttpServerAndClientCreator;
|
||||
import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
|
||||
import org.eclipse.jetty.client.security.ProxyAuthorization;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeaders;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
|
@ -44,17 +36,13 @@ import org.eclipse.jetty.io.ByteArrayBuffer;
|
|||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.io.nio.DirectNIOBuffer;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.toolchain.test.Stress;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -63,37 +51,44 @@ import org.junit.Test;
|
|||
*/
|
||||
public class HttpExchangeTest
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpExchangeTest.class);
|
||||
|
||||
protected int _maxConnectionsPerAddress = 2;
|
||||
protected String _scheme = "http";
|
||||
protected Server _server;
|
||||
protected int _port;
|
||||
protected HttpClient _httpClient;
|
||||
protected Connector _connector;
|
||||
protected AtomicInteger _count = new AtomicInteger();
|
||||
final static boolean verbose=false;
|
||||
protected static int _maxConnectionsPerAddress = 2;
|
||||
protected static String _scheme = "http";
|
||||
protected static Server _server;
|
||||
protected static int _port;
|
||||
protected static HttpClient _httpClient;
|
||||
protected static AtomicInteger _count = new AtomicInteger();
|
||||
protected static ServerAndClientCreator serverAndClientCreator = new HttpServerAndClientCreator();
|
||||
|
||||
protected static URI getBaseURI()
|
||||
{
|
||||
return URI.create(_scheme + "://localhost:" + _port + "/");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
// TODO work out why BeforeClass does not work here?
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
public void setUpOnce() throws Exception
|
||||
{
|
||||
startServer();
|
||||
_httpClient=new HttpClient();
|
||||
_httpClient.setIdleTimeout(3000);
|
||||
_httpClient.setTimeout(3500);
|
||||
_httpClient.setConnectTimeout(2000);
|
||||
_httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
_httpClient.setMaxConnectionsPerAddress(_maxConnectionsPerAddress);
|
||||
_httpClient.start();
|
||||
_scheme = "http";
|
||||
_server = serverAndClientCreator.createServer();
|
||||
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
|
||||
_port = _server.getConnectors()[0].getLocalPort();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@After
|
||||
public void tearDown() throws Exception
|
||||
public void tearDownOnce() throws Exception
|
||||
{
|
||||
_httpClient.stop();
|
||||
Thread.sleep(500);
|
||||
stopServer();
|
||||
long startTime = System.currentTimeMillis();
|
||||
while (!_httpClient.getState().equals(AbstractLifeCycle.STOPPED))
|
||||
{
|
||||
if (System.currentTimeMillis() - startTime > 1000)
|
||||
break;
|
||||
Thread.sleep(5);
|
||||
}
|
||||
_server.stop();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -110,7 +105,9 @@ public class HttpExchangeTest
|
|||
{
|
||||
sender(1,false);
|
||||
sender(1,true);
|
||||
|
||||
sender(10,false);
|
||||
sender(10,true);
|
||||
|
||||
if (Stress.isEnabled())
|
||||
{
|
||||
sender(100,false);
|
||||
|
@ -118,67 +115,72 @@ public class HttpExchangeTest
|
|||
sender(10000,false);
|
||||
sender(10000,true);
|
||||
}
|
||||
else
|
||||
{
|
||||
sender(10,false);
|
||||
sender(10,true);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Test sending data through the exchange.
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void sender(final int nb,final boolean close) throws Exception
|
||||
public void sender(final int nb, final boolean close) throws Exception
|
||||
{
|
||||
_count.set(0);
|
||||
final CountDownLatch complete=new CountDownLatch(nb);
|
||||
final CountDownLatch latch=new CountDownLatch(nb);
|
||||
final CountDownLatch complete = new CountDownLatch(nb);
|
||||
final AtomicInteger allcontent = new AtomicInteger(nb);
|
||||
HttpExchange[] httpExchange = new HttpExchange[nb];
|
||||
long start=System.currentTimeMillis();
|
||||
for (int i=0; i<nb; i++)
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i = 0; i < nb; i++)
|
||||
{
|
||||
final int n=i;
|
||||
final int n = i;
|
||||
|
||||
httpExchange[n]=new HttpExchange()
|
||||
httpExchange[n] = new HttpExchange()
|
||||
{
|
||||
String result="pending";
|
||||
int len=0;
|
||||
String result = "pending";
|
||||
int len = 0;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onRequestCommitted()
|
||||
{
|
||||
result="committed";
|
||||
if (verbose)
|
||||
System.err.println("[ ");
|
||||
result = "committed";
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onRequestComplete() throws IOException
|
||||
{
|
||||
result="sent";
|
||||
if (verbose)
|
||||
System.err.println("[ ==");
|
||||
result = "sent";
|
||||
}
|
||||
|
||||
@Override
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void onResponseStatus(Buffer version, int status, Buffer reason)
|
||||
{
|
||||
result="status";
|
||||
if (verbose)
|
||||
System.err.println("] "+version+" "+status+" "+reason);
|
||||
result = "status";
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onResponseHeader(Buffer name, Buffer value)
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] "+name+": "+value);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onResponseHeaderComplete() throws IOException
|
||||
{
|
||||
result="content";
|
||||
if (verbose)
|
||||
System.err.println("] -");
|
||||
result = "content";
|
||||
super.onResponseHeaderComplete();
|
||||
}
|
||||
|
||||
|
@ -186,20 +188,22 @@ public class HttpExchangeTest
|
|||
@Override
|
||||
protected void onResponseContent(Buffer content)
|
||||
{
|
||||
len+=content.length();
|
||||
len += content.length();
|
||||
if (verbose)
|
||||
System.err.println("] "+content.length()+" -> "+len);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onResponseComplete()
|
||||
{
|
||||
result="complete";
|
||||
if (len==2009)
|
||||
latch.countDown();
|
||||
if (verbose)
|
||||
System.err.println("] == "+len+" "+complete.getCount()+"/"+nb);
|
||||
result = "complete";
|
||||
if (len == 2009)
|
||||
allcontent.decrementAndGet();
|
||||
else
|
||||
{
|
||||
System.err.println(n+" ONLY "+len);
|
||||
}
|
||||
System.err.println(n + " ONLY " + len+ "/2009");
|
||||
complete.countDown();
|
||||
}
|
||||
|
||||
|
@ -207,9 +211,11 @@ public class HttpExchangeTest
|
|||
@Override
|
||||
protected void onConnectionFailed(Throwable ex)
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] "+ex);
|
||||
complete.countDown();
|
||||
result="failed";
|
||||
System.err.println(n+" FAILED "+ex);
|
||||
result = "failed";
|
||||
System.err.println(n + " FAILED " + ex);
|
||||
super.onConnectionFailed(ex);
|
||||
}
|
||||
|
||||
|
@ -217,9 +223,11 @@ public class HttpExchangeTest
|
|||
@Override
|
||||
protected void onException(Throwable ex)
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] "+ex);
|
||||
complete.countDown();
|
||||
result="excepted";
|
||||
System.err.println(n+" EXCEPTED "+ex);
|
||||
result = "excepted";
|
||||
System.err.println(n + " EXCEPTED " + ex);
|
||||
super.onException(ex);
|
||||
}
|
||||
|
||||
|
@ -227,9 +235,11 @@ public class HttpExchangeTest
|
|||
@Override
|
||||
protected void onExpire()
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] expired");
|
||||
complete.countDown();
|
||||
result="expired";
|
||||
System.err.println(n+" EXPIRED "+len);
|
||||
result = "expired";
|
||||
System.err.println(n + " EXPIRED " + len);
|
||||
super.onExpire();
|
||||
}
|
||||
|
||||
|
@ -237,29 +247,24 @@ public class HttpExchangeTest
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return n+" "+result+" "+len;
|
||||
return n+"/"+result+"/"+len+"/"+super.toString();
|
||||
}
|
||||
};
|
||||
|
||||
httpExchange[n].setURL(_scheme+"://localhost:"+_port+"/"+n);
|
||||
httpExchange[n].setURI(getBaseURI().resolve("/" + n));
|
||||
httpExchange[n].addRequestHeader("arbitrary","value");
|
||||
if (close)
|
||||
httpExchange[n].setRequestHeader("Connection","close");
|
||||
|
||||
_httpClient.send(httpExchange[n]);
|
||||
}
|
||||
|
||||
assertTrue(complete.await(45,TimeUnit.SECONDS));
|
||||
|
||||
long elapsed=System.currentTimeMillis()-start;
|
||||
|
||||
// make windows-friendly ... System.currentTimeMillis() on windows is dope!
|
||||
/*
|
||||
if(elapsed>0)
|
||||
System.err.println(nb+"/"+_count+" c="+close+" rate="+(nb*1000/elapsed));
|
||||
*/
|
||||
if (!complete.await(2,TimeUnit.SECONDS))
|
||||
System.err.println(_httpClient.dump());
|
||||
|
||||
assertEquals("nb="+nb+" close="+close,0,latch.getCount());
|
||||
assertTrue(complete.await(20,TimeUnit.SECONDS));
|
||||
|
||||
assertEquals("nb="+nb+" close="+close,0,allcontent.get());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -269,7 +274,7 @@ public class HttpExchangeTest
|
|||
for (int i=0;i<20;i++)
|
||||
{
|
||||
ContentExchange httpExchange=new ContentExchange();
|
||||
httpExchange.setURI(new URI(_scheme, null, "localhost", _port, null, null, null));
|
||||
httpExchange.setURI(getBaseURI());
|
||||
httpExchange.setMethod(HttpMethods.POST);
|
||||
httpExchange.setRequestContent(new ByteArrayBuffer("<hello />"));
|
||||
_httpClient.send(httpExchange);
|
||||
|
@ -288,12 +293,14 @@ public class HttpExchangeTest
|
|||
for (int i=0;i<10;i++)
|
||||
{
|
||||
ContentExchange httpExchange=new ContentExchange();
|
||||
httpExchange.setURI(new URI(_scheme, null, "localhost", _port, "/", "i="+i, null));
|
||||
URI uri = getBaseURI().resolve("?i=" + i);
|
||||
httpExchange.setURI(uri);
|
||||
httpExchange.setMethod(HttpMethods.GET);
|
||||
_httpClient.send(httpExchange);
|
||||
int status = httpExchange.waitForDone();
|
||||
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
|
||||
String result=httpExchange.getResponseContent();
|
||||
assertNotNull("Should have received response content", result);
|
||||
assertEquals("i="+i,0,result.indexOf("<hello>"));
|
||||
assertEquals("i="+i,result.length()-10,result.indexOf("</hello>"));
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
|
@ -308,17 +315,16 @@ public class HttpExchangeTest
|
|||
for (int i=0;i<10;i++)
|
||||
{
|
||||
ContentExchange httpExchange=new ContentExchange();
|
||||
httpExchange.setURL(_scheme+"://localhost:"+_port+"/?i="+i);
|
||||
URI uri = getBaseURI().resolve("?i=" + i);
|
||||
httpExchange.setURI(uri);
|
||||
httpExchange.setMethod(HttpMethods.GET);
|
||||
_httpClient.send(httpExchange);
|
||||
int status = httpExchange.waitForDone();
|
||||
|
||||
assertNotNull(httpExchange.getLocalAddress());
|
||||
|
||||
//System.out.println("Local Address: " + httpExchange.getLocalAddress());
|
||||
|
||||
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
|
||||
String result=httpExchange.getResponseContent();
|
||||
assertNotNull("Should have received response content", result);
|
||||
assertEquals("i="+i,0,result.indexOf("<hello>"));
|
||||
assertEquals("i="+i,result.length()-10,result.indexOf("</hello>"));
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
|
@ -355,7 +361,7 @@ public class HttpExchangeTest
|
|||
throwable.set(x);
|
||||
}
|
||||
};
|
||||
httpExchange.setURL(_scheme+"://localhost:"+_port+"/");
|
||||
httpExchange.setURI(getBaseURI());
|
||||
httpExchange.setMethod("SLEEP");
|
||||
_httpClient.send(httpExchange);
|
||||
new Thread()
|
||||
|
@ -374,6 +380,7 @@ public class HttpExchangeTest
|
|||
System.err.println(throwable.get());
|
||||
assertTrue(throwable.get().toString().indexOf("close")>=0);
|
||||
assertEquals(HttpExchange.STATUS_EXCEPTED, status);
|
||||
_httpClient.start();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -381,7 +388,54 @@ public class HttpExchangeTest
|
|||
public void testBigPostWithContentExchange() throws Exception
|
||||
{
|
||||
int size =32;
|
||||
ContentExchange httpExchange=new ContentExchange();
|
||||
ContentExchange httpExchange=new ContentExchange()
|
||||
{
|
||||
int total;
|
||||
|
||||
@Override
|
||||
protected synchronized void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] "+version+" "+status+" "+reason);
|
||||
super.onResponseStatus(version,status,reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void onResponseHeader(Buffer name, Buffer value) throws IOException
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] "+name+": "+value);
|
||||
super.onResponseHeader(name,value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void onResponseContent(Buffer content) throws IOException
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
total+=content.length();
|
||||
System.err.println("] "+content.length()+" -> "+total);
|
||||
}
|
||||
super.onResponseContent(content);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRequestComplete() throws IOException
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] ==");
|
||||
super.onRequestComplete();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseHeaderComplete() throws IOException
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] --");
|
||||
super.onResponseHeaderComplete();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Buffer babuf = new ByteArrayBuffer(size*36*1024);
|
||||
Buffer niobuf = new DirectNIOBuffer(size*36*1024);
|
||||
|
@ -394,28 +448,27 @@ public class HttpExchangeTest
|
|||
niobuf.put(bytes);
|
||||
}
|
||||
|
||||
httpExchange.setURL(_scheme+"://localhost:"+_port+"/");
|
||||
httpExchange.setURI(getBaseURI());
|
||||
httpExchange.setMethod(HttpMethods.POST);
|
||||
httpExchange.setRequestContentType("application/data");
|
||||
httpExchange.setRequestContent(babuf);
|
||||
|
||||
_httpClient.send(httpExchange);
|
||||
int status = httpExchange.waitForDone();
|
||||
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED,status);
|
||||
String result=httpExchange.getResponseContent();
|
||||
assertEquals(babuf.length(),result.length());
|
||||
|
||||
httpExchange.reset();
|
||||
httpExchange.setURL(_scheme+"://localhost:"+_port+"/");
|
||||
httpExchange.setURI(getBaseURI());
|
||||
httpExchange.setMethod(HttpMethods.POST);
|
||||
httpExchange.setRequestContentType("application/data");
|
||||
httpExchange.setRequestContent(niobuf);
|
||||
_httpClient.send(httpExchange);
|
||||
status = httpExchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
result=httpExchange.getResponseContent();
|
||||
assertEquals(niobuf.length(),result.length());
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -426,7 +479,7 @@ public class HttpExchangeTest
|
|||
{
|
||||
|
||||
};
|
||||
httpExchange.setURL(_scheme+"://localhost:"+_port);
|
||||
httpExchange.setURI(getBaseURI());
|
||||
httpExchange.setMethod(HttpMethods.POST);
|
||||
|
||||
final String data="012345678901234567890123456789012345678901234567890123456789";
|
||||
|
@ -447,7 +500,7 @@ public class HttpExchangeTest
|
|||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException
|
||||
{
|
||||
if (_index>=data.length())
|
||||
if (_index >= data.length())
|
||||
return -1;
|
||||
|
||||
try
|
||||
|
@ -458,28 +511,28 @@ public class HttpExchangeTest
|
|||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
int l=0;
|
||||
|
||||
while (l<5 && _index<data.length() && l<len)
|
||||
b[off+l++]=(byte)data.charAt(_index++);
|
||||
int l = 0;
|
||||
|
||||
while (l < 5 && _index < data.length() && l < len)
|
||||
b[off + l++] = (byte)data.charAt(_index++);
|
||||
return l;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
httpExchange.setRequestContentSource(content);
|
||||
//httpExchange.setRequestContent(new ByteArrayBuffer(data));
|
||||
// httpExchange.setRequestContent(new ByteArrayBuffer(data));
|
||||
|
||||
_httpClient.send(httpExchange);
|
||||
|
||||
int status = httpExchange.waitForDone();
|
||||
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
|
||||
String result=httpExchange.getResponseContent();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
// httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
|
||||
String result = httpExchange.getResponseContent();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED,status);
|
||||
assertEquals(data,result);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Test
|
||||
public void testProxy() throws Exception
|
||||
|
@ -499,6 +552,7 @@ public class HttpExchangeTest
|
|||
int status = httpExchange.waitForDone();
|
||||
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
|
||||
String result=httpExchange.getResponseContent();
|
||||
assertNotNull("Should have received response content", result);
|
||||
result=result.trim();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
assertTrue(result.startsWith("Proxy request: http://jetty.eclipse.org:8080/jetty-6"));
|
||||
|
@ -515,36 +569,42 @@ public class HttpExchangeTest
|
|||
@Test
|
||||
public void testReserveConnections () throws Exception
|
||||
{
|
||||
final HttpDestination destination = _httpClient.getDestination (new Address("localhost", _port), _scheme.equalsIgnoreCase("https"));
|
||||
final org.eclipse.jetty.client.HttpConnection[] connections = new org.eclipse.jetty.client.HttpConnection[_maxConnectionsPerAddress];
|
||||
for (int i=0; i < _maxConnectionsPerAddress; i++)
|
||||
{
|
||||
connections[i] = destination.reserveConnection(200);
|
||||
assertNotNull(connections[i]);
|
||||
HttpExchange ex = new ContentExchange();
|
||||
ex.setURL(_scheme+"://localhost:"+_port+"/?i="+i);
|
||||
ex.setMethod(HttpMethods.GET);
|
||||
connections[i].send(ex);
|
||||
}
|
||||
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
|
||||
final HttpDestination destination = _httpClient.getDestination(new Address("localhost",_port),_scheme.equalsIgnoreCase("https"));
|
||||
final org.eclipse.jetty.client.HttpConnection[] connections = new org.eclipse.jetty.client.HttpConnection[_maxConnectionsPerAddress];
|
||||
for (int i = 0; i < _maxConnectionsPerAddress; i++)
|
||||
{
|
||||
connections[i] = destination.reserveConnection(200);
|
||||
assertNotNull(connections[i]);
|
||||
HttpExchange ex = new ContentExchange();
|
||||
ex.setURI(getBaseURI().resolve("?i=" + i));
|
||||
ex.setMethod(HttpMethods.GET);
|
||||
connections[i].send(ex);
|
||||
}
|
||||
|
||||
//try to get a connection, and only wait 500ms, as we have
|
||||
//already reserved the max, should return null
|
||||
Connection c = destination.reserveConnection(500);
|
||||
assertNull(c);
|
||||
// try to get a connection, and only wait 500ms, as we have
|
||||
// already reserved the max, should return null
|
||||
Connection c = destination.reserveConnection(500);
|
||||
assertNull(c);
|
||||
|
||||
//unreserve first connection
|
||||
destination.returnConnection(connections[0], false);
|
||||
// unreserve first connection
|
||||
destination.returnConnection(connections[0],false);
|
||||
|
||||
//reserving one should now work
|
||||
c = destination.reserveConnection(500);
|
||||
assertNotNull(c);
|
||||
// reserving one should now work
|
||||
c = destination.reserveConnection(500);
|
||||
assertNotNull(c);
|
||||
|
||||
// release connections
|
||||
for (HttpConnection httpConnection : connections){
|
||||
destination.returnConnection(httpConnection,false);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionsWithExchange() throws Exception
|
||||
{
|
||||
ContentExchange httpExchange = new ContentExchange(true);
|
||||
httpExchange.setURL(_scheme+"://localhost:"+_port);
|
||||
httpExchange.setURL(getBaseURI().toASCIIString());
|
||||
httpExchange.setRequestURI("*");
|
||||
httpExchange.setMethod(HttpMethods.OPTIONS);
|
||||
// httpExchange.setRequestHeader("Connection","close");
|
||||
|
@ -555,8 +615,10 @@ public class HttpExchangeTest
|
|||
assertEquals(HttpStatus.OK_200,httpExchange.getResponseStatus());
|
||||
|
||||
HttpFields headers = httpExchange.getResponseFields();
|
||||
assertTrue("Response contains Allow header", headers.containsKey("Allow"));
|
||||
HttpAsserts.assertContainsHeaderKey("Content-Length", headers);
|
||||
assertEquals("Content-Length header value", 0, headers.getLongField("Content-Length"));
|
||||
|
||||
HttpAsserts.assertContainsHeaderKey("Allow",headers);
|
||||
String allow = headers.getStringField("Allow");
|
||||
String expectedMethods[] =
|
||||
{ "GET", "HEAD", "POST", "PUT", "DELETE", "MOVE", "OPTIONS", "TRACE" };
|
||||
|
@ -564,9 +626,6 @@ public class HttpExchangeTest
|
|||
{
|
||||
assertThat(allow,containsString(expectedMethod));
|
||||
}
|
||||
|
||||
assertTrue("Response contains Content-Length header", headers.containsKey("Content-Length"));
|
||||
assertEquals("Content-Length header value", 0, headers.getLongField("Content-Length"));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -574,115 +633,20 @@ public class HttpExchangeTest
|
|||
{
|
||||
try
|
||||
{
|
||||
byte[] buffer=new byte[1024];
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
while ((len=in.read(buffer))>=0)
|
||||
while ((len = in.read(buffer)) >= 0)
|
||||
{
|
||||
out.write(buffer,0,len);
|
||||
}
|
||||
}
|
||||
catch (EofException e)
|
||||
{
|
||||
System.err.println("HttpExchangeTest#copyStream: "+e);
|
||||
System.err.println("HttpExchangeTest#copyStream: " + e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void newServer() throws Exception
|
||||
{
|
||||
_server=new Server();
|
||||
_server.setGracefulShutdown(500);
|
||||
_connector=new SelectChannelConnector();
|
||||
|
||||
_connector.setMaxIdleTime(3000000);
|
||||
|
||||
_connector.setPort(0);
|
||||
_server.setConnectors(new Connector[] { _connector });
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void startServer() throws Exception
|
||||
{
|
||||
newServer();
|
||||
_server.setHandler(new AbstractHandler()
|
||||
{
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
int i=0;
|
||||
try
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.setStatus(200);
|
||||
_count.incrementAndGet();
|
||||
|
||||
if (request.getServerName().equals("jetty.eclipse.org"))
|
||||
{
|
||||
response.getOutputStream().println("Proxy request: "+request.getRequestURL());
|
||||
response.getOutputStream().println(request.getHeader(HttpHeaders.PROXY_AUTHORIZATION));
|
||||
}
|
||||
else if (request.getMethod().equalsIgnoreCase("GET"))
|
||||
{
|
||||
response.getOutputStream().println("<hello>");
|
||||
for (; i<100; i++)
|
||||
{
|
||||
response.getOutputStream().println(" <world>"+i+"</world");
|
||||
if (i%20==0)
|
||||
response.getOutputStream().flush();
|
||||
}
|
||||
response.getOutputStream().println("</hello>");
|
||||
}
|
||||
else if (request.getMethod().equalsIgnoreCase("OPTIONS"))
|
||||
{
|
||||
if ("*".equals(target))
|
||||
{
|
||||
response.setContentLength(0);
|
||||
response.setHeader("Allow","GET,HEAD,POST,PUT,DELETE,MOVE,OPTIONS,TRACE");
|
||||
}
|
||||
}
|
||||
else if (request.getMethod().equalsIgnoreCase("SLEEP"))
|
||||
{
|
||||
Thread.sleep(10000);
|
||||
}
|
||||
else
|
||||
{
|
||||
response.setContentType(request.getContentType());
|
||||
int size=request.getContentLength();
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream(size>0?size:32768);
|
||||
IO.copy(request.getInputStream(),bout);
|
||||
response.getOutputStream().write(bout.toByteArray());
|
||||
}
|
||||
}
|
||||
catch(InterruptedException e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
catch(Throwable e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw new ServletException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
}
|
||||
}
|
||||
});
|
||||
_server.start();
|
||||
_port=_connector.getLocalPort();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void stopServer() throws Exception
|
||||
{
|
||||
_server.stop();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,6 +13,16 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class SocketConnectionTest extends AbstractConnectionTest
|
||||
{
|
||||
protected HttpClient newHttpClient()
|
||||
|
@ -21,10 +31,61 @@ public class SocketConnectionTest extends AbstractConnectionTest
|
|||
httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET);
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void testServerClosedConnection()
|
||||
public void testServerClosedConnection() throws Exception
|
||||
{
|
||||
// TODO work out why this does not work
|
||||
// Differently from the SelectConnector, the SocketConnector cannot detect server closes.
|
||||
// Therefore, upon a second send, the exchange will fail.
|
||||
// Applications needs to retry it explicitly.
|
||||
|
||||
ServerSocket serverSocket = new ServerSocket();
|
||||
serverSocket.bind(null);
|
||||
int port=serverSocket.getLocalPort();
|
||||
|
||||
HttpClient httpClient = this.newHttpClient();
|
||||
httpClient.setMaxConnectionsPerAddress(1);
|
||||
httpClient.start();
|
||||
try
|
||||
{
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
HttpExchange exchange = new ConnectionExchange(latch);
|
||||
exchange.setAddress(new Address("localhost", port));
|
||||
exchange.setRequestURI("/");
|
||||
httpClient.send(exchange);
|
||||
|
||||
Socket remote = serverSocket.accept();
|
||||
|
||||
// HttpClient.send() above is async, so if we write the response immediately
|
||||
// there is a chance that it arrives before the request is being sent, so we
|
||||
// read the request before sending the response to avoid the race
|
||||
InputStream input = remote.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
if (line.length() == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
OutputStream output = remote.getOutputStream();
|
||||
output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8"));
|
||||
output.write("Content-Length: 0\r\n".getBytes("UTF-8"));
|
||||
output.write("\r\n".getBytes("UTF-8"));
|
||||
output.flush();
|
||||
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone());
|
||||
|
||||
remote.close();
|
||||
|
||||
exchange.reset();
|
||||
httpClient.send(exchange);
|
||||
|
||||
assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.waitForDone());
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,67 +13,36 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
|
||||
import org.eclipse.jetty.client.helperClasses.SslServerAndClientCreator;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ssl.SslSocketConnector;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.toolchain.test.OS;
|
||||
import org.eclipse.jetty.toolchain.test.Stress;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Functional testing for HttpExchange.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class SslHttpExchangeTest extends HttpExchangeTest
|
||||
{
|
||||
protected static ServerAndClientCreator serverAndClientCreator = new SslServerAndClientCreator();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Before
|
||||
@Override
|
||||
public void setUp() throws Exception
|
||||
public void setUpOnce() throws Exception
|
||||
{
|
||||
_scheme="https";
|
||||
startServer();
|
||||
_httpClient=new HttpClient();
|
||||
_httpClient.setIdleTimeout(2000);
|
||||
_httpClient.setTimeout(2500);
|
||||
_httpClient.setConnectTimeout(1000);
|
||||
_httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
_httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET);
|
||||
_httpClient.setMaxConnectionsPerAddress(2);
|
||||
_httpClient.start();
|
||||
_server = serverAndClientCreator.createServer();
|
||||
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
|
||||
Connector[] connectors = _server.getConnectors();
|
||||
_port = connectors[0].getLocalPort();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void newServer()
|
||||
{
|
||||
_server = new Server();
|
||||
//SslSelectChannelConnector connector = new SslSelectChannelConnector();
|
||||
SslSocketConnector connector = new SslSocketConnector();
|
||||
|
||||
String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
|
||||
|
||||
connector.setPort(0);
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStore(keystore);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
connector.setAllowRenegotiate(true);
|
||||
|
||||
_server.setConnectors(new Connector[]
|
||||
{ connector });
|
||||
_connector=connector;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void IgnoreTestOnBuggyIBM()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
|
||||
|
||||
package org.eclipse.jetty.client.helperClasses;
|
||||
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
|
||||
import org.eclipse.jetty.server.ssl.SslSocketConnector;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public abstract class AbstractSslServerAndClientCreator implements ServerAndClientCreator
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AbstractSslServerAndClientCreator.class);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Server createServer() throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
//SslSelectChannelConnector connector = new SslSelectChannelConnector();
|
||||
SslSocketConnector connector = new SslSocketConnector();
|
||||
|
||||
String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
|
||||
|
||||
connector.setPort(0);
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStore(keystore);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
connector.setAllowRenegotiate(true);
|
||||
|
||||
server.setConnectors(new Connector[]{ connector });
|
||||
server.setHandler(new GenericServerHandler());
|
||||
server.start();
|
||||
return server;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package org.eclipse.jetty.client.helperClasses;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
|
||||
public class AsyncSslServerAndClientCreator extends AbstractSslServerAndClientCreator implements ServerAndClientCreator
|
||||
{
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public HttpClient createClient(long idleTimeout, long timeout, int connectTimeout) throws Exception
|
||||
{
|
||||
HttpClient httpClient = new HttpClient();
|
||||
httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
httpClient.setMaxConnectionsPerAddress(2);
|
||||
|
||||
String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
|
||||
httpClient.setKeyStoreInputStream(new FileInputStream(keystore));
|
||||
httpClient.setKeyStorePassword("storepwd");
|
||||
httpClient.setKeyManagerPassword("keypwd");
|
||||
httpClient.start();
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package org.eclipse.jetty.client.helperClasses;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
|
||||
public class ExternalKeyStoreAsyncSslServerAndClientCreator extends AbstractSslServerAndClientCreator implements ServerAndClientCreator
|
||||
{
|
||||
|
||||
public HttpClient createClient(long idleTimeout, long timeout, int connectTimeout) throws Exception
|
||||
{
|
||||
HttpClient httpClient = new HttpClient();
|
||||
httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
httpClient.setMaxConnectionsPerAddress(2);
|
||||
|
||||
String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
|
||||
|
||||
httpClient.setKeyStoreInputStream(new FileInputStream(keystore));
|
||||
httpClient.setKeyStorePassword("storepwd");
|
||||
httpClient.setKeyManagerPassword("keypwd");
|
||||
httpClient.start();
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package org.eclipse.jetty.client.helperClasses;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpHeaders;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* Generic Server Handler used for various client tests.
|
||||
*/
|
||||
public class GenericServerHandler extends AbstractHandler
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(GenericServerHandler.class);
|
||||
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
int i = 0;
|
||||
try
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.setStatus(200);
|
||||
|
||||
if (request.getServerName().equals("jetty.eclipse.org"))
|
||||
{
|
||||
response.getOutputStream().println("Proxy request: " + request.getRequestURL());
|
||||
response.getOutputStream().println(request.getHeader(HttpHeaders.PROXY_AUTHORIZATION));
|
||||
}
|
||||
else if (request.getMethod().equalsIgnoreCase("GET"))
|
||||
{
|
||||
response.getOutputStream().println("<hello>");
|
||||
for (; i < 100; i++)
|
||||
{
|
||||
response.getOutputStream().println(" <world>" + i + "</world");
|
||||
if (i % 20 == 0)
|
||||
response.getOutputStream().flush();
|
||||
}
|
||||
response.getOutputStream().println("</hello>");
|
||||
}
|
||||
else if (request.getMethod().equalsIgnoreCase("OPTIONS"))
|
||||
{
|
||||
if ("*".equals(target))
|
||||
{
|
||||
response.setContentLength(0);
|
||||
response.setHeader("Allow","GET,HEAD,POST,PUT,DELETE,MOVE,OPTIONS,TRACE");
|
||||
}
|
||||
}
|
||||
else if (request.getMethod().equalsIgnoreCase("SLEEP"))
|
||||
{
|
||||
Thread.sleep(10000);
|
||||
}
|
||||
else
|
||||
{
|
||||
response.setContentType(request.getContentType());
|
||||
int size = request.getContentLength();
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream(size > 0?size:32768);
|
||||
IO.copy(request.getInputStream(),bout);
|
||||
response.getOutputStream().write(bout.toByteArray());
|
||||
}
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
throw new ServletException(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package org.eclipse.jetty.client.helperClasses;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
|
||||
public class HttpServerAndClientCreator implements ServerAndClientCreator
|
||||
{
|
||||
public HttpClient createClient(long idleTimeout, long timeout, int connectTimeout) throws Exception
|
||||
{
|
||||
HttpClient httpClient = new HttpClient();
|
||||
httpClient.setIdleTimeout(idleTimeout);
|
||||
httpClient.setTimeout(timeout);
|
||||
httpClient.setConnectTimeout(connectTimeout);
|
||||
httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
httpClient.setMaxConnectionsPerAddress(2);
|
||||
httpClient.start();
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
public Server createServer() throws Exception
|
||||
{
|
||||
Server _server = new Server();
|
||||
_server.setGracefulShutdown(500);
|
||||
Connector _connector = new SelectChannelConnector();
|
||||
|
||||
_connector.setMaxIdleTime(3000000);
|
||||
|
||||
_connector.setPort(0);
|
||||
_server.setConnectors(new Connector[]{ _connector });
|
||||
_server.setHandler(new GenericServerHandler());
|
||||
_server.start();
|
||||
return _server;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package org.eclipse.jetty.client.helperClasses;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
|
||||
public interface ServerAndClientCreator
|
||||
{
|
||||
Server createServer() throws Exception;
|
||||
|
||||
HttpClient createClient(long idleTimeout, long timeout, int connectTimeout) throws Exception;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package org.eclipse.jetty.client.helperClasses;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
|
||||
public class SslServerAndClientCreator extends AbstractSslServerAndClientCreator implements ServerAndClientCreator
|
||||
{
|
||||
|
||||
public HttpClient createClient(long idleTimeout, long timeout, int connectTimeout) throws Exception
|
||||
{
|
||||
HttpClient httpClient = new HttpClient();
|
||||
httpClient.setIdleTimeout(idleTimeout);
|
||||
httpClient.setTimeout(timeout);
|
||||
httpClient.setConnectTimeout(connectTimeout);
|
||||
httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET);
|
||||
httpClient.setMaxConnectionsPerAddress(2);
|
||||
httpClient.start();
|
||||
return httpClient;
|
||||
}
|
||||
}
|
|
@ -155,157 +155,6 @@
|
|||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>unpack</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-rewrite</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-ajp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>test-jetty-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jmx</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-deploy</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-plus</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-security</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-policy</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-monitor</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-overlay-deployer</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-annotations</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>config</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy</id>
|
||||
<phase>generate-resources</phase>
|
||||
|
@ -324,187 +173,6 @@
|
|||
<outputDirectory>${assembly-directory}/</outputDirectory>
|
||||
<destFileName>VERSION.txt</destFileName>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-io</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-http</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-security</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlets</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-xml</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<!-- Jetty Deploy -->
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-deploy</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jmx</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-rewrite</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-ajp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-annotations</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jndi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-policy</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-monitor</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib/monitor</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-plus</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-continuation</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>test-jetty-webapp</artifactId>
|
||||
|
@ -525,36 +193,77 @@
|
|||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
<destFileName>start.jar</destFileName>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-overlay-deployer</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-overlay-deployer</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-websocket</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-lib-deps</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeGroupIds>org.eclipse.jetty</includeGroupIds>
|
||||
<excludeArtifactIds>jetty-start,jetty-monitor,jetty-jsp-2.1</excludeArtifactIds>
|
||||
<includeTypes>jar</includeTypes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-lib-jsp-deps</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeGroupIds>org.eclipse.jetty,org.glassfish.web</includeGroupIds>
|
||||
<includeArtifactIds>jetty-jsp-2.1,jsp-impl</includeArtifactIds>
|
||||
<includeTypes>jar</includeTypes>
|
||||
<outputDirectory>${assembly-directory}/lib/jsp</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-lib-monitor-deps</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeGroupIds>org.eclipse.jetty</includeGroupIds>
|
||||
<includeArtifactIds>jetty-monitor</includeArtifactIds>
|
||||
<includeTypes>jar</includeTypes>
|
||||
<excludeTransitive>true</excludeTransitive>
|
||||
<outputDirectory>${assembly-directory}/lib/monitor</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>unpack-config-deps</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>unpack-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeGroupIds>org.eclipse.jetty</includeGroupIds>
|
||||
<classifier>config</classifier>
|
||||
<failOnMissingClassifierArtifact>false</failOnMissingClassifierArtifact>
|
||||
<outputDirectory>${assembly-directory}</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>unpack-javadoc</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>unpack-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<!-- Use already generated javadoc, don't bother regenerating again -->
|
||||
<includeGroupIds>org.eclipse.jetty.aggregate</includeGroupIds>
|
||||
<includeArtifactIds>jetty-all</includeArtifactIds>
|
||||
<includeClassifier>javadoc</includeClassifier>
|
||||
<excludeTransitive>true</excludeTransitive>
|
||||
<outputDirectory>${assembly-directory}/javadoc</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
@ -663,12 +372,12 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-overlay-deployer</artifactId>
|
||||
<artifactId>jetty-servlets</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-overlay-deployer</artifactId>
|
||||
<artifactId>jetty-monitor</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -676,5 +385,17 @@
|
|||
<artifactId>jetty-websocket</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-overlay-deployer</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-all</artifactId>
|
||||
<classifier>javadoc</classifier>
|
||||
<type>jar</type>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -483,8 +483,13 @@ public abstract class AbstractGenerator implements Generator
|
|||
{
|
||||
if (close)
|
||||
_persistent=false;
|
||||
if (!isCommitted())
|
||||
if (isCommitted())
|
||||
{
|
||||
LOG.debug("sendError on committed: {} {}",code,reason);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.debug("sendError: {} {}",code,reason);
|
||||
setResponse(code, reason);
|
||||
if (content != null)
|
||||
{
|
||||
|
|
|
@ -4,15 +4,16 @@
|
|||
// 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
|
||||
// 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.
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
|
||||
package org.eclipse.jetty.http;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
|
@ -67,7 +68,7 @@ public class HttpParser implements Parser
|
|||
private String _multiLineValue;
|
||||
private int _responseStatus; // If >0 then we are parsing a response
|
||||
private boolean _forceContentBuffer;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
protected final View _contentView=new View(); // View of the content in the buffer for {@link Input}
|
||||
protected int _state=STATE_START;
|
||||
|
@ -78,7 +79,7 @@ public class HttpParser implements Parser
|
|||
protected int _chunkLength;
|
||||
protected int _chunkPosition;
|
||||
private boolean _headResponse;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/**
|
||||
* Constructor.
|
||||
|
@ -103,7 +104,7 @@ public class HttpParser implements Parser
|
|||
/* ------------------------------------------------------------------------------- */
|
||||
/**
|
||||
* Constructor.
|
||||
* @param buffers the buffers to use
|
||||
* @param buffers the buffers to use
|
||||
* @param endp the endpoint
|
||||
* @param handler the even handler
|
||||
*/
|
||||
|
@ -134,7 +135,7 @@ public class HttpParser implements Parser
|
|||
{
|
||||
_headResponse=head;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public int getState()
|
||||
{
|
||||
|
@ -170,7 +171,7 @@ public class HttpParser implements Parser
|
|||
{
|
||||
return isState(STATE_END);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isMoreInBuffer()
|
||||
throws IOException
|
||||
|
@ -203,11 +204,11 @@ public class HttpParser implements Parser
|
|||
if (parseNext()<0)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/**
|
||||
* Parse until END state.
|
||||
* This method will parse any remaining content in the current buffer. It does not care about the
|
||||
* This method will parse any remaining content in the current buffer. It does not care about the
|
||||
* {@link #getState current state} of the parser.
|
||||
* @see #parse
|
||||
* @see #parseNext
|
||||
|
@ -216,7 +217,7 @@ public class HttpParser implements Parser
|
|||
{
|
||||
int progress = parseNext();
|
||||
int total=progress>0?1:0;
|
||||
|
||||
|
||||
// continue parsing
|
||||
while (!isComplete() && _buffer!=null && _buffer.length()>0)
|
||||
{
|
||||
|
@ -237,9 +238,9 @@ public class HttpParser implements Parser
|
|||
{
|
||||
int progress=0;
|
||||
|
||||
if (_state == STATE_END)
|
||||
if (_state == STATE_END)
|
||||
return 0;
|
||||
|
||||
|
||||
if (_buffer==null)
|
||||
{
|
||||
if (_header == null)
|
||||
|
@ -252,23 +253,33 @@ public class HttpParser implements Parser
|
|||
_tok0.setPutIndex(_tok0.getIndex());
|
||||
_tok1.setPutIndex(_tok1.getIndex());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (_state == STATE_CONTENT && _contentPosition == _contentLength)
|
||||
{
|
||||
_state=STATE_END;
|
||||
_handler.messageComplete(_contentPosition);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int length=_buffer.length();
|
||||
|
||||
|
||||
// Fill buffer if we can
|
||||
if (length == 0)
|
||||
{
|
||||
long filled=fill();
|
||||
|
||||
if (filled < 0)
|
||||
long filled=-1;
|
||||
IOException ex=null;
|
||||
try
|
||||
{
|
||||
filled=fill();
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
LOG.debug(this.toString(),e);
|
||||
ex=e;
|
||||
}
|
||||
|
||||
if (filled < 0 || _endp.isInputShutdown())
|
||||
{
|
||||
if (_headResponse && _state>STATE_END)
|
||||
{
|
||||
|
@ -284,19 +295,25 @@ public class HttpParser implements Parser
|
|||
Buffer chunk=_buffer.get(_buffer.length());
|
||||
_contentPosition += chunk.length();
|
||||
_contentView.update(chunk);
|
||||
_handler.content(chunk); // May recurse here
|
||||
_handler.content(chunk); // May recurse here
|
||||
}
|
||||
_state=STATE_END;
|
||||
_handler.messageComplete(_contentPosition);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
if (ex!=null)
|
||||
throw ex;
|
||||
|
||||
if (!isComplete() && !isIdle())
|
||||
throw new EOFException();
|
||||
|
||||
return -1;
|
||||
}
|
||||
length=_buffer.length();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// EventHandler header
|
||||
byte ch;
|
||||
byte[] array=_buffer.array();
|
||||
|
@ -308,16 +325,16 @@ public class HttpParser implements Parser
|
|||
progress++;
|
||||
last=_state;
|
||||
}
|
||||
|
||||
|
||||
ch=_buffer.get();
|
||||
|
||||
|
||||
if (_eol == HttpTokens.CARRIAGE_RETURN && ch == HttpTokens.LINE_FEED)
|
||||
{
|
||||
_eol=HttpTokens.LINE_FEED;
|
||||
continue;
|
||||
}
|
||||
_eol=0;
|
||||
|
||||
|
||||
switch (_state)
|
||||
{
|
||||
case STATE_START:
|
||||
|
@ -464,22 +481,22 @@ public class HttpParser implements Parser
|
|||
_state=STATE_HEADER_VALUE;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
{
|
||||
// handler last header if any
|
||||
if (_cached!=null || _tok0.length() > 0 || _tok1.length() > 0 || _multiLineValue != null)
|
||||
{
|
||||
|
||||
|
||||
Buffer header=_cached!=null?_cached:HttpHeaders.CACHE.lookup(_tok0);
|
||||
_cached=null;
|
||||
Buffer value=_multiLineValue == null ? _tok1 : new ByteArrayBuffer(_multiLineValue);
|
||||
|
||||
|
||||
int ho=HttpHeaders.CACHE.getOrdinal(header);
|
||||
if (ho >= 0)
|
||||
{
|
||||
int vo;
|
||||
|
||||
int vo;
|
||||
|
||||
switch (ho)
|
||||
{
|
||||
case HttpHeaders.CONTENT_LENGTH_ORDINAL:
|
||||
|
@ -498,7 +515,7 @@ public class HttpParser implements Parser
|
|||
_contentLength=HttpTokens.NO_CONTENT;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case HttpHeaders.TRANSFER_ENCODING_ORDINAL:
|
||||
value=HttpHeaderValues.CACHE.lookup(value);
|
||||
vo=HttpHeaderValues.CACHE.getOrdinal(value);
|
||||
|
@ -509,22 +526,22 @@ public class HttpParser implements Parser
|
|||
String c=value.toString(StringUtil.__ISO_8859_1);
|
||||
if (c.endsWith(HttpHeaderValues.CHUNKED))
|
||||
_contentLength=HttpTokens.CHUNKED_CONTENT;
|
||||
|
||||
|
||||
else if (c.indexOf(HttpHeaderValues.CHUNKED) >= 0)
|
||||
throw new HttpException(400,null);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_handler.parsedHeader(header, value);
|
||||
_tok0.setPutIndex(_tok0.getIndex());
|
||||
_tok1.setPutIndex(_tok1.getIndex());
|
||||
_multiLineValue=null;
|
||||
}
|
||||
_buffer.setMarkIndex(-1);
|
||||
|
||||
|
||||
|
||||
|
||||
// now handle ch
|
||||
if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
|
||||
{
|
||||
|
@ -544,7 +561,7 @@ public class HttpParser implements Parser
|
|||
_eol=ch;
|
||||
if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED)
|
||||
_eol=_buffer.get();
|
||||
|
||||
|
||||
// We convert _contentLength to an int for this switch statement because
|
||||
// we don't care about the amount of data available just whether there is some.
|
||||
switch (_contentLength > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) _contentLength)
|
||||
|
@ -553,19 +570,19 @@ public class HttpParser implements Parser
|
|||
_state=STATE_EOF_CONTENT;
|
||||
_handler.headerComplete(); // May recurse here !
|
||||
break;
|
||||
|
||||
|
||||
case HttpTokens.CHUNKED_CONTENT:
|
||||
_state=STATE_CHUNKED_CONTENT;
|
||||
_handler.headerComplete(); // May recurse here !
|
||||
break;
|
||||
|
||||
|
||||
case HttpTokens.NO_CONTENT:
|
||||
_state=STATE_END;
|
||||
returnBuffers();
|
||||
_handler.headerComplete();
|
||||
_handler.headerComplete();
|
||||
_handler.messageComplete(_contentPosition);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
_state=STATE_CONTENT;
|
||||
_handler.headerComplete(); // May recurse here !
|
||||
|
@ -579,7 +596,7 @@ public class HttpParser implements Parser
|
|||
_length=1;
|
||||
_buffer.mark();
|
||||
_state=STATE_HEADER_NAME;
|
||||
|
||||
|
||||
// try cached name!
|
||||
if (array!=null)
|
||||
{
|
||||
|
@ -592,10 +609,10 @@ public class HttpParser implements Parser
|
|||
length=_buffer.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case STATE_HEADER_NAME:
|
||||
|
@ -617,16 +634,16 @@ public class HttpParser implements Parser
|
|||
case HttpTokens.SPACE:
|
||||
case HttpTokens.TAB:
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
{
|
||||
_cached=null;
|
||||
if (_length == -1)
|
||||
if (_length == -1)
|
||||
_buffer.mark();
|
||||
_length=_buffer.getIndex() - _buffer.markIndex();
|
||||
_state=STATE_HEADER_IN_NAME;
|
||||
_state=STATE_HEADER_IN_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case STATE_HEADER_IN_NAME:
|
||||
|
@ -682,11 +699,11 @@ public class HttpParser implements Parser
|
|||
break;
|
||||
default:
|
||||
{
|
||||
if (_length == -1)
|
||||
if (_length == -1)
|
||||
_buffer.mark();
|
||||
_length=_buffer.getIndex() - _buffer.markIndex();
|
||||
_state=STATE_HEADER_IN_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -720,9 +737,9 @@ public class HttpParser implements Parser
|
|||
break;
|
||||
}
|
||||
} // end of HEADER states loop
|
||||
|
||||
|
||||
// ==========================
|
||||
|
||||
|
||||
// Handle HEAD response
|
||||
if (_responseStatus>0 && _headResponse)
|
||||
{
|
||||
|
@ -731,10 +748,10 @@ public class HttpParser implements Parser
|
|||
}
|
||||
|
||||
// ==========================
|
||||
|
||||
|
||||
// Handle _content
|
||||
length=_buffer.length();
|
||||
Buffer chunk;
|
||||
Buffer chunk;
|
||||
last=_state;
|
||||
while (_state > STATE_END && length > 0)
|
||||
{
|
||||
|
@ -743,7 +760,7 @@ public class HttpParser implements Parser
|
|||
progress++;
|
||||
last=_state;
|
||||
}
|
||||
|
||||
|
||||
if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer.peek() == HttpTokens.LINE_FEED)
|
||||
{
|
||||
_eol=_buffer.get();
|
||||
|
@ -757,11 +774,11 @@ public class HttpParser implements Parser
|
|||
chunk=_buffer.get(_buffer.length());
|
||||
_contentPosition += chunk.length();
|
||||
_contentView.update(chunk);
|
||||
_handler.content(chunk); // May recurse here
|
||||
_handler.content(chunk); // May recurse here
|
||||
// TODO adjust the _buffer to keep unconsumed content
|
||||
return 1;
|
||||
|
||||
case STATE_CONTENT:
|
||||
case STATE_CONTENT:
|
||||
{
|
||||
long remaining=_contentLength - _contentPosition;
|
||||
if (remaining == 0)
|
||||
|
@ -770,24 +787,24 @@ public class HttpParser implements Parser
|
|||
_handler.messageComplete(_contentPosition);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (length > remaining)
|
||||
|
||||
if (length > remaining)
|
||||
{
|
||||
// We can cast reamining to an int as we know that it is smaller than
|
||||
// or equal to length which is already an int.
|
||||
// or equal to length which is already an int.
|
||||
length=(int)remaining;
|
||||
}
|
||||
|
||||
|
||||
chunk=_buffer.get(length);
|
||||
_contentPosition += chunk.length();
|
||||
_contentView.update(chunk);
|
||||
_handler.content(chunk); // May recurse here
|
||||
|
||||
_handler.content(chunk); // May recurse here
|
||||
|
||||
if(_contentPosition == _contentLength)
|
||||
{
|
||||
_state=STATE_END;
|
||||
_handler.messageComplete(_contentPosition);
|
||||
}
|
||||
}
|
||||
// TODO adjust the _buffer to keep unconsumed content
|
||||
return 1;
|
||||
}
|
||||
|
@ -814,7 +831,7 @@ public class HttpParser implements Parser
|
|||
if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
|
||||
{
|
||||
_eol=ch;
|
||||
|
||||
|
||||
if (_chunkLength == 0)
|
||||
{
|
||||
if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED)
|
||||
|
@ -858,8 +875,8 @@ public class HttpParser implements Parser
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case STATE_CHUNK:
|
||||
|
||||
case STATE_CHUNK:
|
||||
{
|
||||
int remaining=_chunkLength - _chunkPosition;
|
||||
if (remaining == 0)
|
||||
|
@ -867,13 +884,13 @@ public class HttpParser implements Parser
|
|||
_state=STATE_CHUNKED_CONTENT;
|
||||
break;
|
||||
}
|
||||
else if (length > remaining)
|
||||
else if (length > remaining)
|
||||
length=remaining;
|
||||
chunk=_buffer.get(length);
|
||||
_contentPosition += chunk.length();
|
||||
_chunkPosition += chunk.length();
|
||||
_contentView.update(chunk);
|
||||
_handler.content(chunk); // May recurse here
|
||||
_handler.content(chunk); // May recurse here
|
||||
// TODO adjust the _buffer to keep unconsumed content
|
||||
return 1;
|
||||
}
|
||||
|
@ -881,13 +898,13 @@ public class HttpParser implements Parser
|
|||
|
||||
length=_buffer.length();
|
||||
}
|
||||
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/** fill the buffers from the endpoint
|
||||
*
|
||||
*
|
||||
*/
|
||||
public long fill() throws IOException
|
||||
{
|
||||
|
@ -898,14 +915,14 @@ public class HttpParser implements Parser
|
|||
_tok0=new View.CaseInsensitive(_buffer);
|
||||
_tok1=new View.CaseInsensitive(_buffer);
|
||||
}
|
||||
|
||||
|
||||
// Is there unconsumed content in body buffer
|
||||
if (_state>STATE_END && _buffer==_header && _header!=null && !_header.hasContent() && _body!=null && _body.hasContent())
|
||||
{
|
||||
_buffer=_body;
|
||||
return _buffer.length();
|
||||
}
|
||||
|
||||
|
||||
// Shall we switch to a body buffer?
|
||||
if (_buffer==_header && _state>STATE_END && _header.length()==0 && (_forceContentBuffer || (_contentLength-_contentPosition)>_header.capacity()) && (_body!=null||_buffers!=null))
|
||||
{
|
||||
|
@ -913,20 +930,20 @@ public class HttpParser implements Parser
|
|||
_body=_buffers.getBuffer();
|
||||
_buffer=_body;
|
||||
}
|
||||
|
||||
|
||||
// Do we have somewhere to fill from?
|
||||
if (_endp != null )
|
||||
{
|
||||
// Shall we compact the body?
|
||||
if (_buffer==_body || _state>STATE_END)
|
||||
if (_buffer==_body || _state>STATE_END)
|
||||
{
|
||||
_buffer.compact();
|
||||
}
|
||||
|
||||
|
||||
// Are we full?
|
||||
if (_buffer.space() == 0)
|
||||
throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "FULL "+(_buffer==_body?"body":"head"));
|
||||
|
||||
if (_buffer.space() == 0)
|
||||
throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "FULL "+(_buffer==_body?"body":"head"));
|
||||
|
||||
try
|
||||
{
|
||||
return _endp.fill(_buffer);
|
||||
|
@ -943,7 +960,7 @@ public class HttpParser implements Parser
|
|||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/** Skip any CRLFs in buffers
|
||||
*
|
||||
*
|
||||
*/
|
||||
public void skipCRLF()
|
||||
{
|
||||
|
@ -971,12 +988,12 @@ public class HttpParser implements Parser
|
|||
else
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public void reset()
|
||||
{
|
||||
{
|
||||
// reset state
|
||||
_contentView.setGetIndex(_contentView.putIndex());
|
||||
_state=STATE_START;
|
||||
|
@ -1026,12 +1043,12 @@ public class HttpParser implements Parser
|
|||
public void returnBuffers()
|
||||
{
|
||||
if (_body!=null && !_body.hasContent() && _body.markIndex()==-1 && _buffers!=null)
|
||||
{
|
||||
{
|
||||
if (_buffer==_body)
|
||||
_buffer=_header;
|
||||
if (_buffers!=null)
|
||||
_buffers.returnBuffer(_body);
|
||||
_body=null;
|
||||
_body=null;
|
||||
}
|
||||
|
||||
if (_header!=null && !_header.hasContent() && _header.markIndex()==-1 && _buffers!=null)
|
||||
|
@ -1042,7 +1059,7 @@ public class HttpParser implements Parser
|
|||
_header=null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public void setState(int state)
|
||||
{
|
||||
|
@ -1055,13 +1072,13 @@ public class HttpParser implements Parser
|
|||
{
|
||||
return "state=" + _state + " length=" + _length + " buf=" + buf.hashCode();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "state=" + _state + " length=" + _length + " len=" + _contentLength;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Buffer getHeaderBuffer()
|
||||
|
@ -1072,7 +1089,7 @@ public class HttpParser implements Parser
|
|||
}
|
||||
return _header;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Buffer getBodyBuffer()
|
||||
{
|
||||
|
@ -1086,20 +1103,20 @@ public class HttpParser implements Parser
|
|||
public void setForceContentBuffer(boolean force)
|
||||
{
|
||||
_forceContentBuffer=force;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Buffer blockForContent(long maxIdleTime) throws IOException
|
||||
{
|
||||
if (_contentView.length()>0)
|
||||
return _contentView;
|
||||
if (getState() <= HttpParser.STATE_END)
|
||||
if (getState() <= HttpParser.STATE_END)
|
||||
return null;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
parseNext();
|
||||
|
||||
|
||||
// parse until some progress is made (or IOException thrown for timeout)
|
||||
while(_contentView.length() == 0 && !isState(HttpParser.STATE_END) && _endp!=null && _endp.isOpen())
|
||||
{
|
||||
|
@ -1123,9 +1140,9 @@ public class HttpParser implements Parser
|
|||
_endp.close();
|
||||
throw e;
|
||||
}
|
||||
|
||||
return _contentView.length()>0?_contentView:null;
|
||||
}
|
||||
|
||||
return _contentView.length()>0?_contentView:null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* (non-Javadoc)
|
||||
|
@ -1143,11 +1160,11 @@ public class HttpParser implements Parser
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
parseNext();
|
||||
return _contentView==null?0:_contentView.length();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -1175,7 +1192,7 @@ public class HttpParser implements Parser
|
|||
*/
|
||||
public abstract void startRequest(Buffer method, Buffer url, Buffer version)
|
||||
throws IOException;
|
||||
|
||||
|
||||
/**
|
||||
* This is the method called by parser when the HTTP request line is parsed
|
||||
*/
|
||||
|
@ -1185,5 +1202,5 @@ public class HttpParser implements Parser
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
// 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
|
||||
// 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.
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
|
||||
package org.eclipse.jetty.http;
|
||||
|
@ -34,7 +34,7 @@ import org.eclipse.jetty.util.URIUtil;
|
|||
* /foo/bar - an exact path specification.
|
||||
* /foo/* - a prefix path specification (must end '/*').
|
||||
* *.ext - a suffix path specification.
|
||||
* / - the default path specification.
|
||||
* / - the default path specification.
|
||||
* </PRE>
|
||||
* Matching is performed in the following order <NL>
|
||||
* <LI>Exact match.
|
||||
|
@ -43,24 +43,24 @@ import org.eclipse.jetty.util.URIUtil;
|
|||
* <LI>default.
|
||||
* </NL>
|
||||
* Multiple path specifications can be mapped by providing a list of
|
||||
* specifications. By default this class uses characters ":," as path
|
||||
* separators, unless configured differently by calling the static
|
||||
* method @see PathMap#setPathSpecSeparators(String)
|
||||
* specifications. By default this class uses characters ":," as path
|
||||
* separators, unless configured differently by calling the static
|
||||
* method @see PathMap#setPathSpecSeparators(String)
|
||||
* <P>
|
||||
* Special characters within paths such as '?<EFBFBD> and ';' are not treated specially
|
||||
* as it is assumed they would have been either encoded in the original URL or
|
||||
* as it is assumed they would have been either encoded in the original URL or
|
||||
* stripped from the path.
|
||||
* <P>
|
||||
* This class is not synchronized. If concurrent modifications are
|
||||
* possible then it should be synchronized at a higher level.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class PathMap extends HashMap implements Externalizable
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
private static String __pathSpecSeparators = ":,";
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the path spec separator.
|
||||
* Multiple path specification may be included in a single string
|
||||
|
@ -72,7 +72,7 @@ public class PathMap extends HashMap implements Externalizable
|
|||
{
|
||||
__pathSpecSeparators=s;
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
final StringMap _prefixMap=new StringMap();
|
||||
final StringMap _suffixMap=new StringMap();
|
||||
|
@ -83,7 +83,7 @@ public class PathMap extends HashMap implements Externalizable
|
|||
Entry _default=null;
|
||||
final Set _entrySet;
|
||||
boolean _nodefault=false;
|
||||
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
/** Construct empty PathMap.
|
||||
*/
|
||||
|
@ -102,7 +102,7 @@ public class PathMap extends HashMap implements Externalizable
|
|||
_entrySet=entrySet();
|
||||
_nodefault=nodefault;
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
/** Construct empty PathMap.
|
||||
*/
|
||||
|
@ -111,7 +111,7 @@ public class PathMap extends HashMap implements Externalizable
|
|||
super (capacity);
|
||||
_entrySet=entrySet();
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
/** Construct from dictionary PathMap.
|
||||
*/
|
||||
|
@ -120,7 +120,7 @@ public class PathMap extends HashMap implements Externalizable
|
|||
putAll(m);
|
||||
_entrySet=entrySet();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void writeExternal(java.io.ObjectOutput out)
|
||||
throws java.io.IOException
|
||||
|
@ -128,7 +128,7 @@ public class PathMap extends HashMap implements Externalizable
|
|||
HashMap map = new HashMap(this);
|
||||
out.writeObject(map);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void readExternal(java.io.ObjectInput in)
|
||||
throws java.io.IOException, ClassNotFoundException
|
||||
|
@ -136,7 +136,7 @@ public class PathMap extends HashMap implements Externalizable
|
|||
HashMap map = (HashMap)in.readObject();
|
||||
this.putAll(map);
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
/** Add a single path match to the PathMap.
|
||||
* @param pathSpec The path specification, or comma separated list of
|
||||
|
@ -148,16 +148,16 @@ public class PathMap extends HashMap implements Externalizable
|
|||
{
|
||||
StringTokenizer tok = new StringTokenizer(pathSpec.toString(),__pathSpecSeparators);
|
||||
Object old =null;
|
||||
|
||||
|
||||
while (tok.hasMoreTokens())
|
||||
{
|
||||
String spec=tok.nextToken();
|
||||
|
||||
|
||||
if (!spec.startsWith("/") && !spec.startsWith("*."))
|
||||
throw new IllegalArgumentException("PathSpec "+spec+". must start with '/' or '*.'");
|
||||
|
||||
|
||||
old = super.put(spec,object);
|
||||
|
||||
|
||||
// Make entry that was just created.
|
||||
Entry entry = new Entry(spec,object);
|
||||
|
||||
|
@ -176,7 +176,7 @@ public class PathMap extends HashMap implements Externalizable
|
|||
else if (spec.startsWith("*."))
|
||||
_suffixMap.put(spec.substring(2),entry);
|
||||
else if (spec.equals(URIUtil.SLASH))
|
||||
{
|
||||
{
|
||||
if (_nodefault)
|
||||
_exactMap.put(spec,entry);
|
||||
else
|
||||
|
@ -193,7 +193,7 @@ public class PathMap extends HashMap implements Externalizable
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
|
@ -209,8 +209,8 @@ public class PathMap extends HashMap implements Externalizable
|
|||
return entry.getValue();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
/** Get the entry mapped by the best specification.
|
||||
* @param path the path.
|
||||
|
@ -222,14 +222,14 @@ public class PathMap extends HashMap implements Externalizable
|
|||
|
||||
if (path==null)
|
||||
return null;
|
||||
|
||||
int l=path.length();
|
||||
|
||||
int l=path.length();
|
||||
|
||||
// try exact match
|
||||
entry=_exactMap.getEntry(path,0,l);
|
||||
if (entry!=null)
|
||||
return (Entry) entry.getValue();
|
||||
|
||||
|
||||
// prefix search
|
||||
int i=l;
|
||||
while((i=path.lastIndexOf('/',i-1))>=0)
|
||||
|
@ -238,11 +238,11 @@ public class PathMap extends HashMap implements Externalizable
|
|||
if (entry!=null)
|
||||
return (Entry) entry.getValue();
|
||||
}
|
||||
|
||||
|
||||
// Prefix Default
|
||||
if (_prefixDefault!=null)
|
||||
return _prefixDefault;
|
||||
|
||||
|
||||
// Extension search
|
||||
i=0;
|
||||
while ((i=path.indexOf('.',i+1))>0)
|
||||
|
@ -250,12 +250,12 @@ public class PathMap extends HashMap implements Externalizable
|
|||
entry=_suffixMap.getEntry(path,i+1,l-i-1);
|
||||
if (entry!=null)
|
||||
return (Entry) entry.getValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Default
|
||||
return _default;
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
/** Get all entries matched by the path.
|
||||
* Best match first.
|
||||
|
@ -263,20 +263,20 @@ public class PathMap extends HashMap implements Externalizable
|
|||
* @return LazyList of Map.Entry instances key=pathSpec
|
||||
*/
|
||||
public Object getLazyMatches(String path)
|
||||
{
|
||||
{
|
||||
Map.Entry entry;
|
||||
Object entries=null;
|
||||
|
||||
if (path==null)
|
||||
return LazyList.getList(entries);
|
||||
|
||||
|
||||
int l=path.length();
|
||||
|
||||
// try exact match
|
||||
entry=_exactMap.getEntry(path,0,l);
|
||||
if (entry!=null)
|
||||
entries=LazyList.add(entries,entry.getValue());
|
||||
|
||||
|
||||
// prefix search
|
||||
int i=l-1;
|
||||
while((i=path.lastIndexOf('/',i-1))>=0)
|
||||
|
@ -285,11 +285,11 @@ public class PathMap extends HashMap implements Externalizable
|
|||
if (entry!=null)
|
||||
entries=LazyList.add(entries,entry.getValue());
|
||||
}
|
||||
|
||||
|
||||
// Prefix Default
|
||||
if (_prefixDefault!=null)
|
||||
entries=LazyList.add(entries,_prefixDefault);
|
||||
|
||||
|
||||
// Extension search
|
||||
i=0;
|
||||
while ((i=path.indexOf('.',i+1))>0)
|
||||
|
@ -305,13 +305,13 @@ public class PathMap extends HashMap implements Externalizable
|
|||
// Optimization for just the default
|
||||
if (entries==null)
|
||||
return _defaultSingletonList;
|
||||
|
||||
|
||||
entries=LazyList.add(entries,_default);
|
||||
}
|
||||
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
/** Get all entries matched by the path.
|
||||
* Best match first.
|
||||
|
@ -319,7 +319,7 @@ public class PathMap extends HashMap implements Externalizable
|
|||
* @return List of Map.Entry instances key=pathSpec
|
||||
*/
|
||||
public List getMatches(String path)
|
||||
{
|
||||
{
|
||||
return LazyList.getList(getLazyMatches(path));
|
||||
}
|
||||
|
||||
|
@ -330,12 +330,12 @@ public class PathMap extends HashMap implements Externalizable
|
|||
* @return Whether the PathMap contains any entries that match this
|
||||
*/
|
||||
public boolean containsMatch(String path)
|
||||
{
|
||||
{
|
||||
Entry match = getMatch(path);
|
||||
return match!=null && !match.equals(_default);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
/* --------------------------------------------------------------- */
|
||||
@Override
|
||||
public Object remove(Object pathSpec)
|
||||
{
|
||||
|
@ -362,7 +362,7 @@ public class PathMap extends HashMap implements Externalizable
|
|||
}
|
||||
return super.remove(pathSpec);
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
@Override
|
||||
public void clear()
|
||||
|
@ -374,7 +374,7 @@ public class PathMap extends HashMap implements Externalizable
|
|||
_defaultSingletonList=null;
|
||||
super.clear();
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
/**
|
||||
* @return true if match.
|
||||
|
@ -397,7 +397,7 @@ public class PathMap extends HashMap implements Externalizable
|
|||
{
|
||||
if (!noDefault && pathSpec.length()==1 || pathSpec.equals(path))
|
||||
return true;
|
||||
|
||||
|
||||
if(isPathWildcardMatch(pathSpec, path))
|
||||
return true;
|
||||
}
|
||||
|
@ -419,24 +419,24 @@ public class PathMap extends HashMap implements Externalizable
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
/** Return the portion of a path that matches a path spec.
|
||||
* @return null if no match at all.
|
||||
*/
|
||||
public static String pathMatch(String pathSpec, String path)
|
||||
{
|
||||
{
|
||||
char c = pathSpec.charAt(0);
|
||||
|
||||
|
||||
if (c=='/')
|
||||
{
|
||||
if (pathSpec.length()==1)
|
||||
return path;
|
||||
|
||||
|
||||
if (pathSpec.equals(path))
|
||||
return path;
|
||||
|
||||
|
||||
if (isPathWildcardMatch(pathSpec, path))
|
||||
return path.substring(0,pathSpec.length()-2);
|
||||
}
|
||||
|
@ -448,7 +448,7 @@ public class PathMap extends HashMap implements Externalizable
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
/** Return the portion of a path that is after a path spec.
|
||||
* @return The path info string
|
||||
|
@ -456,12 +456,12 @@ public class PathMap extends HashMap implements Externalizable
|
|||
public static String pathInfo(String pathSpec, String path)
|
||||
{
|
||||
char c = pathSpec.charAt(0);
|
||||
|
||||
|
||||
if (c=='/')
|
||||
{
|
||||
if (pathSpec.length()==1)
|
||||
return null;
|
||||
|
||||
|
||||
boolean wildcard = isPathWildcardMatch(pathSpec, path);
|
||||
|
||||
// handle the case where pathSpec uses a wildcard and path info is "/*"
|
||||
|
@ -474,7 +474,7 @@ public class PathMap extends HashMap implements Externalizable
|
|||
return null;
|
||||
return path.substring(pathSpec.length()-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -484,7 +484,7 @@ public class PathMap extends HashMap implements Externalizable
|
|||
* @param base The base the path is relative to.
|
||||
* @param pathSpec The spec of the path segment to ignore.
|
||||
* @param path the additional path
|
||||
* @return base plus path with pathspec removed
|
||||
* @return base plus path with pathspec removed
|
||||
*/
|
||||
public static String relativePath(String base,
|
||||
String pathSpec,
|
||||
|
@ -508,7 +508,7 @@ public class PathMap extends HashMap implements Externalizable
|
|||
path = base + URIUtil.SLASH + info;
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -516,7 +516,7 @@ public class PathMap extends HashMap implements Externalizable
|
|||
{
|
||||
private final Object key;
|
||||
private final Object value;
|
||||
private String mapped;
|
||||
private String mapped;
|
||||
private transient String string;
|
||||
|
||||
Entry(Object key, Object value)
|
||||
|
@ -529,7 +529,7 @@ public class PathMap extends HashMap implements Externalizable
|
|||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
public Object getValue()
|
||||
{
|
||||
return value;
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.io.ByteArrayOutputStream;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.security.InvalidParameterException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.SecureRandom;
|
||||
|
@ -42,7 +43,10 @@ import javax.net.ssl.KeyManager;
|
|||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLSessionContext;
|
||||
import javax.net.ssl.SSLServerSocket;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509KeyManager;
|
||||
|
@ -51,6 +55,8 @@ import javax.net.ssl.X509TrustManager;
|
|||
import org.eclipse.jetty.http.security.Password;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.security.CertificateUtils;
|
||||
import org.eclipse.jetty.util.security.CertificateValidator;
|
||||
|
@ -65,6 +71,8 @@ import org.eclipse.jetty.util.security.CertificateValidator;
|
|||
*/
|
||||
public class SslContextFactory extends AbstractLifeCycle
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(SslContextFactory.class);
|
||||
|
||||
public static final String DEFAULT_KEYMANAGERFACTORY_ALGORITHM =
|
||||
(Security.getProperty("ssl.KeyManagerFactory.algorithm") == null ?
|
||||
"SunX509" : Security.getProperty("ssl.KeyManagerFactory.algorithm"));
|
||||
|
@ -82,8 +90,14 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
/** String name of keystore password property. */
|
||||
public static final String PASSWORD_PROPERTY = "org.eclipse.jetty.ssl.password";
|
||||
|
||||
/** Excluded protocols. */
|
||||
private final Set<String> _excludeProtocols = new HashSet<String>();
|
||||
// private final Set<String> _excludeProtocols = new HashSet<String>(Collections.singleton("SSLv2Hello"));
|
||||
/** Included protocols. */
|
||||
private Set<String> _includeProtocols = null;
|
||||
|
||||
/** Excluded cipher suites. */
|
||||
private Set<String> _excludeCipherSuites = null;
|
||||
private final Set<String> _excludeCipherSuites = new HashSet<String>();
|
||||
/** Included cipher suites. */
|
||||
private Set<String> _includeCipherSuites = null;
|
||||
|
||||
|
@ -196,6 +210,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
if (_keyStoreInputStream == null && _keyStorePath == null &&
|
||||
_trustStoreInputStream == null && _trustStorePath == null )
|
||||
{
|
||||
LOG.debug("No keystore or trust store configured. ACCEPTING UNTRUSTED CERTIFICATES!!!!!");
|
||||
// Create a trust manager that does not validate certificate chains
|
||||
TrustManager trustAllCerts = new X509TrustManager()
|
||||
{
|
||||
|
@ -218,11 +233,115 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
}
|
||||
else
|
||||
{
|
||||
createSSLContext();
|
||||
// verify that keystore and truststore
|
||||
// parameters are set up correctly
|
||||
try
|
||||
{
|
||||
checkKeyStore();
|
||||
}
|
||||
catch(IllegalStateException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
|
||||
KeyStore keyStore = loadKeyStore();
|
||||
KeyStore trustStore = loadTrustStore();
|
||||
|
||||
Collection<? extends CRL> crls = loadCRL(_crlPath);
|
||||
|
||||
if (_validateCerts && keyStore != null)
|
||||
{
|
||||
if (_certAlias == null)
|
||||
{
|
||||
List<String> aliases = Collections.list(keyStore.aliases());
|
||||
_certAlias = aliases.size() == 1 ? aliases.get(0) : null;
|
||||
}
|
||||
|
||||
Certificate cert = _certAlias == null?null:keyStore.getCertificate(_certAlias);
|
||||
if (cert == null)
|
||||
{
|
||||
throw new Exception("No certificate found in the keystore" + (_certAlias==null ? "":" for alias " + _certAlias));
|
||||
}
|
||||
|
||||
CertificateValidator validator = new CertificateValidator(trustStore, crls);
|
||||
validator.setMaxCertPathLength(_maxCertPathLength);
|
||||
validator.setEnableCRLDP(_enableCRLDP);
|
||||
validator.setEnableOCSP(_enableOCSP);
|
||||
validator.setOcspResponderURL(_ocspResponderURL);
|
||||
validator.validate(keyStore, cert);
|
||||
}
|
||||
|
||||
KeyManager[] keyManagers = getKeyManagers(keyStore);
|
||||
TrustManager[] trustManagers = getTrustManagers(trustStore,crls);
|
||||
|
||||
SecureRandom secureRandom = (_secureRandomAlgorithm == null)?null:SecureRandom.getInstance(_secureRandomAlgorithm);
|
||||
_context = (_sslProvider == null)?SSLContext.getInstance(_sslProtocol):SSLContext.getInstance(_sslProtocol,_sslProvider);
|
||||
_context.init(keyManagers,trustManagers,secureRandom);
|
||||
|
||||
SSLEngine engine=newSslEngine();
|
||||
LOG.info("Enabled Protocols {} of {}",Arrays.asList(engine.getEnabledProtocols()),Arrays.asList(engine.getSupportedProtocols()));
|
||||
LOG.debug("Enabled Ciphers {} of {}",Arrays.asList(engine.getEnabledCipherSuites()),Arrays.asList(engine.getSupportedCipherSuites()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return The array of protocol names to exclude from
|
||||
* {@link SSLEngine#setEnabledProtocols(String[])}
|
||||
*/
|
||||
public String[] getExcludeProtocols()
|
||||
{
|
||||
return _excludeProtocols.toArray(new String[_excludeProtocols.size()]);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param Protocols
|
||||
* The array of protocol names to exclude from
|
||||
* {@link SSLEngine#setEnabledProtocols(String[])}
|
||||
*/
|
||||
public void setExcludeProtocols(String... protocols)
|
||||
{
|
||||
checkNotStarted();
|
||||
|
||||
_excludeProtocols.clear();
|
||||
_excludeProtocols.addAll(Arrays.asList(protocols));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param protocol Protocol names to add to {@link SSLEngine#setEnabledProtocols(String[])}
|
||||
*/
|
||||
public void addExcludeProtocols(String... protocol)
|
||||
{
|
||||
checkNotStarted();
|
||||
_excludeProtocols.addAll(Arrays.asList(protocol));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return The array of protocol names to include in
|
||||
* {@link SSLEngine#setEnabledProtocols(String[])}
|
||||
*/
|
||||
public String[] getIncludeProtocols()
|
||||
{
|
||||
return _includeProtocols.toArray(new String[_includeProtocols.size()]);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param Protocols
|
||||
* The array of protocol names to include in
|
||||
* {@link SSLEngine#setEnabledProtocols(String[])}
|
||||
*/
|
||||
public void setIncludeProtocols(String... protocols)
|
||||
{
|
||||
checkNotStarted();
|
||||
|
||||
_includeProtocols = new HashSet<String>(Arrays.asList(protocols));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return The array of cipher suite names to exclude from
|
||||
|
@ -239,11 +358,21 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
* The array of cipher suite names to exclude from
|
||||
* {@link SSLEngine#setEnabledCipherSuites(String[])}
|
||||
*/
|
||||
public void setExcludeCipherSuites(String[] cipherSuites)
|
||||
public void setExcludeCipherSuites(String... cipherSuites)
|
||||
{
|
||||
checkStarted();
|
||||
|
||||
_excludeCipherSuites = new HashSet<String>(Arrays.asList(cipherSuites));
|
||||
checkNotStarted();
|
||||
_excludeCipherSuites.clear();
|
||||
_excludeCipherSuites.addAll(Arrays.asList(cipherSuites));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param cipher Cipher names to add to {@link SSLEngine#setEnabledCipherSuites(String[])}
|
||||
*/
|
||||
public void addExcludeCipherSuites(String... cipher)
|
||||
{
|
||||
checkNotStarted();
|
||||
_excludeCipherSuites.addAll(Arrays.asList(cipher));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -262,9 +391,9 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
* The array of cipher suite names to include in
|
||||
* {@link SSLEngine#setEnabledCipherSuites(String[])}
|
||||
*/
|
||||
public void setIncludeCipherSuites(String[] cipherSuites)
|
||||
public void setIncludeCipherSuites(String... cipherSuites)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_includeCipherSuites = new HashSet<String>(Arrays.asList(cipherSuites));
|
||||
}
|
||||
|
@ -285,7 +414,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setKeyStore(String keyStorePath)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_keyStorePath = keyStorePath;
|
||||
}
|
||||
|
@ -306,7 +435,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setKeyStoreProvider(String keyStoreProvider)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_keyStoreProvider = keyStoreProvider;
|
||||
}
|
||||
|
@ -327,7 +456,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setKeyStoreType(String keyStoreType)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_keyStoreType = keyStoreType;
|
||||
}
|
||||
|
@ -341,7 +470,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
@Deprecated
|
||||
public InputStream getKeyStoreInputStream()
|
||||
{
|
||||
checkConfig();
|
||||
checkKeyStore();
|
||||
|
||||
return _keyStoreInputStream;
|
||||
}
|
||||
|
@ -355,7 +484,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
@Deprecated
|
||||
public void setKeyStoreInputStream(InputStream keyStoreInputStream)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_keyStoreInputStream = keyStoreInputStream;
|
||||
}
|
||||
|
@ -376,7 +505,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setCertAlias(String certAlias)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_certAlias = certAlias;
|
||||
}
|
||||
|
@ -397,7 +526,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setTrustStore(String trustStorePath)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_trustStorePath = trustStorePath;
|
||||
}
|
||||
|
@ -418,7 +547,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setTrustStoreProvider(String trustStoreProvider)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_trustStoreProvider = trustStoreProvider;
|
||||
}
|
||||
|
@ -439,7 +568,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setTrustStoreType(String trustStoreType)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_trustStoreType = trustStoreType;
|
||||
}
|
||||
|
@ -453,7 +582,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
@Deprecated
|
||||
public InputStream getTrustStoreInputStream()
|
||||
{
|
||||
checkConfig();
|
||||
checkKeyStore();
|
||||
|
||||
return _trustStoreInputStream;
|
||||
}
|
||||
|
@ -467,7 +596,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
@Deprecated
|
||||
public void setTrustStoreInputStream(InputStream trustStoreInputStream)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_trustStoreInputStream = trustStoreInputStream;
|
||||
}
|
||||
|
@ -490,7 +619,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setNeedClientAuth(boolean needClientAuth)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_needClientAuth = needClientAuth;
|
||||
}
|
||||
|
@ -513,7 +642,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setWantClientAuth(boolean wantClientAuth)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_wantClientAuth = wantClientAuth;
|
||||
}
|
||||
|
@ -545,7 +674,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setValidateCerts(boolean validateCerts)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_validateCerts = validateCerts;
|
||||
}
|
||||
|
@ -566,7 +695,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setValidatePeerCerts(boolean validatePeerCerts)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_validatePeerCerts = validatePeerCerts;
|
||||
}
|
||||
|
@ -593,7 +722,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setAllowRenegotiate(boolean allowRenegotiate)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_allowRenegotiate = allowRenegotiate;
|
||||
}
|
||||
|
@ -605,7 +734,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setKeyStorePassword(String password)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_keyStorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
|
||||
}
|
||||
|
@ -617,7 +746,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setKeyManagerPassword(String password)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_keyManagerPassword = Password.getPassword(KEYPASSWORD_PROPERTY,password,null);
|
||||
}
|
||||
|
@ -629,7 +758,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setTrustStorePassword(String password)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_trustStorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
|
||||
}
|
||||
|
@ -652,7 +781,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setProvider(String provider)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_sslProvider = provider;
|
||||
}
|
||||
|
@ -675,7 +804,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setProtocol(String protocol)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_sslProtocol = protocol;
|
||||
}
|
||||
|
@ -700,7 +829,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setSecureRandomAlgorithm(String algorithm)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_secureRandomAlgorithm = algorithm;
|
||||
}
|
||||
|
@ -721,7 +850,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setSslKeyManagerFactoryAlgorithm(String algorithm)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_keyManagerFactoryAlgorithm = algorithm;
|
||||
}
|
||||
|
@ -742,7 +871,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setTrustManagerFactoryAlgorithm(String algorithm)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_trustManagerFactoryAlgorithm = algorithm;
|
||||
}
|
||||
|
@ -763,7 +892,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setCrlPath(String crlPath)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_crlPath = crlPath;
|
||||
}
|
||||
|
@ -786,7 +915,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setMaxCertPathLength(int maxCertPathLength)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_maxCertPathLength = maxCertPathLength;
|
||||
}
|
||||
|
@ -797,6 +926,8 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public SSLContext getSslContext()
|
||||
{
|
||||
if (!isStarted())
|
||||
throw new IllegalStateException(getState());
|
||||
return _context;
|
||||
}
|
||||
|
||||
|
@ -807,60 +938,11 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setSslContext(SSLContext sslContext)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_context = sslContext;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
protected void createSSLContext() throws Exception
|
||||
{
|
||||
// verify that keystore and truststore
|
||||
// parameters are set up correctly
|
||||
checkConfig();
|
||||
|
||||
KeyStore keyStore = loadKeyStore();
|
||||
KeyStore trustStore = loadTrustStore();
|
||||
|
||||
Collection<? extends CRL> crls = loadCRL(_crlPath);
|
||||
|
||||
if (_validateCerts && keyStore != null)
|
||||
{
|
||||
if (_certAlias == null)
|
||||
{
|
||||
List<String> aliases = Collections.list(keyStore.aliases());
|
||||
_certAlias = aliases.size() == 1 ? aliases.get(0) : null;
|
||||
}
|
||||
|
||||
Certificate cert = _certAlias == null?null:keyStore.getCertificate(_certAlias);
|
||||
if (cert == null)
|
||||
{
|
||||
throw new Exception("No certificate found in the keystore" + (_certAlias==null ? "":" for alias " + _certAlias));
|
||||
}
|
||||
|
||||
CertificateValidator validator = new CertificateValidator(trustStore, crls);
|
||||
validator.setMaxCertPathLength(_maxCertPathLength);
|
||||
validator.setEnableCRLDP(_enableCRLDP);
|
||||
validator.setEnableOCSP(_enableOCSP);
|
||||
validator.setOcspResponderURL(_ocspResponderURL);
|
||||
validator.validate(keyStore, cert);
|
||||
}
|
||||
|
||||
KeyManager[] keyManagers = getKeyManagers(keyStore);
|
||||
TrustManager[] trustManagers = getTrustManagers(trustStore,crls);
|
||||
|
||||
SecureRandom secureRandom = (_secureRandomAlgorithm == null)?null:SecureRandom.getInstance(_secureRandomAlgorithm);
|
||||
_context = (_sslProvider == null)?SSLContext.getInstance(_sslProtocol):SSLContext.getInstance(_sslProtocol,_sslProvider);
|
||||
_context.init(keyManagers,trustManagers,secureRandom);
|
||||
|
||||
SSLSessionContext sslSessionContext = _context.getServerSessionContext();
|
||||
sslSessionContext.setSessionCacheSize(_sslSessionCacheSize);
|
||||
sslSessionContext.setSessionTimeout(_sslSessionTimeout);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Override this method to provide alternate way to load a keystore.
|
||||
|
@ -1014,33 +1096,27 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Check configuration. Ensures that if keystore has been
|
||||
* Check KetyStore Configuration. Ensures that if keystore has been
|
||||
* configured but there's no truststore, that keystore is
|
||||
* used as truststore.
|
||||
* @return true SslContextFactory configuration can be used in server connector.
|
||||
* @throws IllegalStateException if SslContextFactory configuration can't be used.
|
||||
*/
|
||||
public boolean checkConfig()
|
||||
public void checkKeyStore()
|
||||
{
|
||||
boolean check = true;
|
||||
if (_keyStore == null && _keyStoreInputStream == null && _keyStorePath == null)
|
||||
throw new IllegalStateException("SSL doesn't have a valid keystore");
|
||||
|
||||
// if the keystore has been configured but there is no
|
||||
// truststore configured, use the keystore as the truststore
|
||||
if (_trustStore == null && _trustStoreInputStream == null && _trustStorePath == null)
|
||||
{
|
||||
// configuration doesn't have a valid keystore
|
||||
check = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the keystore has been configured but there is no
|
||||
// truststore configured, use the keystore as the truststore
|
||||
if (_trustStore == null && _trustStoreInputStream == null && _trustStorePath == null)
|
||||
{
|
||||
_trustStore = _keyStore;
|
||||
_trustStorePath = _keyStorePath;
|
||||
_trustStoreInputStream = _keyStoreInputStream;
|
||||
_trustStoreType = _keyStoreType;
|
||||
_trustStoreProvider = _keyStoreProvider;
|
||||
_trustStorePassword = _keyStorePassword;
|
||||
_trustManagerFactoryAlgorithm = _keyManagerFactoryAlgorithm;
|
||||
}
|
||||
_trustStore = _keyStore;
|
||||
_trustStorePath = _keyStorePath;
|
||||
_trustStoreInputStream = _keyStoreInputStream;
|
||||
_trustStoreType = _keyStoreType;
|
||||
_trustStoreProvider = _keyStoreProvider;
|
||||
_trustStorePassword = _keyStorePassword;
|
||||
_trustManagerFactoryAlgorithm = _keyManagerFactoryAlgorithm;
|
||||
}
|
||||
|
||||
// It's the same stream we cannot read it twice, so read it once in memory
|
||||
|
@ -1057,11 +1133,9 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new RuntimeException(ex);
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -1073,57 +1147,68 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
* @param supportedCipherSuites Array of supported cipher suites
|
||||
* @return Array of cipher suites to enable
|
||||
*/
|
||||
public String[] selectCipherSuites(String[] enabledCipherSuites, String[] supportedCipherSuites)
|
||||
public String[] selectProtocols(String[] enabledProtocols, String[] supportedProtocols)
|
||||
{
|
||||
Set<String> selectedCipherSuites = null;
|
||||
if (enabledCipherSuites != null)
|
||||
Set<String> selected_protocols = new HashSet<String>();
|
||||
|
||||
// Set the starting protocols - either from the included or enabled list
|
||||
if (_includeProtocols!=null)
|
||||
{
|
||||
selectedCipherSuites = new HashSet<String>(Arrays.asList(enabledCipherSuites));
|
||||
// Use only the supported included protocols
|
||||
for (String protocol : supportedProtocols)
|
||||
if (_includeProtocols.contains(protocol))
|
||||
selected_protocols.add(protocol);
|
||||
}
|
||||
else
|
||||
selected_protocols.addAll(Arrays.asList(enabledProtocols));
|
||||
|
||||
|
||||
// Remove any excluded protocols
|
||||
if (_excludeProtocols != null)
|
||||
selected_protocols.removeAll(_excludeProtocols);
|
||||
|
||||
return selected_protocols.toArray(new String[selected_protocols.size()]);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Select cipher suites to be used by the connector
|
||||
* based on configured inclusion and exclusion lists
|
||||
* as well as enabled and supported cipher suite lists.
|
||||
* @param enabledCipherSuites Array of enabled cipher suites
|
||||
* @param supportedCipherSuites Array of supported cipher suites
|
||||
* @return Array of cipher suites to enable
|
||||
*/
|
||||
public String[] selectCipherSuites(String[] enabledCipherSuites, String[] supportedCipherSuites)
|
||||
{
|
||||
Set<String> selected_ciphers = new HashSet<String>();
|
||||
|
||||
// Set the starting ciphers - either from the included or enabled list
|
||||
if (_includeCipherSuites!=null)
|
||||
{
|
||||
selectedCipherSuites = new HashSet<String>();
|
||||
// Use only the supported included ciphers
|
||||
for (String cipherSuite : supportedCipherSuites)
|
||||
if (_includeCipherSuites.contains(cipherSuite))
|
||||
selected_ciphers.add(cipherSuite);
|
||||
}
|
||||
|
||||
if ((supportedCipherSuites != null && supportedCipherSuites.length > 0) &&
|
||||
(_includeCipherSuites != null && _includeCipherSuites.size() > 0))
|
||||
{
|
||||
Set<String> supportedCSList = new HashSet<String>(Arrays.asList(supportedCipherSuites));
|
||||
|
||||
for (String cipherName : _includeCipherSuites)
|
||||
{
|
||||
if ((!selectedCipherSuites.contains(cipherName)) &&
|
||||
supportedCSList.contains(cipherName))
|
||||
{
|
||||
selectedCipherSuites.add(cipherName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_excludeCipherSuites != null && _excludeCipherSuites.size() > 0)
|
||||
{
|
||||
for (String cipherName : _excludeCipherSuites)
|
||||
{
|
||||
if (selectedCipherSuites.contains(cipherName))
|
||||
{
|
||||
selectedCipherSuites.remove(cipherName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return selectedCipherSuites.toArray(new String[selectedCipherSuites.size()]);
|
||||
else
|
||||
selected_ciphers.addAll(Arrays.asList(enabledCipherSuites));
|
||||
|
||||
|
||||
// Remove any excluded ciphers
|
||||
if (_excludeCipherSuites != null)
|
||||
selected_ciphers.removeAll(_excludeCipherSuites);
|
||||
return selected_ciphers.toArray(new String[selected_ciphers.size()]);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Check if the lifecycle has been started and throw runtime exception
|
||||
*/
|
||||
protected void checkStarted()
|
||||
protected void checkNotStarted()
|
||||
{
|
||||
if (isStarted())
|
||||
{
|
||||
throw new IllegalStateException("Cannot modify configuration after SslContextFactory was started");
|
||||
}
|
||||
throw new IllegalStateException("Cannot modify configuration when "+getState());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -1141,7 +1226,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setEnableCRLDP(boolean enableCRLDP)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_enableCRLDP = enableCRLDP;
|
||||
}
|
||||
|
@ -1161,7 +1246,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setEnableOCSP(boolean enableOCSP)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_enableOCSP = enableOCSP;
|
||||
}
|
||||
|
@ -1181,7 +1266,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setOcspResponderURL(String ocspResponderURL)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_ocspResponderURL = ocspResponderURL;
|
||||
}
|
||||
|
@ -1192,7 +1277,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setKeyStore(KeyStore keyStore)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_keyStore = keyStore;
|
||||
}
|
||||
|
@ -1203,7 +1288,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setTrustStore(KeyStore trustStore)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
_trustStore = trustStore;
|
||||
}
|
||||
|
@ -1214,7 +1299,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setKeyStoreResource(Resource resource)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -1233,7 +1318,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public void setTrustStore(Resource resource)
|
||||
{
|
||||
checkStarted();
|
||||
checkNotStarted();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -1299,4 +1384,83 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
{
|
||||
_sslSessionTimeout = sslSessionTimeout;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SSLServerSocket newSslServerSocket(String host,int port,int backlog) throws IOException
|
||||
{
|
||||
SSLServerSocketFactory factory = _context.getServerSocketFactory();
|
||||
|
||||
SSLServerSocket socket =
|
||||
(SSLServerSocket) (host==null ?
|
||||
factory.createServerSocket(port,backlog):
|
||||
factory.createServerSocket(port,backlog,InetAddress.getByName(host)));
|
||||
|
||||
if (getWantClientAuth())
|
||||
socket.setWantClientAuth(getWantClientAuth());
|
||||
if (getNeedClientAuth())
|
||||
socket.setNeedClientAuth(getNeedClientAuth());
|
||||
|
||||
socket.setEnabledCipherSuites(selectCipherSuites(
|
||||
socket.getEnabledCipherSuites(),
|
||||
socket.getSupportedCipherSuites()));
|
||||
socket.setEnabledProtocols(selectProtocols(socket.getEnabledProtocols(),socket.getSupportedProtocols()));
|
||||
|
||||
return socket;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SSLSocket newSslSocket() throws IOException
|
||||
{
|
||||
SSLSocketFactory factory = _context.getSocketFactory();
|
||||
|
||||
SSLSocket socket = (SSLSocket)factory.createSocket();
|
||||
|
||||
if (getWantClientAuth())
|
||||
socket.setWantClientAuth(getWantClientAuth());
|
||||
if (getNeedClientAuth())
|
||||
socket.setNeedClientAuth(getNeedClientAuth());
|
||||
|
||||
socket.setEnabledCipherSuites(selectCipherSuites(
|
||||
socket.getEnabledCipherSuites(),
|
||||
socket.getSupportedCipherSuites()));
|
||||
socket.setEnabledProtocols(selectProtocols(socket.getEnabledProtocols(),socket.getSupportedProtocols()));
|
||||
|
||||
return socket;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SSLEngine newSslEngine(String host,int port)
|
||||
{
|
||||
SSLEngine sslEngine=isSessionCachingEnabled()
|
||||
?_context.createSSLEngine(host, port)
|
||||
:_context.createSSLEngine();
|
||||
|
||||
customize(sslEngine);
|
||||
return sslEngine;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SSLEngine newSslEngine()
|
||||
{
|
||||
SSLEngine sslEngine=_context.createSSLEngine();
|
||||
customize(sslEngine);
|
||||
return sslEngine;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void customize(SSLEngine sslEngine)
|
||||
{
|
||||
if (getWantClientAuth())
|
||||
sslEngine.setWantClientAuth(getWantClientAuth());
|
||||
if (getNeedClientAuth())
|
||||
sslEngine.setNeedClientAuth(getNeedClientAuth());
|
||||
|
||||
sslEngine.setEnabledCipherSuites(selectCipherSuites(
|
||||
sslEngine.getEnabledCipherSuites(),
|
||||
sslEngine.getSupportedCipherSuites()));
|
||||
|
||||
sslEngine.setEnabledProtocols(selectProtocols(sslEngine.getEnabledProtocols(),sslEngine.getSupportedProtocols()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ public interface EndPoint
|
|||
* The buffer may chose to do a compact before filling.
|
||||
* @return an <code>int</code> value indicating the number of bytes
|
||||
* filled or -1 if EOF is reached.
|
||||
* @throws EofException If input is shutdown or the endpoint is closed.
|
||||
*/
|
||||
int fill(Buffer buffer) throws IOException;
|
||||
|
||||
|
@ -59,6 +60,7 @@ public interface EndPoint
|
|||
*
|
||||
* @param buffer The buffer to flush. This buffers getIndex is updated.
|
||||
* @return the number of bytes written
|
||||
* @throws EofException If the endpoint is closed or output is shutdown.
|
||||
*/
|
||||
int flush(Buffer buffer) throws IOException;
|
||||
|
||||
|
@ -157,7 +159,7 @@ public interface EndPoint
|
|||
/* ------------------------------------------------------------ */
|
||||
/** Flush any buffered output.
|
||||
* May fail to write all data if endpoint is non-blocking
|
||||
* @throws IOException
|
||||
* @throws EofException If the endpoint is closed or output is shutdown.
|
||||
*/
|
||||
public void flush() throws IOException;
|
||||
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
// 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
|
||||
// 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.
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
|
||||
package org.eclipse.jetty.io.bio;
|
||||
|
@ -17,6 +17,7 @@ import java.io.IOException;
|
|||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -34,13 +35,13 @@ public class SocketEndPoint extends StreamEndPoint
|
|||
final Socket _socket;
|
||||
final InetSocketAddress _local;
|
||||
final InetSocketAddress _remote;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
public SocketEndPoint(Socket socket)
|
||||
throws IOException
|
||||
throws IOException
|
||||
{
|
||||
super(socket.getInputStream(),socket.getOutputStream());
|
||||
_socket=socket;
|
||||
|
@ -48,13 +49,13 @@ public class SocketEndPoint extends StreamEndPoint
|
|||
_remote=(InetSocketAddress)_socket.getRemoteSocketAddress();
|
||||
super.setMaxIdleTime(_socket.getSoTimeout());
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
protected SocketEndPoint(Socket socket, int maxIdleTime)
|
||||
throws IOException
|
||||
throws IOException
|
||||
{
|
||||
super(socket.getInputStream(),socket.getOutputStream());
|
||||
_socket=socket;
|
||||
|
@ -63,7 +64,7 @@ public class SocketEndPoint extends StreamEndPoint
|
|||
_socket.setSoTimeout(maxIdleTime>0?maxIdleTime:0);
|
||||
super.setMaxIdleTime(maxIdleTime);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.io.BufferIO#isClosed()
|
||||
|
@ -73,19 +74,19 @@ public class SocketEndPoint extends StreamEndPoint
|
|||
{
|
||||
return super.isOpen() && _socket!=null && !_socket.isClosed();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public boolean isInputShutdown()
|
||||
{
|
||||
return !super.isOpen() || _socket!=null && _socket.isInputShutdown();
|
||||
return !isOpen() || super.isInputShutdown();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public boolean isOutputShutdown()
|
||||
{
|
||||
return !super.isOpen() || _socket!=null && _socket.isOutputShutdown();
|
||||
return !isOpen() || super.isOutputShutdown();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -94,9 +95,13 @@ public class SocketEndPoint extends StreamEndPoint
|
|||
*/
|
||||
@Override
|
||||
public void shutdownOutput() throws IOException
|
||||
{
|
||||
if (!_socket.isClosed() && !_socket.isOutputShutdown())
|
||||
_socket.shutdownOutput();
|
||||
{
|
||||
if (!isOutputShutdown())
|
||||
{
|
||||
super.shutdownOutput();
|
||||
if (!(_socket instanceof SSLSocket))
|
||||
_socket.shutdownOutput();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -106,11 +111,15 @@ public class SocketEndPoint extends StreamEndPoint
|
|||
*/
|
||||
@Override
|
||||
public void shutdownInput() throws IOException
|
||||
{
|
||||
if (!_socket.isClosed() && !_socket.isInputShutdown())
|
||||
_socket.shutdownInput();
|
||||
{
|
||||
if (!isInputShutdown())
|
||||
{
|
||||
super.shutdownInput();
|
||||
if (!(_socket instanceof SSLSocket))
|
||||
_socket.shutdownInput();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.io.BufferIO#close()
|
||||
|
@ -122,10 +131,10 @@ public class SocketEndPoint extends StreamEndPoint
|
|||
_in=null;
|
||||
_out=null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#getLocalAddr()
|
||||
*/
|
||||
@Override
|
||||
|
@ -133,12 +142,12 @@ public class SocketEndPoint extends StreamEndPoint
|
|||
{
|
||||
if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress())
|
||||
return StringUtil.ALL_INTERFACES;
|
||||
|
||||
|
||||
return _local.getAddress().getHostAddress();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#getLocalHost()
|
||||
*/
|
||||
@Override
|
||||
|
@ -146,12 +155,12 @@ public class SocketEndPoint extends StreamEndPoint
|
|||
{
|
||||
if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress())
|
||||
return StringUtil.ALL_INTERFACES;
|
||||
|
||||
|
||||
return _local.getAddress().getCanonicalHostName();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#getLocalPort()
|
||||
*/
|
||||
@Override
|
||||
|
@ -163,7 +172,7 @@ public class SocketEndPoint extends StreamEndPoint
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#getRemoteAddr()
|
||||
*/
|
||||
@Override
|
||||
|
@ -176,7 +185,7 @@ public class SocketEndPoint extends StreamEndPoint
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#getRemoteHost()
|
||||
*/
|
||||
@Override
|
||||
|
@ -188,7 +197,7 @@ public class SocketEndPoint extends StreamEndPoint
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#getRemotePort()
|
||||
*/
|
||||
@Override
|
||||
|
@ -200,7 +209,7 @@ public class SocketEndPoint extends StreamEndPoint
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#getConnection()
|
||||
*/
|
||||
@Override
|
||||
|
@ -237,5 +246,5 @@ public class SocketEndPoint extends StreamEndPoint
|
|||
_socket.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -22,17 +22,13 @@ import java.net.SocketTimeoutException;
|
|||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* To change the template for this generated type comment go to
|
||||
* Window - Preferences - Java - Code Generation - Code and Comments
|
||||
*/
|
||||
public class StreamEndPoint implements EndPoint
|
||||
{
|
||||
InputStream _in;
|
||||
OutputStream _out;
|
||||
int _maxIdleTime;
|
||||
boolean _ishut;
|
||||
boolean _oshut;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -75,23 +71,33 @@ public class StreamEndPoint implements EndPoint
|
|||
}
|
||||
|
||||
public void shutdownOutput() throws IOException
|
||||
{
|
||||
{
|
||||
if (_oshut)
|
||||
return;
|
||||
_oshut = true;
|
||||
if (_out!=null)
|
||||
_out.close();
|
||||
}
|
||||
|
||||
|
||||
public boolean isInputShutdown()
|
||||
{
|
||||
return !isOpen();
|
||||
return _ishut;
|
||||
}
|
||||
|
||||
public void shutdownInput() throws IOException
|
||||
{
|
||||
{
|
||||
if (_ishut)
|
||||
return;
|
||||
_ishut = true;
|
||||
if (_in!=null)
|
||||
_in.close();
|
||||
}
|
||||
|
||||
|
||||
public boolean isOutputShutdown()
|
||||
{
|
||||
return !isOpen();
|
||||
return _oshut;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @see org.eclipse.io.BufferIO#close()
|
||||
*/
|
||||
|
@ -107,35 +113,43 @@ public class StreamEndPoint implements EndPoint
|
|||
|
||||
protected void idleExpired() throws IOException
|
||||
{
|
||||
_in.close();
|
||||
if (_in!=null)
|
||||
_in.close();
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.io.BufferIO#fill(org.eclipse.io.Buffer)
|
||||
*/
|
||||
public int fill(Buffer buffer) throws IOException
|
||||
{
|
||||
// TODO handle null array()
|
||||
if (_in==null)
|
||||
return 0;
|
||||
|
||||
int space=buffer.space();
|
||||
if (space<=0)
|
||||
{
|
||||
if (buffer.hasContent())
|
||||
return 0;
|
||||
throw new IOException("FULL");
|
||||
}
|
||||
int space=buffer.space();
|
||||
if (space<=0)
|
||||
{
|
||||
if (buffer.hasContent())
|
||||
return 0;
|
||||
throw new IOException("FULL");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return buffer.readFrom(_in,space);
|
||||
}
|
||||
catch(SocketTimeoutException e)
|
||||
{
|
||||
idleExpired();
|
||||
return -1;
|
||||
}
|
||||
try
|
||||
{
|
||||
int read=buffer.readFrom(_in, space);
|
||||
if (read<0 && isOpen())
|
||||
{
|
||||
if (!isInputShutdown())
|
||||
shutdownInput();
|
||||
else if (isOutputShutdown())
|
||||
close();
|
||||
}
|
||||
return read;
|
||||
}
|
||||
catch(SocketTimeoutException e)
|
||||
{
|
||||
idleExpired();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
@ -143,7 +157,6 @@ public class StreamEndPoint implements EndPoint
|
|||
*/
|
||||
public int flush(Buffer buffer) throws IOException
|
||||
{
|
||||
// TODO handle null array()
|
||||
if (_out==null)
|
||||
return -1;
|
||||
int length=buffer.length();
|
||||
|
@ -313,13 +326,13 @@ public class StreamEndPoint implements EndPoint
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public int getMaxIdleTime()
|
||||
{
|
||||
return _maxIdleTime;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setMaxIdleTime(int timeMs) throws IOException
|
||||
{
|
||||
|
|
|
@ -109,9 +109,12 @@ public class ChannelEndPoint implements EndPoint
|
|||
if (_channel.isOpen() && _channel instanceof SocketChannel)
|
||||
{
|
||||
Socket socket= ((SocketChannel)_channel).socket();
|
||||
if (!socket.isClosed()&&!socket.isInputShutdown())
|
||||
if (!socket.isClosed())
|
||||
{
|
||||
socket.shutdownInput();
|
||||
if(socket.isOutputShutdown())
|
||||
socket.close();
|
||||
else if (!socket.isInputShutdown())
|
||||
socket.shutdownInput();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,9 +127,12 @@ public class ChannelEndPoint implements EndPoint
|
|||
if (_channel.isOpen() && _channel instanceof SocketChannel)
|
||||
{
|
||||
Socket socket= ((SocketChannel)_channel).socket();
|
||||
if (!socket.isClosed()&&!socket.isOutputShutdown())
|
||||
if (!socket.isClosed())
|
||||
{
|
||||
socket.shutdownOutput();
|
||||
if (socket.isInputShutdown())
|
||||
socket.close();
|
||||
else if (!socket.isOutputShutdown())
|
||||
socket.shutdownOutput();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -160,8 +166,8 @@ public class ChannelEndPoint implements EndPoint
|
|||
{
|
||||
final NIOBuffer nbuf = (NIOBuffer)buf;
|
||||
final ByteBuffer bbuf=nbuf.getByteBuffer();
|
||||
//noinspection SynchronizationOnLocalVariableOrMethodParameter
|
||||
|
||||
//noinspection SynchronizationOnLocalVariableOrMethodParameter
|
||||
try
|
||||
{
|
||||
synchronized(bbuf)
|
||||
|
@ -178,13 +184,17 @@ public class ChannelEndPoint implements EndPoint
|
|||
}
|
||||
}
|
||||
|
||||
if (len<0 && isOpen() && !isInputShutdown())
|
||||
if (len<0 && isOpen())
|
||||
{
|
||||
shutdownInput();
|
||||
if (!isInputShutdown())
|
||||
shutdownInput();
|
||||
else if (isOutputShutdown())
|
||||
_channel.close();
|
||||
}
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
LOG.debug(x);
|
||||
try
|
||||
{
|
||||
close();
|
||||
|
@ -196,7 +206,6 @@ public class ChannelEndPoint implements EndPoint
|
|||
|
||||
if (len>0)
|
||||
throw x;
|
||||
LOG.ignore(x);
|
||||
len=-1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,27 +34,48 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
*/
|
||||
public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPoint, ConnectedEndPoint
|
||||
{
|
||||
public static final Logger __log=Log.getLogger("org.eclipse.jetty.io.nio");
|
||||
public static final Logger LOG=Log.getLogger("org.eclipse.jetty.io.nio");
|
||||
|
||||
private final SelectorManager.SelectSet _selectSet;
|
||||
private final SelectorManager _manager;
|
||||
private SelectionKey _key;
|
||||
private final Runnable _handler = new Runnable()
|
||||
{
|
||||
public void run() { handle(); }
|
||||
};
|
||||
|
||||
/** The desired value for {@link SelectionKey#interestOps()} */
|
||||
private int _interestOps;
|
||||
|
||||
/**
|
||||
* The connection instance is the handler for any IO activity on the endpoint.
|
||||
* There is a different type of connection for HTTP, AJP, WebSocket and
|
||||
* ProxyConnect. The connection may change for an SCEP as it is upgraded
|
||||
* from HTTP to proxy connect or websocket.
|
||||
*/
|
||||
private volatile Connection _connection;
|
||||
|
||||
/** true if a thread has been dispatched to handle this endpoint */
|
||||
private boolean _dispatched = false;
|
||||
|
||||
/** true if a non IO dispatch (eg async resume) is outstanding */
|
||||
private boolean _redispatched = false;
|
||||
|
||||
/** true if the last write operation succeed and wrote all offered bytes */
|
||||
private volatile boolean _writable = true;
|
||||
|
||||
private SelectionKey _key;
|
||||
private int _interestOps;
|
||||
|
||||
/** True if a thread has is blocked in {@link #blockReadable(long)} */
|
||||
private boolean _readBlocked;
|
||||
private boolean _writeBlocked;
|
||||
private boolean _open;
|
||||
private volatile long _idleTimestamp;
|
||||
|
||||
/** True if a thread has is blocked in {@link #blockWritable(long)} */
|
||||
private boolean _writeBlocked;
|
||||
|
||||
/** true if {@link SelectSet#destroyEndPoint(SelectChannelEndPoint)} has not been called */
|
||||
private boolean _open;
|
||||
|
||||
private volatile long _idleTimestamp;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SelectChannelEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key, int maxIdleTime)
|
||||
throws IOException
|
||||
|
@ -90,6 +111,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
|
||||
scheduleIdle();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SelectionKey getSelectionKey()
|
||||
{
|
||||
|
@ -205,7 +227,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
if(!dispatched)
|
||||
{
|
||||
_dispatched = false;
|
||||
__log.warn("Dispatched Failed! "+this+" to "+_manager);
|
||||
LOG.warn("Dispatched Failed! "+this+" to "+_manager);
|
||||
updateKey();
|
||||
}
|
||||
}
|
||||
|
@ -250,7 +272,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
public void checkIdleTimestamp(long now)
|
||||
{
|
||||
long idleTimestamp=_idleTimestamp;
|
||||
if (idleTimestamp!=0 && _maxIdleTime>0 && now>(idleTimestamp+_maxIdleTime))
|
||||
if (!getChannel().isOpen() || idleTimestamp!=0 && _maxIdleTime>0 && now>(idleTimestamp+_maxIdleTime))
|
||||
idleExpired();
|
||||
}
|
||||
|
||||
|
@ -260,6 +282,15 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
_connection.idleExpired();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return True if the endpoint has produced/consumed bytes itself (non application data).
|
||||
*/
|
||||
public boolean isProgressing()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
*/
|
||||
|
@ -340,7 +371,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
__log.warn(e);
|
||||
LOG.warn(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -385,7 +416,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
__log.warn(e);
|
||||
LOG.warn(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -398,7 +429,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
catch(Throwable e)
|
||||
{
|
||||
// TODO remove this if it finds nothing
|
||||
__log.warn(e);
|
||||
LOG.warn(e);
|
||||
if (e instanceof RuntimeException)
|
||||
throw (RuntimeException)e;
|
||||
if (e instanceof Error)
|
||||
|
@ -414,10 +445,20 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* short cut for busyselectChannelServerTest */
|
||||
public void clearWritable()
|
||||
{
|
||||
_writable=false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void scheduleWrite()
|
||||
{
|
||||
if (_writable==true)
|
||||
LOG.debug("Required scheduleWrite {}",this);
|
||||
|
||||
_writable=false;
|
||||
updateKey();
|
||||
}
|
||||
|
@ -445,7 +486,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
catch(Exception e)
|
||||
{
|
||||
_key=null;
|
||||
__log.ignore(e);
|
||||
LOG.ignore(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -483,7 +524,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
__log.ignore(e);
|
||||
LOG.ignore(e);
|
||||
if (_key!=null && _key.isValid())
|
||||
{
|
||||
_key.cancel();
|
||||
|
@ -520,9 +561,9 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
cancelIdle();
|
||||
if (_open)
|
||||
{
|
||||
_open=false;
|
||||
_selectSet.destroyEndPoint(this);
|
||||
}
|
||||
_open=false;
|
||||
_key = null;
|
||||
}
|
||||
}
|
||||
|
@ -545,7 +586,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
final Connection next = _connection.handle();
|
||||
if (next!=_connection)
|
||||
{
|
||||
__log.debug("{} replaced {}",next,_connection);
|
||||
LOG.debug("{} replaced {}",next,_connection);
|
||||
_connection=next;
|
||||
continue;
|
||||
}
|
||||
|
@ -554,26 +595,26 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
}
|
||||
catch (ClosedChannelException e)
|
||||
{
|
||||
__log.ignore(e);
|
||||
LOG.ignore(e);
|
||||
}
|
||||
catch (EofException e)
|
||||
{
|
||||
__log.debug("EOF", e);
|
||||
try{close();}
|
||||
catch(IOException e2){__log.ignore(e2);}
|
||||
LOG.debug("EOF", e);
|
||||
try{getChannel().close();}
|
||||
catch(IOException e2){LOG.ignore(e2);}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
__log.warn(e.toString());
|
||||
__log.debug(e);
|
||||
try{close();}
|
||||
catch(IOException e2){__log.ignore(e2);}
|
||||
LOG.warn(e.toString());
|
||||
LOG.debug(e);
|
||||
try{getChannel().close();}
|
||||
catch(IOException e2){LOG.ignore(e2);}
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
__log.warn("handle failed", e);
|
||||
try{close();}
|
||||
catch(IOException e2){__log.ignore(e2);}
|
||||
LOG.warn("handle failed", e);
|
||||
try{getChannel().close();}
|
||||
catch(IOException e2){LOG.ignore(e2);}
|
||||
}
|
||||
dispatched=!undispatch();
|
||||
}
|
||||
|
@ -585,7 +626,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
dispatched=!undispatch();
|
||||
while (dispatched)
|
||||
{
|
||||
__log.warn("SCEP.run() finally DISPATCHED");
|
||||
LOG.warn("SCEP.run() finally DISPATCHED");
|
||||
dispatched=!undispatch();
|
||||
}
|
||||
}
|
||||
|
@ -605,7 +646,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
__log.ignore(e);
|
||||
LOG.ignore(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -620,7 +661,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
synchronized(this)
|
||||
{
|
||||
return "SCEP@" + hashCode() + _channel+
|
||||
"[d=" + _dispatched + ",io=" + _interestOps+
|
||||
"[o="+isOpen()+" d=" + _dispatched + ",io=" + _interestOps+
|
||||
",w=" + _writable + ",rb=" + _readBlocked + ",wb=" + _writeBlocked + "]";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
// 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
|
||||
// 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.
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
|
||||
package org.eclipse.jetty.io.nio;
|
||||
|
@ -30,7 +30,6 @@ import java.util.concurrent.ConcurrentMap;
|
|||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
import org.eclipse.jetty.io.ConnectedEndPoint;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
|
@ -49,21 +48,16 @@ import org.eclipse.jetty.util.thread.Timeout.Task;
|
|||
* The Selector Manager manages and number of SelectSets to allow
|
||||
* NIO scheduling to scale to large numbers of connections.
|
||||
* <p>
|
||||
* This class works around a number of know JVM bugs. For details
|
||||
* see http://wiki.eclipse.org/Jetty/Feature/JVM_NIO_Bug
|
||||
*/
|
||||
public abstract class SelectorManager extends AbstractLifeCycle implements Dumpable
|
||||
{
|
||||
public static final Logger LOG=Log.getLogger("org.eclipse.jetty.io.nio");
|
||||
|
||||
// TODO Tune these by approx system speed.
|
||||
private static final int __JVMBUG_THRESHHOLD=Integer.getInteger("org.eclipse.jetty.io.nio.JVMBUG_THRESHHOLD",0).intValue();
|
||||
|
||||
private static final int __MONITOR_PERIOD=Integer.getInteger("org.eclipse.jetty.io.nio.MONITOR_PERIOD",1000).intValue();
|
||||
private static final int __MAX_SELECTS=Integer.getInteger("org.eclipse.jetty.io.nio.MAX_SELECTS",25000).intValue();
|
||||
private static final int __BUSY_PAUSE=Integer.getInteger("org.eclipse.jetty.io.nio.BUSY_PAUSE",50).intValue();
|
||||
private static final int __BUSY_KEY=Integer.getInteger("org.eclipse.jetty.io.nio.BUSY_KEY",-1).intValue();
|
||||
private static final int __IDLE_TICK=Integer.getInteger("org.eclipse.jetty.io.nio.IDLE_TICK",400).intValue();
|
||||
|
||||
|
||||
private int _maxIdleTime;
|
||||
private int _lowResourcesMaxIdleTime;
|
||||
private long _lowResourcesConnections;
|
||||
|
@ -72,7 +66,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
private volatile int _set;
|
||||
private boolean _deferringInterestedOps0=true;
|
||||
private int _selectorPriorityDelta=0;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param maxIdleTime The maximum period in milli seconds that a connection may be idle before it is closed.
|
||||
|
@ -82,18 +76,18 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
_maxIdleTime=(int)maxIdleTime;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param selectSets number of select sets to create
|
||||
*/
|
||||
public void setSelectSets(int selectSets)
|
||||
{
|
||||
long lrc = _lowResourcesConnections * _selectSets;
|
||||
long lrc = _lowResourcesConnections * _selectSets;
|
||||
_selectSets=selectSets;
|
||||
_lowResourcesConnections=lrc/_selectSets;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return the max idle time
|
||||
|
@ -102,7 +96,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
return _maxIdleTime;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return the number of select sets in use
|
||||
|
@ -114,14 +108,14 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param i
|
||||
* @param i
|
||||
* @return The select set
|
||||
*/
|
||||
public SelectSet getSelectSet(int i)
|
||||
{
|
||||
return _selectSet[i];
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Register a channel
|
||||
* @param channel
|
||||
|
@ -132,8 +126,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
// The ++ increment here is not atomic, but it does not matter.
|
||||
// so long as the value changes sometimes, then connections will
|
||||
// be distributed over the available sets.
|
||||
|
||||
int s=_set++;
|
||||
|
||||
int s=_set++;
|
||||
s=s%_selectSets;
|
||||
SelectSet[] sets=_selectSet;
|
||||
if (sets!=null)
|
||||
|
@ -144,7 +138,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Register a channel
|
||||
* @param channel
|
||||
|
@ -154,8 +148,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
// The ++ increment here is not atomic, but it does not matter.
|
||||
// so long as the value changes sometimes, then connections will
|
||||
// be distributed over the available sets.
|
||||
|
||||
int s=_set++;
|
||||
|
||||
int s=_set++;
|
||||
s=s%_selectSets;
|
||||
SelectSet[] sets=_selectSet;
|
||||
if (sets!=null)
|
||||
|
@ -165,14 +159,14 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
set.wakeup();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Register a {@link ServerSocketChannel}
|
||||
* @param acceptChannel
|
||||
*/
|
||||
public void register(ServerSocketChannel acceptChannel)
|
||||
{
|
||||
int s=_set++;
|
||||
int s=_set++;
|
||||
s=s%_selectSets;
|
||||
SelectSet set=_selectSet[s];
|
||||
set.addChange(acceptChannel);
|
||||
|
@ -196,8 +190,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
_selectorPriorityDelta=delta;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return the lowResourcesConnections
|
||||
|
@ -237,7 +231,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
_lowResourcesMaxIdleTime=(int)lowResourcesMaxIdleTime;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public abstract boolean dispatch(Runnable task);
|
||||
|
@ -254,7 +248,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
_selectSet[i]= new SelectSet(i);
|
||||
|
||||
super.doStart();
|
||||
|
||||
|
||||
// start a thread to Select
|
||||
for (int i=0;i<getSelectSets();i++)
|
||||
{
|
||||
|
@ -271,7 +265,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
if (sets==null)
|
||||
return;
|
||||
SelectSet set=sets[id];
|
||||
|
||||
|
||||
Thread.currentThread().setName(name+" Selector"+id);
|
||||
if (getSelectorPriorityDelta()!=0)
|
||||
Thread.currentThread().setPriority(Thread.currentThread().getPriority()+getSelectorPriorityDelta());
|
||||
|
@ -362,7 +356,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
LOG.warn(ex+","+channel+","+attachment);
|
||||
LOG.debug(ex);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String dump()
|
||||
{
|
||||
|
@ -375,8 +369,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
out.append(String.valueOf(this)).append("\n");
|
||||
AggregateLifeCycle.dump(out,indent,TypeUtil.asList(_selectSet));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
|
@ -384,27 +378,19 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
private final int _setID;
|
||||
private final Timeout _timeout;
|
||||
|
||||
|
||||
private final ConcurrentLinkedQueue<Object> _changes = new ConcurrentLinkedQueue<Object>();
|
||||
|
||||
|
||||
private volatile Selector _selector;
|
||||
|
||||
|
||||
private volatile Thread _selecting;
|
||||
private int _jvmBug;
|
||||
private int _selects;
|
||||
private long _monitorStart;
|
||||
private int _busySelects;
|
||||
private long _monitorNext;
|
||||
private boolean _pausing;
|
||||
private SelectionKey _busyKey;
|
||||
private int _busyKeyCount;
|
||||
private long _log;
|
||||
private int _paused;
|
||||
private int _jvmFix0;
|
||||
private int _jvmFix1;
|
||||
private int _jvmFix2;
|
||||
private boolean _paused;
|
||||
private volatile long _idleTick;
|
||||
private ConcurrentMap<SelectChannelEndPoint,Object> _endPoints = new ConcurrentHashMap<SelectChannelEndPoint, Object>();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
SelectSet(int acceptorID) throws Exception
|
||||
{
|
||||
|
@ -416,11 +402,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
|
||||
// create a selector;
|
||||
_selector = Selector.open();
|
||||
_monitorStart=System.currentTimeMillis();
|
||||
_monitorNext=_monitorStart+__MONITOR_PERIOD;
|
||||
_log=_monitorStart+60000;
|
||||
_monitorNext=System.currentTimeMillis()+__MONITOR_PERIOD;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void addChange(Object change)
|
||||
{
|
||||
|
@ -429,7 +413,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void addChange(SelectableChannel channel, Object att)
|
||||
{
|
||||
{
|
||||
if (att==null)
|
||||
addChange(channel);
|
||||
else if (att instanceof EndPoint)
|
||||
|
@ -437,11 +421,11 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
else
|
||||
addChange(new ChannelAndAttachment(channel,att));
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Select and dispatch tasks found from changes and the selector.
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void doSelect() throws IOException
|
||||
|
@ -450,6 +434,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
_selecting=Thread.currentThread();
|
||||
final Selector selector=_selector;
|
||||
// Stopped concurrently ?
|
||||
if (selector == null)
|
||||
return;
|
||||
|
||||
// Make any key changes required
|
||||
Object change;
|
||||
|
@ -458,7 +445,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
Channel ch=null;
|
||||
SelectionKey key=null;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
if (change instanceof EndPoint)
|
||||
|
@ -475,7 +462,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
final SelectableChannel channel=asc._channel;
|
||||
ch=channel;
|
||||
final Object att = asc._attachment;
|
||||
|
||||
|
||||
if ((channel instanceof SocketChannel) && ((SocketChannel)channel).isConnected())
|
||||
{
|
||||
key = channel.register(selector,SelectionKey.OP_READ,att);
|
||||
|
@ -517,7 +504,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
if (e instanceof ThreadDeath)
|
||||
throw (ThreadDeath)e;
|
||||
|
||||
|
||||
if (isRunning())
|
||||
LOG.warn(e);
|
||||
else
|
||||
|
@ -525,7 +512,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
|
||||
try
|
||||
{
|
||||
ch.close();
|
||||
if (ch!=null)
|
||||
ch.close();
|
||||
}
|
||||
catch(IOException e2)
|
||||
{
|
||||
|
@ -537,10 +525,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
|
||||
// Do and instant select to see if any connections can be handled.
|
||||
int selected=selector.selectNow();
|
||||
_selects++;
|
||||
|
||||
long now=System.currentTimeMillis();
|
||||
|
||||
|
||||
// if no immediate things to do
|
||||
if (selected==0 && selector.selectedKeys().isEmpty())
|
||||
{
|
||||
|
@ -562,7 +549,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
_timeout.setNow(now);
|
||||
long to_next_timeout=_timeout.getTimeToNext();
|
||||
|
||||
long wait = _changes.size()==0?__IDLE_TICK:0L;
|
||||
long wait = _changes.size()==0?__IDLE_TICK:0L;
|
||||
if (wait > 0 && to_next_timeout >= 0 && wait > to_next_timeout)
|
||||
wait = to_next_timeout;
|
||||
|
||||
|
@ -571,24 +558,48 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
long before=now;
|
||||
selected=selector.select(wait);
|
||||
_selects++;
|
||||
now = System.currentTimeMillis();
|
||||
_timeout.setNow(now);
|
||||
|
||||
if (__JVMBUG_THRESHHOLD>0)
|
||||
checkJvmBugs(before, now, wait, selected);
|
||||
|
||||
// If we are monitoring for busy selector
|
||||
// and this select did not wait more than 1ms
|
||||
if (__MONITOR_PERIOD>0 && now-before <=1)
|
||||
{
|
||||
// count this as a busy select and if there have been too many this monitor cycle
|
||||
if (++_busySelects>__MAX_SELECTS)
|
||||
{
|
||||
// Start injecting pauses
|
||||
_pausing=true;
|
||||
|
||||
// if this is the first pause
|
||||
if (!_paused)
|
||||
{
|
||||
// Log and dump some status
|
||||
_paused=true;
|
||||
LOG.warn("Selector {} is too busy, pausing!",this);
|
||||
final SelectSet set = this;
|
||||
SelectorManager.this.dispatch(
|
||||
new Runnable(){
|
||||
public void run()
|
||||
{
|
||||
System.err.println(set+":\n"+set.dump());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// have we been destroyed while sleeping
|
||||
if (_selector==null || !selector.isOpen())
|
||||
return;
|
||||
|
||||
// Look for things to do
|
||||
for (SelectionKey key: selector.selectedKeys())
|
||||
{
|
||||
{
|
||||
SocketChannel channel=null;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
if (!key.isValid())
|
||||
|
@ -641,7 +652,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
SelectChannelEndPoint endpoint = createEndPoint(channel,key);
|
||||
key.attach(endpoint);
|
||||
if (key.isReadable())
|
||||
endpoint.schedule();
|
||||
endpoint.schedule();
|
||||
}
|
||||
key = null;
|
||||
}
|
||||
|
@ -665,15 +676,15 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
LOG.debug(e2);
|
||||
}
|
||||
|
||||
|
||||
if (key != null && !(key.channel() instanceof ServerSocketChannel) && key.isValid())
|
||||
key.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Everything always handled
|
||||
selector.selectedKeys().clear();
|
||||
|
||||
|
||||
now=System.currentTimeMillis();
|
||||
_timeout.setNow(now);
|
||||
Task task = _timeout.expired();
|
||||
|
@ -688,11 +699,11 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
if (now-_idleTick>__IDLE_TICK)
|
||||
{
|
||||
_idleTick=now;
|
||||
|
||||
|
||||
final long idle_now=((_lowResourcesConnections>0 && selector.keys().size()>_lowResourcesConnections))
|
||||
?(now+_maxIdleTime-_lowResourcesMaxIdleTime)
|
||||
:now;
|
||||
|
||||
|
||||
dispatch(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
|
@ -703,6 +714,16 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Reset busy select monitor counts
|
||||
if (__MONITOR_PERIOD>0 && now>_monitorNext)
|
||||
{
|
||||
_busySelects=0;
|
||||
_pausing=false;
|
||||
_monitorNext=now+__MONITOR_PERIOD;
|
||||
|
||||
}
|
||||
}
|
||||
catch (ClosedSelectorException e)
|
||||
|
@ -721,130 +742,10 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
_selecting=null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void checkJvmBugs(long before, long now, long wait, int selected)
|
||||
throws IOException
|
||||
{
|
||||
Selector selector = _selector;
|
||||
if (selector==null)
|
||||
return;
|
||||
|
||||
// Look for JVM bugs over a monitor period.
|
||||
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6403933
|
||||
// http://bugs.sun.com/view_bug.do?bug_id=6693490
|
||||
if (now>_monitorNext)
|
||||
{
|
||||
_selects=(int)(_selects*__MONITOR_PERIOD/(now-_monitorStart));
|
||||
_pausing=_selects>__MAX_SELECTS;
|
||||
if (_pausing)
|
||||
_paused++;
|
||||
|
||||
_selects=0;
|
||||
_jvmBug=0;
|
||||
_monitorStart=now;
|
||||
_monitorNext=now+__MONITOR_PERIOD;
|
||||
}
|
||||
|
||||
if (now>_log)
|
||||
{
|
||||
if (_paused>0)
|
||||
LOG.debug(this+" Busy selector - injecting delay "+_paused+" times");
|
||||
|
||||
if (_jvmFix2>0)
|
||||
LOG.debug(this+" JVM BUG(s) - injecting delay"+_jvmFix2+" times");
|
||||
|
||||
if (_jvmFix1>0)
|
||||
LOG.debug(this+" JVM BUG(s) - recreating selector "+_jvmFix1+" times, cancelled keys "+_jvmFix0+" times");
|
||||
|
||||
else if(LOG.isDebugEnabled() && _jvmFix0>0)
|
||||
LOG.debug(this+" JVM BUG(s) - cancelled keys "+_jvmFix0+" times");
|
||||
_paused=0;
|
||||
_jvmFix2=0;
|
||||
_jvmFix1=0;
|
||||
_jvmFix0=0;
|
||||
_log=now+60000;
|
||||
}
|
||||
|
||||
// If we see signature of possible JVM bug, increment count.
|
||||
if (selected==0 && wait>10 && (now-before)<(wait/2))
|
||||
{
|
||||
// Increment bug count and try a work around
|
||||
_jvmBug++;
|
||||
if (_jvmBug>(__JVMBUG_THRESHHOLD))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_jvmBug==__JVMBUG_THRESHHOLD+1)
|
||||
_jvmFix2++;
|
||||
|
||||
Thread.sleep(__BUSY_PAUSE); // pause to avoid busy loop
|
||||
}
|
||||
catch(InterruptedException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
}
|
||||
else if (_jvmBug==__JVMBUG_THRESHHOLD)
|
||||
{
|
||||
renewSelector();
|
||||
}
|
||||
else if (_jvmBug%32==31) // heuristic attempt to cancel key 31,63,95,... loops
|
||||
{
|
||||
// Cancel keys with 0 interested ops
|
||||
int cancelled=0;
|
||||
for (SelectionKey k: selector.keys())
|
||||
{
|
||||
if (k.isValid()&&k.interestOps()==0)
|
||||
{
|
||||
k.cancel();
|
||||
cancelled++;
|
||||
}
|
||||
}
|
||||
if (cancelled>0)
|
||||
_jvmFix0++;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (__BUSY_KEY>0 && selected==1 && _selects>__MAX_SELECTS)
|
||||
{
|
||||
// Look for busy key
|
||||
SelectionKey busy = selector.selectedKeys().iterator().next();
|
||||
if (busy==_busyKey)
|
||||
{
|
||||
if (++_busyKeyCount>__BUSY_KEY && !(busy.channel() instanceof ServerSocketChannel))
|
||||
{
|
||||
final SelectChannelEndPoint endpoint = (SelectChannelEndPoint)busy.attachment();
|
||||
LOG.warn("Busy Key "+busy.channel()+" "+endpoint);
|
||||
busy.cancel();
|
||||
if (endpoint!=null)
|
||||
{
|
||||
dispatch(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
endpoint.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
_busyKeyCount=0;
|
||||
_busyKey=busy;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void renewSelector()
|
||||
private void renewSelector()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -876,7 +777,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
throw new RuntimeException("recreating selector",e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SelectorManager getManager()
|
||||
{
|
||||
|
@ -891,9 +792,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param task The task to timeout. If it implements Runnable, then
|
||||
* @param task The task to timeout. If it implements Runnable, then
|
||||
* expired will be called from a dispatched thread.
|
||||
*
|
||||
*
|
||||
* @param timeoutMs
|
||||
*/
|
||||
public void scheduleTimeout(Timeout.Task task, long timeoutMs)
|
||||
|
@ -902,7 +803,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
throw new IllegalArgumentException("!Runnable");
|
||||
_timeout.schedule(task, timeoutMs);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void cancelTimeout(Timeout.Task task)
|
||||
{
|
||||
|
@ -927,23 +828,24 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
renewSelector();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
renewSelector();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private SelectChannelEndPoint createEndPoint(SocketChannel channel, SelectionKey sKey) throws IOException
|
||||
{
|
||||
SelectChannelEndPoint endp = newEndPoint(channel,this,sKey);
|
||||
endPointOpened(endp);
|
||||
endPointOpened(endp);
|
||||
_endPoints.put(endp,this);
|
||||
return endp;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void destroyEndPoint(SelectChannelEndPoint endp)
|
||||
{
|
||||
LOG.debug("destroyEndPoint {}",endp);
|
||||
_endPoints.remove(endp);
|
||||
endPointClosed(endp);
|
||||
}
|
||||
|
@ -953,11 +855,11 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
return _selector;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
void stop() throws Exception
|
||||
{
|
||||
// Spin for a while waiting for selector to complete
|
||||
// Spin for a while waiting for selector to complete
|
||||
// to avoid unneccessary closed channel exceptions
|
||||
try
|
||||
{
|
||||
|
@ -994,8 +896,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
_timeout.cancelAll();
|
||||
try
|
||||
{
|
||||
|
@ -1006,7 +908,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
catch (IOException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
}
|
||||
_selector=null;
|
||||
}
|
||||
}
|
||||
|
@ -1021,9 +923,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
out.append(String.valueOf(this)).append(" id=").append(String.valueOf(_setID)).append("\n");
|
||||
|
||||
|
||||
Thread selecting = _selecting;
|
||||
|
||||
|
||||
Object where = "not selecting";
|
||||
StackTraceElement[] trace =selecting==null?null:selecting.getStackTrace();
|
||||
if (trace!=null)
|
||||
|
@ -1037,28 +939,32 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
}
|
||||
|
||||
Selector selector=_selector;
|
||||
final ArrayList<Object> dump = new ArrayList<Object>(selector.keys().size()*2);
|
||||
dump.add(where);
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
addChange(new Runnable(){
|
||||
public void run()
|
||||
if (selector!=null)
|
||||
{
|
||||
final ArrayList<Object> dump = new ArrayList<Object>(selector.keys().size()*2);
|
||||
dump.add(where);
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
addChange(new ChangeTask()
|
||||
{
|
||||
dumpKeyState(dump);
|
||||
latch.countDown();
|
||||
public void run()
|
||||
{
|
||||
dumpKeyState(dump);
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
latch.await(5,TimeUnit.SECONDS);
|
||||
}
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
latch.await(5,TimeUnit.SECONDS);
|
||||
catch(InterruptedException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
AggregateLifeCycle.dump(out,indent,dump);
|
||||
}
|
||||
catch(InterruptedException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
AggregateLifeCycle.dump(out,indent,dump);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -1081,7 +987,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
final SelectableChannel _channel;
|
||||
final Object _attachment;
|
||||
|
||||
|
||||
public ChannelAndAttachment(SelectableChannel channel, Object attachment)
|
||||
{
|
||||
super();
|
||||
|
@ -1101,12 +1007,12 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
_deferringInterestedOps0 = deferringInterestedOps0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
private interface ChangeTask extends Runnable
|
||||
{}
|
||||
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -14,9 +14,15 @@
|
|||
package org.eclipse.jetty.io;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.Reader;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.junit.Test;
|
||||
|
@ -42,4 +48,88 @@ public class IOTest
|
|||
out.toString(),
|
||||
"The quick brown fox jumped over the lazy dog");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHalfCloses() throws Exception
|
||||
{
|
||||
ServerSocket connector = new ServerSocket(0);
|
||||
|
||||
Socket client = new Socket("localhost",connector.getLocalPort());
|
||||
System.err.println(client);
|
||||
Socket server = connector.accept();
|
||||
System.err.println(server);
|
||||
|
||||
// we can write both ways
|
||||
client.getOutputStream().write(1);
|
||||
assertEquals(1,server.getInputStream().read());
|
||||
server.getOutputStream().write(1);
|
||||
assertEquals(1,client.getInputStream().read());
|
||||
|
||||
// shutdown output results in read -1
|
||||
client.shutdownOutput();
|
||||
assertEquals(-1,server.getInputStream().read());
|
||||
|
||||
// Even though EOF has been read, the server input is not seen as shutdown
|
||||
assertFalse(server.isInputShutdown());
|
||||
|
||||
// and we can read -1 again
|
||||
assertEquals(-1,server.getInputStream().read());
|
||||
|
||||
// but cannot write
|
||||
try { client.getOutputStream().write(1); assertTrue(false); } catch (SocketException e) {}
|
||||
|
||||
// but can still write in opposite direction.
|
||||
server.getOutputStream().write(1);
|
||||
assertEquals(1,client.getInputStream().read());
|
||||
|
||||
|
||||
// server can shutdown input to match the shutdown out of client
|
||||
server.shutdownInput();
|
||||
|
||||
// now we EOF instead of reading -1
|
||||
try { server.getInputStream().read(); assertTrue(false); } catch (SocketException e) {}
|
||||
|
||||
|
||||
// but can still write in opposite direction.
|
||||
server.getOutputStream().write(1);
|
||||
assertEquals(1,client.getInputStream().read());
|
||||
|
||||
// client can shutdown input
|
||||
client.shutdownInput();
|
||||
|
||||
// now we EOF instead of reading -1
|
||||
try { client.getInputStream().read(); assertTrue(false); } catch (SocketException e) {}
|
||||
|
||||
// But we can still write at the server (data which will never be read)
|
||||
server.getOutputStream().write(1);
|
||||
|
||||
// and the server output is not shutdown
|
||||
assertFalse( server.isOutputShutdown() );
|
||||
|
||||
// until we explictly shut it down
|
||||
server.shutdownOutput();
|
||||
|
||||
// and now we can't write
|
||||
try { server.getOutputStream().write(1); assertTrue(false); } catch (SocketException e) {}
|
||||
|
||||
// but the sockets are still open
|
||||
assertFalse(client.isClosed());
|
||||
assertFalse(server.isClosed());
|
||||
|
||||
// but if we close one end
|
||||
client.close();
|
||||
|
||||
// it is seen as closed.
|
||||
assertTrue(client.isClosed());
|
||||
|
||||
// but not the other end
|
||||
assertFalse(server.isClosed());
|
||||
|
||||
// which has to be closed explictly
|
||||
server.close();
|
||||
assertTrue(server.isClosed());
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2011 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.jndi;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.naming.Binding;
|
||||
import javax.naming.NamingEnumeration;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
/** BindingEnumeration
|
||||
* <p>Implementation of NamingEnumeration
|
||||
*
|
||||
* <p><h4>Notes</h4>
|
||||
* <p>Used to return results of Context.listBindings();
|
||||
*
|
||||
* <p><h4>Usage</h4>
|
||||
*
|
||||
*/
|
||||
public class BindingEnumeration implements NamingEnumeration<Binding>
|
||||
{
|
||||
Iterator<Binding> _delegate;
|
||||
|
||||
public BindingEnumeration (Iterator<Binding> e)
|
||||
{
|
||||
_delegate = e;
|
||||
}
|
||||
|
||||
public void close()
|
||||
throws NamingException
|
||||
{
|
||||
}
|
||||
|
||||
public boolean hasMore ()
|
||||
throws NamingException
|
||||
{
|
||||
return _delegate.hasNext();
|
||||
}
|
||||
|
||||
public Binding next()
|
||||
throws NamingException
|
||||
{
|
||||
Binding b = (Binding)_delegate.next();
|
||||
return new Binding (b.getName(), b.getClassName(), b.getObject(), true);
|
||||
}
|
||||
|
||||
public boolean hasMoreElements()
|
||||
{
|
||||
return _delegate.hasNext();
|
||||
}
|
||||
|
||||
public Binding nextElement()
|
||||
{
|
||||
Binding b = (Binding)_delegate.next();
|
||||
return new Binding (b.getName(), b.getClassName(), b.getObject(),true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2011 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.jndi;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.naming.Binding;
|
||||
import javax.naming.NameClassPair;
|
||||
import javax.naming.NamingEnumeration;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
/** NameEnumeration
|
||||
* <p>Implementation of NamingEnumeration interface.
|
||||
*
|
||||
* <p><h4>Notes</h4>
|
||||
* <p>Used for returning results of Context.list();
|
||||
*
|
||||
* <p><h4>Usage</h4>
|
||||
*
|
||||
*/
|
||||
public class NameEnumeration implements NamingEnumeration<NameClassPair>
|
||||
{
|
||||
Iterator<Binding> _delegate;
|
||||
|
||||
public NameEnumeration (Iterator<Binding> e)
|
||||
{
|
||||
_delegate = e;
|
||||
}
|
||||
|
||||
public void close()
|
||||
throws NamingException
|
||||
{
|
||||
}
|
||||
|
||||
public boolean hasMore ()
|
||||
throws NamingException
|
||||
{
|
||||
return _delegate.hasNext();
|
||||
}
|
||||
|
||||
public NameClassPair next()
|
||||
throws NamingException
|
||||
{
|
||||
Binding b = _delegate.next();
|
||||
return new NameClassPair(b.getName(),b.getClassName(),true);
|
||||
}
|
||||
|
||||
public boolean hasMoreElements()
|
||||
{
|
||||
return _delegate.hasNext();
|
||||
}
|
||||
|
||||
public NameClassPair nextElement()
|
||||
{
|
||||
Binding b = _delegate.next();
|
||||
return new NameClassPair(b.getName(),b.getClassName(),true);
|
||||
}
|
||||
}
|
|
@ -20,7 +20,6 @@ import java.util.Collection;
|
|||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -31,7 +30,6 @@ import javax.naming.InitialContext;
|
|||
import javax.naming.LinkRef;
|
||||
import javax.naming.Name;
|
||||
import javax.naming.NameAlreadyBoundException;
|
||||
import javax.naming.NameClassPair;
|
||||
import javax.naming.NameNotFoundException;
|
||||
import javax.naming.NameParser;
|
||||
import javax.naming.NamingEnumeration;
|
||||
|
@ -53,17 +51,8 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
* <p><h4>Notes</h4>
|
||||
* <p>All Names are expected to be Compound, not Composite.
|
||||
*
|
||||
* <p><h4>Usage</h4>
|
||||
* <pre>
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* </pre>
|
||||
*
|
||||
* @see
|
||||
*
|
||||
*
|
||||
* @version 1.0
|
||||
*/
|
||||
public class NamingContext implements Context, Cloneable, Dumpable
|
||||
{
|
||||
private final static Logger __log=NamingUtil.__log;
|
||||
|
@ -101,123 +90,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
|||
void unbind(NamingContext ctx, Binding binding);
|
||||
}
|
||||
|
||||
/*------------------------------------------------*/
|
||||
/** NameEnumeration
|
||||
* <p>Implementation of NamingEnumeration interface.
|
||||
*
|
||||
* <p><h4>Notes</h4>
|
||||
* <p>Used for returning results of Context.list();
|
||||
*
|
||||
* <p><h4>Usage</h4>
|
||||
* <pre>
|
||||
*/
|
||||
/*
|
||||
* </pre>
|
||||
*
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
public class NameEnumeration implements NamingEnumeration<NameClassPair>
|
||||
{
|
||||
Iterator<Binding> _delegate;
|
||||
|
||||
public NameEnumeration (Iterator<Binding> e)
|
||||
{
|
||||
_delegate = e;
|
||||
}
|
||||
|
||||
public void close()
|
||||
throws NamingException
|
||||
{
|
||||
}
|
||||
|
||||
public boolean hasMore ()
|
||||
throws NamingException
|
||||
{
|
||||
return _delegate.hasNext();
|
||||
}
|
||||
|
||||
public NameClassPair next()
|
||||
throws NamingException
|
||||
{
|
||||
Binding b = _delegate.next();
|
||||
return new NameClassPair(b.getName(),b.getClassName(),true);
|
||||
}
|
||||
|
||||
public boolean hasMoreElements()
|
||||
{
|
||||
return _delegate.hasNext();
|
||||
}
|
||||
|
||||
public NameClassPair nextElement()
|
||||
{
|
||||
Binding b = _delegate.next();
|
||||
return new NameClassPair(b.getName(),b.getClassName(),true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*------------------------------------------------*/
|
||||
/** BindingEnumeration
|
||||
* <p>Implementation of NamingEnumeration
|
||||
*
|
||||
* <p><h4>Notes</h4>
|
||||
* <p>Used to return results of Context.listBindings();
|
||||
*
|
||||
* <p><h4>Usage</h4>
|
||||
* <pre>
|
||||
*/
|
||||
/*
|
||||
* </pre>
|
||||
*
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
public class BindingEnumeration implements NamingEnumeration<Binding>
|
||||
{
|
||||
Iterator<Binding> _delegate;
|
||||
|
||||
public BindingEnumeration (Iterator<Binding> e)
|
||||
{
|
||||
_delegate = e;
|
||||
}
|
||||
|
||||
public void close()
|
||||
throws NamingException
|
||||
{
|
||||
}
|
||||
|
||||
public boolean hasMore ()
|
||||
throws NamingException
|
||||
{
|
||||
return _delegate.hasNext();
|
||||
}
|
||||
|
||||
public Binding next()
|
||||
throws NamingException
|
||||
{
|
||||
Binding b = (Binding)_delegate.next();
|
||||
return new Binding (b.getName(), b.getClassName(), b.getObject(), true);
|
||||
}
|
||||
|
||||
public boolean hasMoreElements()
|
||||
{
|
||||
return _delegate.hasNext();
|
||||
}
|
||||
|
||||
public Binding nextElement()
|
||||
{
|
||||
Binding b = (Binding)_delegate.next();
|
||||
return new Binding (b.getName(), b.getClassName(), b.getObject(),true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*------------------------------------------------*/
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -240,26 +112,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
|||
}
|
||||
|
||||
|
||||
/*------------------------------------------------*/
|
||||
/**
|
||||
* Creates a new <code>NamingContext</code> instance.
|
||||
*
|
||||
* @param env a <code>Hashtable</code> value
|
||||
*/
|
||||
public NamingContext (Hashtable<String,Object> env)
|
||||
{
|
||||
if (env != null)
|
||||
_env.putAll(env);
|
||||
}
|
||||
|
||||
/*------------------------------------------------*/
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
*/
|
||||
public NamingContext ()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------*/
|
||||
|
@ -312,8 +164,24 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
|||
_parser = parser;
|
||||
}
|
||||
|
||||
|
||||
public void setEnv (Hashtable<String,Object> env)
|
||||
{
|
||||
_env.clear();
|
||||
_env.putAll(env);
|
||||
}
|
||||
|
||||
|
||||
public Map<String,Binding> getBindings ()
|
||||
{
|
||||
return _bindings;
|
||||
}
|
||||
|
||||
public void setBindings(Map<String,Binding> bindings)
|
||||
{
|
||||
_bindings = bindings;
|
||||
}
|
||||
|
||||
/*------------------------------------------------*/
|
||||
/**
|
||||
* Bind a name to an object
|
||||
|
@ -435,8 +303,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
|||
ne.setRemainingName(name);
|
||||
throw ne;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Name cname = toCanonicalName (name);
|
||||
|
||||
|
@ -521,7 +387,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
|||
|
||||
/*------------------------------------------------*/
|
||||
/**
|
||||
* Not supported
|
||||
*
|
||||
*
|
||||
* @param name name of subcontext to remove
|
||||
* @exception NamingException if an error occurs
|
||||
|
@ -536,7 +402,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
|||
|
||||
/*------------------------------------------------*/
|
||||
/**
|
||||
* Not supported
|
||||
*
|
||||
*
|
||||
* @param name name of subcontext to remove
|
||||
* @exception NamingException if an error occurs
|
||||
|
@ -1128,7 +994,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
|||
|
||||
ctx = binding.getObject();
|
||||
|
||||
|
||||
if (ctx instanceof Reference)
|
||||
{
|
||||
//deference the object
|
||||
|
@ -1154,8 +1019,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
|||
}
|
||||
else
|
||||
throw new NotContextException ("Object bound at "+firstComponent +" is not a Context");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------*/
|
||||
|
@ -1182,11 +1046,11 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
|||
* @param newName a <code>Name</code> value
|
||||
* @exception NamingException if an error occurs
|
||||
*/ public void rename(String oldName,
|
||||
String newName)
|
||||
throws NamingException
|
||||
{
|
||||
throw new OperationNotSupportedException();
|
||||
}
|
||||
String newName)
|
||||
throws NamingException
|
||||
{
|
||||
throw new OperationNotSupportedException();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1247,9 +1111,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
|||
*/
|
||||
public void close ()
|
||||
throws NamingException
|
||||
{
|
||||
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
@ -1362,7 +1224,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
|||
* @param name a <code>Name</code> value
|
||||
* @param obj an <code>Object</code> value
|
||||
*/
|
||||
protected void addBinding (Name name, Object obj) throws NameAlreadyBoundException
|
||||
public void addBinding (Name name, Object obj) throws NameAlreadyBoundException
|
||||
{
|
||||
String key = name.toString();
|
||||
Binding binding=new Binding (key, obj);
|
||||
|
@ -1394,7 +1256,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
|||
* @param name a <code>Name</code> value
|
||||
* @return a <code>Binding</code> value
|
||||
*/
|
||||
protected Binding getBinding (Name name)
|
||||
public Binding getBinding (Name name)
|
||||
{
|
||||
return (Binding) _bindings.get(name.toString());
|
||||
}
|
||||
|
@ -1407,13 +1269,13 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
|||
* @param name as a String
|
||||
* @return null or the Binding
|
||||
*/
|
||||
protected Binding getBinding (String name)
|
||||
public Binding getBinding (String name)
|
||||
{
|
||||
return (Binding) _bindings.get(name);
|
||||
}
|
||||
|
||||
/*------------------------------------------------*/
|
||||
protected void removeBinding (Name name)
|
||||
public void removeBinding (Name name)
|
||||
{
|
||||
String key = name.toString();
|
||||
if (__log.isDebugEnabled())
|
||||
|
@ -1455,7 +1317,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private boolean isLocked()
|
||||
public boolean isLocked()
|
||||
{
|
||||
if ((_env.get(LOCK_PROPERTY) == null) && (_env.get(UNLOCK_PROPERTY) == null))
|
||||
return false;
|
||||
|
|
|
@ -67,8 +67,7 @@ public class javaRootURLContext implements Context
|
|||
try
|
||||
{
|
||||
__javaNameParser = new javaNameParser();
|
||||
__nameRoot = new NamingContext();
|
||||
__nameRoot.setNameParser(__javaNameParser);
|
||||
__nameRoot = new NamingContext(null,null,null,__javaNameParser);
|
||||
|
||||
StringRefAddr parserAddr = new StringRefAddr("parser", __javaNameParser.getClass().getName());
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -12,11 +12,19 @@
|
|||
// ========================================================================
|
||||
package org.eclipse.jetty.jndi.java;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.Name;
|
||||
import javax.naming.NameNotFoundException;
|
||||
import javax.naming.NameParser;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.RefAddr;
|
||||
import javax.naming.Reference;
|
||||
import javax.naming.Referenceable;
|
||||
import javax.naming.StringRefAddr;
|
||||
import javax.naming.spi.ObjectFactory;
|
||||
|
||||
import org.eclipse.jetty.jndi.NamingUtil;
|
||||
import org.junit.After;
|
||||
|
@ -31,13 +39,152 @@ import static org.junit.Assert.fail;
|
|||
*/
|
||||
public class TestLocalJNDI
|
||||
{
|
||||
public static class FruitFactory implements ObjectFactory
|
||||
{
|
||||
public FruitFactory()
|
||||
{
|
||||
}
|
||||
|
||||
public Object getObjectInstance(Object obj, Name name, Context ctx, Hashtable env) throws Exception
|
||||
{
|
||||
|
||||
if (!env.containsKey("flavour"))
|
||||
throw new Exception ("No flavour!");
|
||||
|
||||
if (obj instanceof Reference)
|
||||
{
|
||||
Reference ref = (Reference)obj;
|
||||
if (ref.getClassName().equals(Fruit.class.getName()))
|
||||
{
|
||||
RefAddr addr = ref.get("fruit");
|
||||
if (addr != null)
|
||||
{
|
||||
return new Fruit((String)addr.getContent());
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class Fruit implements Referenceable
|
||||
{
|
||||
String fruit;
|
||||
|
||||
public Fruit(String f)
|
||||
{
|
||||
fruit = f;
|
||||
}
|
||||
|
||||
public Reference getReference() throws NamingException
|
||||
{
|
||||
return new Reference(
|
||||
Fruit.class.getName(),
|
||||
new StringRefAddr("fruit", fruit),
|
||||
FruitFactory.class.getName(),
|
||||
null); // Factory location
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return fruit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception
|
||||
{
|
||||
InitialContext ic = new InitialContext();
|
||||
ic.destroySubcontext("a");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLocalReferenceable() throws Exception
|
||||
{
|
||||
Hashtable<String,String> env1 = new Hashtable<String,String>();
|
||||
env1.put("flavour", "orange");
|
||||
InitialContext ic1 = new InitialContext(env1);
|
||||
|
||||
ic1.bind("valencia", new Fruit("orange"));
|
||||
|
||||
Object o = ic1.lookup("valencia");
|
||||
|
||||
Hashtable<String,String> env2 = new Hashtable<String,String>();
|
||||
InitialContext ic2 = new InitialContext(env2);
|
||||
try
|
||||
{
|
||||
o = ic2.lookup("valencia");
|
||||
fail("Constructed object from reference without correct environment");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
assertEquals("No flavour!", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLocalEnvironment() throws Exception
|
||||
{
|
||||
Hashtable<String,String> env1 = new Hashtable<String,String>();
|
||||
env1.put("make", "holden");
|
||||
env1.put("model", "commodore");
|
||||
|
||||
Object car1 = new Object();
|
||||
|
||||
InitialContext ic = new InitialContext(env1);
|
||||
ic.bind("car1", car1);
|
||||
assertNotNull(ic.lookup("car1"));
|
||||
assertEquals(car1, ic.lookup("car1"));
|
||||
|
||||
Context carz = ic.createSubcontext("carz");
|
||||
assertNotNull(carz);
|
||||
Hashtable ht = carz.getEnvironment();
|
||||
assertNotNull(ht);
|
||||
assertEquals("holden", ht.get("make"));
|
||||
assertEquals("commodore", ht.get("model"));
|
||||
|
||||
Hashtable<String,String> env2 = new Hashtable<String,String>();
|
||||
env2.put("flavour", "strawberry");
|
||||
InitialContext ic2 = new InitialContext(env2);
|
||||
assertEquals(car1, ic2.lookup("car1"));
|
||||
Context c = (Context)ic2.lookup("carz");
|
||||
assertNotNull(c);
|
||||
ht = c.getEnvironment();
|
||||
assertEquals("holden", ht.get("make"));
|
||||
assertEquals("commodore", ht.get("model"));
|
||||
|
||||
Context icecreamz = ic2.createSubcontext("icecreamz");
|
||||
ht = icecreamz.getEnvironment();
|
||||
assertNotNull(ht);
|
||||
assertEquals("strawberry", ht.get("flavour"));
|
||||
|
||||
Context hatchbackz = ic2.createSubcontext("carz/hatchbackz");
|
||||
assertNotNull(hatchbackz);
|
||||
ht = hatchbackz.getEnvironment();
|
||||
assertNotNull(ht);
|
||||
assertEquals("holden", ht.get("make"));
|
||||
assertEquals("commodore", ht.get("model"));
|
||||
assertEquals(null, ht.get("flavour"));
|
||||
|
||||
c = (Context)ic.lookup("carz/hatchbackz");
|
||||
assertNotNull(c);
|
||||
assertEquals(hatchbackz, c);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testLocal () throws Exception
|
||||
{
|
||||
|
|
|
@ -84,7 +84,8 @@ public class NestedConnection extends HttpConnection
|
|||
{
|
||||
getServer().handle(this);
|
||||
completeResponse();
|
||||
_generator.flushBuffer();
|
||||
while (!_generator.isComplete() && _endp.isOpen())
|
||||
_generator.flushBuffer();
|
||||
_endp.flush();
|
||||
}
|
||||
finally
|
||||
|
|
|
@ -4,29 +4,25 @@
|
|||
// 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
|
||||
// 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.
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
package org.eclipse.jetty.nested;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.io.bio.StreamEndPoint;
|
||||
|
||||
public class NestedEndPoint extends StreamEndPoint
|
||||
{
|
||||
private final HttpServletRequest _outerRequest;
|
||||
|
||||
|
||||
public NestedEndPoint(HttpServletRequest outerRequest, HttpServletResponse outerResponse)
|
||||
throws IOException
|
||||
{
|
||||
|
@ -65,7 +61,6 @@ public class NestedEndPoint extends StreamEndPoint
|
|||
@Override
|
||||
public String getRemoteHost()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return _outerRequest.getRemoteHost();
|
||||
}
|
||||
@Override
|
||||
|
|
|
@ -43,7 +43,7 @@ public class NestedGenerator extends AbstractGenerator
|
|||
|
||||
public void addContent(Buffer content, boolean last) throws IOException
|
||||
{
|
||||
// LOG.debug("addContent {} {}",content.length(),last);
|
||||
LOG.debug("addContent {} {}",content.length(),last);
|
||||
if (_noContent)
|
||||
{
|
||||
content.clear();
|
||||
|
@ -70,7 +70,6 @@ public class NestedGenerator extends AbstractGenerator
|
|||
// Handle any unfinished business?
|
||||
if (_content != null && _content.length() > 0)
|
||||
{
|
||||
|
||||
flushBuffer();
|
||||
if (_content != null && _content.length() > 0)
|
||||
throw new IllegalStateException("FULL");
|
||||
|
@ -86,20 +85,22 @@ public class NestedGenerator extends AbstractGenerator
|
|||
content.clear();
|
||||
_content = null;
|
||||
}
|
||||
else
|
||||
else if (!last || _buffer!=null)
|
||||
{
|
||||
// Yes - so we better check we have a buffer
|
||||
initContent();
|
||||
initBuffer();
|
||||
// Copy _content to buffer;
|
||||
int len = 0;
|
||||
len = _buffer.put(_content);
|
||||
|
||||
// make sure there is space for a trailing null
|
||||
// make sure there is space for a trailing null (???)
|
||||
if (len > 0 && _buffer.space() == 0)
|
||||
{
|
||||
len--;
|
||||
_buffer.setPutIndex(_buffer.putIndex() - 1);
|
||||
}
|
||||
|
||||
LOG.debug("copied {} to buffer",len);
|
||||
|
||||
_content.skip(len);
|
||||
|
||||
|
@ -139,7 +140,7 @@ public class NestedGenerator extends AbstractGenerator
|
|||
return false;
|
||||
|
||||
// we better check we have a buffer
|
||||
initContent();
|
||||
initBuffer();
|
||||
|
||||
// Copy _content to buffer;
|
||||
|
||||
|
@ -149,7 +150,7 @@ public class NestedGenerator extends AbstractGenerator
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void initContent() throws IOException
|
||||
private void initBuffer() throws IOException
|
||||
{
|
||||
if (_buffer == null)
|
||||
{
|
||||
|
@ -176,7 +177,7 @@ public class NestedGenerator extends AbstractGenerator
|
|||
@Override
|
||||
public int prepareUncheckedAddContent() throws IOException
|
||||
{
|
||||
initContent();
|
||||
initBuffer();
|
||||
return _buffer.space();
|
||||
}
|
||||
|
||||
|
@ -229,6 +230,26 @@ public class NestedGenerator extends AbstractGenerator
|
|||
_state = STATE_CONTENT;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Complete the message.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void complete() throws IOException
|
||||
{
|
||||
if (_state == STATE_END)
|
||||
return;
|
||||
|
||||
super.complete();
|
||||
|
||||
if (_state < STATE_FLUSHING)
|
||||
_state = STATE_FLUSHING;
|
||||
|
||||
flushBuffer();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public long flushBuffer() throws IOException
|
||||
|
@ -236,23 +257,44 @@ public class NestedGenerator extends AbstractGenerator
|
|||
if (_state == STATE_HEADER)
|
||||
throw new IllegalStateException("State==HEADER");
|
||||
|
||||
|
||||
if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
|
||||
{
|
||||
initContent();
|
||||
_buffer.put(_content);
|
||||
_content.clear();
|
||||
_content = null;
|
||||
}
|
||||
int len = 0;
|
||||
|
||||
if (_buffer==null)
|
||||
return 0;
|
||||
{
|
||||
|
||||
if (_content!=null && _content.length()>0)
|
||||
{
|
||||
// flush content directly
|
||||
len = _endp.flush(_content);
|
||||
if (len>0)
|
||||
_content.skip(len);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_buffer.length()==0 && _content!=null && _content.length()>0)
|
||||
{
|
||||
// Copy content to buffer
|
||||
_content.skip(_buffer.put(_content));
|
||||
}
|
||||
|
||||
int size=_buffer.length();
|
||||
len =_endp.flush(_buffer);
|
||||
LOG.debug("flushBuffer {} of {}",len,size);
|
||||
if (len>0)
|
||||
_buffer.skip(len);
|
||||
}
|
||||
|
||||
int size=_buffer.length();
|
||||
int len = _buffer==null?0:_endp.flush(_buffer);
|
||||
LOG.debug("flushBuffer {} of {}",len,size);
|
||||
if (len>0)
|
||||
_buffer.skip(len);
|
||||
if (_content!=null && _content.length()==0)
|
||||
_content=null;
|
||||
if (_buffer!=null && _buffer.length()==0 && _content==null)
|
||||
{
|
||||
_buffers.returnBuffer(_buffer);
|
||||
_buffer=null;
|
||||
}
|
||||
|
||||
if (_state==STATE_FLUSHING && _buffer==null && _content==null)
|
||||
_state=STATE_END;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
|
|
@ -428,7 +428,6 @@ public class MongoSessionManager extends NoSqlSessionManager
|
|||
return o;
|
||||
}
|
||||
|
||||
bout.reset();
|
||||
out.reset();
|
||||
out.writeUnshared(value);
|
||||
out.flush();
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2010-2011 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.osgi.servletbridge;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.equinox.servletbridge.BridgeServlet;
|
||||
|
||||
/**
|
||||
* Override the BridgeServlet to report on whether equinox is actually started or not
|
||||
* in case it is started asynchroneously.
|
||||
*
|
||||
* @author hmalphettes
|
||||
*/
|
||||
public class BridgeServletExtended extends BridgeServlet {
|
||||
|
||||
@Override
|
||||
protected void service(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
if (FrameworkLauncherExtended.ASYNCH_START_IN_PROGRESS != null
|
||||
&& req.getMethod().equals("GET")) {
|
||||
if (FrameworkLauncherExtended.ASYNCH_START_IN_PROGRESS) {
|
||||
resp.getWriter().append("Equinox is currently starting...\n");
|
||||
return;
|
||||
} else if (FrameworkLauncherExtended.ASYNCH_START_FAILURE != null) {
|
||||
resp.getWriter().append("Equinox failed to start:\n");
|
||||
FrameworkLauncherExtended.ASYNCH_START_FAILURE.printStackTrace(resp.getWriter());
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.service(req, resp);
|
||||
}
|
||||
|
||||
}
|
|
@ -13,146 +13,114 @@
|
|||
|
||||
package org.eclipse.jetty.plus.jaas.spi;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.security.Principal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
|
||||
import org.eclipse.jetty.http.security.Credential;
|
||||
import org.eclipse.jetty.security.PropertyUserStore;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* PropertyFileLoginModule
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class PropertyFileLoginModule extends AbstractLoginModule
|
||||
{
|
||||
public static final String DEFAULT_FILENAME = "realm.properties";
|
||||
|
||||
private static final Logger LOG = Log.getLogger(PropertyFileLoginModule.class);
|
||||
|
||||
public static final String DEFAULT_FILENAME = "realm.properties";
|
||||
public static final Map<String, Map<String, UserInfo>> fileMap = new HashMap<String, Map<String, UserInfo>>();
|
||||
|
||||
private String propertyFileName;
|
||||
|
||||
|
||||
private static Map<String, PropertyUserStore> _propertyUserStores = new HashMap<String, PropertyUserStore>();
|
||||
|
||||
/**
|
||||
private int _refreshInterval = 0;
|
||||
private String _filename = DEFAULT_FILENAME;
|
||||
|
||||
/**
|
||||
* Read contents of the configured property file.
|
||||
*
|
||||
* @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, java.util.Map)
|
||||
* @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map,
|
||||
* java.util.Map)
|
||||
* @param subject
|
||||
* @param callbackHandler
|
||||
* @param sharedState
|
||||
* @param options
|
||||
*/
|
||||
public void initialize(Subject subject, CallbackHandler callbackHandler,
|
||||
Map<String,?> sharedState, Map<String,?> options)
|
||||
public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options)
|
||||
{
|
||||
super.initialize(subject, callbackHandler, sharedState, options);
|
||||
loadProperties((String)options.get("file"));
|
||||
super.initialize(subject,callbackHandler,sharedState,options);
|
||||
setupPropertyUserStore(options);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void loadProperties (String filename)
|
||||
{
|
||||
File propsFile;
|
||||
|
||||
if (filename == null)
|
||||
{
|
||||
propsFile = new File(System.getProperty("user.dir"), DEFAULT_FILENAME);
|
||||
//look for a file called realm.properties in the current directory
|
||||
//if that fails, look for a file called realm.properties in $jetty.home/etc
|
||||
if (!propsFile.exists())
|
||||
propsFile = new File(System.getProperty("jetty.home"), DEFAULT_FILENAME);
|
||||
}
|
||||
else
|
||||
{
|
||||
propsFile = new File(filename);
|
||||
}
|
||||
|
||||
//give up, can't find a property file to load
|
||||
if (!propsFile.exists())
|
||||
{
|
||||
LOG.warn("No property file found");
|
||||
throw new IllegalStateException ("No property file specified in login module configuration file");
|
||||
}
|
||||
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
this.propertyFileName = propsFile.getCanonicalPath();
|
||||
if (fileMap.get(propertyFileName) != null)
|
||||
{
|
||||
if (LOG.isDebugEnabled()) {LOG.debug("Properties file "+propertyFileName+" already in cache, skipping load");}
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, UserInfo> userInfoMap = new HashMap<String, UserInfo>();
|
||||
Properties props = new Properties();
|
||||
props.load(new FileInputStream(propsFile));
|
||||
Iterator<Map.Entry<Object,Object>> iter = props.entrySet().iterator();
|
||||
while(iter.hasNext())
|
||||
{
|
||||
|
||||
Map.Entry<Object,Object> entry = iter.next();
|
||||
String username=entry.getKey().toString().trim();
|
||||
String credentials=entry.getValue().toString().trim();
|
||||
String roles=null;
|
||||
int c=credentials.indexOf(',');
|
||||
if (c>0)
|
||||
{
|
||||
roles=credentials.substring(c+1).trim();
|
||||
credentials=credentials.substring(0,c).trim();
|
||||
}
|
||||
|
||||
if (username!=null && username.length()>0 &&
|
||||
credentials!=null && credentials.length()>0)
|
||||
{
|
||||
ArrayList<String> roleList = new ArrayList<String>();
|
||||
if(roles!=null && roles.length()>0)
|
||||
{
|
||||
StringTokenizer tok = new StringTokenizer(roles,", ");
|
||||
|
||||
while (tok.hasMoreTokens())
|
||||
roleList.add(tok.nextToken());
|
||||
}
|
||||
|
||||
userInfoMap.put(username, (new UserInfo(username, Credential.getCredential(credentials.toString()), roleList)));
|
||||
}
|
||||
}
|
||||
|
||||
fileMap.put(propertyFileName, userInfoMap);
|
||||
}
|
||||
catch (Exception e)
|
||||
private void setupPropertyUserStore(Map<String, ?> options)
|
||||
{
|
||||
if (_propertyUserStores.get(_filename) == null)
|
||||
{
|
||||
LOG.warn("Error loading properties from file", e);
|
||||
throw new RuntimeException(e);
|
||||
parseConfig(options);
|
||||
|
||||
PropertyUserStore _propertyUserStore = new PropertyUserStore();
|
||||
_propertyUserStore.setConfig(_filename);
|
||||
_propertyUserStore.setRefreshInterval(_refreshInterval);
|
||||
LOG.debug("setupPropertyUserStore: Starting new PropertyUserStore. PropertiesFile: " + _filename + " refreshInterval: " + _refreshInterval);
|
||||
|
||||
try
|
||||
{
|
||||
_propertyUserStore.start();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Exception while starting propertyUserStore: ",e);
|
||||
}
|
||||
|
||||
_propertyUserStores.put(_filename,_propertyUserStore);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't implement this as we want to pre-fetch all of the
|
||||
* users.
|
||||
* @param username
|
||||
private void parseConfig(Map<String, ?> options)
|
||||
{
|
||||
_filename = (String)options.get("file") != null?(String)options.get("file"):DEFAULT_FILENAME;
|
||||
String refreshIntervalString = (String)options.get("refreshInterval");
|
||||
_refreshInterval = refreshIntervalString == null?_refreshInterval:Integer.parseInt(refreshIntervalString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't implement this as we want to pre-fetch all of the users.
|
||||
*
|
||||
* @param userName
|
||||
* @throws Exception
|
||||
*/
|
||||
public UserInfo getUserInfo (String username) throws Exception
|
||||
public UserInfo getUserInfo(String userName) throws Exception
|
||||
{
|
||||
Map<?, ?> userInfoMap = (Map<?, ?>)fileMap.get(propertyFileName);
|
||||
if (userInfoMap == null)
|
||||
PropertyUserStore propertyUserStore = _propertyUserStores.get(_filename);
|
||||
if (propertyUserStore == null)
|
||||
throw new IllegalStateException("PropertyUserStore should never be null here!");
|
||||
|
||||
UserIdentity userIdentity = propertyUserStore.getUserIdentity(userName);
|
||||
if(userIdentity==null)
|
||||
return null;
|
||||
return (UserInfo)userInfoMap.get(username);
|
||||
|
||||
Set<Principal> principals = userIdentity.getSubject().getPrincipals();
|
||||
|
||||
List<String> roles = new ArrayList<String>();
|
||||
|
||||
for ( Principal principal : principals )
|
||||
{
|
||||
roles.add( principal.getName() );
|
||||
}
|
||||
|
||||
Credential credential = (Credential)userIdentity.getSubject().getPrivateCredentials().iterator().next();
|
||||
LOG.debug("Found: " + userName + " in PropertyUserStore");
|
||||
return new UserInfo(userName, credential, roles);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -74,10 +74,11 @@
|
|||
<artifactId>jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${servlet.spec.groupId}</groupId>
|
||||
<artifactId>${servlet.spec.artifactId}</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>test-jetty-servlet</artifactId>
|
||||
|
|
|
@ -0,0 +1,487 @@
|
|||
package org.eclipse.jetty.rewrite.handler;
|
||||
|
||||
//========================================================================
|
||||
//Copyright (c) 2006-2009 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.
|
||||
//========================================================================
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.HttpExchange;
|
||||
import org.eclipse.jetty.http.HttpHeaderValues;
|
||||
import org.eclipse.jetty.http.HttpHeaders;
|
||||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.http.PathMap;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
|
||||
/**
|
||||
* This rule allows the user to configure a particular rewrite rule that will proxy out
|
||||
* to a configured location. This rule uses the jetty http client.
|
||||
*
|
||||
* Rule rule = new ProxyRule();
|
||||
* rule.setPattern("/foo/*");
|
||||
* rule.setProxyTo("http://url.com");
|
||||
*
|
||||
* see api for other configuration options which influence the configuration of the jetty
|
||||
* client instance
|
||||
*
|
||||
*/
|
||||
public class ProxyRule extends PatternRule
|
||||
{
|
||||
private static final Logger _log = Log.getLogger(ProxyRule.class);
|
||||
|
||||
private HttpClient _client;
|
||||
private String _hostHeader;
|
||||
private String _proxyTo;
|
||||
|
||||
private int _connectorType = 2;
|
||||
private String _maxThreads;
|
||||
private String _maxConnections;
|
||||
private String _timeout;
|
||||
private String _idleTimeout;
|
||||
private String _requestHeaderSize;
|
||||
private String _requestBufferSize;
|
||||
private String _responseHeaderSize;
|
||||
private String _responseBufferSize;
|
||||
|
||||
private HashSet<String> _DontProxyHeaders = new HashSet<String>();
|
||||
{
|
||||
_DontProxyHeaders.add("proxy-connection");
|
||||
_DontProxyHeaders.add("connection");
|
||||
_DontProxyHeaders.add("keep-alive");
|
||||
_DontProxyHeaders.add("transfer-encoding");
|
||||
_DontProxyHeaders.add("te");
|
||||
_DontProxyHeaders.add("trailer");
|
||||
_DontProxyHeaders.add("proxy-authorization");
|
||||
_DontProxyHeaders.add("proxy-authenticate");
|
||||
_DontProxyHeaders.add("upgrade");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ProxyRule()
|
||||
{
|
||||
_handling = true;
|
||||
_terminating = true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void initializeClient() throws Exception
|
||||
{
|
||||
_client = new HttpClient();
|
||||
_client.setConnectorType(_connectorType);
|
||||
|
||||
if ( _maxThreads != null )
|
||||
{
|
||||
_client.setThreadPool(new QueuedThreadPool(Integer.parseInt(_maxThreads)));
|
||||
}
|
||||
else
|
||||
{
|
||||
_client.setThreadPool(new QueuedThreadPool());
|
||||
}
|
||||
|
||||
if ( _maxConnections != null )
|
||||
{
|
||||
_client.setMaxConnectionsPerAddress(Integer.parseInt(_maxConnections));
|
||||
}
|
||||
|
||||
if ( _timeout != null )
|
||||
{
|
||||
_client.setTimeout(Long.parseLong(_timeout));
|
||||
}
|
||||
|
||||
if ( _idleTimeout != null )
|
||||
{
|
||||
_client.setIdleTimeout(Long.parseLong(_idleTimeout));
|
||||
}
|
||||
|
||||
if ( _requestBufferSize != null )
|
||||
{
|
||||
_client.setRequestBufferSize(Integer.parseInt(_requestBufferSize));
|
||||
}
|
||||
|
||||
if ( _requestHeaderSize != null )
|
||||
{
|
||||
_client.setRequestHeaderSize(Integer.parseInt(_requestHeaderSize));
|
||||
}
|
||||
|
||||
if ( _responseBufferSize != null )
|
||||
{
|
||||
_client.setResponseBufferSize(Integer.parseInt(_responseBufferSize));
|
||||
}
|
||||
|
||||
if ( _responseHeaderSize != null )
|
||||
{
|
||||
_client.setResponseHeaderSize(Integer.parseInt(_responseHeaderSize));
|
||||
}
|
||||
|
||||
_client.start();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private HttpURI proxyHttpURI(String uri) throws MalformedURLException
|
||||
{
|
||||
return new HttpURI(_proxyTo + uri);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected String apply(String target, HttpServletRequest request, final HttpServletResponse response) throws IOException
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (_client == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
initializeClient();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IOException("Unable to proxy: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final int debug = _log.isDebugEnabled()?request.hashCode():0;
|
||||
|
||||
final InputStream in = request.getInputStream();
|
||||
final OutputStream out = response.getOutputStream();
|
||||
|
||||
HttpURI url = createUrl(request,debug);
|
||||
|
||||
if (url == null)
|
||||
{
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN);
|
||||
return target;
|
||||
}
|
||||
|
||||
HttpExchange exchange = new HttpExchange()
|
||||
{
|
||||
@Override
|
||||
protected void onRequestCommitted() throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRequestComplete() throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseComplete() throws IOException
|
||||
{
|
||||
if (debug != 0)
|
||||
_log.debug(debug + " complete");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseContent(Buffer content) throws IOException
|
||||
{
|
||||
if (debug != 0)
|
||||
_log.debug(debug + " content" + content.length());
|
||||
content.writeTo(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseHeaderComplete() throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
|
||||
{
|
||||
if (debug != 0)
|
||||
_log.debug(debug + " " + version + " " + status + " " + reason);
|
||||
|
||||
if (reason != null && reason.length() > 0)
|
||||
response.setStatus(status,reason.toString());
|
||||
else
|
||||
response.setStatus(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseHeader(Buffer name, Buffer value) throws IOException
|
||||
{
|
||||
String s = name.toString().toLowerCase();
|
||||
if (!_DontProxyHeaders.contains(s) || (HttpHeaders.CONNECTION_BUFFER.equals(name) && HttpHeaderValues.CLOSE_BUFFER.equals(value)))
|
||||
{
|
||||
if (debug != 0)
|
||||
_log.debug(debug + " " + name + ": " + value);
|
||||
|
||||
response.addHeader(name.toString(),value.toString());
|
||||
}
|
||||
else if (debug != 0)
|
||||
_log.debug(debug + " " + name + "! " + value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConnectionFailed(Throwable ex)
|
||||
{
|
||||
_log.warn(ex.toString());
|
||||
_log.debug(ex);
|
||||
if (!response.isCommitted())
|
||||
{
|
||||
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Throwable ex)
|
||||
{
|
||||
if (ex instanceof EofException)
|
||||
{
|
||||
_log.ignore(ex);
|
||||
return;
|
||||
}
|
||||
_log.warn(ex.toString());
|
||||
_log.debug(ex);
|
||||
if (!response.isCommitted())
|
||||
{
|
||||
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExpire()
|
||||
{
|
||||
if (!response.isCommitted())
|
||||
{
|
||||
response.setStatus(HttpServletResponse.SC_GATEWAY_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
exchange.setMethod(request.getMethod());
|
||||
exchange.setURL(url.toString());
|
||||
exchange.setVersion(request.getProtocol());
|
||||
|
||||
if (debug != 0)
|
||||
{
|
||||
_log.debug(debug + " " + request.getMethod() + " " + url + " " + request.getProtocol());
|
||||
}
|
||||
|
||||
boolean hasContent = createHeaders(request,debug,exchange);
|
||||
|
||||
if (hasContent)
|
||||
{
|
||||
exchange.setRequestContentSource(in);
|
||||
}
|
||||
|
||||
/*
|
||||
* we need to set the timeout on the exchange to take into account the timeout of the HttpClient and the HttpExchange
|
||||
*/
|
||||
long ctimeout = (_client.getTimeout() > exchange.getTimeout())?_client.getTimeout():exchange.getTimeout();
|
||||
exchange.setTimeout(ctimeout);
|
||||
|
||||
_client.send(exchange);
|
||||
|
||||
try
|
||||
{
|
||||
exchange.waitForDone();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
_log.info("Exception while waiting for response on proxied request", e);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private HttpURI createUrl(HttpServletRequest request, final int debug) throws MalformedURLException
|
||||
{
|
||||
String uri = request.getRequestURI();
|
||||
|
||||
if (request.getQueryString() != null)
|
||||
{
|
||||
uri += "?" + request.getQueryString();
|
||||
}
|
||||
|
||||
uri = PathMap.pathInfo(_pattern,uri);
|
||||
|
||||
if(uri==null)
|
||||
{
|
||||
uri = "/";
|
||||
}
|
||||
|
||||
HttpURI url = proxyHttpURI(uri);
|
||||
|
||||
if (debug != 0)
|
||||
{
|
||||
_log.debug(debug + " proxy " + uri + "-->" + url);
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private boolean createHeaders(final HttpServletRequest request, final int debug, HttpExchange exchange)
|
||||
{
|
||||
// check connection header
|
||||
String connectionHdr = request.getHeader("Connection");
|
||||
if (connectionHdr != null)
|
||||
{
|
||||
connectionHdr = connectionHdr.toLowerCase();
|
||||
if (connectionHdr.indexOf("keep-alive") < 0 && connectionHdr.indexOf("close") < 0)
|
||||
{
|
||||
connectionHdr = null;
|
||||
}
|
||||
}
|
||||
|
||||
// force host
|
||||
if (_hostHeader != null)
|
||||
{
|
||||
exchange.setRequestHeader("Host",_hostHeader);
|
||||
}
|
||||
|
||||
// copy headers
|
||||
boolean xForwardedFor = false;
|
||||
boolean hasContent = false;
|
||||
long contentLength = -1;
|
||||
Enumeration<?> enm = request.getHeaderNames();
|
||||
while (enm.hasMoreElements())
|
||||
{
|
||||
// TODO could be better than this!
|
||||
String hdr = (String)enm.nextElement();
|
||||
String lhdr = hdr.toLowerCase();
|
||||
|
||||
if (_DontProxyHeaders.contains(lhdr))
|
||||
continue;
|
||||
if (connectionHdr != null && connectionHdr.indexOf(lhdr) >= 0)
|
||||
continue;
|
||||
if (_hostHeader != null && "host".equals(lhdr))
|
||||
continue;
|
||||
|
||||
if ("content-type".equals(lhdr))
|
||||
hasContent = true;
|
||||
else if ("content-length".equals(lhdr))
|
||||
{
|
||||
contentLength = request.getContentLength();
|
||||
exchange.setRequestHeader(HttpHeaders.CONTENT_LENGTH,Long.toString(contentLength));
|
||||
if (contentLength > 0)
|
||||
hasContent = true;
|
||||
}
|
||||
else if ("x-forwarded-for".equals(lhdr))
|
||||
xForwardedFor = true;
|
||||
|
||||
Enumeration<?> vals = request.getHeaders(hdr);
|
||||
while (vals.hasMoreElements())
|
||||
{
|
||||
String val = (String)vals.nextElement();
|
||||
if (val != null)
|
||||
{
|
||||
if (debug != 0)
|
||||
_log.debug(debug + " " + hdr + ": " + val);
|
||||
|
||||
exchange.setRequestHeader(hdr,val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Proxy headers
|
||||
exchange.setRequestHeader("Via","1.1 (jetty)");
|
||||
if (!xForwardedFor)
|
||||
{
|
||||
exchange.addRequestHeader("X-Forwarded-For",request.getRemoteAddr());
|
||||
exchange.addRequestHeader("X-Forwarded-Proto",request.getScheme());
|
||||
exchange.addRequestHeader("X-Forwarded-Host",request.getServerName());
|
||||
exchange.addRequestHeader("X-Forwarded-Server",request.getLocalName());
|
||||
}
|
||||
return hasContent;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setProxyTo(String proxyTo)
|
||||
{
|
||||
this._proxyTo = proxyTo;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setMaxThreads(String maxThreads)
|
||||
{
|
||||
this._maxThreads = maxThreads;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setMaxConnections(String maxConnections)
|
||||
{
|
||||
_maxConnections = maxConnections;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setTimeout(String timeout)
|
||||
{
|
||||
_timeout = timeout;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setIdleTimeout(String idleTimeout)
|
||||
{
|
||||
_idleTimeout = idleTimeout;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setRequestHeaderSize(String requestHeaderSize)
|
||||
{
|
||||
_requestHeaderSize = requestHeaderSize;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setRequestBufferSize(String requestBufferSize)
|
||||
{
|
||||
_requestBufferSize = requestBufferSize;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setResponseHeaderSize(String responseHeaderSize)
|
||||
{
|
||||
_responseHeaderSize = responseHeaderSize;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setResponseBufferSize(String responseBufferSize)
|
||||
{
|
||||
_responseBufferSize = responseBufferSize;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void addDontProxyHeaders(String dontProxyHeader)
|
||||
{
|
||||
_DontProxyHeaders.add(dontProxyHeader);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* CONNECTOR_SOCKET = 0;
|
||||
* CONNECTOR_SELECT_CHANNEL = 2; (default)
|
||||
*
|
||||
* @param connectorType
|
||||
*/
|
||||
public void setConnectorType( int connectorType )
|
||||
{
|
||||
_connectorType = connectorType;
|
||||
}
|
||||
|
||||
}
|
|
@ -5,11 +5,11 @@
|
|||
// 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
|
||||
// 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.
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
package org.eclipse.jetty.rewrite.handler;
|
||||
|
||||
|
@ -19,25 +19,24 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.PathMap;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*<p> Rewrite handler is responsible for managing the rules. Its capabilities
|
||||
* is not only limited for URL rewrites such as RewritePatternRule or RewriteRegexRule.
|
||||
* There is also handling for cookies, headers, redirection, setting status or error codes
|
||||
* whenever the rule finds a match.
|
||||
*
|
||||
* <p> The rules can be matched by the either: pattern matching of PathMap
|
||||
* (eg {@link PatternRule}), regular expressions (eg {@link RegexRule}) or certain conditions set
|
||||
* is not only limited for URL rewrites such as RewritePatternRule or RewriteRegexRule.
|
||||
* There is also handling for cookies, headers, redirection, setting status or error codes
|
||||
* whenever the rule finds a match.
|
||||
*
|
||||
* <p> The rules can be matched by the either: pattern matching of PathMap
|
||||
* (eg {@link PatternRule}), regular expressions (eg {@link RegexRule}) or certain conditions set
|
||||
* (eg {@link MsieSslRule} - the requests must be in SSL mode).
|
||||
*
|
||||
* <p> The rules can be grouped into rule containers (class {@link RuleContainer}), and will only
|
||||
*
|
||||
* <p> The rules can be grouped into rule containers (class {@link RuleContainer}), and will only
|
||||
* be applied if the request matches the conditions for their container
|
||||
* (e.g., by virtual host name)
|
||||
*
|
||||
*
|
||||
* <p>The list of predefined rules is:
|
||||
* <ul>
|
||||
* <li> {@link CookiePatternRule} - adds a new cookie in response. </li>
|
||||
|
@ -46,28 +45,36 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
|
|||
* <li> {@link ResponsePatternRule} - sets the status/error codes. </li>
|
||||
* <li> {@link RewritePatternRule} - rewrites the requested URI. </li>
|
||||
* <li> {@link RewriteRegexRule} - rewrites the requested URI using regular expression for pattern matching. </li>
|
||||
* <li> {@link ProxyRule} - proxies the requested URI to the host defined in proxyTo. </li>
|
||||
* <li> {@link MsieSslRule} - disables the keep alive on SSL for IE5 and IE6. </li>
|
||||
* <li> {@link LegacyRule} - the old version of rewrite. </li>
|
||||
* <li> {@link ForwardedSchemeHeaderRule} - set the scheme according to the headers present. </li>
|
||||
* <li> {@link VirtualHostRuleContainer} - checks whether the request matches one of a set of virtual host names.</li>
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
*
|
||||
* Here is a typical jetty.xml configuration would be: <pre>
|
||||
*
|
||||
*
|
||||
* <Set name="handler">
|
||||
* <New id="Handlers" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
|
||||
* <Set name="rules">
|
||||
* <Array type="org.eclipse.jetty.rewrite.handler.Rule">
|
||||
*
|
||||
* <Item>
|
||||
* <Item>
|
||||
* <New id="rewrite" class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
* <Set name="pattern">/*</Set>
|
||||
* <Set name="replacement">/test</Set>
|
||||
* </New>
|
||||
* </Item>
|
||||
*
|
||||
* <Item>
|
||||
* <Item>
|
||||
* <New id="rewrite" class="org.eclipse.jetty.rewrite.handler.ProxyRule">
|
||||
* <Set name="pattern">/*</Set>
|
||||
* <Set name="proxyTo">http://webtide.com:8080</Set>
|
||||
* </New>
|
||||
* </Item>
|
||||
*
|
||||
* <Item>
|
||||
* <New id="response" class="org.eclipse.jetty.rewrite.handler.ResponsePatternRule">
|
||||
* <Set name="pattern">/session/</Set>
|
||||
* <Set name="code">400</Set>
|
||||
|
@ -75,7 +82,7 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
|
|||
* </New>
|
||||
* </Item>
|
||||
*
|
||||
* <Item>
|
||||
* <Item>
|
||||
* <New id="header" class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
|
||||
* <Set name="pattern">*.jsp</Set>
|
||||
* <Set name="name">server</Set>
|
||||
|
@ -83,7 +90,7 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
|
|||
* </New>
|
||||
* </Item>
|
||||
*
|
||||
* <Item>
|
||||
* <Item>
|
||||
* <New id="header" class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
|
||||
* <Set name="pattern">*.jsp</Set>
|
||||
* <Set name="name">title</Set>
|
||||
|
@ -91,28 +98,28 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
|
|||
* </New>
|
||||
* </Item>
|
||||
*
|
||||
* <Item>
|
||||
* <Item>
|
||||
* <New id="redirect" class="org.eclipse.jetty.rewrite.handler.RedirectPatternRule">
|
||||
* <Set name="pattern">/test/dispatch</Set>
|
||||
* <Set name="location">http://jetty.eclipse.org</Set>
|
||||
* </New>
|
||||
* </Item>
|
||||
*
|
||||
* <Item>
|
||||
* <Item>
|
||||
* <New id="regexRewrite" class="org.eclipse.jetty.rewrite.handler.RewriteRegexRule">
|
||||
* <Set name="regex">/test-jaas/$</Set>
|
||||
* <Set name="replacement">/demo</Set>
|
||||
* </New>
|
||||
* </Item>
|
||||
*
|
||||
* <Item>
|
||||
*
|
||||
* <Item>
|
||||
* <New id="forwardedHttps" class="org.eclipse.jetty.rewrite.handler.ForwardedSchemeHeaderRule">
|
||||
* <Set name="header">X-Forwarded-Scheme</Set>
|
||||
* <Set name="headerValue">https</Set>
|
||||
* <Set name="scheme">https</Set>
|
||||
* </New>
|
||||
* </Item>
|
||||
*
|
||||
*
|
||||
* <Item>
|
||||
* <New id="virtualHost" class="org.eclipse.jetty.rewrite.handler.VirtualHostRuleContainer">
|
||||
*
|
||||
|
@ -134,10 +141,10 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
|
|||
* </New>
|
||||
* </Arg>
|
||||
* </Call>
|
||||
*
|
||||
*
|
||||
* </New>
|
||||
* </ Item>
|
||||
*
|
||||
*
|
||||
* </Array>
|
||||
* </Set>
|
||||
*
|
||||
|
@ -162,13 +169,13 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
|
|||
* </New>
|
||||
* </Set>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class RewriteHandler extends HandlerWrapper
|
||||
{
|
||||
|
||||
|
||||
private RuleContainer _rules;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public RewriteHandler()
|
||||
{
|
||||
|
@ -179,7 +186,7 @@ public class RewriteHandler extends HandlerWrapper
|
|||
/**
|
||||
* To enable configuration from jetty.xml on rewriteRequestURI, rewritePathInfo and
|
||||
* originalPathAttribute
|
||||
*
|
||||
*
|
||||
* @param legacyRule old style rewrite rule
|
||||
*/
|
||||
@Deprecated
|
||||
|
@ -201,7 +208,7 @@ public class RewriteHandler extends HandlerWrapper
|
|||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Assigns the rules to process.
|
||||
* @param rules an array of {@link Rule}.
|
||||
* @param rules an array of {@link Rule}.
|
||||
*/
|
||||
public void setRules(Rule[] rules)
|
||||
{
|
||||
|
@ -297,13 +304,13 @@ public class RewriteHandler extends HandlerWrapper
|
|||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
if (isStarted())
|
||||
{
|
||||
{
|
||||
String returned = _rules.matchAndApply(target, request, response);
|
||||
target = (returned == null) ? target : returned;
|
||||
|
||||
|
||||
if (!baseRequest.isHandled())
|
||||
super.handle(target, baseRequest, request, response);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
package org.eclipse.jetty.rewrite.handler;
|
||||
|
||||
//========================================================================
|
||||
//Copyright (c) 2006-2009 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.
|
||||
//========================================================================
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.client.ContentExchange;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.HttpExchange;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ProxyRuleTest
|
||||
{
|
||||
private static ProxyRule _rule;
|
||||
private static RewriteHandler _handler;
|
||||
private static Server _proxyServer = new Server();
|
||||
private static Connector _proxyServerConnector = new SelectChannelConnector();
|
||||
private static Server _targetServer = new Server();
|
||||
private static Connector _targetServerConnector = new SelectChannelConnector();
|
||||
private static HttpClient _httpClient = new HttpClient();
|
||||
|
||||
@BeforeClass
|
||||
public static void setupOnce() throws Exception
|
||||
{
|
||||
_targetServer.addConnector(_targetServerConnector);
|
||||
_targetServer.setHandler(new AbstractHandler()
|
||||
{
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
String responseString = "uri: " + request.getRequestURI() + " some content";
|
||||
response.getOutputStream().write(responseString.getBytes());
|
||||
response.setStatus(201);
|
||||
}
|
||||
});
|
||||
_targetServer.start();
|
||||
|
||||
_rule = new ProxyRule();
|
||||
_rule.setPattern("/foo/*");
|
||||
_rule.setProxyTo("http://localhost:" + _targetServerConnector.getLocalPort());
|
||||
_handler = new RewriteHandler();
|
||||
_handler.setRewriteRequestURI(true);
|
||||
_handler.setRules(new Rule[] { _rule });
|
||||
|
||||
_proxyServer.addConnector(_proxyServerConnector);
|
||||
_proxyServer.setHandler(_handler);
|
||||
_proxyServer.start();
|
||||
|
||||
_httpClient.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void destroy() throws Exception
|
||||
{
|
||||
_httpClient.stop();
|
||||
_proxyServer.stop();
|
||||
_targetServer.stop();
|
||||
_rule = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProxy() throws Exception
|
||||
{
|
||||
|
||||
ContentExchange exchange = new ContentExchange(true);
|
||||
exchange.setMethod(HttpMethods.GET);
|
||||
String body = "BODY";
|
||||
String url = "http://localhost:" + _proxyServerConnector.getLocalPort() + "/foo?body=" + URLEncoder.encode(body,"UTF-8");
|
||||
exchange.setURL(url);
|
||||
|
||||
_httpClient.send(exchange);
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED,exchange.waitForDone());
|
||||
assertEquals("uri: / some content",exchange.getResponseContent());
|
||||
assertEquals(201,exchange.getResponseStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProxyWithDeeperPath() throws Exception
|
||||
{
|
||||
|
||||
ContentExchange exchange = new ContentExchange(true);
|
||||
exchange.setMethod(HttpMethods.GET);
|
||||
String body = "BODY";
|
||||
String url = "http://localhost:" + _proxyServerConnector.getLocalPort() + "/foo/bar/foobar?body=" + URLEncoder.encode(body,"UTF-8");
|
||||
exchange.setURL(url);
|
||||
|
||||
_httpClient.send(exchange);
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED,exchange.waitForDone());
|
||||
assertEquals("uri: /bar/foobar some content",exchange.getResponseContent());
|
||||
assertEquals(201,exchange.getResponseStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProxyNoMatch() throws Exception
|
||||
{
|
||||
ContentExchange exchange = new ContentExchange(true);
|
||||
exchange.setMethod(HttpMethods.GET);
|
||||
String body = "BODY";
|
||||
String url = "http://localhost:" + _proxyServerConnector.getLocalPort() + "/foobar?body=" + URLEncoder.encode(body,"UTF-8");
|
||||
exchange.setURL(url);
|
||||
|
||||
_httpClient.send(exchange);
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED,exchange.waitForDone());
|
||||
assertEquals(404,exchange.getResponseStatus());
|
||||
}
|
||||
}
|
|
@ -17,6 +17,9 @@ import java.security.Principal;
|
|||
|
||||
import javax.security.auth.Subject;
|
||||
|
||||
import org.eclipse.jetty.http.security.Credential;
|
||||
import org.eclipse.jetty.security.MappedLoginService.KnownUser;
|
||||
import org.eclipse.jetty.security.MappedLoginService.RolePrincipal;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
|
||||
|
||||
|
|
|
@ -13,21 +13,12 @@
|
|||
|
||||
package org.eclipse.jetty.security;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.http.security.Credential;
|
||||
import org.eclipse.jetty.security.PropertyUserStore.UserListener;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
import org.eclipse.jetty.util.Scanner;
|
||||
import org.eclipse.jetty.util.Scanner.BulkListener;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
@ -36,27 +27,24 @@ import org.eclipse.jetty.util.resource.Resource;
|
|||
/**
|
||||
* Properties User Realm.
|
||||
*
|
||||
* An implementation of UserRealm that stores users and roles in-memory in
|
||||
* HashMaps.
|
||||
* An implementation of UserRealm that stores users and roles in-memory in HashMaps.
|
||||
* <P>
|
||||
* Typically these maps are populated by calling the load() method or passing a
|
||||
* properties resource to the constructor. The format of the properties file is:
|
||||
* Typically these maps are populated by calling the load() method or passing a properties resource to the constructor. The format of the properties file is:
|
||||
*
|
||||
* <PRE>
|
||||
* username: password [,rolename ...]
|
||||
* </PRE>
|
||||
*
|
||||
* Passwords may be clear text, obfuscated or checksummed. The class
|
||||
* com.eclipse.Util.Password should be used to generate obfuscated passwords or
|
||||
* password checksums.
|
||||
* Passwords may be clear text, obfuscated or checksummed. The class com.eclipse.Util.Password should be used to generate obfuscated passwords or password
|
||||
* checksums.
|
||||
*
|
||||
* If DIGEST Authentication is used, the password must be in a recoverable
|
||||
* format, either plain text or OBF:.
|
||||
* If DIGEST Authentication is used, the password must be in a recoverable format, either plain text or OBF:.
|
||||
*/
|
||||
public class HashLoginService extends MappedLoginService
|
||||
public class HashLoginService extends MappedLoginService implements UserListener
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HashLoginService.class);
|
||||
|
||||
private PropertyUserStore _propertyUserStore;
|
||||
private String _config;
|
||||
private Resource _configResource;
|
||||
private Scanner _scanner;
|
||||
|
@ -72,14 +60,14 @@ public class HashLoginService extends MappedLoginService
|
|||
{
|
||||
setName(name);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public HashLoginService(String name, String config)
|
||||
{
|
||||
setName(name);
|
||||
setConfig(config);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String getConfig()
|
||||
{
|
||||
|
@ -89,7 +77,7 @@ public class HashLoginService extends MappedLoginService
|
|||
/* ------------------------------------------------------------ */
|
||||
public void getConfig(String config)
|
||||
{
|
||||
_config=config;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -100,11 +88,10 @@ public class HashLoginService extends MappedLoginService
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Load realm users from properties file. The property file maps usernames
|
||||
* to password specs followed by an optional comma separated list of role
|
||||
* names.
|
||||
* Load realm users from properties file. The property file maps usernames to password specs followed by an optional comma separated list of role names.
|
||||
*
|
||||
* @param config Filename or url of user properties file.
|
||||
* @param config
|
||||
* Filename or url of user properties file.
|
||||
*/
|
||||
public void setConfig(String config)
|
||||
{
|
||||
|
@ -129,52 +116,14 @@ public class HashLoginService extends MappedLoginService
|
|||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void loadUsers() throws IOException
|
||||
{
|
||||
if (_config==null)
|
||||
return;
|
||||
_configResource = Resource.newResource(_config);
|
||||
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Load " + this + " from " + _config);
|
||||
Properties properties = new Properties();
|
||||
properties.load(_configResource.getInputStream());
|
||||
Set<String> known = new HashSet<String>();
|
||||
|
||||
for (Map.Entry<Object, Object> entry : properties.entrySet())
|
||||
{
|
||||
String username = ((String) entry.getKey()).trim();
|
||||
String credentials = ((String) entry.getValue()).trim();
|
||||
String roles = null;
|
||||
int c = credentials.indexOf(',');
|
||||
if (c > 0)
|
||||
{
|
||||
roles = credentials.substring(c + 1).trim();
|
||||
credentials = credentials.substring(0, c).trim();
|
||||
}
|
||||
|
||||
if (username != null && username.length() > 0 && credentials != null && credentials.length() > 0)
|
||||
{
|
||||
String[] roleArray = IdentityService.NO_ROLES;
|
||||
if (roles != null && roles.length() > 0)
|
||||
roleArray = roles.split(",");
|
||||
known.add(username);
|
||||
putUser(username,Credential.getCredential(credentials),roleArray);
|
||||
}
|
||||
}
|
||||
|
||||
Iterator<String> users = _users.keySet().iterator();
|
||||
while(users.hasNext())
|
||||
{
|
||||
String user=users.next();
|
||||
if (!known.contains(user))
|
||||
users.remove();
|
||||
}
|
||||
// TODO: Consider refactoring MappedLoginService to not have to override with unused methods
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
|
||||
|
@ -183,54 +132,17 @@ public class HashLoginService extends MappedLoginService
|
|||
{
|
||||
super.doStart();
|
||||
|
||||
if (getRefreshInterval() > 0)
|
||||
if (_propertyUserStore == null)
|
||||
{
|
||||
_scanner = new Scanner();
|
||||
_scanner.setScanInterval(getRefreshInterval());
|
||||
List<File> dirList = new ArrayList<File>(1);
|
||||
dirList.add(_configResource.getFile());
|
||||
_scanner.setScanDirs(dirList);
|
||||
_scanner.setFilenameFilter(new FilenameFilter()
|
||||
if(LOG.isDebugEnabled())
|
||||
{
|
||||
public boolean accept(File dir, String name)
|
||||
{
|
||||
File f = new File(dir, name);
|
||||
try
|
||||
{
|
||||
if (f.compareTo(_configResource.getFile()) == 0) return true;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
_scanner.addListener(new BulkListener()
|
||||
{
|
||||
public void filesChanged(List<String> filenames) throws Exception
|
||||
{
|
||||
if (filenames == null) return;
|
||||
if (filenames.isEmpty()) return;
|
||||
if (filenames.size() == 1)
|
||||
{
|
||||
Resource r = Resource.newResource(filenames.get(0));
|
||||
if (r.getFile().equals(_configResource.getFile()))
|
||||
loadUsers();
|
||||
}
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "HashLoginService$Scanner";
|
||||
}
|
||||
|
||||
});
|
||||
_scanner.setReportExistingFilesOnStartup(false);
|
||||
_scanner.setRecursive(false);
|
||||
_scanner.start();
|
||||
LOG.debug("doStart: Starting new PropertyUserStore. PropertiesFile: " + _config + " refreshInterval: " + _refreshInterval);
|
||||
}
|
||||
_propertyUserStore = new PropertyUserStore();
|
||||
_propertyUserStore.setRefreshInterval(_refreshInterval);
|
||||
_propertyUserStore.setConfig(_config);
|
||||
_propertyUserStore.registerUserListener(this);
|
||||
_propertyUserStore.start();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,9 +153,24 @@ public class HashLoginService extends MappedLoginService
|
|||
protected void doStop() throws Exception
|
||||
{
|
||||
super.doStop();
|
||||
if (_scanner != null) _scanner.stop();
|
||||
if (_scanner != null)
|
||||
_scanner.stop();
|
||||
_scanner = null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void update(String userName, Credential credential, String[] roleArray)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("update: " + userName + " Roles: " + roleArray.length);
|
||||
putUser(userName,credential,roleArray);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void remove(String userName)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("remove: " + userName);
|
||||
removeUser(userName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
package org.eclipse.jetty.security;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
|
||||
import org.eclipse.jetty.http.security.Credential;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
|
||||
|
|
|
@ -3,7 +3,9 @@ package org.eclipse.jetty.security;
|
|||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
@ -11,7 +13,12 @@ import java.util.Map;
|
|||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
|
||||
import org.eclipse.jetty.http.security.Credential;
|
||||
import org.eclipse.jetty.security.MappedLoginService.KnownUser;
|
||||
import org.eclipse.jetty.security.MappedLoginService.RolePrincipal;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
import org.eclipse.jetty.util.Scanner;
|
||||
import org.eclipse.jetty.util.Scanner.BulkListener;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
|
@ -42,8 +49,10 @@ public class PropertyUserStore extends AbstractLifeCycle
|
|||
private Scanner _scanner;
|
||||
private int _refreshInterval = 0;// default is not to reload
|
||||
|
||||
private IdentityService _identityService = new DefaultIdentityService();
|
||||
private boolean _firstLoad = true; // true if first load, false from that point on
|
||||
private final List<String> _knownUsers = new ArrayList<String>();
|
||||
private final Map<String, UserIdentity> _knownUserIdentities = new HashMap<String, UserIdentity>();
|
||||
private List<UserListener> _listeners;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -57,6 +66,12 @@ public class PropertyUserStore extends AbstractLifeCycle
|
|||
{
|
||||
_config = config;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public UserIdentity getUserIdentity(String userName)
|
||||
{
|
||||
return _knownUserIdentities.get(userName);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -119,9 +134,29 @@ public class PropertyUserStore extends AbstractLifeCycle
|
|||
{
|
||||
String[] roleArray = IdentityService.NO_ROLES;
|
||||
if (roles != null && roles.length() > 0)
|
||||
{
|
||||
roleArray = roles.split(",");
|
||||
}
|
||||
known.add(username);
|
||||
notifyUpdate(username,Credential.getCredential(credentials),roleArray);
|
||||
Credential credential = Credential.getCredential(credentials);
|
||||
|
||||
Principal userPrincipal = new KnownUser(username,credential);
|
||||
Subject subject = new Subject();
|
||||
subject.getPrincipals().add(userPrincipal);
|
||||
subject.getPrivateCredentials().add(credential);
|
||||
|
||||
if (roles != null)
|
||||
{
|
||||
for (String role : roleArray)
|
||||
{
|
||||
subject.getPrincipals().add(new RolePrincipal(role));
|
||||
}
|
||||
}
|
||||
|
||||
subject.setReadOnly();
|
||||
|
||||
_knownUserIdentities.put(username,_identityService.newUserIdentity(subject,userPrincipal,roleArray));
|
||||
notifyUpdate(username,credential,roleArray);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,6 +173,7 @@ public class PropertyUserStore extends AbstractLifeCycle
|
|||
String user = users.next();
|
||||
if (!known.contains(user))
|
||||
{
|
||||
_knownUserIdentities.remove(user);
|
||||
notifyRemove(user);
|
||||
}
|
||||
}
|
||||
|
@ -201,15 +237,17 @@ public class PropertyUserStore extends AbstractLifeCycle
|
|||
|
||||
_scanner.addListener(new BulkListener()
|
||||
{
|
||||
public void filesChanged(List filenames) throws Exception
|
||||
public void filesChanged(List<String> filenames) throws Exception
|
||||
{
|
||||
if (filenames == null)
|
||||
return;
|
||||
if (filenames.isEmpty())
|
||||
return;
|
||||
if (filenames.size() == 1 && filenames.get(0).equals(getConfigResource().getFile().getAbsolutePath()))
|
||||
if (filenames.size() == 1)
|
||||
{
|
||||
loadUsers();
|
||||
Resource r = Resource.newResource(filenames.get(0));
|
||||
if (r.getFile().equals(_configResource.getFile()))
|
||||
loadUsers();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -65,20 +65,28 @@ public class BasicAuthenticator extends LoginAuthenticator
|
|||
return _deferred;
|
||||
|
||||
if (credentials != null)
|
||||
{
|
||||
credentials = credentials.substring(credentials.indexOf(' ')+1);
|
||||
credentials = B64Code.decode(credentials,StringUtil.__ISO_8859_1);
|
||||
int i = credentials.indexOf(':');
|
||||
if (i>0)
|
||||
{
|
||||
int space=credentials.indexOf(' ');
|
||||
if (space>0)
|
||||
{
|
||||
String username = credentials.substring(0,i);
|
||||
String password = credentials.substring(i+1);
|
||||
|
||||
UserIdentity user = _loginService.login(username,password);
|
||||
if (user!=null)
|
||||
String method=credentials.substring(0,space);
|
||||
if ("basic".equalsIgnoreCase(method))
|
||||
{
|
||||
renewSessionOnAuthentication(request,response);
|
||||
return new UserAuthentication(getAuthMethod(),user);
|
||||
credentials = credentials.substring(space+1);
|
||||
credentials = B64Code.decode(credentials,StringUtil.__ISO_8859_1);
|
||||
int i = credentials.indexOf(':');
|
||||
if (i>0)
|
||||
{
|
||||
String username = credentials.substring(0,i);
|
||||
String password = credentials.substring(i+1);
|
||||
|
||||
UserIdentity user = _loginService.login(username,password);
|
||||
if (user!=null)
|
||||
{
|
||||
renewSessionOnAuthentication(request,response);
|
||||
return new UserAuthentication(getAuthMethod(),user);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,12 @@ package org.eclipse.jetty.security.authentication;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
@ -42,17 +48,29 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
/**
|
||||
* @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
|
||||
*
|
||||
* The nonce max age can be set with the {@link SecurityHandler#setInitParameter(String, String)}
|
||||
* The nonce max age in ms can be set with the {@link SecurityHandler#setInitParameter(String, String)}
|
||||
* using the name "maxNonceAge"
|
||||
*/
|
||||
public class DigestAuthenticator extends LoginAuthenticator
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(DigestAuthenticator.class);
|
||||
SecureRandom _random = new SecureRandom();
|
||||
private long _maxNonceAgeMs = 60*1000;
|
||||
private ConcurrentMap<String, Nonce> _nonceCount = new ConcurrentHashMap<String, Nonce>();
|
||||
private Queue<Nonce> _nonceQueue = new ConcurrentLinkedQueue<Nonce>();
|
||||
private static class Nonce
|
||||
{
|
||||
final String _nonce;
|
||||
final long _ts;
|
||||
AtomicInteger _nc=new AtomicInteger();
|
||||
public Nonce(String nonce, long ts)
|
||||
{
|
||||
_nonce=nonce;
|
||||
_ts=ts;
|
||||
}
|
||||
}
|
||||
|
||||
protected long _maxNonceAge = 0;
|
||||
protected long _nonceSecret = this.hashCode() ^ System.currentTimeMillis();
|
||||
protected boolean _useStale = false;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public DigestAuthenticator()
|
||||
{
|
||||
super();
|
||||
|
@ -69,19 +87,22 @@ public class DigestAuthenticator extends LoginAuthenticator
|
|||
|
||||
String mna=configuration.getInitParameter("maxNonceAge");
|
||||
if (mna!=null)
|
||||
_maxNonceAge=Long.valueOf(mna);
|
||||
_maxNonceAgeMs=Long.valueOf(mna);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String getAuthMethod()
|
||||
{
|
||||
return Constraint.__DIGEST_AUTH;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, User validatedUser) throws ServerAuthException
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException
|
||||
{
|
||||
if (!mandatory)
|
||||
|
@ -144,7 +165,7 @@ public class DigestAuthenticator extends LoginAuthenticator
|
|||
}
|
||||
}
|
||||
|
||||
int n = checkNonce(digest.nonce, (Request)request);
|
||||
int n = checkNonce(digest,(Request)request);
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
|
@ -170,8 +191,8 @@ public class DigestAuthenticator extends LoginAuthenticator
|
|||
+ domain
|
||||
+ "\", nonce=\""
|
||||
+ newNonce((Request)request)
|
||||
+ "\", algorithm=MD5, qop=\"auth\""
|
||||
+ (_useStale ? (" stale=" + stale) : ""));
|
||||
+ "\", algorithm=MD5, qop=\"auth\","
|
||||
+ " stale=" + stale);
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
|
||||
return Authentication.SEND_CONTINUE;
|
||||
|
@ -186,87 +207,59 @@ public class DigestAuthenticator extends LoginAuthenticator
|
|||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String newNonce(Request request)
|
||||
{
|
||||
long ts=request.getTimeStamp();
|
||||
long sk = _nonceSecret;
|
||||
|
||||
byte[] nounce = new byte[24];
|
||||
for (int i = 0; i < 8; i++)
|
||||
Nonce nonce;
|
||||
|
||||
do
|
||||
{
|
||||
nounce[i] = (byte) (ts & 0xff);
|
||||
ts = ts >> 8;
|
||||
nounce[8 + i] = (byte) (sk & 0xff);
|
||||
sk = sk >> 8;
|
||||
}
|
||||
byte[] nounce = new byte[24];
|
||||
_random.nextBytes(nounce);
|
||||
|
||||
byte[] hash = null;
|
||||
try
|
||||
{
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
md.reset();
|
||||
md.update(nounce, 0, 16);
|
||||
hash = md.digest();
|
||||
nonce = new Nonce(new String(B64Code.encode(nounce)),request.getTimeStamp());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
|
||||
for (int i = 0; i < hash.length; i++)
|
||||
{
|
||||
nounce[8 + i] = hash[i];
|
||||
if (i == 23) break;
|
||||
}
|
||||
|
||||
return new String(B64Code.encode(nounce));
|
||||
while (_nonceCount.putIfAbsent(nonce._nonce,nonce)!=null);
|
||||
_nonceQueue.add(nonce);
|
||||
|
||||
return nonce._nonce;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nonce nonce to check
|
||||
* @param nstring nonce to check
|
||||
* @param request
|
||||
* @return -1 for a bad nonce, 0 for a stale none, 1 for a good nonce
|
||||
*/
|
||||
/* ------------------------------------------------------------ */
|
||||
private int checkNonce(String nonce, Request request)
|
||||
private int checkNonce(Digest digest, Request request)
|
||||
{
|
||||
// firstly let's expire old nonces
|
||||
long expired = request.getTimeStamp()-_maxNonceAgeMs;
|
||||
|
||||
Nonce nonce=_nonceQueue.peek();
|
||||
while (nonce!=null && nonce._ts<expired)
|
||||
{
|
||||
_nonceQueue.remove();
|
||||
_nonceCount.remove(nonce._nonce);
|
||||
nonce=_nonceQueue.peek();
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
byte[] n = B64Code.decode(nonce.toCharArray());
|
||||
if (n.length != 24) return -1;
|
||||
|
||||
long ts = 0;
|
||||
long sk = _nonceSecret;
|
||||
byte[] n2 = new byte[16];
|
||||
System.arraycopy(n, 0, n2, 0, 8);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
n2[8 + i] = (byte) (sk & 0xff);
|
||||
sk = sk >> 8;
|
||||
ts = (ts << 8) + (0xff & (long) n[7 - i]);
|
||||
}
|
||||
|
||||
long age = request.getTimeStamp() - ts;
|
||||
if (LOG.isDebugEnabled()) LOG.debug("age=" + age);
|
||||
|
||||
byte[] hash = null;
|
||||
try
|
||||
{
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
md.reset();
|
||||
md.update(n2, 0, 16);
|
||||
hash = md.digest();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
if (n[i + 8] != hash[i]) return -1;
|
||||
|
||||
if (_maxNonceAge > 0 && (age < 0 || age > _maxNonceAge)) return 0; // stale
|
||||
|
||||
nonce = _nonceCount.get(digest.nonce);
|
||||
if (nonce==null)
|
||||
return 0;
|
||||
|
||||
long count = Long.parseLong(digest.nc,16);
|
||||
if (count>Integer.MAX_VALUE)
|
||||
return 0;
|
||||
int old=nonce._nc.get();
|
||||
while (!nonce._nc.compareAndSet(old,(int)count))
|
||||
old=nonce._nc.get();
|
||||
if (count<=old)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -276,18 +269,21 @@ public class DigestAuthenticator extends LoginAuthenticator
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
private static class Digest extends Credential
|
||||
{
|
||||
private static final long serialVersionUID = -2484639019549527724L;
|
||||
String method = null;
|
||||
String username = null;
|
||||
String realm = null;
|
||||
String nonce = null;
|
||||
String nc = null;
|
||||
String cnonce = null;
|
||||
String qop = null;
|
||||
String uri = null;
|
||||
String response = null;
|
||||
final String method;
|
||||
String username = "";
|
||||
String realm = "";
|
||||
String nonce = "";
|
||||
String nc = "";
|
||||
String cnonce = "";
|
||||
String qop = "";
|
||||
String uri = "";
|
||||
String response = "";
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
Digest(String m)
|
||||
|
|
|
@ -201,13 +201,13 @@ public class ConstraintTest
|
|||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: " + B64Code.encode("user:wrong") + "\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user:wrong") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: " + B64Code.encode("user:password") + "\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
|
@ -218,20 +218,20 @@ public class ConstraintTest
|
|||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Authorization: " + B64Code.encode("admin:wrong") + "\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("admin:wrong") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Authorization: " + B64Code.encode("user:password") + "\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user:password") + "\r\n" +
|
||||
"\r\n");
|
||||
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 "));
|
||||
assertTrue(response.indexOf("!role") > 0);
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Authorization: " + B64Code.encode("admin:password") + "\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("admin:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
|
@ -490,18 +490,18 @@ public class ConstraintTest
|
|||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: " + B64Code.encode("user:wrong") + "\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user:wrong") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: " + B64Code.encode("user:password") + "\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: " + B64Code.encode("user2:password") + "\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user2:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
|
@ -512,20 +512,20 @@ public class ConstraintTest
|
|||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Authorization: " + B64Code.encode("admin:wrong") + "\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("admin:wrong") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Authorization: " + B64Code.encode("user:password") + "\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user:password") + "\r\n" +
|
||||
"\r\n");
|
||||
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 "));
|
||||
assertTrue(response.indexOf("!role") > 0);
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Authorization: " + B64Code.encode("admin:password") + "\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("admin:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
|
@ -776,7 +776,7 @@ public class ConstraintTest
|
|||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: " + B64Code.encode("user2:password") + "\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user2:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 500 "));
|
||||
|
||||
|
@ -789,7 +789,7 @@ public class ConstraintTest
|
|||
_server.start();
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: " + B64Code.encode("user2:password") + "\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user2:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
}
|
||||
|
@ -809,13 +809,13 @@ public class ConstraintTest
|
|||
assertTrue(response.indexOf("user=null") > 0);
|
||||
|
||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n"+
|
||||
"Authorization: " + B64Code.encode("admin:wrong") + "\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("admin:wrong") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertTrue(response.indexOf("user=null") > 0);
|
||||
|
||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n"+
|
||||
"Authorization: " + B64Code.encode("admin:password") + "\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("admin:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertTrue(response.indexOf("user=admin") > 0);
|
||||
|
|
|
@ -78,6 +78,9 @@ public class PropertyUserStoreTest
|
|||
|
||||
store.start();
|
||||
|
||||
Assert.assertNotNull("Failed to retrieve UserIdentity directly from PropertyUserStore", store.getUserIdentity("tom"));
|
||||
Assert.assertNotNull("Failed to retrieve UserIdentity directly from PropertyUserStore", store.getUserIdentity("dick"));
|
||||
Assert.assertNotNull("Failed to retrieve UserIdentity directly from PropertyUserStore", store.getUserIdentity("harry"));
|
||||
Assert.assertEquals(3,userCount.get());
|
||||
}
|
||||
|
||||
|
@ -117,7 +120,11 @@ public class PropertyUserStoreTest
|
|||
|
||||
long start = System.currentTimeMillis();
|
||||
while (userCount.get() < 4 && (System.currentTimeMillis() - start) < 10000)
|
||||
{
|
||||
Thread.sleep(10);
|
||||
}
|
||||
|
||||
Assert.assertNotNull("Failed to retrieve UserIdentity from PropertyUserStore directly", store.getUserIdentity("skip"));
|
||||
Assert.assertEquals(4,userCount.get());
|
||||
|
||||
Assert.assertTrue(users.contains("skip"));
|
||||
|
|
|
@ -112,5 +112,11 @@
|
|||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.8.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -7,12 +7,18 @@ import org.eclipse.jetty.http.HttpStatus;
|
|||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.nio.ChannelEndPoint;
|
||||
import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class AsyncHttpConnection extends HttpConnection
|
||||
{
|
||||
private final static int NO_PROGRESS_INFO = Integer.getInteger("org.mortbay.jetty.NO_PROGRESS_INFO",100);
|
||||
private final static int NO_PROGRESS_CLOSE = Integer.getInteger("org.mortbay.jetty.NO_PROGRESS_CLOSE",200);
|
||||
|
||||
private static final Logger LOG = Log.getLogger(AsyncHttpConnection.class);
|
||||
private int _total_no_progress;
|
||||
|
||||
public AsyncHttpConnection(Connector connector, EndPoint endpoint, Server server)
|
||||
{
|
||||
|
@ -22,21 +28,21 @@ public class AsyncHttpConnection extends HttpConnection
|
|||
public Connection handle() throws IOException
|
||||
{
|
||||
Connection connection = this;
|
||||
boolean some_progress=false;
|
||||
boolean progress=true;
|
||||
|
||||
// Loop while more in buffer
|
||||
try
|
||||
{
|
||||
setCurrentConnection(this);
|
||||
|
||||
boolean progress=true;
|
||||
boolean more_in_buffer =false;
|
||||
|
||||
while (_endp.isOpen() && (more_in_buffer || progress))
|
||||
while (_endp.isOpen() && (more_in_buffer || progress) && connection==this)
|
||||
{
|
||||
progress=false;
|
||||
try
|
||||
{
|
||||
LOG.debug("async request",_request);
|
||||
|
||||
// Handle resumed request
|
||||
if (_request._async.isAsync() && !_request._async.isComplete())
|
||||
|
@ -53,6 +59,11 @@ public class AsyncHttpConnection extends HttpConnection
|
|||
// Flush output from buffering endpoint
|
||||
if (_endp.isBufferingOutput())
|
||||
_endp.flush();
|
||||
|
||||
// Special case close handling.
|
||||
// If we were dispatched and have made no progress, but io is shutdown, then close
|
||||
if (!progress && !some_progress && (_endp.isInputShutdown()||_endp.isOutputShutdown()))
|
||||
_endp.close();
|
||||
}
|
||||
catch (HttpException e)
|
||||
{
|
||||
|
@ -88,7 +99,7 @@ public class AsyncHttpConnection extends HttpConnection
|
|||
{
|
||||
_parser.reset();
|
||||
_generator.reset(true);
|
||||
return switched;
|
||||
connection=switched;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,7 +109,6 @@ public class AsyncHttpConnection extends HttpConnection
|
|||
reset(false);
|
||||
more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
|
||||
}
|
||||
|
||||
// else Are we suspended?
|
||||
else if (_request.isAsyncStarted())
|
||||
{
|
||||
|
@ -108,6 +118,8 @@ public class AsyncHttpConnection extends HttpConnection
|
|||
}
|
||||
else
|
||||
more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
|
||||
|
||||
some_progress|=progress|((SelectChannelEndPoint)_endp).isProgressing();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -115,12 +127,31 @@ public class AsyncHttpConnection extends HttpConnection
|
|||
{
|
||||
setCurrentConnection(null);
|
||||
_parser.returnBuffers();
|
||||
_generator.returnBuffers();
|
||||
|
||||
// Are we write blocked
|
||||
if (_generator.isCommitted() && !_generator.isComplete())
|
||||
((AsyncEndPoint)_endp).scheduleWrite();
|
||||
else
|
||||
_generator.returnBuffers();
|
||||
// Check if we are write blocked
|
||||
if (_generator.isCommitted() && !_generator.isComplete() && _endp.isOpen() && !_endp.isOutputShutdown())
|
||||
((AsyncEndPoint)_endp).scheduleWrite(); // TODO. This should not be required
|
||||
|
||||
if (!some_progress)
|
||||
{
|
||||
_total_no_progress++;
|
||||
|
||||
if (NO_PROGRESS_INFO>0 && _total_no_progress%NO_PROGRESS_INFO==0 && (NO_PROGRESS_CLOSE<=0 || _total_no_progress< NO_PROGRESS_CLOSE))
|
||||
{
|
||||
LOG.info("EndPoint making no progress: "+_total_no_progress+" "+_endp);
|
||||
}
|
||||
|
||||
if (NO_PROGRESS_CLOSE>0 && _total_no_progress>NO_PROGRESS_CLOSE)
|
||||
{
|
||||
LOG.warn("Closing EndPoint making no progress: "+_total_no_progress+" "+_endp);
|
||||
_endp.close();
|
||||
if (_endp instanceof SelectChannelEndPoint)
|
||||
{
|
||||
System.err.println(((SelectChannelEndPoint)_endp).getSelectManager().dump());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
|
|
@ -76,9 +76,8 @@ public class BlockingHttpConnection extends HttpConnection
|
|||
LOG.debug(e);
|
||||
}
|
||||
_generator.sendError(e.getStatus(), e.getReason(), null, true);
|
||||
|
||||
_parser.reset();
|
||||
_endp.close();
|
||||
_endp.shutdownOutput();
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -205,6 +205,7 @@ public class Dispatcher implements RequestDispatcher
|
|||
if (!(response instanceof HttpServletResponse))
|
||||
response = new ServletResponseHttpWrapper(response);
|
||||
|
||||
final boolean old_handled=baseRequest.isHandled();
|
||||
final String old_uri=baseRequest.getRequestURI();
|
||||
final String old_context_path=baseRequest.getContextPath();
|
||||
final String old_servlet_path=baseRequest.getServletPath();
|
||||
|
@ -216,6 +217,7 @@ public class Dispatcher implements RequestDispatcher
|
|||
|
||||
try
|
||||
{
|
||||
baseRequest.setHandled(false);
|
||||
baseRequest.setDispatcherType(dispatch);
|
||||
|
||||
if (_named!=null)
|
||||
|
@ -262,6 +264,8 @@ public class Dispatcher implements RequestDispatcher
|
|||
|
||||
baseRequest.setRequestURI(_uri);
|
||||
baseRequest.setContextPath(_contextHandler.getContextPath());
|
||||
baseRequest.setServletPath(null);
|
||||
baseRequest.setPathInfo(_uri);
|
||||
baseRequest.setAttributes(attr);
|
||||
|
||||
_contextHandler.handle(_path,baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
|
||||
|
@ -286,6 +290,7 @@ public class Dispatcher implements RequestDispatcher
|
|||
}
|
||||
finally
|
||||
{
|
||||
baseRequest.setHandled(old_handled);
|
||||
baseRequest.setRequestURI(old_uri);
|
||||
baseRequest.setContextPath(old_context_path);
|
||||
baseRequest.setServletPath(old_servlet_path);
|
||||
|
|
|
@ -327,7 +327,7 @@ public abstract class HttpConnection extends AbstractConnection
|
|||
}
|
||||
|
||||
if (_in == null)
|
||||
_in = new HttpInput(((HttpParser)_parser),_connector.getMaxIdleTime());
|
||||
_in = new HttpInput(HttpConnection.this);
|
||||
return _in;
|
||||
}
|
||||
|
||||
|
@ -455,22 +455,22 @@ public abstract class HttpConnection extends AbstractConnection
|
|||
{
|
||||
async_exception=e;
|
||||
LOG.debug(e);
|
||||
_request.setHandled(true);
|
||||
error=true;
|
||||
_request.setHandled(true);
|
||||
}
|
||||
catch (UncheckedIOException e)
|
||||
{
|
||||
async_exception=e;
|
||||
LOG.debug(e);
|
||||
_request.setHandled(true);
|
||||
error=true;
|
||||
_request.setHandled(true);
|
||||
}
|
||||
catch (HttpException e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
error=true;
|
||||
_request.setHandled(true);
|
||||
_response.sendError(e.getStatus(), e.getReason());
|
||||
error=true;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
|
@ -478,9 +478,8 @@ public abstract class HttpConnection extends AbstractConnection
|
|||
throw (ThreadDeath)e;
|
||||
|
||||
async_exception=e;
|
||||
|
||||
error=true;
|
||||
LOG.warn(String.valueOf(_uri),e);
|
||||
error=true;
|
||||
_request.setHandled(true);
|
||||
_generator.sendError(info==null?400:500, null, null, true);
|
||||
}
|
||||
|
@ -515,7 +514,12 @@ public abstract class HttpConnection extends AbstractConnection
|
|||
if(_endp.isOpen())
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
_endp.shutdownOutput();
|
||||
_generator.setPersistent(false);
|
||||
if (!_generator.isComplete())
|
||||
_response.complete();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_response.isCommitted() && !_request.isHandled())
|
||||
|
@ -677,6 +681,16 @@ public abstract class HttpConnection extends AbstractConnection
|
|||
return _expect102Processing;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public int getMaxIdleTime()
|
||||
{
|
||||
if (_connector.isLowResources() && _endp.getMaxIdleTime()==_connector.getMaxIdleTime())
|
||||
return _connector.getLowResourceMaxIdleTime();
|
||||
if (_endp.getMaxIdleTime()>0)
|
||||
return _endp.getMaxIdleTime();
|
||||
return _connector.getMaxIdleTime();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -966,8 +980,7 @@ public abstract class HttpConnection extends AbstractConnection
|
|||
{
|
||||
Output()
|
||||
{
|
||||
super((AbstractGenerator)HttpConnection.this._generator,
|
||||
_connector.isLowResources()?_connector.getLowResourceMaxIdleTime():_connector.getMaxIdleTime());
|
||||
super(HttpConnection.this);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -22,14 +22,14 @@ import org.eclipse.jetty.io.Buffer;
|
|||
|
||||
public class HttpInput extends ServletInputStream
|
||||
{
|
||||
protected final HttpConnection _connection;
|
||||
protected final HttpParser _parser;
|
||||
protected final long _maxIdleTime;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public HttpInput(HttpParser parser, long maxIdleTime)
|
||||
public HttpInput(HttpConnection connection)
|
||||
{
|
||||
_parser=parser;
|
||||
_maxIdleTime=maxIdleTime;
|
||||
_connection=connection;
|
||||
_parser=(HttpParser)connection.getParser();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -40,7 +40,7 @@ public class HttpInput extends ServletInputStream
|
|||
public int read() throws IOException
|
||||
{
|
||||
int c=-1;
|
||||
Buffer content=_parser.blockForContent(_maxIdleTime);
|
||||
Buffer content=_parser.blockForContent(_connection.getMaxIdleTime());
|
||||
if (content!=null)
|
||||
c= 0xff & content.get();
|
||||
return c;
|
||||
|
@ -54,7 +54,7 @@ public class HttpInput extends ServletInputStream
|
|||
public int read(byte[] b, int off, int len) throws IOException
|
||||
{
|
||||
int l=-1;
|
||||
Buffer content=_parser.blockForContent(_maxIdleTime);
|
||||
Buffer content=_parser.blockForContent(_connection.getMaxIdleTime());
|
||||
if (content!=null)
|
||||
l= content.get(b, off, len);
|
||||
return l;
|
||||
|
|
|
@ -36,9 +36,8 @@ import org.eclipse.jetty.util.ByteArrayOutputStream2;
|
|||
*/
|
||||
public class HttpOutput extends ServletOutputStream
|
||||
{
|
||||
protected final HttpConnection _connection;
|
||||
protected final AbstractGenerator _generator;
|
||||
protected final long _maxIdleTime;
|
||||
protected final ByteArrayBuffer _buf = new ByteArrayBuffer(AbstractGenerator.NO_BYTES);
|
||||
private boolean _closed;
|
||||
|
||||
// These are held here for reuse by Writer
|
||||
|
@ -46,15 +45,20 @@ public class HttpOutput extends ServletOutputStream
|
|||
Writer _converter;
|
||||
char[] _chars;
|
||||
ByteArrayOutputStream2 _bytes;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public HttpOutput(AbstractGenerator generator, long maxIdleTime)
|
||||
public HttpOutput(HttpConnection connection)
|
||||
{
|
||||
_generator=generator;
|
||||
_maxIdleTime=maxIdleTime;
|
||||
_connection=connection;
|
||||
_generator=(AbstractGenerator)connection.getGenerator();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public int getMaxIdleTime()
|
||||
{
|
||||
return _connection.getMaxIdleTime();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isWritten()
|
||||
{
|
||||
|
@ -87,7 +91,7 @@ public class HttpOutput extends ServletOutputStream
|
|||
@Override
|
||||
public void flush() throws IOException
|
||||
{
|
||||
_generator.flush(_maxIdleTime);
|
||||
_generator.flush(getMaxIdleTime());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -122,7 +126,7 @@ public class HttpOutput extends ServletOutputStream
|
|||
// Block until we can add _content.
|
||||
while (_generator.isBufferFull())
|
||||
{
|
||||
_generator.blockForOutput(_maxIdleTime);
|
||||
_generator.blockForOutput(getMaxIdleTime());
|
||||
if (_closed)
|
||||
throw new IOException("Closed");
|
||||
if (!_generator.isOpen())
|
||||
|
@ -152,7 +156,7 @@ public class HttpOutput extends ServletOutputStream
|
|||
// Block until we can add _content.
|
||||
while (_generator.isBufferFull())
|
||||
{
|
||||
_generator.blockForOutput(_maxIdleTime);
|
||||
_generator.blockForOutput(getMaxIdleTime());
|
||||
if (_closed)
|
||||
throw new IOException("Closed");
|
||||
if (!_generator.isOpen())
|
||||
|
@ -175,7 +179,7 @@ public class HttpOutput extends ServletOutputStream
|
|||
// Block until our buffer is free
|
||||
while (buffer.length() > 0 && _generator.isOpen())
|
||||
{
|
||||
_generator.blockForOutput(_maxIdleTime);
|
||||
_generator.blockForOutput(getMaxIdleTime());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,9 +23,12 @@ import org.eclipse.jetty.io.ByteArrayBuffer;
|
|||
import org.eclipse.jetty.io.ByteArrayEndPoint;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class LocalConnector extends AbstractConnector
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(LocalConnector.class);
|
||||
private final BlockingQueue<Request> _requests = new LinkedBlockingQueue<Request>();
|
||||
|
||||
public LocalConnector()
|
||||
|
@ -135,8 +138,14 @@ public class LocalConnector extends AbstractConnector
|
|||
}
|
||||
}
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
LOG.debug(x);
|
||||
leaveOpen = false;
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
LOG.warn(x);
|
||||
leaveOpen = false;
|
||||
}
|
||||
finally
|
||||
|
|
|
@ -202,79 +202,36 @@ public class Request implements HttpServletRequest
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Extract Paramters from query string and/or form _content.
|
||||
* Extract Parameters from query string and/or form _content.
|
||||
*/
|
||||
public void extractParameters()
|
||||
{
|
||||
if (_baseParameters == null)
|
||||
_baseParameters = new MultiMap(16);
|
||||
|
||||
|
||||
if (_paramsExtracted)
|
||||
{
|
||||
if (_parameters==null)
|
||||
_parameters=_baseParameters;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_paramsExtracted = true;
|
||||
|
||||
// Handle query string
|
||||
if (_uri!=null && _uri.hasQuery())
|
||||
try
|
||||
{
|
||||
if (_queryEncoding==null)
|
||||
_uri.decodeQueryTo(_baseParameters);
|
||||
else
|
||||
// Handle query string
|
||||
if (_uri!=null && _uri.hasQuery())
|
||||
{
|
||||
try
|
||||
{
|
||||
_uri.decodeQueryTo(_baseParameters,_queryEncoding);
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.warn(e);
|
||||
else
|
||||
LOG.warn(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle any _content.
|
||||
String encoding = getCharacterEncoding();
|
||||
String content_type = getContentType();
|
||||
if (content_type != null && content_type.length() > 0)
|
||||
{
|
||||
content_type = HttpFields.valueParameters(content_type, null);
|
||||
|
||||
if (MimeTypes.FORM_ENCODED.equalsIgnoreCase(content_type) && _inputState==__NONE &&
|
||||
(HttpMethods.POST.equals(getMethod()) || HttpMethods.PUT.equals(getMethod())))
|
||||
{
|
||||
int content_length = getContentLength();
|
||||
if (content_length != 0)
|
||||
if (_queryEncoding==null)
|
||||
_uri.decodeQueryTo(_baseParameters);
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
int maxFormContentSize=-1;
|
||||
|
||||
if (_context!=null)
|
||||
maxFormContentSize=_context.getContextHandler().getMaxFormContentSize();
|
||||
else
|
||||
{
|
||||
Integer size = (Integer)_connection.getConnector().getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormContentSize");
|
||||
if (size!=null)
|
||||
maxFormContentSize =size.intValue();
|
||||
}
|
||||
|
||||
if (content_length>maxFormContentSize && maxFormContentSize > 0)
|
||||
{
|
||||
throw new IllegalStateException("Form too large"+content_length+">"+maxFormContentSize);
|
||||
}
|
||||
InputStream in = getInputStream();
|
||||
|
||||
// Add form params to query params
|
||||
UrlEncoded.decodeTo(in, _baseParameters, encoding,content_length<0?maxFormContentSize:-1);
|
||||
_uri.decodeQueryTo(_baseParameters,_queryEncoding);
|
||||
}
|
||||
catch (IOException e)
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.warn(e);
|
||||
|
@ -283,23 +240,75 @@ public class Request implements HttpServletRequest
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_parameters==null)
|
||||
_parameters=_baseParameters;
|
||||
else if (_parameters!=_baseParameters)
|
||||
{
|
||||
// Merge parameters (needed if parameters extracted after a forward).
|
||||
Iterator iter = _baseParameters.entrySet().iterator();
|
||||
while (iter.hasNext())
|
||||
|
||||
// handle any _content.
|
||||
String encoding = getCharacterEncoding();
|
||||
String content_type = getContentType();
|
||||
if (content_type != null && content_type.length() > 0)
|
||||
{
|
||||
Map.Entry entry = (Map.Entry)iter.next();
|
||||
String name=(String)entry.getKey();
|
||||
Object values=entry.getValue();
|
||||
for (int i=0;i<LazyList.size(values);i++)
|
||||
_parameters.add(name, LazyList.get(values, i));
|
||||
content_type = HttpFields.valueParameters(content_type, null);
|
||||
|
||||
if (MimeTypes.FORM_ENCODED.equalsIgnoreCase(content_type) && _inputState==__NONE &&
|
||||
(HttpMethods.POST.equals(getMethod()) || HttpMethods.PUT.equals(getMethod())))
|
||||
{
|
||||
int content_length = getContentLength();
|
||||
if (content_length != 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
int maxFormContentSize=-1;
|
||||
|
||||
if (_context!=null)
|
||||
maxFormContentSize=_context.getContextHandler().getMaxFormContentSize();
|
||||
else
|
||||
{
|
||||
Integer size = (Integer)_connection.getConnector().getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormContentSize");
|
||||
if (size!=null)
|
||||
maxFormContentSize =size.intValue();
|
||||
}
|
||||
|
||||
if (content_length>maxFormContentSize && maxFormContentSize > 0)
|
||||
{
|
||||
throw new IllegalStateException("Form too large"+content_length+">"+maxFormContentSize);
|
||||
}
|
||||
InputStream in = getInputStream();
|
||||
|
||||
// Add form params to query params
|
||||
UrlEncoded.decodeTo(in, _baseParameters, encoding,content_length<0?maxFormContentSize:-1);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.warn(e);
|
||||
else
|
||||
LOG.warn(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_parameters==null)
|
||||
_parameters=_baseParameters;
|
||||
else if (_parameters!=_baseParameters)
|
||||
{
|
||||
// Merge parameters (needed if parameters extracted after a forward).
|
||||
Iterator iter = _baseParameters.entrySet().iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
Map.Entry entry = (Map.Entry)iter.next();
|
||||
String name=(String)entry.getKey();
|
||||
Object values=entry.getValue();
|
||||
for (int i=0;i<LazyList.size(values);i++)
|
||||
_parameters.add(name, LazyList.get(values, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
//ensure params always set (even if empty) after extraction
|
||||
if (_parameters==null)
|
||||
_parameters=_baseParameters;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -431,7 +431,7 @@ public class Response implements HttpServletResponse
|
|||
if (!canonical.equals(path))
|
||||
{
|
||||
buf = _connection.getRequest().getRootURL();
|
||||
buf.append(canonical);
|
||||
buf.append(URIUtil.encodePath(canonical));
|
||||
if (uri.getQuery()!=null)
|
||||
{
|
||||
buf.append('?');
|
||||
|
|
|
@ -17,6 +17,7 @@ import java.io.IOException;
|
|||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
@ -81,7 +82,7 @@ public class SocketConnector extends AbstractConnector
|
|||
_localPort=_serverSocket.getLocalPort();
|
||||
if (_localPort<=0)
|
||||
throw new IllegalStateException("port not allocated for "+this);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -175,7 +176,6 @@ public class SocketConnector extends AbstractConnector
|
|||
/* ------------------------------------------------------------------------------- */
|
||||
protected class ConnectorEndPoint extends SocketEndPoint implements Runnable, ConnectedEndPoint
|
||||
{
|
||||
boolean _dispatched=false;
|
||||
volatile Connection _connection;
|
||||
protected final Socket _socket;
|
||||
|
||||
|
@ -251,6 +251,12 @@ public class SocketConnector extends AbstractConnector
|
|||
try{close();}
|
||||
catch(IOException e2){LOG.ignore(e2);}
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
LOG.debug("EOF", e);
|
||||
try{close();}
|
||||
catch(IOException e2){LOG.ignore(e2);}
|
||||
}
|
||||
catch (HttpException e)
|
||||
{
|
||||
LOG.debug("BAD", e);
|
||||
|
@ -277,7 +283,7 @@ public class SocketConnector extends AbstractConnector
|
|||
if (!_socket.isClosed())
|
||||
{
|
||||
long timestamp=System.currentTimeMillis();
|
||||
int max_idle=getMaxIdleTime();
|
||||
int max_idle=getMaxIdleTime();
|
||||
|
||||
_socket.setSoTimeout(getMaxIdleTime());
|
||||
int c=0;
|
||||
|
|
|
@ -833,7 +833,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
|
|||
String old_path_info = null;
|
||||
ClassLoader old_classloader = null;
|
||||
Thread current_thread = null;
|
||||
String pathInfo = null;
|
||||
String pathInfo = target;
|
||||
|
||||
DispatcherType dispatch = baseRequest.getDispatcherType();
|
||||
|
||||
|
|
|
@ -159,7 +159,7 @@ public class GzipHandler extends HandlerWrapper
|
|||
*
|
||||
* @return the buffer size
|
||||
*/
|
||||
public int setBufferSize()
|
||||
public int getBufferSize()
|
||||
{
|
||||
return _bufferSize;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.eclipse.jetty.http.MimeTypes;
|
|||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.io.WriterOutputStream;
|
||||
import org.eclipse.jetty.server.Dispatcher;
|
||||
import org.eclipse.jetty.server.HttpConnection;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
|
@ -45,7 +46,7 @@ import org.eclipse.jetty.util.resource.Resource;
|
|||
*
|
||||
* This handle will serve static content and handle If-Modified-Since headers.
|
||||
* No caching is done.
|
||||
* Requests that cannot be handled are let pass (Eg no 404's)
|
||||
* Requests for resources that do not exist are let pass (Eg no 404's).
|
||||
*
|
||||
*
|
||||
* @org.apache.xbean.XBean
|
||||
|
@ -205,7 +206,7 @@ public class ResourceHandler extends AbstractHandler
|
|||
{
|
||||
try
|
||||
{
|
||||
_defaultStylesheet = Resource.newResource(this.getClass().getResource("/jetty-default.css"));
|
||||
_defaultStylesheet = Resource.newResource(this.getClass().getResource("/jetty-dir.css"));
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
|
@ -292,10 +293,29 @@ public class ResourceHandler extends AbstractHandler
|
|||
/* ------------------------------------------------------------ */
|
||||
protected Resource getResource(HttpServletRequest request) throws MalformedURLException
|
||||
{
|
||||
String path_info=request.getPathInfo();
|
||||
if (path_info==null)
|
||||
return null;
|
||||
return getResource(path_info);
|
||||
String servletPath;
|
||||
String pathInfo;
|
||||
Boolean included = request.getAttribute(Dispatcher.INCLUDE_REQUEST_URI) != null;
|
||||
if (included != null && included.booleanValue())
|
||||
{
|
||||
servletPath = (String)request.getAttribute(Dispatcher.INCLUDE_SERVLET_PATH);
|
||||
pathInfo = (String)request.getAttribute(Dispatcher.INCLUDE_PATH_INFO);
|
||||
|
||||
if (servletPath == null && pathInfo == null)
|
||||
{
|
||||
servletPath = request.getServletPath();
|
||||
pathInfo = request.getPathInfo();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
included = Boolean.FALSE;
|
||||
servletPath = request.getServletPath();
|
||||
pathInfo = request.getPathInfo();
|
||||
}
|
||||
|
||||
String pathInContext=URIUtil.addPaths(servletPath,pathInfo);
|
||||
return getResource(pathInContext);
|
||||
}
|
||||
|
||||
|
||||
|
@ -326,7 +346,7 @@ public class ResourceHandler extends AbstractHandler
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* @see org.eclipse.jetty.server.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
|
||||
* @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
|
||||
*/
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
|
@ -334,17 +354,21 @@ public class ResourceHandler extends AbstractHandler
|
|||
return;
|
||||
|
||||
boolean skipContentBody = false;
|
||||
|
||||
if(!HttpMethods.GET.equals(request.getMethod()))
|
||||
{
|
||||
if(!HttpMethods.HEAD.equals(request.getMethod()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
skipContentBody = true;
|
||||
}
|
||||
|
||||
Resource resource = getResource(request);
|
||||
|
||||
if (resource==null || !resource.exists())
|
||||
{
|
||||
if (target.endsWith("/jetty-stylesheet.css"))
|
||||
if (target.endsWith("/jetty-dir.css"))
|
||||
{
|
||||
response.setContentType("text/css");
|
||||
resource = getStylesheet();
|
||||
|
@ -359,7 +383,7 @@ public class ResourceHandler extends AbstractHandler
|
|||
return;
|
||||
}
|
||||
|
||||
// We are going to server something
|
||||
// We are going to serve something
|
||||
baseRequest.setHandled(true);
|
||||
|
||||
if (resource.isDirectory())
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2009-2009 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.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* A handler that shuts the server down on a valid request. Used to do "soft" restarts from Java. If _exitJvm ist set to true a hard System.exit() call is being
|
||||
* made.
|
||||
*
|
||||
* This handler is a contribution from Johannes Brodwall: https://bugs.eclipse.org/bugs/show_bug.cgi?id=357687
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* <pre>
|
||||
* Server server = new Server(8080);
|
||||
* HandlerList handlers = new HandlerList();
|
||||
* handlers.setHandlers(new Handler[]
|
||||
* { someOtherHandler, new ShutdownHandler(server,"secret password") });
|
||||
* server.setHandler(handlers);
|
||||
* server.start();
|
||||
* </pre>
|
||||
*/
|
||||
public class ShutdownHandler extends AbstractHandler
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ShutdownHandler.class);
|
||||
|
||||
private final String _shutdownToken;
|
||||
|
||||
private final Server _server;
|
||||
|
||||
private boolean _exitJvm = false;
|
||||
|
||||
/**
|
||||
* Creates a listener that lets the server be shut down remotely (but only from localhost).
|
||||
*
|
||||
* @param server
|
||||
* the Jetty instance that should be shut down
|
||||
* @param shutdownToken
|
||||
* a secret password to avoid unauthorized shutdown attempts
|
||||
*/
|
||||
public ShutdownHandler(Server server, String shutdownToken)
|
||||
{
|
||||
this._server = server;
|
||||
this._shutdownToken = shutdownToken;
|
||||
}
|
||||
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
if (!target.equals("/shutdown"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!request.getMethod().equals("POST"))
|
||||
{
|
||||
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
if (!hasCorrectSecurityToken(request))
|
||||
{
|
||||
LOG.warn("Unauthorized shutdown attempt from " + getRemoteAddr(request));
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
return;
|
||||
}
|
||||
if (!requestFromLocalhost(request))
|
||||
{
|
||||
LOG.warn("Unauthorized shutdown attempt from " + getRemoteAddr(request));
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG.info("Shutting down by request from " + getRemoteAddr(request));
|
||||
|
||||
try
|
||||
{
|
||||
shutdownServer();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException("Shutting down server",e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean requestFromLocalhost(HttpServletRequest request)
|
||||
{
|
||||
return "127.0.0.1".equals(getRemoteAddr(request));
|
||||
}
|
||||
|
||||
protected String getRemoteAddr(HttpServletRequest request)
|
||||
{
|
||||
return request.getRemoteAddr();
|
||||
}
|
||||
|
||||
private boolean hasCorrectSecurityToken(HttpServletRequest request)
|
||||
{
|
||||
return _shutdownToken.equals(request.getParameter("token"));
|
||||
}
|
||||
|
||||
private void shutdownServer() throws Exception
|
||||
{
|
||||
_server.stop();
|
||||
|
||||
if (_exitJvm)
|
||||
{
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void setExitJvm(boolean exitJvm)
|
||||
{
|
||||
this._exitJvm = exitJvm;
|
||||
}
|
||||
|
||||
}
|
|
@ -133,6 +133,12 @@ public class SelectChannelConnector extends AbstractNIOConnector
|
|||
super.persist(endpoint);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SelectorManager getSelectorManager()
|
||||
{
|
||||
return _manager;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Object getConnection()
|
||||
{
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
package org.eclipse.jetty.server.session;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
@ -46,6 +48,34 @@ public class HashSessionIdManager extends AbstractSessionIdManager
|
|||
super(random);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return Collection of String session IDs
|
||||
*/
|
||||
public Collection<String> getSessions()
|
||||
{
|
||||
return Collections.unmodifiableCollection(_sessions.keySet());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return Collection of Sessions for the passed session ID
|
||||
*/
|
||||
public Collection<HttpSession> getSession(String id)
|
||||
{
|
||||
ArrayList<HttpSession> sessions = new ArrayList<HttpSession>();
|
||||
Set<WeakReference<HttpSession>> refs =_sessions.get(id);
|
||||
if (refs!=null)
|
||||
{
|
||||
for (WeakReference<HttpSession> ref: refs)
|
||||
{
|
||||
HttpSession session = ref.get();
|
||||
if (session!=null)
|
||||
sessions.add(session);
|
||||
}
|
||||
}
|
||||
return sessions;
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the session ID with any worker ID.
|
||||
*
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.io.InputStream;
|
|||
import java.sql.Blob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.Driver;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
|
@ -56,6 +57,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
|||
|
||||
protected final HashSet<String> _sessionIds = new HashSet<String>();
|
||||
protected Server _server;
|
||||
protected Driver _driver;
|
||||
protected String _driverClassName;
|
||||
protected String _connectionUrl;
|
||||
protected DataSource _datasource;
|
||||
|
@ -184,6 +186,19 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
|||
_connectionUrl=connectionUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure jdbc connection information via a jdbc Driver
|
||||
*
|
||||
* @param driverClass
|
||||
* @param connectionUrl
|
||||
*/
|
||||
public void setDriverInfo (Driver driverClass, String connectionUrl)
|
||||
{
|
||||
_driver=driverClass;
|
||||
_connectionUrl=connectionUrl;
|
||||
}
|
||||
|
||||
|
||||
public String getDriverClassName()
|
||||
{
|
||||
return _driverClassName;
|
||||
|
@ -461,7 +476,11 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
|||
InitialContext ic = new InitialContext();
|
||||
_datasource = (DataSource)ic.lookup(_jndiName);
|
||||
}
|
||||
else if (_driverClassName!=null && _connectionUrl!=null)
|
||||
else if ( _driver != null && _connectionUrl != null )
|
||||
{
|
||||
DriverManager.registerDriver(_driver);
|
||||
}
|
||||
else if (_driverClassName != null && _connectionUrl != null)
|
||||
{
|
||||
Class.forName(_driverClassName);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ package org.eclipse.jetty.server.ssl;
|
|||
import java.io.IOException;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
@ -36,7 +38,6 @@ import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint;
|
|||
import org.eclipse.jetty.server.HttpConnection;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -97,7 +98,7 @@ public class SslSelectChannelConnector extends SelectChannelConnector implements
|
|||
SslSelectChannelEndPoint sslHttpChannelEndpoint=(SslSelectChannelEndPoint)endpoint;
|
||||
SSLEngine sslEngine=sslHttpChannelEndpoint.getSSLEngine();
|
||||
SSLSession sslSession=sslEngine.getSession();
|
||||
|
||||
|
||||
SslCertificates.customize(sslSession,endpoint,request);
|
||||
}
|
||||
|
||||
|
@ -565,33 +566,19 @@ public class SslSelectChannelConnector extends SelectChannelConnector implements
|
|||
protected SSLEngine createSSLEngine(SocketChannel channel) throws IOException
|
||||
{
|
||||
SSLEngine engine;
|
||||
if (channel != null && _sslContextFactory.isSessionCachingEnabled())
|
||||
if (channel != null)
|
||||
{
|
||||
String peerHost = channel.socket().getInetAddress().getHostAddress();
|
||||
int peerPort = channel.socket().getPort();
|
||||
engine = _sslContextFactory.getSslContext().createSSLEngine(peerHost, peerPort);
|
||||
engine = _sslContextFactory.newSslEngine(peerHost, peerPort);
|
||||
}
|
||||
else
|
||||
{
|
||||
engine = _sslContextFactory.getSslContext().createSSLEngine();
|
||||
engine = _sslContextFactory.newSslEngine();
|
||||
}
|
||||
customizeEngine(engine);
|
||||
return engine;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void customizeEngine(SSLEngine engine)
|
||||
{
|
||||
|
||||
engine.setUseClientMode(false);
|
||||
|
||||
if (_sslContextFactory.getWantClientAuth())
|
||||
engine.setWantClientAuth(_sslContextFactory.getWantClientAuth());
|
||||
if (_sslContextFactory.getNeedClientAuth())
|
||||
engine.setNeedClientAuth(_sslContextFactory.getNeedClientAuth());
|
||||
|
||||
engine.setEnabledCipherSuites(
|
||||
_sslContextFactory.selectCipherSuites(engine.getEnabledCipherSuites(),
|
||||
engine.getSupportedCipherSuites()));
|
||||
return engine;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -601,22 +588,13 @@ public class SslSelectChannelConnector extends SelectChannelConnector implements
|
|||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
if (!_sslContextFactory.checkConfig())
|
||||
{
|
||||
throw new IllegalStateException("SSL context is not configured correctly.");
|
||||
}
|
||||
_sslContextFactory.checkKeyStore();
|
||||
|
||||
_sslContextFactory.start();
|
||||
|
||||
SSLEngine sslEngine = _sslContextFactory.getSslContext().createSSLEngine();
|
||||
SSLEngine sslEngine = _sslContextFactory.newSslEngine();
|
||||
|
||||
sslEngine.setUseClientMode(false);
|
||||
sslEngine.setWantClientAuth(_sslContextFactory.getWantClientAuth());
|
||||
sslEngine.setNeedClientAuth(_sslContextFactory.getNeedClientAuth());
|
||||
|
||||
sslEngine.setEnabledCipherSuites(_sslContextFactory.selectCipherSuites(
|
||||
sslEngine.getEnabledCipherSuites(),
|
||||
sslEngine.getSupportedCipherSuites()));
|
||||
|
||||
SSLSession sslSession = sslEngine.getSession();
|
||||
|
||||
|
|
|
@ -4,32 +4,30 @@
|
|||
// 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
|
||||
// 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.
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
|
||||
package org.eclipse.jetty.server.ssl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
import javax.net.ssl.HandshakeCompletedEvent;
|
||||
import javax.net.ssl.HandshakeCompletedListener;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLServerSocket;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
import org.eclipse.jetty.http.HttpSchemes;
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.RuntimeIOException;
|
||||
import org.eclipse.jetty.io.bio.SocketEndPoint;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.bio.SocketConnector;
|
||||
|
@ -39,17 +37,17 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* SSL Socket Connector.
|
||||
*
|
||||
*
|
||||
* This specialization of SocketConnector is an abstract listener that can be used as the basis for a
|
||||
* specific JSSE listener.
|
||||
*
|
||||
* The original of this class was heavily based on the work from Court Demas, which in turn is
|
||||
*
|
||||
* The original of this class was heavily based on the work from Court Demas, which in turn is
|
||||
* based on the work from Forge Research. Since JSSE, this class has evolved significantly from
|
||||
* that early work.
|
||||
*
|
||||
*
|
||||
* @org.apache.xbean.XBean element="sslSocketConnector" description="Creates an ssl socket connector"
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class SslSocketConnector extends SocketConnector implements SslConnector
|
||||
{
|
||||
|
@ -67,6 +65,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
this(new SslContextFactory(SslContextFactory.DEFAULT_KEYSTORE_PATH));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SslSocketConnector(SslContextFactory sslContextFactory)
|
||||
{
|
||||
_sslContextFactory = sslContextFactory;
|
||||
|
@ -85,7 +84,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
/**
|
||||
* Set if SSL re-negotiation is allowed. CVE-2009-3555 discovered
|
||||
* a vulnerability in SSL/TLS with re-negotiation. If your JVM
|
||||
* does not have CVE-2009-3555 fixed, then re-negotiation should
|
||||
* does not have CVE-2009-3555 fixed, then re-negotiation should
|
||||
* not be allowed.
|
||||
* @param allowRenegotiate true if re-negotiation is allowed (default false)
|
||||
*/
|
||||
|
@ -98,19 +97,19 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
@Override
|
||||
public void accept(int acceptorID)
|
||||
throws IOException, InterruptedException
|
||||
{
|
||||
{
|
||||
Socket socket = _serverSocket.accept();
|
||||
configure(socket);
|
||||
|
||||
|
||||
ConnectorEndPoint connection=new SslConnectorEndPoint(socket);
|
||||
connection.dispatch();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void configure(Socket socket)
|
||||
throws IOException
|
||||
{
|
||||
{
|
||||
super.configure(socket);
|
||||
}
|
||||
|
||||
|
@ -129,8 +128,8 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
* certificate in the chain is the one set by the client, the next is the one used to
|
||||
* authenticate the first, and so on. </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param endpoint The Socket the request arrived on.
|
||||
*
|
||||
* @param endpoint The Socket the request arrived on.
|
||||
* This should be a {@link SocketEndPoint} wrapping a {@link SSLSocket}.
|
||||
* @param request HttpRequest to be customised.
|
||||
*/
|
||||
|
@ -140,7 +139,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
{
|
||||
super.customize(endpoint, request);
|
||||
request.setScheme(HttpSchemes.HTTPS);
|
||||
|
||||
|
||||
SocketEndPoint socket_end_point = (SocketEndPoint)endpoint;
|
||||
SSLSocket sslSocket = (SSLSocket)socket_end_point.getTransport();
|
||||
SSLSession sslSession = sslSocket.getSession();
|
||||
|
@ -148,7 +147,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
SslCertificates.customize(sslSession,endpoint,request);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#getExcludeCipherSuites()
|
||||
* @deprecated
|
||||
|
@ -157,7 +156,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
public String[] getExcludeCipherSuites() {
|
||||
return _sslContextFactory.getExcludeCipherSuites();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#getIncludeCipherSuites()
|
||||
|
@ -186,7 +185,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public String getKeystoreType()
|
||||
public String getKeystoreType()
|
||||
{
|
||||
return _sslContextFactory.getKeyStoreType();
|
||||
}
|
||||
|
@ -208,7 +207,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public String getProtocol()
|
||||
public String getProtocol()
|
||||
{
|
||||
return _sslContextFactory.getProtocol();
|
||||
}
|
||||
|
@ -229,7 +228,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public String getSecureRandomAlgorithm()
|
||||
public String getSecureRandomAlgorithm()
|
||||
{
|
||||
return _sslContextFactory.getSecureRandomAlgorithm();
|
||||
}
|
||||
|
@ -240,7 +239,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public String getSslKeyManagerFactoryAlgorithm()
|
||||
public String getSslKeyManagerFactoryAlgorithm()
|
||||
{
|
||||
return _sslContextFactory.getSslKeyManagerFactoryAlgorithm();
|
||||
}
|
||||
|
@ -251,7 +250,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public String getSslTrustManagerFactoryAlgorithm()
|
||||
public String getSslTrustManagerFactoryAlgorithm()
|
||||
{
|
||||
return _sslContextFactory.getTrustManagerFactoryAlgorithm();
|
||||
}
|
||||
|
@ -313,7 +312,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
final int confidentialPort = getConfidentialPort();
|
||||
return confidentialPort == 0 || confidentialPort == request.getServerPort();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* By default, we're integral, given we speak SSL. But, if we've been told about an integral
|
||||
|
@ -329,6 +328,22 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
return integralPort == 0 || integralPort == request.getServerPort();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void open() throws IOException
|
||||
{
|
||||
_sslContextFactory.checkKeyStore();
|
||||
try
|
||||
{
|
||||
_sslContextFactory.start();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeIOException(e);
|
||||
}
|
||||
super.open();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
|
@ -336,16 +351,12 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
if (!_sslContextFactory.checkConfig())
|
||||
{
|
||||
throw new IllegalStateException("SSL context is not configured correctly.");
|
||||
}
|
||||
|
||||
_sslContextFactory.checkKeyStore();
|
||||
_sslContextFactory.start();
|
||||
|
||||
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.bio.SocketConnector#doStop()
|
||||
|
@ -357,14 +368,14 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
|
||||
super.doStop();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param host The host name that this server should listen on
|
||||
* @param port the port that this server should listen on
|
||||
* @param port the port that this server should listen on
|
||||
* @param backlog See {@link ServerSocket#bind(java.net.SocketAddress, int)}
|
||||
* @return A new {@link ServerSocket socket object} bound to the supplied address with all other
|
||||
* settings as per the current configuration of this connector.
|
||||
* settings as per the current configuration of this connector.
|
||||
* @see #setWantClientAuth(boolean)
|
||||
* @see #setNeedClientAuth(boolean)
|
||||
* @exception IOException
|
||||
|
@ -372,22 +383,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
@Override
|
||||
protected ServerSocket newServerSocket(String host, int port,int backlog) throws IOException
|
||||
{
|
||||
SSLServerSocketFactory factory = _sslContextFactory.getSslContext().getServerSocketFactory();
|
||||
|
||||
SSLServerSocket socket =
|
||||
(SSLServerSocket) (host==null ?
|
||||
factory.createServerSocket(port,backlog):
|
||||
factory.createServerSocket(port,backlog,InetAddress.getByName(host)));
|
||||
|
||||
if (_sslContextFactory.getWantClientAuth())
|
||||
socket.setWantClientAuth(_sslContextFactory.getWantClientAuth());
|
||||
if (_sslContextFactory.getNeedClientAuth())
|
||||
socket.setNeedClientAuth(_sslContextFactory.getNeedClientAuth());
|
||||
|
||||
socket.setEnabledCipherSuites(_sslContextFactory.selectCipherSuites(
|
||||
socket.getEnabledCipherSuites(),
|
||||
socket.getSupportedCipherSuites()));
|
||||
return socket;
|
||||
return _sslContextFactory.newSslServerSocket(host,port,backlog);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -440,7 +436,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setKeystoreType(String keystoreType)
|
||||
public void setKeystoreType(String keystoreType)
|
||||
{
|
||||
_sslContextFactory.setKeyStoreType(keystoreType);
|
||||
}
|
||||
|
@ -448,7 +444,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Set the value of the needClientAuth property
|
||||
*
|
||||
*
|
||||
* @param needClientAuth true iff we require client certificate authentication.
|
||||
* @deprecated
|
||||
*/
|
||||
|
@ -457,7 +453,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
{
|
||||
_sslContextFactory.setNeedClientAuth(needClientAuth);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setPassword(java.lang.String)
|
||||
|
@ -468,7 +464,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
{
|
||||
_sslContextFactory.setKeyStorePassword(password);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setTrustPassword(java.lang.String)
|
||||
|
@ -486,7 +482,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setProtocol(String protocol)
|
||||
public void setProtocol(String protocol)
|
||||
{
|
||||
_sslContextFactory.setProtocol(protocol);
|
||||
}
|
||||
|
@ -507,7 +503,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setSecureRandomAlgorithm(String algorithm)
|
||||
public void setSecureRandomAlgorithm(String algorithm)
|
||||
{
|
||||
_sslContextFactory.setSecureRandomAlgorithm(algorithm);
|
||||
}
|
||||
|
@ -518,18 +514,18 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setSslKeyManagerFactoryAlgorithm(String algorithm)
|
||||
public void setSslKeyManagerFactoryAlgorithm(String algorithm)
|
||||
{
|
||||
_sslContextFactory.setSslKeyManagerFactoryAlgorithm(algorithm);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setSslTrustManagerFactoryAlgorithm(java.lang.String)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setSslTrustManagerFactoryAlgorithm(String algorithm)
|
||||
public void setSslTrustManagerFactoryAlgorithm(String algorithm)
|
||||
{
|
||||
_sslContextFactory.setTrustManagerFactoryAlgorithm(algorithm);
|
||||
}
|
||||
|
@ -544,7 +540,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
{
|
||||
_sslContextFactory.setTrustStore(truststore);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setTruststoreType(java.lang.String)
|
||||
|
@ -555,7 +551,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
{
|
||||
_sslContextFactory.setTrustStoreType(truststoreType);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext)
|
||||
|
@ -580,9 +576,9 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Set the value of the _wantClientAuth property. This property is used
|
||||
* Set the value of the _wantClientAuth property. This property is used
|
||||
* internally when opening server sockets.
|
||||
*
|
||||
*
|
||||
* @param wantClientAuth true if we want client certificate authentication.
|
||||
* @see SSLServerSocket#setWantClientAuth
|
||||
* @deprecated
|
||||
|
@ -603,7 +599,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
{
|
||||
_handshakeTimeout = msec;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public int getHandshakeTimeout ()
|
||||
|
@ -618,19 +614,19 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
{
|
||||
super(socket);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void shutdownOutput() throws IOException
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void shutdownInput() throws IOException
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
|
@ -638,7 +634,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
{
|
||||
int handshakeTimeout = getHandshakeTimeout();
|
||||
int oldTimeout = _socket.getSoTimeout();
|
||||
if (handshakeTimeout > 0)
|
||||
if (handshakeTimeout > 0)
|
||||
_socket.setSoTimeout(handshakeTimeout);
|
||||
|
||||
final SSLSocket ssl=(SSLSocket)_socket;
|
||||
|
@ -668,7 +664,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
}
|
||||
catch (SSLException e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
LOG.debug(e);
|
||||
try{close();}
|
||||
catch(IOException e2){LOG.ignore(e2);}
|
||||
}
|
||||
|
@ -677,14 +673,14 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
LOG.debug(e);
|
||||
try{close();}
|
||||
catch(IOException e2){LOG.ignore(e2);}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Unsupported.
|
||||
*
|
||||
*
|
||||
* TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past)
|
||||
* @deprecated
|
||||
*/
|
||||
|
@ -697,7 +693,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Unsupported.
|
||||
*
|
||||
*
|
||||
* TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past)
|
||||
* @deprecated
|
||||
*/
|
||||
|
|
|
@ -52,7 +52,10 @@ public class BusySelectChannelServerTest extends HttpServerTestBase
|
|||
{
|
||||
int x=write++&0xff;
|
||||
if (x<8)
|
||||
{
|
||||
clearWritable();
|
||||
return 0;
|
||||
}
|
||||
if (x<32)
|
||||
return flush(header);
|
||||
return super.flush(header,buffer,trailer);
|
||||
|
@ -67,7 +70,10 @@ public class BusySelectChannelServerTest extends HttpServerTestBase
|
|||
{
|
||||
int x=write++&0xff;
|
||||
if (x<8)
|
||||
{
|
||||
clearWritable();
|
||||
return 0;
|
||||
}
|
||||
if (x<32)
|
||||
{
|
||||
View v = new View(buffer);
|
||||
|
@ -75,6 +81,7 @@ public class BusySelectChannelServerTest extends HttpServerTestBase
|
|||
int l=super.flush(v);
|
||||
if (l>0)
|
||||
buffer.skip(l);
|
||||
clearWritable();
|
||||
return l;
|
||||
}
|
||||
return super.flush(buffer);
|
||||
|
|
|
@ -37,8 +37,11 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.StdErrLog;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
|
@ -106,7 +109,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
|||
* Feed the server the entire request at once.
|
||||
*/
|
||||
@Test
|
||||
public void testRequest1_jetty() throws Exception
|
||||
public void testRequest1() throws Exception
|
||||
{
|
||||
configureServer(new HelloWorldHandler());
|
||||
|
||||
|
@ -164,7 +167,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
|||
* Feed the server fragmentary headers and see how it copes with it.
|
||||
*/
|
||||
@Test
|
||||
public void testRequest1Fragments_jetty() throws Exception, InterruptedException
|
||||
public void testRequest1Fragments() throws Exception, InterruptedException
|
||||
{
|
||||
configureServer(new HelloWorldHandler());
|
||||
|
||||
|
@ -197,7 +200,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testRequest2_jetty() throws Exception
|
||||
public void testRequest2() throws Exception
|
||||
{
|
||||
configureServer(new EchoHandler());
|
||||
|
||||
|
@ -226,7 +229,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testRequest2Fragments_jetty() throws Exception
|
||||
public void testRequest2Fragments() throws Exception
|
||||
{
|
||||
configureServer(new EchoHandler());
|
||||
|
||||
|
@ -270,7 +273,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testRequest2Iterate_jetty() throws Exception
|
||||
public void testRequest2Iterate() throws Exception
|
||||
{
|
||||
configureServer(new EchoHandler());
|
||||
|
||||
|
@ -309,7 +312,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
|||
* After several iterations, I generated some known bad fragment points.
|
||||
*/
|
||||
@Test
|
||||
public void testRequest2KnownBad_jetty() throws Exception
|
||||
public void testRequest2KnownBad() throws Exception
|
||||
{
|
||||
configureServer(new EchoHandler());
|
||||
|
||||
|
@ -425,7 +428,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
|||
|
||||
while(len>=0)
|
||||
{
|
||||
Thread.sleep(500);
|
||||
Thread.sleep(100);
|
||||
len=is.read(buf);
|
||||
if (len>0)
|
||||
total+=len;
|
||||
|
@ -447,6 +450,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
|||
|
||||
long start=System.currentTimeMillis();
|
||||
Socket client=newSocket(HOST,_connector.getLocalPort());
|
||||
int total=0;
|
||||
try
|
||||
{
|
||||
OutputStream os=client.getOutputStream();
|
||||
|
@ -461,7 +465,6 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
|||
).getBytes());
|
||||
os.flush();
|
||||
|
||||
int total=0;
|
||||
int len=0;
|
||||
byte[] buf=new byte[1024*32];
|
||||
|
||||
|
@ -480,6 +483,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
|||
}
|
||||
finally
|
||||
{
|
||||
System.err.println("Got "+total+" of "+(512*1024));
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
@ -490,17 +494,17 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
|||
configureServer(new BigBlockHandler());
|
||||
|
||||
Socket client=newSocket(HOST,_connector.getLocalPort());
|
||||
client.setSoTimeout(10000);
|
||||
client.setSoTimeout(20000);
|
||||
try
|
||||
{
|
||||
OutputStream os=client.getOutputStream();
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
|
||||
|
||||
os.write((
|
||||
"GET / HTTP/1.1\r\n"+
|
||||
"GET /r1 HTTP/1.1\r\n"+
|
||||
"host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+
|
||||
"\r\n"+
|
||||
"GET / HTTP/1.1\r\n"+
|
||||
"GET /r2 HTTP/1.1\r\n"+
|
||||
"host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+
|
||||
"connection: close\r\n"+
|
||||
"\r\n"
|
||||
|
@ -583,6 +587,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
|||
}
|
||||
}
|
||||
|
||||
// Handler that sends big blocks of data in each of 10 writes, and then sends the time it took for each big block.
|
||||
protected static class BigBlockHandler extends AbstractHandler
|
||||
{
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
|
@ -598,10 +603,12 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
|||
long[] times=new long[10];
|
||||
for (int i=0;i<times.length;i++)
|
||||
{
|
||||
// System.err.println("\nBLOCK "+request.getRequestURI()+" "+i);
|
||||
long start=System.currentTimeMillis();
|
||||
out.write(buf);
|
||||
long end=System.currentTimeMillis();
|
||||
times[i]=end-start;
|
||||
// System.err.println("Block "+request.getRequestURI()+" "+i+" "+times[i]);
|
||||
}
|
||||
out.println();
|
||||
for (long t : times)
|
||||
|
@ -910,6 +917,68 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommittedError() throws Exception
|
||||
{
|
||||
CommittedErrorHandler handler =new CommittedErrorHandler();
|
||||
configureServer(handler);
|
||||
|
||||
Socket client=newSocket(HOST,_connector.getLocalPort());
|
||||
try
|
||||
{
|
||||
((StdErrLog)Log.getLogger(HttpConnection.class)).setHideStacks(true);
|
||||
OutputStream os=client.getOutputStream();
|
||||
InputStream is=client.getInputStream();
|
||||
|
||||
// Send a request
|
||||
os.write((
|
||||
"GET / HTTP/1.1\r\n"+
|
||||
"Host: "+HOST+":"+_connector.getLocalPort()+"\r\n" +
|
||||
"\r\n"
|
||||
).getBytes());
|
||||
os.flush();
|
||||
|
||||
client.setSoTimeout(2000);
|
||||
String in = IO.toString(is);
|
||||
|
||||
assertEquals(-1,is.read()); // Closed by error!
|
||||
|
||||
assertTrue(in.indexOf("HTTP/1.1 200 OK")>=0);
|
||||
assertTrue(in.indexOf("Transfer-Encoding: chunked")>0);
|
||||
assertTrue(in.indexOf("Now is the time for all good men to come to the aid of the party")>0);
|
||||
assertTrue(in.indexOf("\r\n0\r\n")==-1); // chunking is interrupted by error close
|
||||
|
||||
client.close();
|
||||
Thread.sleep(100);
|
||||
assertTrue(!handler._endp.isOpen());
|
||||
}
|
||||
finally
|
||||
{
|
||||
((StdErrLog)Log.getLogger(HttpConnection.class)).setHideStacks(false);
|
||||
|
||||
if (!client.isClosed())
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected static class CommittedErrorHandler extends AbstractHandler
|
||||
{
|
||||
public EndPoint _endp;
|
||||
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
_endp=baseRequest.getConnection().getEndPoint();
|
||||
response.setHeader("test","value");
|
||||
response.setStatus(200);
|
||||
response.setContentType("text/plain");
|
||||
response.getWriter().println("Now is the time for all good men to come to the aid of the party");
|
||||
response.getWriter().flush();
|
||||
response.flushBuffer();
|
||||
|
||||
throw new ServletException(new Exception("exception after commit"));
|
||||
}
|
||||
}
|
||||
|
||||
protected static class AvailableHandler extends AbstractHandler
|
||||
{
|
||||
public Exchanger<Object> _ex = new Exchanger<Object>();
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.eclipse.jetty.io.Buffer;
|
|||
import org.eclipse.jetty.io.Buffers;
|
||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.io.ByteArrayEndPoint;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.SimpleBuffers;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
|
@ -75,7 +76,17 @@ public class HttpWriterTest
|
|||
|
||||
};
|
||||
|
||||
HttpOutput httpOut = new HttpOutput(generator,60000);
|
||||
HttpConnection connection = new HttpConnection(null,endp,new Server(),null,generator,null)
|
||||
{
|
||||
@Override
|
||||
public Connection handle() throws IOException
|
||||
{
|
||||
return null;
|
||||
}
|
||||
};
|
||||
endp.setMaxIdleTime(60000);
|
||||
|
||||
HttpOutput httpOut = new HttpOutput(connection);
|
||||
_writer = new HttpWriter(httpOut);
|
||||
}
|
||||
|
||||
|
@ -158,7 +169,17 @@ public class HttpWriterTest
|
|||
|
||||
hb.setResponse(200,"OK");
|
||||
|
||||
HttpOutput output = new HttpOutput(hb,10000);
|
||||
HttpConnection connection = new HttpConnection(null,endp,new Server(),null,hb,null)
|
||||
{
|
||||
@Override
|
||||
public Connection handle() throws IOException
|
||||
{
|
||||
return null;
|
||||
}
|
||||
};
|
||||
endp.setMaxIdleTime(10000);
|
||||
hb.setSendServerVersion(false);
|
||||
HttpOutput output = new HttpOutput(connection);
|
||||
HttpWriter writer = new HttpWriter(output);
|
||||
writer.setCharacterEncoding(StringUtil.__UTF8);
|
||||
|
||||
|
|
|
@ -24,12 +24,16 @@ import java.io.InputStream;
|
|||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
@ -68,7 +72,50 @@ public class RequestTest
|
|||
_server.stop();
|
||||
_server.join();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParamExtraction() throws Exception
|
||||
{
|
||||
_handler._checker = new RequestTester()
|
||||
{
|
||||
public boolean check(HttpServletRequest request,HttpServletResponse response)
|
||||
{
|
||||
Map map = null;
|
||||
try
|
||||
{
|
||||
//do the parse
|
||||
request.getParameterMap();
|
||||
Assert.fail("Expected parsing failure");
|
||||
return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//catch the error and check the param map is not null
|
||||
map = request.getParameterMap();
|
||||
assertFalse(map == null);
|
||||
assertTrue(map.isEmpty());
|
||||
|
||||
Enumeration names = request.getParameterNames();
|
||||
assertFalse(names.hasMoreElements());
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
//Send a request with query string with illegal hex code to cause
|
||||
//an exception parsing the params
|
||||
String request="GET /?param=%ZZaaa HTTP/1.1\r\n"+
|
||||
"Host: whatever\r\n"+
|
||||
"Content-Type: text/html;charset=utf8\n"+
|
||||
"\n";
|
||||
|
||||
String response = _connector.getResponses(request);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testContentTypeEncoding() throws Exception
|
||||
{
|
||||
|
|
|
@ -383,31 +383,45 @@ public class ResponseTest
|
|||
public void testSendRedirect()
|
||||
throws Exception
|
||||
{
|
||||
ByteArrayEndPoint out=new ByteArrayEndPoint(new byte[]{},4096);
|
||||
HttpConnection connection=new TestHttpConnection(connector,out, connector.getServer());
|
||||
Response response = new Response(connection);
|
||||
Request request = connection.getRequest();
|
||||
request.setServerName("myhost");
|
||||
request.setServerPort(8888);
|
||||
request.setUri(new HttpURI("/path/info;param;jsessionid=12345?query=0&more=1#target"));
|
||||
request.setContextPath("/path");
|
||||
request.setRequestedSessionId("12345");
|
||||
request.setRequestedSessionIdFromCookie(false);
|
||||
AbstractSessionManager manager=new HashSessionManager();
|
||||
manager.setSessionIdManager(new HashSessionIdManager());
|
||||
request.setSessionManager(manager);
|
||||
request.setSession(new TestSession(manager,"12345"));
|
||||
manager.setCheckingRemoteSessionIdEncoding(false);
|
||||
String[][] tests={
|
||||
{"/other/location?name=value","http://myhost:8888/other/location;jsessionid=12345?name=value"},
|
||||
{"/other/location","http://myhost:8888/other/location"},
|
||||
{"/other/l%20cation","http://myhost:8888/other/l%20cation"},
|
||||
{"location","http://myhost:8888/path/location"},
|
||||
{"./location","http://myhost:8888/path/location"},
|
||||
{"../location","http://myhost:8888/location"},
|
||||
{"/other/l%20cation","http://myhost:8888/other/l%20cation"},
|
||||
{"l%20cation","http://myhost:8888/path/l%20cation"},
|
||||
{"./l%20cation","http://myhost:8888/path/l%20cation"},
|
||||
{"../l%20cation","http://myhost:8888/l%20cation"},
|
||||
};
|
||||
|
||||
for (int i=1;i<tests.length;i++)
|
||||
{
|
||||
ByteArrayEndPoint out=new ByteArrayEndPoint(new byte[]{},4096);
|
||||
HttpConnection connection=new TestHttpConnection(connector,out, connector.getServer());
|
||||
Response response = new Response(connection);
|
||||
Request request = connection.getRequest();
|
||||
request.setServerName("myhost");
|
||||
request.setServerPort(8888);
|
||||
request.setUri(new HttpURI("/path/info;param;jsessionid=12345?query=0&more=1#target"));
|
||||
request.setContextPath("/path");
|
||||
request.setRequestedSessionId("12345");
|
||||
request.setRequestedSessionIdFromCookie(i>0);
|
||||
AbstractSessionManager manager=new HashSessionManager();
|
||||
manager.setSessionIdManager(new HashSessionIdManager());
|
||||
request.setSessionManager(manager);
|
||||
request.setSession(new TestSession(manager,"12345"));
|
||||
manager.setCheckingRemoteSessionIdEncoding(false);
|
||||
|
||||
response.sendRedirect("/other/location");
|
||||
|
||||
String location = out.getOut().toString();
|
||||
int l=location.indexOf("Location: ");
|
||||
int e=location.indexOf('\n',l);
|
||||
location=location.substring(l+10,e).trim();
|
||||
|
||||
assertEquals("http://myhost:8888/other/location;jsessionid=12345",location);
|
||||
|
||||
response.sendRedirect(tests[i][0]);
|
||||
|
||||
String location = out.getOut().toString();
|
||||
int l=location.indexOf("Location: ");
|
||||
int e=location.indexOf('\n',l);
|
||||
location=location.substring(l+10,e).trim();
|
||||
assertEquals(tests[i][0],tests[i][1],location);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -25,10 +25,12 @@ public class SelectChannelServerTest extends HttpServerTestBase
|
|||
{
|
||||
startServer(new SelectChannelConnector());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void testBigBlocks() throws Exception
|
||||
public void testCommittedError() throws Exception
|
||||
{
|
||||
super.testBigBlocks();
|
||||
super.testCommittedError();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ public class StressTest
|
|||
_server.setThreadPool(_threads);
|
||||
|
||||
_connector = new SelectChannelConnector();
|
||||
_connector.setAcceptors(Math.max(1, Runtime.getRuntime().availableProcessors() / 2));
|
||||
_connector.setAcceptors(1);
|
||||
_connector.setAcceptQueueSize(5000);
|
||||
_connector.setMaxIdleTime(30000);
|
||||
_server.addConnector(_connector);
|
||||
|
@ -123,7 +123,7 @@ public class StressTest
|
|||
// TODO needs to be further investigated
|
||||
assumeTrue(!OS.IS_OSX || Stress.isEnabled());
|
||||
|
||||
doThreads(10,100,false);
|
||||
doThreads(10,10,false);
|
||||
if (Stress.isEnabled())
|
||||
{
|
||||
Thread.sleep(1000);
|
||||
|
@ -139,7 +139,7 @@ public class StressTest
|
|||
// TODO needs to be further investigated
|
||||
assumeTrue(!OS.IS_OSX || Stress.isEnabled());
|
||||
|
||||
doThreads(20,100,true);
|
||||
doThreads(20,10,true);
|
||||
if (Stress.isEnabled())
|
||||
{
|
||||
Thread.sleep(1000);
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
package org.eclipse.jetty.server.handler;
|
||||
//========================================================================
|
||||
//Copyright (c) 1999-2009 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.
|
||||
//========================================================================
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.bio.SocketConnector;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.toolchain.test.SimpleRequest;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Resource Handler test
|
||||
*
|
||||
* TODO: increase the testing going on here
|
||||
*/
|
||||
public class ResourceHandlerTest extends TestCase
|
||||
{
|
||||
private static Server _server;
|
||||
private static Connector _connector;
|
||||
private static ContextHandler _contextHandler;
|
||||
private static ResourceHandler _resourceHandler;
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
_server = new Server();
|
||||
_connector = new SocketConnector();
|
||||
_server.setConnectors(new Connector[] { _connector });
|
||||
|
||||
_resourceHandler = new ResourceHandler();
|
||||
|
||||
_contextHandler = new ContextHandler("/resource");
|
||||
_contextHandler.setHandler(_resourceHandler);
|
||||
_server.setHandler(_contextHandler);
|
||||
_server.start();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@AfterClass
|
||||
public void tearDown() throws Exception
|
||||
{
|
||||
_server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleResourceHandler() throws Exception
|
||||
{
|
||||
_resourceHandler.setResourceBase(MavenTestingUtils.getTestResourceDir("simple").getAbsolutePath());
|
||||
|
||||
SimpleRequest sr = new SimpleRequest(new URI("http://localhost:" + _connector.getLocalPort()));
|
||||
|
||||
Assert.assertEquals("simple text", sr.getString("/resource/simple.txt"));
|
||||
|
||||
Assert.assertNotNull("missing jetty.css" , sr.getString("/resource/jetty-dir.css"));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package org.eclipse.jetty.server.handler;
|
||||
|
||||
//========================================================================
|
||||
//Copyright (c) 2009-2009 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.
|
||||
//========================================================================
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
public class ShutdownHandlerTest
|
||||
{
|
||||
@Mock private HttpServletRequest request;
|
||||
@Mock private HttpServletResponse response;
|
||||
|
||||
private Server server = new Server(0);
|
||||
private String shutdownToken = "asdlnsldgnklns";
|
||||
|
||||
// class under test
|
||||
private ShutdownHandler shutdownHandler;
|
||||
|
||||
@Before
|
||||
public void startServer() throws Exception
|
||||
{
|
||||
MockitoAnnotations.initMocks(this);
|
||||
server.start();
|
||||
shutdownHandler = new ShutdownHandler(server,shutdownToken);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shutdownServerWithCorrectTokenAndIPTest() throws Exception
|
||||
{
|
||||
setDefaultExpectations();
|
||||
shutdownHandler.handle("/shutdown",null,request,response);
|
||||
assertEquals("Server should be stopped","STOPPED",server.getState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongTokenTest() throws Exception
|
||||
{
|
||||
setDefaultExpectations();
|
||||
when(request.getParameter("token")).thenReturn("anothertoken");
|
||||
shutdownHandler.handle("/shutdown",null,request,response);
|
||||
assertEquals("Server should be running","STARTED",server.getState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shutdownRequestNotFromLocalhostTest() throws Exception
|
||||
{
|
||||
setDefaultExpectations();
|
||||
when(request.getRemoteAddr()).thenReturn("192.168.3.3");
|
||||
shutdownHandler.handle("/shutdown",null,request,response);
|
||||
assertEquals("Server should be running","STARTED",server.getState());
|
||||
}
|
||||
|
||||
private void setDefaultExpectations()
|
||||
{
|
||||
when(request.getMethod()).thenReturn("POST");
|
||||
when(request.getParameter("token")).thenReturn(shutdownToken);
|
||||
when(request.getRemoteAddr()).thenReturn("127.0.0.1");
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue