Merge branch 'jetty-9' into jetty-9-aggregation

This commit is contained in:
Greg Wilkins 2012-08-24 20:17:08 +10:00
commit 72bfacd5a4
48 changed files with 3129 additions and 3734 deletions

View File

@ -1,82 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-ajp</artifactId>
<name>Jetty :: AJP</name>
<properties>
<bundle-symbolic-name>${project.groupId}.ajp</bundle-symbolic-name>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Import-Package>javax.servlet.*;version="2.6.0",*</Import-Package>
</instructions>
</configuration>
</execution>
</executions>
</plugin>
<!--
Required for OSGI
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorRefs>
<descriptorRef>config</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<configuration>
<onlyAnalyze>org.eclipse.jetty.ajp.*</onlyAnalyze>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,18 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- Add a AJP listener on port 8009 -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<Call name="addConnector">
<Arg>
<New class="org.eclipse.jetty.ajp.Ajp13SocketConnector">
<Set name="port">8009</Set>
</New>
</Arg>
</Call>
</Configure>

View File

@ -1,250 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ajp;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Collection;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpException;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.server.BlockingHttpConnection;
import org.eclipse.jetty.server.Connector;
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;
/**
* Connection implementation of the Ajp13 protocol. <p/> XXX Refactor to remove
* duplication of HttpConnection
*
*/
public class Ajp13Connection extends BlockingHttpConnection
{
private static final Logger LOG = Log.getLogger(Ajp13Connection.class);
public Ajp13Connection(Connector connector, EndPoint endPoint, Server server)
{
super(connector, endPoint, server,
new Ajp13Parser(connector.getRequestBuffers(), endPoint),
new Ajp13Generator(connector.getResponseBuffers(), endPoint),
new Ajp13Request()
);
((Ajp13Parser)_parser).setEventHandler(new RequestHandler());
((Ajp13Parser)_parser).setGenerator((Ajp13Generator)_generator);
((Ajp13Request)_request).setConnection(this);
}
@Override
public boolean isConfidential(Request request)
{
return ((Ajp13Request) request).isSslSecure();
}
@Override
public boolean isIntegral(Request request)
{
return ((Ajp13Request) request).isSslSecure();
}
@Override
public ServletInputStream getInputStream()
{
if (_in == null)
_in = new Ajp13Parser.Input((Ajp13Parser) _parser, _connector.getMaxIdleTime());
return _in;
}
private class RequestHandler implements Ajp13Parser.EventHandler
{
public void startForwardRequest() throws IOException
{
_uri.clear();
((Ajp13Request) _request).setSslSecure(false);
_request.setTimeStamp(System.currentTimeMillis());
_request.setUri(_uri);
}
public void parsedAuthorizationType(Buffer authType) throws IOException
{
//TODO JASPI this doesn't appear to make sense yet... how does ajp auth fit into jetty auth?
// _request.setAuthType(authType.toString());
}
public void parsedRemoteUser(Buffer remoteUser) throws IOException
{
((Ajp13Request)_request).setRemoteUser(remoteUser.toString());
}
public void parsedServletPath(Buffer servletPath) throws IOException
{
_request.setServletPath(servletPath.toString());
}
public void parsedContextPath(Buffer context) throws IOException
{
_request.setContextPath(context.toString());
}
public void parsedSslCert(Buffer sslCert) throws IOException
{
try
{
CertificateFactory cf = CertificateFactory.getInstance("X.509");
ByteArrayInputStream bis = new ByteArrayInputStream(sslCert.toString().getBytes());
Collection<? extends java.security.cert.Certificate> certCollection = cf.generateCertificates(bis);
X509Certificate[] certificates = new X509Certificate[certCollection.size()];
int i=0;
for (Object aCertCollection : certCollection)
{
certificates[i++] = (X509Certificate) aCertCollection;
}
_request.setAttribute("javax.servlet.request.X509Certificate", certificates);
}
catch (Exception e)
{
LOG.warn(e.toString());
LOG.ignore(e);
if (sslCert!=null)
_request.setAttribute("javax.servlet.request.X509Certificate", sslCert.toString());
}
}
public void parsedSslCipher(Buffer sslCipher) throws IOException
{
_request.setAttribute("javax.servlet.request.cipher_suite", sslCipher.toString());
}
public void parsedSslSession(Buffer sslSession) throws IOException
{
_request.setAttribute("javax.servlet.request.ssl_session", sslSession.toString());
}
public void parsedSslKeySize(int keySize) throws IOException
{
_request.setAttribute("javax.servlet.request.key_size", new Integer(keySize));
}
public void parsedMethod(Buffer method) throws IOException
{
if (method == null)
throw new HttpException(HttpServletResponse.SC_BAD_REQUEST);
_request.setMethod(method.toString());
}
public void parsedUri(Buffer uri) throws IOException
{
_uri.parse(uri.toString());
}
public void parsedProtocol(Buffer protocol) throws IOException
{
if (protocol != null && protocol.length()>0)
{
_request.setProtocol(protocol.toString());
}
}
public void parsedRemoteAddr(Buffer addr) throws IOException
{
if (addr != null && addr.length()>0)
{
_request.setRemoteAddr(addr.toString());
}
}
public void parsedRemoteHost(Buffer name) throws IOException
{
if (name != null && name.length()>0)
{
_request.setRemoteHost(name.toString());
}
}
public void parsedServerName(Buffer name) throws IOException
{
if (name != null && name.length()>0)
{
_request.setServerName(name.toString());
}
}
public void parsedServerPort(int port) throws IOException
{
_request.setServerPort(port);
}
public void parsedSslSecure(boolean secure) throws IOException
{
((Ajp13Request) _request).setSslSecure(secure);
}
public void parsedQueryString(Buffer value) throws IOException
{
String u = _uri + "?" + value;
_uri.parse(u);
}
public void parsedHeader(Buffer name, Buffer value) throws IOException
{
_requestFields.add(name, value);
}
public void parsedRequestAttribute(String key, Buffer value) throws IOException
{
if (value==null)
_request.removeAttribute(key);
else
_request.setAttribute(key,value.toString());
}
public void parsedRequestAttribute(String key, int value) throws IOException
{
_request.setAttribute(key, Integer.toString(value));
}
public void headerComplete() throws IOException
{
handleRequest();
}
public void messageComplete(long contextLength) throws IOException
{
}
public void content(Buffer ref) throws IOException
{
}
}
}

View File

@ -1,831 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ajp;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import org.eclipse.jetty.http.AbstractGenerator;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpGenerator;
import org.eclipse.jetty.http.HttpTokens;
import org.eclipse.jetty.http.HttpVersions;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.Buffers;
import org.eclipse.jetty.io.ByteArrayBuffer;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
*
*
*/
public class Ajp13Generator extends AbstractGenerator
{
private static final Logger LOG = Log.getLogger(Ajp13Generator.class);
private static HashMap __headerHash = new HashMap();
static
{
byte[] xA001 =
{ (byte)0xA0, (byte)0x01 };
byte[] xA002 =
{ (byte)0xA0, (byte)0x02 };
byte[] xA003 =
{ (byte)0xA0, (byte)0x03 };
byte[] xA004 =
{ (byte)0xA0, (byte)0x04 };
byte[] xA005 =
{ (byte)0xA0, (byte)0x05 };
byte[] xA006 =
{ (byte)0xA0, (byte)0x06 };
byte[] xA007 =
{ (byte)0xA0, (byte)0x07 };
byte[] xA008 =
{ (byte)0xA0, (byte)0x08 };
byte[] xA009 =
{ (byte)0xA0, (byte)0x09 };
byte[] xA00A =
{ (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);
}
// A, B ajp response header
// 0, 1 ajp int 1 packet length
// 9 CPONG response Code
private static final byte[] AJP13_CPONG_RESPONSE =
{ 'A', 'B', 0, 1, 9 };
private static final byte[] AJP13_END_RESPONSE =
{ 'A', 'B', 0, 2, 5, 1 };
// AB ajp respose
// 0, 3 int = 3 packets in length
// 6, send signal to get more data
// 31, -7 byte values for int 8185 = (8 * 1024) - 7 MAX_DATA
private static final byte[] AJP13_MORE_CONTENT =
{ 'A', 'B', 0, 3, 6, 31, -7 };
private static String SERVER = "Server: Jetty(7.x.x)";
public static void setServerVersion(String version)
{
SERVER = "Jetty(" + version + ")";
}
/* ------------------------------------------------------------ */
private boolean _expectMore = false;
private boolean _needMore = false;
private boolean _needEOC = false;
private boolean _bufferPrepared = false;
/* ------------------------------------------------------------ */
public Ajp13Generator(Buffers buffers, EndPoint io)
{
super(buffers,io);
}
/* ------------------------------------------------------------ */
@Override
public boolean isRequest()
{
return false;
}
/* ------------------------------------------------------------ */
@Override
public boolean isResponse()
{
return true;
}
/* ------------------------------------------------------------ */
@Override
public void reset()
{
super.reset();
_needEOC = false;
_needMore = false;
_expectMore = false;
_bufferPrepared = false;
_last = false;
_state = STATE_HEADER;
_status = 0;
_version = HttpVersions.HTTP_1_1_ORDINAL;
_reason = null;
_method = null;
_uri = null;
_contentWritten = 0;
_contentLength = HttpTokens.UNKNOWN_CONTENT;
_last = false;
_head = false;
_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
}
/* ------------------------------------------------------------ */
@Override
public int getContentBufferSize()
{
try
{
initContent();
}
catch (IOException e)
{
throw new RuntimeException(e);
}
return super.getContentBufferSize() - 7;
}
/* ------------------------------------------------------------ */
@Override
public void increaseContentBufferSize(int contentBufferSize)
{
// Not supported with AJP
}
/* ------------------------------------------------------------ */
/**
* Add content.
*
* @param content
* @param last
* @throws IllegalArgumentException
* 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.
* @throws IOException
* if there is a problem flushing the buffers.
*/
public void addContent(Buffer content, boolean last) throws IOException
{
if (_noContent)
{
content.clear();
return;
}
if (content.isImmutable())
throw new IllegalArgumentException("immutable");
if (_last || _state == STATE_END)
{
LOG.debug("Ignoring extra content {}",content);
content.clear();
return;
}
_last = last;
if (!_endp.isOpen())
{
_state = STATE_END;
return;
}
// Handle any unfinished business?
if (_content != null && _content.length() > 0)
{
flushBuffer();
if (_content != null && _content.length() > 0)
throw new IllegalStateException("FULL");
}
_content = content;
_contentWritten += content.length();
// Handle the _content
if (_head)
{
content.clear();
_content = null;
}
else
{
// Yes - so we better check we have a buffer
initContent();
// Copy _content to buffer;
int len = 0;
len = _buffer.put(_content);
// make sure there is space for a trailing null
if (len > 0 && _buffer.space() == 0)
{
len--;
_buffer.setPutIndex(_buffer.putIndex() - 1);
}
_content.skip(len);
if (_content.length() == 0)
_content = null;
}
}
/* ------------------------------------------------------------ */
/**
* Add content.
*
* @param b
* byte
* @return true if the buffers are full
* @throws IOException
*/
public boolean addContent(byte b) throws IOException
{
if (_noContent)
return false;
if (_last || _state == STATE_END)
throw new IllegalStateException("Closed");
if (!_endp.isOpen())
{
_state = STATE_END;
return false;
}
// Handle any unfinished business?
if (_content != null && _content.length() > 0)
{
flushBuffer();
if (_content != null && _content.length() > 0)
throw new IllegalStateException("FULL");
}
_contentWritten++;
// Handle the _content
if (_head)
return false;
// we better check we have a buffer
initContent();
// Copy _content to buffer;
_buffer.put(b);
return _buffer.space() <= 1;
}
/* ------------------------------------------------------------ */
/**
* Prepare buffer for unchecked writes. Prepare the generator buffer to receive unchecked writes
*
* @return the available space in the buffer.
* @throws IOException
*/
@Override
public int prepareUncheckedAddContent() throws IOException
{
if (_noContent)
return -1;
if (_last || _state == STATE_END)
throw new IllegalStateException("Closed");
if (!_endp.isOpen())
{
_state = STATE_END;
return -1;
}
// Handle any unfinished business?
Buffer content = _content;
if (content != null && content.length() > 0)
{
flushBuffer();
if (content != null && content.length() > 0)
throw new IllegalStateException("FULL");
}
// we better check we have a buffer
initContent();
_contentWritten -= _buffer.length();
// Handle the _content
if (_head)
return Integer.MAX_VALUE;
return _buffer.space() - 1;
}
/* ------------------------------------------------------------ */
@Override
public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException
{
if (_state != STATE_HEADER)
return;
if (_last && !allContentAdded)
throw new IllegalStateException("last?");
_last = _last | allContentAdded;
boolean has_server = false;
if (_persistent == null)
_persistent = (_version > HttpVersions.HTTP_1_0_ORDINAL);
// get a header buffer
if (_header == null)
_header = _buffers.getHeader();
Buffer tmpbuf = _buffer;
_buffer = _header;
try
{
// start the header
_buffer.put((byte)'A');
_buffer.put((byte)'B');
addInt(0);
_buffer.put((byte)0x4);
addInt(_status);
if (_reason == null)
_reason = HttpGenerator.getReasonBuffer(_status);
if (_reason == null)
_reason = new ByteArrayBuffer(Integer.toString(_status));
addBuffer(_reason);
if (_status == 100 || _status == 204 || _status == 304)
{
_noContent = true;
_content = null;
}
// allocate 2 bytes for number of headers
int field_index = _buffer.putIndex();
addInt(0);
int num_fields = 0;
if (fields != null)
{
// Add headers
int s = fields.size();
for (int f = 0; f < s; f++)
{
HttpFields.Field field = fields.getField(f);
if (field == null)
continue;
num_fields++;
byte[] codes = (byte[])__headerHash.get(field.getName());
if (codes != null)
{
_buffer.put(codes);
}
else
{
addString(field.getName());
}
addString(field.getValue());
}
}
if (!has_server && _status > 100 && getSendServerVersion())
{
num_fields++;
addString("Server");
addString(SERVER);
}
// TODO Add content length if last content known.
// insert the number of headers
int tmp = _buffer.putIndex();
_buffer.setPutIndex(field_index);
addInt(num_fields);
_buffer.setPutIndex(tmp);
// get the payload size ( - 4 bytes for the ajp header)
// excluding the
// ajp header
int payloadSize = _buffer.length() - 4;
// insert the total packet size on 2nd and 3rd byte that
// was previously
// allocated
addInt(2,payloadSize);
}
finally
{
_buffer = tmpbuf;
}
_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;
_needEOC = true;
}
flushBuffer();
}
/* ------------------------------------------------------------ */
@Override
public int flushBuffer() throws IOException
{
try
{
if (_state == STATE_HEADER && !_expectMore)
throw new IllegalStateException("State==HEADER");
prepareBuffers();
if (_endp == null)
{
// TODO - probably still needed!
// if (_rneedMore && _buffe != null)
// {
// if(!_hasSentEOC)
// _buffer.put(AJP13_MORE_CONTENT);
// }
if (!_expectMore && _needEOC && _buffer != null)
{
_buffer.put(AJP13_END_RESPONSE);
}
_needEOC = false;
return 0;
}
// Keep flushing while there is something to flush
// (except break below)
int total = 0;
long last_len = -1;
Flushing: while (true)
{
int len = -1;
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);
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)
{
_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();
// }
//
break Flushing;
}
// Try to prepare more to write.
prepareBuffers();
}
}
// If we failed to flush anything twice in a row
// break
if (len <= 0)
{
if (last_len <= 0)
break Flushing;
break;
}
last_len = len;
total += len;
}
return total;
}
catch (IOException e)
{
LOG.ignore(e);
throw (e instanceof EofException)?e:new EofException(e);
}
}
/* ------------------------------------------------------------ */
private void prepareBuffers()
{
if (!_bufferPrepared)
{
// Refill buffer if possible
if (_content != null && _content.length() > 0 && _buffer != null && _buffer.space() > 0)
{
int len = _buffer.put(_content);
// Make sure there is space for a trailing null
if (len > 0 && _buffer.space() == 0)
{
len--;
_buffer.setPutIndex(_buffer.putIndex() - 1);
}
_content.skip(len);
if (_content.length() == 0)
_content = null;
if (_buffer.length() == 0)
{
_content = null;
}
}
// add header if needed
if (_buffer != null)
{
int payloadSize = _buffer.length();
// 4 bytes for the ajp header
// 1 byte for response type
// 2 bytes for the response size
// 1 byte because we count from zero??
if (payloadSize > 0)
{
_bufferPrepared = true;
_buffer.put((byte)0);
int put = _buffer.putIndex();
_buffer.setGetIndex(0);
_buffer.setPutIndex(0);
_buffer.put((byte)'A');
_buffer.put((byte)'B');
addInt(payloadSize + 4);
_buffer.put((byte)3);
addInt(payloadSize);
_buffer.setPutIndex(put);
}
}
if (_needMore)
{
if (_header == null)
{
_header = _buffers.getHeader();
}
if (_buffer == null && _header != null && _header.space() >= AJP13_MORE_CONTENT.length)
{
_header.put(AJP13_MORE_CONTENT);
_needMore = false;
}
else if (_buffer != null && _buffer.space() >= AJP13_MORE_CONTENT.length)
{
// send closing packet if all contents
// are added
_buffer.put(AJP13_MORE_CONTENT);
_needMore = false;
_bufferPrepared = true;
}
}
if (!_expectMore && _needEOC)
{
if (_buffer == null && _header.space() >= AJP13_END_RESPONSE.length)
{
_header.put(AJP13_END_RESPONSE);
_needEOC = false;
}
else if (_buffer != null && _buffer.space() >= AJP13_END_RESPONSE.length)
{
// send closing packet if all contents
// are added
_buffer.put(AJP13_END_RESPONSE);
_needEOC = false;
_bufferPrepared = true;
}
}
}
}
/* ------------------------------------------------------------ */
@Override
public boolean isComplete()
{
return !_expectMore && _state == STATE_END;
}
/* ------------------------------------------------------------ */
private void initContent() throws IOException
{
if (_buffer == null)
{
_buffer = _buffers.getBuffer();
_buffer.setPutIndex(7);
_buffer.setGetIndex(7);
}
}
/* ------------------------------------------------------------ */
private void addInt(int i)
{
_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));
}
/* ------------------------------------------------------------ */
private void addString(String str) throws UnsupportedEncodingException
{
if (str == null)
{
addInt(0xFFFF);
return;
}
// TODO - need to use a writer to convert, to avoid this hacky
// conversion and temp buffer
byte[] b = str.getBytes(StringUtil.__ISO_8859_1);
addInt(b.length);
_buffer.put(b);
_buffer.put((byte)0);
}
/* ------------------------------------------------------------ */
private void addBuffer(Buffer b)
{
if (b == null)
{
addInt(0xFFFF);
return;
}
addInt(b.length());
_buffer.put(b);
_buffer.put((byte)0);
}
/* ------------------------------------------------------------ */
public void getBodyChunk() throws IOException
{
ByteArrayBuffer bf = new ByteArrayBuffer(AJP13_MORE_CONTENT);
_endp.flush(bf);
}
/* ------------------------------------------------------------ */
public void gotBody()
{
_needMore = false;
_expectMore = false;
}
/* ------------------------------------------------------------ */
public void sendCPong() throws IOException
{
Buffer buff = _buffers.getBuffer();
buff.put(AJP13_CPONG_RESPONSE);
// flushing cpong response
do
{
_endp.flush(buff);
}
while (buff.length() > 0);
_buffers.returnBuffer(buff);
reset();
}
}

View File

@ -1,68 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ajp;
import org.eclipse.jetty.io.BufferCache;
/**
*
*/
public class Ajp13Packet
{
public final static int MAX_PACKET_SIZE=(8*1024);
public final static int HDR_SIZE=4;
// Used in writing response...
public final static int DATA_HDR_SIZE=7;
public final static int MAX_DATA_SIZE=MAX_PACKET_SIZE-DATA_HDR_SIZE;
public final static String
// Server -> Container
FORWARD_REQUEST="FORWARD REQUEST",
SHUTDOWN="SHUTDOWN",
PING_REQUEST="PING REQUEST", // Obsolete
CPING_REQUEST="CPING REQUEST",
// Server <- Container
SEND_BODY_CHUNK="SEND BODY CHUNK", SEND_HEADERS="SEND HEADERS", END_RESPONSE="END RESPONSE",
GET_BODY_CHUNK="GET BODY CHUNK",
CPONG_REPLY="CPONG REPLY";
public final static int FORWARD_REQUEST_ORDINAL=2, SHUTDOWN_ORDINAL=7,
PING_REQUEST_ORDINAL=8, // Obsolete
CPING_REQUEST_ORDINAL=10, SEND_BODY_CHUNK_ORDINAL=3, SEND_HEADERS_ORDINAL=4, END_RESPONSE_ORDINAL=5, GET_BODY_CHUNK_ORDINAL=6,
CPONG_REPLY_ORDINAL=9;
public final static BufferCache CACHE=new BufferCache();
static
{
CACHE.add(FORWARD_REQUEST,FORWARD_REQUEST_ORDINAL);
CACHE.add(SHUTDOWN,SHUTDOWN_ORDINAL);
CACHE.add(PING_REQUEST,PING_REQUEST_ORDINAL); // Obsolete
CACHE.add(CPING_REQUEST,CPING_REQUEST_ORDINAL);
CACHE.add(SEND_BODY_CHUNK,SEND_BODY_CHUNK_ORDINAL);
CACHE.add(SEND_HEADERS,SEND_HEADERS_ORDINAL);
CACHE.add(END_RESPONSE,END_RESPONSE_ORDINAL);
CACHE.add(GET_BODY_CHUNK,GET_BODY_CHUNK_ORDINAL);
CACHE.add(CPONG_REPLY,CPONG_REPLY_ORDINAL);
}
}

View File

@ -1,74 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ajp;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.BufferCache;
/**
*
*/
public class Ajp13PacketMethods
{
// TODO - this can probably be replaced by HttpMethods or at least an
// extension of it.
// It is probably most efficient if "GET" ends up as the same instance
public final static String OPTIONS="OPTIONS", GET="GET", HEAD="HEAD", POST="POST", PUT="PUT", DELETE="DELETE", TRACE="TRACE", PROPFIND="PROPFIND",
PROPPATCH="PROPPATCH", MKCOL="MKCOL", COPY="COPY", MOVE="MOVE", LOCK="LOCK", UNLOCK="UNLOCK", ACL="ACL", REPORT="REPORT",
VERSION_CONTROL="VERSION-CONTROL", CHECKIN="CHECKIN", CHECKOUT="CHECKOUT", UNCHCKOUT="UNCHECKOUT", SEARCH="SEARCH", MKWORKSPACE="MKWORKSPACE",
UPDATE="UPDATE", LABEL="LABEL", MERGE="MERGE", BASELINE_CONTROL="BASELINE-CONTROL", MKACTIVITY="MKACTIVITY";
public final static int OPTIONS_ORDINAL=1, GET_ORDINAL=2, HEAD_ORDINAL=3, POST__ORDINAL=4, PUT_ORDINAL=5, DELETE_ORDINAL=6, TRACE_ORDINAL=7,
PROPFIND_ORDINAL=8, PROPPATCH_ORDINAL=9, MKCOL_ORDINAL=10, COPY_ORDINAL=11, MOVE_ORDINAL=12, LOCK_ORDINAL=13, UNLOCK_ORDINAL=14, ACL_ORDINAL=15,
REPORT_ORDINAL=16, VERSION_CONTROL_ORDINAL=17, CHECKIN_ORDINAL=18, CHECKOUT_ORDINAL=19, UNCHCKOUT_ORDINAL=20, SEARCH_ORDINAL=21,
MKWORKSPACE_ORDINAL=22, UPDATE_ORDINAL=23, LABEL_ORDINAL=24, MERGE_ORDINAL=25, BASELINE_CONTROL_ORDINAL=26, MKACTIVITY_ORDINAL=27;
public final static BufferCache CACHE=new BufferCache();
public final static Buffer
OPTIONS_BUFFER=CACHE.add(OPTIONS,OPTIONS_ORDINAL),
GET_BUFFER=CACHE.add(GET,GET_ORDINAL),
HEAD_BUFFER=CACHE.add(HEAD, HEAD_ORDINAL),
POST__BUFFER=CACHE.add(POST,POST__ORDINAL),
PUT_BUFFER=CACHE.add(PUT,PUT_ORDINAL),
DELETE_BUFFER=CACHE.add(DELETE,DELETE_ORDINAL),
TRACE_BUFFER=CACHE.add(TRACE,TRACE_ORDINAL),
PROPFIND_BUFFER=CACHE.add(PROPFIND,PROPFIND_ORDINAL),
PROPPATCH_BUFFER=CACHE.add(PROPPATCH, PROPPATCH_ORDINAL),
MKCOL_BUFFER=CACHE.add(MKCOL,MKCOL_ORDINAL),
COPY_BUFFER=CACHE.add(COPY,COPY_ORDINAL),
MOVE_BUFFER=CACHE.add(MOVE,MOVE_ORDINAL),
LOCK_BUFFER=CACHE.add(LOCK,LOCK_ORDINAL),
UNLOCK_BUFFER=CACHE.add(UNLOCK,UNLOCK_ORDINAL),
ACL_BUFFER=CACHE.add(ACL,ACL_ORDINAL),
REPORT_BUFFER=CACHE.add(REPORT,REPORT_ORDINAL),
VERSION_CONTROL_BUFFER=CACHE.add(VERSION_CONTROL,VERSION_CONTROL_ORDINAL),
CHECKIN_BUFFER=CACHE.add(CHECKIN,CHECKIN_ORDINAL),
CHECKOUT_BUFFER=CACHE.add(CHECKOUT,CHECKOUT_ORDINAL),
UNCHCKOUT_BUFFER=CACHE.add(UNCHCKOUT,UNCHCKOUT_ORDINAL),
SEARCH_BUFFER=CACHE.add(SEARCH,SEARCH_ORDINAL),
MKWORKSPACE_BUFFER=CACHE.add(MKWORKSPACE,MKWORKSPACE_ORDINAL),
UPDATE_BUFFER=CACHE.add(UPDATE,UPDATE_ORDINAL),
LABEL_BUFFER=CACHE.add(LABEL,LABEL_ORDINAL),
MERGE_BUFFER=CACHE.add(MERGE,MERGE_ORDINAL),
BASELINE_CONTROL_BUFFER=CACHE.add(BASELINE_CONTROL,BASELINE_CONTROL_ORDINAL),
MKACTIVITY_BUFFER=CACHE.add(MKACTIVITY,MKACTIVITY_ORDINAL);
}

View File

@ -1,890 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ajp;
import java.io.IOException;
import java.io.InterruptedIOException;
import javax.servlet.ServletInputStream;
import org.eclipse.jetty.http.HttpTokens;
import org.eclipse.jetty.http.Parser;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.BufferUtil;
import org.eclipse.jetty.io.Buffers;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.View;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
*
*/
public class Ajp13Parser implements Parser
{
private static final Logger LOG = Log.getLogger(Ajp13Parser.class);
private final static int STATE_START = -1;
private final static int STATE_END = 0;
private final static int STATE_AJP13CHUNK_START = 1;
private final static int STATE_AJP13CHUNK = 2;
private int _state = STATE_START;
private long _contentLength;
private long _contentPosition;
private int _chunkLength;
private int _chunkPosition;
private int _headers;
private Buffers _buffers;
private EndPoint _endp;
private Buffer _buffer;
private Buffer _header; // Buffer for header data (and small _content)
private Buffer _body; // Buffer for large content
private View _contentView = new View();
private EventHandler _handler;
private Ajp13Generator _generator;
private View _tok0; // Saved token: header name, request method or response version
private View _tok1; // Saved token: header value, request URI orresponse code
protected int _length;
protected int _packetLength;
/* ------------------------------------------------------------------------------- */
public Ajp13Parser(Buffers buffers, EndPoint endPoint)
{
_buffers = buffers;
_endp = endPoint;
}
/* ------------------------------------------------------------------------------- */
public void setEventHandler(EventHandler handler)
{
_handler=handler;
}
/* ------------------------------------------------------------------------------- */
public void setGenerator(Ajp13Generator generator)
{
_generator=generator;
}
/* ------------------------------------------------------------------------------- */
public long getContentLength()
{
return _contentLength;
}
/* ------------------------------------------------------------------------------- */
public int getState()
{
return _state;
}
/* ------------------------------------------------------------------------------- */
public boolean inContentState()
{
return _state > 0;
}
/* ------------------------------------------------------------------------------- */
public boolean inHeaderState()
{
return _state < 0;
}
/* ------------------------------------------------------------------------------- */
public boolean isIdle()
{
return _state == STATE_START;
}
/* ------------------------------------------------------------------------------- */
public boolean isComplete()
{
return _state == STATE_END;
}
/* ------------------------------------------------------------------------------- */
public boolean isMoreInBuffer()
{
if (_header != null && _header.hasContent() || _body != null && _body.hasContent())
return true;
return false;
}
/* ------------------------------------------------------------------------------- */
public boolean isState(int state)
{
return _state == state;
}
/* ------------------------------------------------------------------------------- */
public void parse() throws IOException
{
if (_state == STATE_END)
reset();
if (_state != STATE_START)
throw new IllegalStateException("!START");
// continue parsing
while (!isComplete())
{
parseNext();
}
}
/* ------------------------------------------------------------------------------- */
public boolean parseAvailable() throws IOException
{
boolean progress=parseNext()>0;
// continue parsing
while (!isComplete() && _buffer!=null && _buffer.length()>0)
{
progress |= parseNext()>0;
}
return progress;
}
/* ------------------------------------------------------------------------------- */
private int fill() throws IOException
{
int filled = -1;
if (_body != null && _buffer != _body)
{
// mod_jk implementations may have some partial data from header
// check if there are partial contents in the header
// copy it to the body if there are any
if(_header.length() > 0)
{
// copy the patial data from the header to the body
_body.put(_header);
}
_buffer = _body;
if (_buffer.length()>0)
{
filled = _buffer.length();
return filled;
}
}
if (_buffer.markIndex() == 0 && _buffer.putIndex() == _buffer.capacity())
throw new IOException("FULL");
if (_endp != null && filled <= 0)
{
// Compress buffer if handling _content buffer
// TODO check this is not moving data too much
if (_buffer == _body)
_buffer.compact();
if (_buffer.space() == 0)
throw new IOException("FULL");
try
{
filled = _endp.fill(_buffer);
}
catch (IOException e)
{
// This is normal in AJP since the socket closes on timeout only
LOG.debug(e);
reset();
throw (e instanceof EofException) ? e : new EofException(e);
}
}
if (filled < 0)
{
if (_state > STATE_END)
{
_state = STATE_END;
_handler.messageComplete(_contentPosition);
return filled;
}
reset();
throw new EofException();
}
return filled;
}
volatile int _seq=0;
/* ------------------------------------------------------------------------------- */
public int parseNext() throws IOException
{
int total_filled = 0;
if (_buffer == null)
{
if (_header == null)
_header = _buffers.getHeader();
_buffer = _header;
_tok0 = new View(_header);
_tok1 = new View(_header);
_tok0.setPutIndex(_tok0.getIndex());
_tok1.setPutIndex(_tok1.getIndex());
}
if (_state == STATE_END)
throw new IllegalStateException("STATE_END");
if (_state > STATE_END && _contentPosition == _contentLength)
{
_state = STATE_END;
_handler.messageComplete(_contentPosition);
return 1;
}
if (_state < 0)
{
// have we seen a packet?
if (_packetLength<=0)
{
if (_buffer.length()<4)
{
if (total_filled<0)
total_filled=0;
total_filled+=fill();
if (_buffer.length()<4)
return total_filled;
}
_contentLength = HttpTokens.UNKNOWN_CONTENT;
int _magic = Ajp13RequestPacket.getInt(_buffer);
if (_magic != Ajp13RequestHeaders.MAGIC)
throw new IOException("Bad AJP13 rcv packet: " + "0x" + Integer.toHexString(_magic) + " expected " + "0x" + Integer.toHexString(Ajp13RequestHeaders.MAGIC) + " " + this);
_packetLength = Ajp13RequestPacket.getInt(_buffer);
if (_packetLength > Ajp13Packet.MAX_PACKET_SIZE)
throw new IOException("AJP13 packet (" + _packetLength + "bytes) too large for buffer");
}
if (_buffer.length() < _packetLength)
{
if (total_filled<0)
total_filled=0;
total_filled+=fill();
if (_buffer.length() < _packetLength)
return total_filled;
}
// Parse Header
Buffer bufHeaderName = null;
Buffer bufHeaderValue = null;
int attr_type = 0;
byte packetType = Ajp13RequestPacket.getByte(_buffer);
switch (packetType)
{
case Ajp13Packet.FORWARD_REQUEST_ORDINAL:
_handler.startForwardRequest();
break;
case Ajp13Packet.CPING_REQUEST_ORDINAL:
(_generator).sendCPong();
if(_header != null)
{
_buffers.returnBuffer(_header);
_header = null;
}
if(_body != null)
{
_buffers.returnBuffer(_body);
_body = null;
}
_buffer= null;
reset();
return -1;
case Ajp13Packet.SHUTDOWN_ORDINAL:
shutdownRequest();
return -1;
default:
// XXX Throw an Exception here?? Close
// connection!
LOG.warn("AJP13 message type ({PING}: "+packetType+" ) not supported/recognized as an AJP request");
throw new IllegalStateException("PING is not implemented");
}
_handler.parsedMethod(Ajp13RequestPacket.getMethod(_buffer));
_handler.parsedProtocol(Ajp13RequestPacket.getString(_buffer, _tok0));
_handler.parsedUri(Ajp13RequestPacket.getString(_buffer, _tok1));
_handler.parsedRemoteAddr(Ajp13RequestPacket.getString(_buffer, _tok1));
_handler.parsedRemoteHost(Ajp13RequestPacket.getString(_buffer, _tok1));
_handler.parsedServerName(Ajp13RequestPacket.getString(_buffer, _tok1));
_handler.parsedServerPort(Ajp13RequestPacket.getInt(_buffer));
_handler.parsedSslSecure(Ajp13RequestPacket.getBool(_buffer));
_headers = Ajp13RequestPacket.getInt(_buffer);
for (int h=0;h<_headers;h++)
{
bufHeaderName = Ajp13RequestPacket.getHeaderName(_buffer, _tok0);
bufHeaderValue = Ajp13RequestPacket.getString(_buffer, _tok1);
if (bufHeaderName != null && bufHeaderName.toString().equals(Ajp13RequestHeaders.CONTENT_LENGTH))
{
_contentLength = BufferUtil.toLong(bufHeaderValue);
if (_contentLength == 0)
_contentLength = HttpTokens.NO_CONTENT;
}
_handler.parsedHeader(bufHeaderName, bufHeaderValue);
}
attr_type = Ajp13RequestPacket.getByte(_buffer) & 0xff;
while (attr_type != 0xFF)
{
switch (attr_type)
{
// XXX How does this plug into the web
// containers
// authentication?
case Ajp13RequestHeaders.REMOTE_USER_ATTR:
_handler.parsedRemoteUser(Ajp13RequestPacket.getString(_buffer, _tok1));
break;
case Ajp13RequestHeaders.AUTH_TYPE_ATTR:
//XXX JASPI how does this make sense?
_handler.parsedAuthorizationType(Ajp13RequestPacket.getString(_buffer, _tok1));
break;
case Ajp13RequestHeaders.QUERY_STRING_ATTR:
_handler.parsedQueryString(Ajp13RequestPacket.getString(_buffer, _tok1));
break;
case Ajp13RequestHeaders.JVM_ROUTE_ATTR:
// moved to Eclipse naming usage
// used in org.eclipse.jetty.servlet.HashSessionIdManager
_handler.parsedRequestAttribute("org.eclipse.jetty.ajp.JVMRoute", Ajp13RequestPacket.getString(_buffer, _tok1));
break;
case Ajp13RequestHeaders.SSL_CERT_ATTR:
_handler.parsedSslCert(Ajp13RequestPacket.getString(_buffer, _tok1));
break;
case Ajp13RequestHeaders.SSL_CIPHER_ATTR:
_handler.parsedSslCipher(Ajp13RequestPacket.getString(_buffer, _tok1));
// SslSocketConnector.customize()
break;
case Ajp13RequestHeaders.SSL_SESSION_ATTR:
_handler.parsedSslSession(Ajp13RequestPacket.getString(_buffer, _tok1));
break;
case Ajp13RequestHeaders.REQUEST_ATTR:
_handler.parsedRequestAttribute(Ajp13RequestPacket.getString(_buffer, _tok0).toString(), Ajp13RequestPacket.getString(_buffer, _tok1));
break;
// New Jk API?
// Check if experimental or can they
// assumed to be
// supported
case Ajp13RequestHeaders.SSL_KEYSIZE_ATTR:
// This has been implemented in AJP13 as either a string or a integer.
// Servlet specs say javax.servlet.request.key_size must be an Integer
// Does it look like a string containing digits?
int length = Ajp13RequestPacket.getInt(_buffer);
if (length>0 && length<16)
{
// this must be a string length rather than a key length
_buffer.skip(-2);
_handler.parsedSslKeySize(Integer.parseInt(Ajp13RequestPacket.getString(_buffer, _tok1).toString()));
}
else
_handler.parsedSslKeySize(length);
break;
// Used to lock down jk requests with a
// secreate
// key.
case Ajp13RequestHeaders.SECRET_ATTR:
// XXX Investigate safest way to
// deal with
// this...
// should this tie into shutdown
// packet?
break;
case Ajp13RequestHeaders.STORED_METHOD_ATTR:
// XXX Confirm this should
// really overide
// previously parsed method?
// _handler.parsedMethod(Ajp13PacketMethods.CACHE.get(Ajp13RequestPacket.getString()));
break;
case Ajp13RequestHeaders.CONTEXT_ATTR:
_handler.parsedContextPath(Ajp13RequestPacket.getString(_buffer, _tok1));
break;
case Ajp13RequestHeaders.SERVLET_PATH_ATTR:
_handler.parsedServletPath(Ajp13RequestPacket.getString(_buffer, _tok1));
break;
default:
LOG.warn("Unsupported Ajp13 Request Attribute {}", new Integer(attr_type));
break;
}
attr_type = Ajp13RequestPacket.getByte(_buffer) & 0xff;
}
_contentPosition = 0;
switch ((int) _contentLength)
{
case HttpTokens.NO_CONTENT:
_state = STATE_END;
_handler.headerComplete();
_handler.messageComplete(_contentPosition);
break;
case HttpTokens.UNKNOWN_CONTENT:
_generator.getBodyChunk();
if (_buffers != null && _body == null && _buffer == _header && _header.length() <= 0)
{
_body = _buffers.getBuffer();
_body.clear();
}
_state = STATE_AJP13CHUNK_START;
_handler.headerComplete(); // May recurse here!
return total_filled;
default:
if (_buffers != null && _body == null && _buffer == _header && _contentLength > (_header.capacity() - _header.getIndex()))
{
_body = _buffers.getBuffer();
_body.clear();
}
_state = STATE_AJP13CHUNK_START;
_handler.headerComplete(); // May recurse here!
return total_filled;
}
}
Buffer chunk;
while (_state>STATE_END)
{
switch (_state)
{
case STATE_AJP13CHUNK_START:
if (_buffer.length()<6)
{
if (total_filled<0)
total_filled=0;
total_filled+=fill();
if (_buffer.length()<6)
return total_filled;
}
int _magic=Ajp13RequestPacket.getInt(_buffer);
if (_magic!=Ajp13RequestHeaders.MAGIC)
{
throw new IOException("Bad AJP13 rcv packet: "+"0x"+Integer.toHexString(_magic)+" expected "+"0x"
+Integer.toHexString(Ajp13RequestHeaders.MAGIC)+" "+this);
}
_chunkPosition=0;
_chunkLength=Ajp13RequestPacket.getInt(_buffer)-2;
Ajp13RequestPacket.getInt(_buffer);
if (_chunkLength==0)
{
_state=STATE_END;
_generator.gotBody();
_handler.messageComplete(_contentPosition);
return total_filled;
}
_state=STATE_AJP13CHUNK;
break;
case STATE_AJP13CHUNK:
if (_buffer.length()<_chunkLength)
{
if (total_filled<0)
total_filled=0;
total_filled+=fill();
if (_buffer.length()<_chunkLength)
return total_filled;
}
int remaining=_chunkLength-_chunkPosition;
if (remaining==0)
{
_state=STATE_AJP13CHUNK_START;
if (_contentPosition<_contentLength)
{
_generator.getBodyChunk();
}
else
{
_generator.gotBody();
}
return total_filled;
}
if (_buffer.length()<remaining)
{
remaining=_buffer.length();
}
chunk=Ajp13RequestPacket.get(_buffer,remaining);
_contentPosition+=chunk.length();
_chunkPosition+=chunk.length();
_contentView.update(chunk);
remaining=_chunkLength-_chunkPosition;
if (remaining==0)
{
_state=STATE_AJP13CHUNK_START;
if (_contentPosition<_contentLength || _contentLength == HttpTokens.UNKNOWN_CONTENT)
{
_generator.getBodyChunk();
}
else
{
_generator.gotBody();
}
}
_handler.content(chunk);
return total_filled;
default:
throw new IllegalStateException("Invalid Content State");
}
}
return total_filled;
}
/* ------------------------------------------------------------------------------- */
public void reset()
{
_state = STATE_START;
_contentLength = HttpTokens.UNKNOWN_CONTENT;
_contentPosition = 0;
_length = 0;
_packetLength = 0;
if (_body!=null && _body.hasContent())
{
// There is content in the body after the end of the request.
// This is probably a pipelined header of the next request, so we need to
// copy it to the header buffer.
if (_header==null)
{
_header=_buffers.getHeader();
_tok0.update(_header);
_tok0.update(0,0);
_tok1.update(_header);
_tok1.update(0,0);
}
else
{
_header.setMarkIndex(-1);
_header.compact();
}
int take=_header.space();
if (take>_body.length())
take=_body.length();
_body.peek(_body.getIndex(),take);
_body.skip(_header.put(_body.peek(_body.getIndex(),take)));
}
if (_header!=null)
_header.setMarkIndex(-1);
if (_body!=null)
_body.setMarkIndex(-1);
_buffer=_header;
}
/* ------------------------------------------------------------------------------- */
public void returnBuffers()
{
if (_body!=null && !_body.hasContent() && _body.markIndex()==-1)
{
if (_buffer==_body)
_buffer=_header;
if (_buffers!=null)
_buffers.returnBuffer(_body);
_body=null;
}
if (_header!=null && !_header.hasContent() && _header.markIndex()==-1)
{
if (_buffer==_header)
_buffer=null;
_buffers.returnBuffer(_header);
_header=null;
}
}
/* ------------------------------------------------------------------------------- */
Buffer getHeaderBuffer()
{
return _buffer;
}
private void shutdownRequest()
{
_state = STATE_END;
if(!Ajp13SocketConnector.__allowShutdown)
{
LOG.warn("AJP13: Shutdown Request is Denied, allowShutdown is set to false!!!");
return;
}
if(Ajp13SocketConnector.__secretWord != null)
{
LOG.warn("AJP13: Validating Secret Word");
try
{
String secretWord = Ajp13RequestPacket.getString(_buffer, _tok1).toString();
if(!Ajp13SocketConnector.__secretWord.equals(secretWord))
{
LOG.warn("AJP13: Shutdown Request Denied, Invalid Sercret word!!!");
throw new IllegalStateException("AJP13: Secret Word is Invalid: Peer has requested shutdown but, Secret Word did not match");
}
}
catch (Exception e)
{
LOG.warn("AJP13: Secret Word is Required!!!");
LOG.debug(e);
throw new IllegalStateException("AJP13: Secret Word is Required: Peer has requested shutdown but, has not provided a Secret Word");
}
LOG.warn("AJP13: Shutdown Request is Denied, allowShutdown is set to false!!!");
return;
}
LOG.warn("AJP13: Peer Has Requested for Shutdown!!!");
LOG.warn("AJP13: Jetty 6 is shutting down !!!");
System.exit(0);
}
/* ------------------------------------------------------------------------------- */
public interface EventHandler
{
// public void shutdownRequest() throws IOException;
// public void cpingRequest() throws IOException;
public void content(Buffer ref) throws IOException;
public void headerComplete() throws IOException;
public void messageComplete(long contextLength) throws IOException;
public void parsedHeader(Buffer name, Buffer value) throws IOException;
public void parsedMethod(Buffer method) throws IOException;
public void parsedProtocol(Buffer protocol) throws IOException;
public void parsedQueryString(Buffer value) throws IOException;
public void parsedRemoteAddr(Buffer addr) throws IOException;
public void parsedRemoteHost(Buffer host) throws IOException;
public void parsedRequestAttribute(String key, Buffer value) throws IOException;
public void parsedRequestAttribute(String key, int value) throws IOException;
public void parsedServerName(Buffer name) throws IOException;
public void parsedServerPort(int port) throws IOException;
public void parsedSslSecure(boolean secure) throws IOException;
public void parsedUri(Buffer uri) throws IOException;
public void startForwardRequest() throws IOException;
public void parsedAuthorizationType(Buffer authType) throws IOException;
public void parsedRemoteUser(Buffer remoteUser) throws IOException;
public void parsedServletPath(Buffer servletPath) throws IOException;
public void parsedContextPath(Buffer context) throws IOException;
public void parsedSslCert(Buffer sslCert) throws IOException;
public void parsedSslCipher(Buffer sslCipher) throws IOException;
public void parsedSslSession(Buffer sslSession) throws IOException;
public void parsedSslKeySize(int keySize) throws IOException;
}
/* ------------------------------------------------------------ */
/**
* TODO Make this common with HttpParser
*
*/
public static class Input extends ServletInputStream
{
private Ajp13Parser _parser;
private EndPoint _endp;
private long _maxIdleTime;
private View _content;
/* ------------------------------------------------------------ */
public Input(Ajp13Parser parser, long maxIdleTime)
{
_parser = parser;
_endp = parser._endp;
_maxIdleTime = maxIdleTime;
_content = _parser._contentView;
}
/* ------------------------------------------------------------ */
@Override
public int read() throws IOException
{
int c = -1;
if (blockForContent())
c = 0xff & _content.get();
return c;
}
/* ------------------------------------------------------------ */
/*
* @see java.io.InputStream#read(byte[], int, int)
*/
@Override
public int read(byte[] b, int off, int len) throws IOException
{
int l = -1;
if (blockForContent())
l = _content.get(b, off, len);
return l;
}
/* ------------------------------------------------------------ */
private boolean blockForContent() throws IOException
{
if (_content.length() > 0)
return true;
if (_parser.isState(Ajp13Parser.STATE_END) || _parser.isState(Ajp13Parser.STATE_START))
return false;
// Handle simple end points.
if (_endp == null)
_parser.parseNext();
// Handle blocking end points
else if (_endp.isBlocking())
{
_parser.parseNext();
// parse until some progress is made (or IOException thrown for timeout)
while (_content.length() == 0 && !_parser.isState(Ajp13Parser.STATE_END))
{
// Try to get more _parser._content
_parser.parseNext();
}
}
else // Handle non-blocking end point
{
long filled = _parser.parseNext();
boolean blocked = false;
// parse until some progress is made (or
// IOException thrown for timeout)
while (_content.length() == 0 && !_parser.isState(Ajp13Parser.STATE_END))
{
// if fill called, but no bytes read,
// then block
if (filled > 0)
blocked = false;
else if (filled == 0)
{
if (blocked)
throw new InterruptedIOException("timeout");
blocked = true;
_endp.blockReadable(_maxIdleTime);
}
// Try to get more _parser._content
filled = _parser.parseNext();
}
}
return _content.length() > 0;
}
}
public boolean isPersistent()
{
return true;
}
public void setPersistent(boolean persistent)
{
LOG.warn("AJP13.setPersistent is not IMPLEMENTED!");
}
}

View File

@ -1,124 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ajp;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.Request;
public class Ajp13Request extends Request
{
protected String _remoteAddr;
protected String _remoteHost;
protected String _remoteUser;
protected boolean _sslSecure;
/* ------------------------------------------------------------ */
public Ajp13Request(AbstractHttpConnection connection)
{
super(connection);
}
/* ------------------------------------------------------------ */
public Ajp13Request()
{
}
/* ------------------------------------------------------------ */
void setConnection(Ajp13Connection connection)
{
super.setConnection(connection);
}
/* ------------------------------------------------------------ */
public void setRemoteUser(String remoteUser)
{
_remoteUser = remoteUser;
}
/* ------------------------------------------------------------ */
@Override
public String getRemoteUser()
{
if(_remoteUser != null)
return _remoteUser;
return super.getRemoteUser();
}
/* ------------------------------------------------------------ */
@Override
public String getRemoteAddr()
{
if (_remoteAddr != null)
return _remoteAddr;
if (_remoteHost != null)
return _remoteHost;
return super.getRemoteAddr();
}
/* ------------------------------------------------------------ */
@Override
public void setRemoteAddr(String remoteAddr)
{
_remoteAddr = remoteAddr;
}
/* ------------------------------------------------------------ */
@Override
public String getRemoteHost()
{
if (_remoteHost != null)
return _remoteHost;
if (_remoteAddr != null)
return _remoteAddr;
return super.getRemoteHost();
}
/* ------------------------------------------------------------ */
@Override
public void setRemoteHost(String remoteHost)
{
_remoteHost = remoteHost;
}
/* ------------------------------------------------------------ */
public boolean isSslSecure()
{
return _sslSecure;
}
/* ------------------------------------------------------------ */
public void setSslSecure(boolean sslSecure)
{
_sslSecure = sslSecure;
}
/* ------------------------------------------------------------ */
@Override
protected void recycle()
{
super.recycle();
_remoteAddr = null;
_remoteHost = null;
_remoteUser = null;
_sslSecure = false;
}
}

View File

@ -1,67 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ajp;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.BufferCache;
/**
* XXX Should this implement the Buffer interface?
*
*
*/
public class Ajp13RequestHeaders extends BufferCache
{
public final static int MAGIC=0x1234;
public final static String ACCEPT="accept", ACCEPT_CHARSET="accept-charset", ACCEPT_ENCODING="accept-encoding", ACCEPT_LANGUAGE="accept-language",
AUTHORIZATION="authorization", CONNECTION="connection", CONTENT_TYPE="content-type", CONTENT_LENGTH="content-length", COOKIE="cookie",
COOKIE2="cookie2", HOST="host", PRAGMA="pragma", REFERER="referer", USER_AGENT="user-agent";
public final static int ACCEPT_ORDINAL=1, ACCEPT_CHARSET_ORDINAL=2, ACCEPT_ENCODING_ORDINAL=3, ACCEPT_LANGUAGE_ORDINAL=4, AUTHORIZATION_ORDINAL=5,
CONNECTION_ORDINAL=6, CONTENT_TYPE_ORDINAL=7, CONTENT_LENGTH_ORDINAL=8, COOKIE_ORDINAL=9, COOKIE2_ORDINAL=10, HOST_ORDINAL=11, PRAGMA_ORDINAL=12,
REFERER_ORDINAL=13, USER_AGENT_ORDINAL=14;
public final static BufferCache CACHE=new BufferCache();
public final static Buffer ACCEPT_BUFFER=CACHE.add(ACCEPT,ACCEPT_ORDINAL), ACCEPT_CHARSET_BUFFER=CACHE.add(ACCEPT_CHARSET,ACCEPT_CHARSET_ORDINAL),
ACCEPT_ENCODING_BUFFER=CACHE.add(ACCEPT_ENCODING,ACCEPT_ENCODING_ORDINAL), ACCEPT_LANGUAGE_BUFFER=CACHE
.add(ACCEPT_LANGUAGE,ACCEPT_LANGUAGE_ORDINAL), AUTHORIZATION_BUFFER=CACHE.add(AUTHORIZATION,AUTHORIZATION_ORDINAL), CONNECTION_BUFFER=CACHE
.add(CONNECTION,CONNECTION_ORDINAL), CONTENT_TYPE_BUFFER=CACHE.add(CONTENT_TYPE,CONTENT_TYPE_ORDINAL), CONTENT_LENGTH_BUFFER=CACHE.add(
CONTENT_LENGTH,CONTENT_LENGTH_ORDINAL), COOKIE_BUFFER=CACHE.add(COOKIE,COOKIE_ORDINAL), COOKIE2_BUFFER=CACHE.add(COOKIE2,COOKIE2_ORDINAL),
HOST_BUFFER=CACHE.add(HOST,HOST_ORDINAL), PRAGMA_BUFFER=CACHE.add(PRAGMA,PRAGMA_ORDINAL), REFERER_BUFFER=CACHE.add(REFERER,REFERER_ORDINAL),
USER_AGENT_BUFFER=CACHE.add(USER_AGENT,USER_AGENT_ORDINAL);
public final static byte
CONTEXT_ATTR=1, // Legacy
SERVLET_PATH_ATTR=2, // Legacy
REMOTE_USER_ATTR=3,
AUTH_TYPE_ATTR=4,
QUERY_STRING_ATTR=5,
JVM_ROUTE_ATTR=6,
SSL_CERT_ATTR=7,
SSL_CIPHER_ATTR=8,
SSL_SESSION_ATTR=9,
REQUEST_ATTR=10,
SSL_KEYSIZE_ATTR=11,
SECRET_ATTR=12,
STORED_METHOD_ATTR=13;
}

View File

@ -1,90 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ajp;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.View;
/**
*
*
*
*/
public class Ajp13RequestPacket
{
public static boolean isEmpty(Buffer _buffer)
{
return _buffer.length()==0;
}
public static int getInt(Buffer _buffer)
{
return ((_buffer.get()&0xFF)<<8)|(_buffer.get()&0xFF);
}
public static Buffer getString(Buffer _buffer, View tok)
{
int len=((_buffer.peek()&0xFF)<<8)|(_buffer.peek(_buffer.getIndex()+1)&0xFF);
if (len==0xffff)
{
_buffer.skip(2);
return null;
}
int start=_buffer.getIndex();
tok.update(start+2,start+len+2);
_buffer.skip(len+3);
return tok;
}
public static byte getByte(Buffer _buffer)
{
return _buffer.get();
}
public static boolean getBool(Buffer _buffer)
{
return _buffer.get()>0;
}
public static Buffer getMethod(Buffer _buffer)
{
return Ajp13PacketMethods.CACHE.get(_buffer.get());
}
public static Buffer getHeaderName(Buffer _buffer, View tok)
{
int len=((_buffer.peek()&0xFF)<<8)|(_buffer.peek(_buffer.getIndex()+1)&0xFF);
if ((0xFF00&len)==0xA000)
{
_buffer.skip(1);
return Ajp13RequestHeaders.CACHE.get(_buffer.get());
}
int start=_buffer.getIndex();
tok.update(start+2,start+len+2);
_buffer.skip(len+3);
return tok;
}
public static Buffer get(Buffer buffer, int length)
{
return buffer.get(length);
}
}

View File

@ -1,48 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ajp;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.BufferCache;
/**
*
*/
public class Ajp13ResponseHeaders extends BufferCache
{
public final static int MAGIC=0xab00;
public final static String CONTENT_TYPE="Content-Type", CONTENT_LANGUAGE="Content-Language", CONTENT_LENGTH="Content-Length", DATE="Date",
LAST_MODIFIED="Last-Modified", LOCATION="Location", SET_COOKIE="Set-Cookie", SET_COOKIE2="Set-Cookie2", SERVLET_ENGINE="Servlet-Engine",
STATUS="Status", WWW_AUTHENTICATE="WWW-Authenticate";
public final static int CONTENT_TYPE_ORDINAL=1, CONTENT_LANGUAGE_ORDINAL=2, CONTENT_LENGTH_ORDINAL=3, DATE_ORDINAL=4, LAST_MODIFIED_ORDINAL=5,
LOCATION_ORDINAL=6, SET_COOKIE_ORDINAL=7, SET_COOKIE2_ORDINAL=8, SERVLET_ENGINE_ORDINAL=9, STATUS_ORDINAL=10, WWW_AUTHENTICATE_ORDINAL=11;
public final static BufferCache CACHE=new BufferCache();
public final static Buffer CONTENT_TYPE_BUFFER=CACHE.add(CONTENT_TYPE,CONTENT_TYPE_ORDINAL), CONTENT_LANGUAGE_BUFFER=CACHE.add(CONTENT_LANGUAGE,
CONTENT_LANGUAGE_ORDINAL), CONTENT_LENGTH_BUFFER=CACHE.add(CONTENT_LENGTH,CONTENT_LENGTH_ORDINAL), DATE_BUFFER=CACHE.add(DATE,DATE_ORDINAL),
LAST_MODIFIED_BUFFER=CACHE.add(LAST_MODIFIED,LAST_MODIFIED_ORDINAL), LOCATION_BUFFER=CACHE.add(LOCATION,LOCATION_ORDINAL), SET_COOKIE_BUFFER=CACHE
.add(SET_COOKIE,SET_COOKIE_ORDINAL), SET_COOKIE2_BUFFER=CACHE.add(SET_COOKIE2,SET_COOKIE2_ORDINAL), SERVLET_ENGINE_BUFFER=CACHE.add(
SERVLET_ENGINE,SERVLET_ENGINE_ORDINAL), STATUS_BUFFER=CACHE.add(STATUS,STATUS_ORDINAL), WWW_AUTHENTICATE_BUFFER=CACHE.add(WWW_AUTHENTICATE,
WWW_AUTHENTICATE_ORDINAL);
}

View File

@ -1,132 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ajp;
import java.io.IOException;
import org.eclipse.jetty.http.HttpSchemes;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.bio.SocketConnector;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
*
*
*
*/
public class Ajp13SocketConnector extends SocketConnector
{
private static final Logger LOG = Log.getLogger(Ajp13SocketConnector.class);
static String __secretWord = null;
static boolean __allowShutdown = false;
public Ajp13SocketConnector()
{
super.setRequestHeaderSize(Ajp13Packet.MAX_PACKET_SIZE);
super.setResponseHeaderSize(Ajp13Packet.MAX_PACKET_SIZE);
super.setRequestBufferSize(Ajp13Packet.MAX_PACKET_SIZE);
super.setResponseBufferSize(Ajp13Packet.MAX_PACKET_SIZE);
// IN AJP protocol the socket stay open, so
// by default the time out is set to 0 seconds
super.setMaxIdleTime(0);
}
@Override
protected void doStart() throws Exception
{
super.doStart();
LOG.info("AJP13 is not a secure protocol. Please protect port {}",Integer.toString(getLocalPort()));
}
/* ------------------------------------------------------------ */
/* (non-Javadoc)
* @see org.eclipse.jetty.server.bio.SocketConnector#customize(org.eclipse.io.EndPoint, org.eclipse.jetty.server.Request)
*/
@Override
public void customize(EndPoint endpoint, Request request) throws IOException
{
super.customize(endpoint,request);
if (request.isSecure())
request.setScheme(HttpSchemes.HTTPS);
}
/* ------------------------------------------------------------ */
@Override
protected Connection newConnection(EndPoint endpoint)
{
return new Ajp13Connection(this,endpoint,getServer());
}
/* ------------------------------------------------------------ */
// Secured on a packet by packet bases not by connection
@Override
public boolean isConfidential(Request request)
{
return ((Ajp13Request) request).isSslSecure();
}
/* ------------------------------------------------------------ */
// Secured on a packet by packet bases not by connection
@Override
public boolean isIntegral(Request request)
{
return ((Ajp13Request) request).isSslSecure();
}
/* ------------------------------------------------------------ */
@Deprecated
public void setHeaderBufferSize(int headerBufferSize)
{
LOG.debug(Log.IGNORED);
}
/* ------------------------------------------------------------ */
@Override
public void setRequestBufferSize(int requestBufferSize)
{
LOG.debug(Log.IGNORED);
}
/* ------------------------------------------------------------ */
@Override
public void setResponseBufferSize(int responseBufferSize)
{
LOG.debug(Log.IGNORED);
}
/* ------------------------------------------------------------ */
public void setAllowShutdown(boolean allowShutdown)
{
LOG.warn("AJP13: Shutdown Request is: " + allowShutdown);
__allowShutdown = allowShutdown;
}
/* ------------------------------------------------------------ */
public void setSecretWord(String secretWord)
{
LOG.warn("AJP13: Shutdown Request secret word is : " + secretWord);
__secretWord = secretWord;
}
}

View File

@ -1,331 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ajp;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketTimeoutException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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.util.IO;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class Ajp13ConnectionTest
{
private static final Logger LOG = Log.getLogger(Ajp13ConnectionTest.class);
private static Server _server;
private static Ajp13SocketConnector _connector;
private Socket _client;
@BeforeClass
public static void startServer() throws Exception
{
_server=new Server();
_connector=new Ajp13SocketConnector();
_connector.setPort(0);
_server.setConnectors(new Connector[] { _connector });
_server.setHandler(new Handler());
_server.start();
}
@AfterClass
public static void stopServer() throws Exception
{
_connector.close();
_server.stop();
}
@Before
public void openSocket() throws Exception
{
_client=new Socket("localhost",_connector.getLocalPort());
_client.setSoTimeout(500);
}
@After
public void closeSocket() throws Exception
{
_client.close();
}
@Test
public void testPacket1() throws Exception
{
OutputStream os=_client.getOutputStream();
String packet="123401070202000f77696474683d20485454502f312e300000122f636f6e74726f6c2f70726f647563742f2200000e3230382e32372e3230332e31323800ffff000c7777772e756c74612e636f6d000050000005a006000a6b6565702d616c69766500a00b000c7777772e756c74612e636f6d00a00e002b4d6f7a696c6c612f342e302028636f6d70617469626c653b20426f726465724d616e6167657220332e302900a0010043696d6167652f6769662c20696d6167652f782d786269746d61702c20696d6167652f6a7065672c20696d6167652f706a7065672c20696d6167652f706d672c202a2f2a00a008000130000600067570726f64310008000a4145533235362d53484100ff";
os.write(TypeUtil.fromHexString(packet));
os.flush();
readResponse(_client);
assertTrue(true);
}
@Test
public void testPacket2() throws Exception
{
OutputStream os=_client.getOutputStream();
String packet="1234020102020008485454502f312e3100000f2f6363632d7777777777772f61616100000c38382e3838382e38382e383830ffff00116363632e6363636363636363632e636f6d0001bb010009a00b00116363632e6363636363636363632e636f6d00a00e005a4d6f7a696c6c612f352e30202857696e646f77733b20553b2057696e646f7773204e5420352e313b20656e2d55533b2072763a312e382e312e3129204765636b6f2f32303036313230342046697265666f782f322e302e302e3100a0010063746578742f786d6c2c6170706c69636174696f6e2f786d6c2c6170706c69636174696f6e2f7868746d6c2b786d6c2c746578742f68746d6c3b713d302e392c746578742f706c61696e3b713d302e382c696d6167652f706e672c2a2f2a3b713d302e3500a004000e656e2d75732c656e3b713d302e3500a003000c677a69702c6465666c61746500a002001e49534f2d383835392d312c7574662d383b713d302e372c2a3b713d302e3700000a4b6565702d416c69766500000333303000a006000a6b6565702d616c69766500000c4d61782d466f7277617264730000023130000800124448452d5253412d4145533235362d5348410009004039324643303544413043444141443232303137413743443141453939353132413330443938363838423843433041454643364231363035323543433232353341000b0100ff";
os.write(TypeUtil.fromHexString(packet));
os.flush();
readResponse(_client);
assertTrue(true);
}
@Test
public void testPacket3() throws Exception
{
OutputStream os=_client.getOutputStream();
String packet="1234028f02020008485454502f312e3100000d2f666f726d746573742e6a737000000d3139322e3136382e342e31383000ffff00107777772e777265636b6167652e6f726700005000000aa0010063746578742f786d6c2c6170706c69636174696f6e2f786d6c2c6170706c69636174696f6e2f7868746d6c2b786d6c2c746578742f68746d6c3b713d302e392c746578742f706c61696e3b713d302e382c696d6167652f706e672c2a2f2a3b713d302e3500a00200075554462d382c2a00a003000c677a69702c6465666c61746500a004000e656e2d67622c656e3b713d302e3500a006000a6b6565702d616c69766500a00900f95048505345535349443d37626361383232616638333466316465373663633630336366636435313938633b20667041757468436f6f6b69653d433035383430394537393344364245434633324230353234344242303039343230383344443645443533304230454637464137414544413745453231313538333745363033454435364332364446353531383635333335423433374531423637414641343533364345304546323342333642323133374243423932333943363631433131443330393842333938414546334546334146454344423746353842443b204a53455353494f4e49443d7365366331623864663432762e6a657474793300a00b00107777772e777265636b6167652e6f726700000a6b6565702d616c69766500000333303000a00e00654d6f7a696c6c612f352e3020285831313b20553b204c696e7578207838365f36343b20656e2d55533b2072763a312e382e302e3929204765636b6f2f3230303631323035202844656269616e2d312e382e302e392d3129204570697068616e792f322e313400a008000130000600066a657474793300ff";
os.write(TypeUtil.fromHexString(packet));
os.flush();
readResponse(_client);
assertTrue(true);
}
@Test
public void testSSLPacketWithIntegerKeySize() throws Exception
{
OutputStream os=_client.getOutputStream();
String packet="1234025002020008485454502f312e3100000f2f746573742f64756d702f696e666f00000e3139322e3136382e3130302e343000ffff000c776562746964652d746573740001bb01000ca00b000c776562746964652d7465737400a00e005a4d6f7a696c6c612f352e30202857696e646f77733b20553b2057696e646f7773204e5420352e313b20656e2d55533b2072763a312e382e312e3129204765636b6f2f32303036313230342046697265666f782f322e302e302e3100a0010063746578742f786d6c2c6170706c69636174696f6e2f786d6c2c6170706c69636174696f6e2f7868746d6c2b786d6c2c746578742f68746d6c3b713d302e392c746578742f706c61696e3b713d302e382c696d6167652f706e672c2a2f2a3b713d302e3500a004000e656e2d75732c656e3b713d302e3500a003000c677a69702c6465666c61746500a002001e49534f2d383835392d312c7574662d383b713d302e372c2a3b713d302e3700000a4b6565702d416c69766500000333303000a006000a6b6565702d616c69766500a00d001a68747470733a2f2f776562746964652d746573742f746573742f00a00900174a53455353494f4e49443d69326c6e307539773573387300000d43616368652d436f6e74726f6c0000096d61782d6167653d3000000c4d61782d466f7277617264730000023130000800124448452d5253412d4145533235362d5348410009004032413037364245323330433238393130383941414132303631344139384441443131314230323132343030374130363642454531363742303941464337383942000b0100ff";
os.write(TypeUtil.fromHexString(packet));
os.flush();
readResponse(_client);
assertTrue(true);
}
@Test
public void testSSLPacketWithStringKeySize() throws Exception
{
OutputStream os=_client.getOutputStream();
String packet="1234025002020008485454502f312e3100000f2f746573742f64756d702f696e666f00000e3139322e3136382e3130302e343000ffff000c776562746964652d746573740001bb01000ca00b000c776562746964652d7465737400a00e005a4d6f7a696c6c612f352e30202857696e646f77733b20553b2057696e646f7773204e5420352e313b20656e2d55533b2072763a312e382e312e3129204765636b6f2f32303036313230342046697265666f782f322e302e302e3100a0010063746578742f786d6c2c6170706c69636174696f6e2f786d6c2c6170706c69636174696f6e2f7868746d6c2b786d6c2c746578742f68746d6c3b713d302e392c746578742f706c61696e3b713d302e382c696d6167652f706e672c2a2f2a3b713d302e3500a004000e656e2d75732c656e3b713d302e3500a003000c677a69702c6465666c61746500a002001e49534f2d383835392d312c7574662d383b713d302e372c2a3b713d302e3700000a4b6565702d416c69766500000333303000a006000a6b6565702d616c69766500a00d001a68747470733a2f2f776562746964652d746573742f746573742f00a00900174a53455353494f4e49443d69326c6e307539773573387300000d43616368652d436f6e74726f6c0000096d61782d6167653d3000000c4d61782d466f7277617264730000023130000800124448452d5253412d4145533235362d5348410009004032413037364245323330433238393130383941414132303631344139384441443131314230323132343030374130363642454531363742303941464337383942000b000332353600ff";
os.write(TypeUtil.fromHexString(packet));
os.flush();
readResponse(_client);
assertTrue(true);
}
@Test
public void testPacketWithBody() throws Exception
{
OutputStream os=_client.getOutputStream();
os.write(TypeUtil.fromHexString(getTestHeader()));
os.write(TypeUtil.fromHexString(getTestShortBody()));
os.write(TypeUtil.fromHexString(getTestTinyBody()));
readResponse(_client);
assertTrue(true);
}
@Test
public void testPacketWithChunkedBody() throws Exception
{
OutputStream os=_client.getOutputStream();
String packet="123400ff02040008485454502f312e3100000f2f746573742f64756d702f696e666f0000093132372e302e302e3100ffff00096c6f63616c686f7374000050000007a00e000d4a6176612f312e352e305f313100a00b00096c6f63616c686f737400a0010034746578742f68746d6c2c20696d6167652f6769662c20696d6167652f6a7065672c202a3b20713d2e322c202a2f2a3b20713d2e3200a006000a6b6565702d616c69766500a00700216170706c69636174696f6e2f782d7777772d666f726d2d75726c656e636f6465640000115472616e736665722d456e636f64696e670000076368756e6b656400000c4d61782d466f727761726473000002313000ff";
os.write(TypeUtil.fromHexString(packet));
os.flush();
os.write(TypeUtil.fromHexString("1234007e007c7468656e616d653d746865253230717569636b25323062726f776e253230666f782532306a756d70732532306f766572253230746f2532307468652532306c617a79253230646f67253230544845253230515549434b25323042524f574e253230464f582532304a554d50532532304f564552253230544f25323054"));
os.flush();
os.write(TypeUtil.fromHexString("12340042004048452532304c415a59253230444f472532302676616c75656f66323d6162636465666768696a6b6c6d6e6f707172737475767778797a31323334353637383930"));
os.flush();
os.write(TypeUtil.fromHexString("123400020000"));
os.flush();
readResponse(_client);
assertTrue(true);
}
private String getTestHeader()
{
StringBuffer header=new StringBuffer("");
header.append("1234026902040008485454502f31");
header.append("2e310000162f61646d696e2f496d6167");
header.append("6555706c6f61642e68746d00000a3130");
header.append("2e34382e31302e3100ffff000a31302e");
header.append("34382e31302e3200005000000da00b00");
header.append("0a31302e34382e31302e3200a00e005a");
header.append("4d6f7a696c6c612f352e30202857696e");
header.append("646f77733b20553b2057696e646f7773");
header.append("204e5420352e313b20656e2d55533b20");
header.append("72763a312e382e312e3129204765636b");
header.append("6f2f3230303631323034204669726566");
header.append("6f782f322e302e302e3100a001006374");
header.append("6578742f786d6c2c6170706c69636174");
header.append("696f6e2f786d6c2c6170706c69636174");
header.append("696f6e2f7868746d6c2b786d6c2c7465");
header.append("78742f68746d6c3b713d302e392c7465");
header.append("78742f706c61696e3b713d302e382c69");
header.append("6d6167652f706e672c2a2f2a3b713d30");
header.append("2e3500a004000e656e2d75732c656e3b");
header.append("713d302e3500a003000c677a69702c64");
header.append("65666c61746500a002001e49534f2d38");
header.append("3835392d312c7574662d383b713d302e");
header.append("372c2a3b713d302e3700000a4b656570");
header.append("2d416c69766500000333303000a00600");
header.append("0a6b6565702d616c69766500a00d003f");
header.append("687474703a2f2f31302e34382e31302e");
header.append("322f61646d696e2f496d61676555706c");
header.append("6f61642e68746d3f6964303d4974656d");
header.append("266964313d32266964323d696d673200");
header.append("a00900174a53455353494f4e49443d75");
header.append("383977733070696168746d00a0070046");
header.append("6d756c7469706172742f666f726d2d64");
header.append("6174613b20626f756e646172793d2d2d");
header.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
header.append("2d2d2d2d2d2d2d2d2d39343338333235");
header.append("34323630383700a00800033735390000");
header.append("0c4d61782d466f727761726473000002");
header.append("3130000500176964303d4974656d2669");
header.append("64313d32266964323d696d673200ff");
return header.toString();
}
private String getTestShortBody()
{
StringBuffer body=new StringBuffer("");
body.append("123402f702f52d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d3934333833323534323630");
body.append("38370d0a436f6e74656e742d44697370");
body.append("6f736974696f6e3a20666f726d2d6461");
body.append("74613b206e616d653d227265636f7264");
body.append("4964220d0a0d0a320d0a2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d393433383332353432");
body.append("363038370d0a436f6e74656e742d4469");
body.append("73706f736974696f6e3a20666f726d2d");
body.append("646174613b206e616d653d226e616d65");
body.append("220d0a0d0a4974656d0d0a2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d3934333833323534");
body.append("32363038370d0a436f6e74656e742d44");
body.append("6973706f736974696f6e3a20666f726d");
body.append("2d646174613b206e616d653d22746e49");
body.append("6d674964220d0a0d0a696d67320d0a2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d39343338");
body.append("3332353432363038370d0a436f6e7465");
body.append("6e742d446973706f736974696f6e3a20");
body.append("666f726d2d646174613b206e616d653d");
body.append("227468756d624e61696c496d61676546");
body.append("696c65223b2066696c656e616d653d22");
body.append("6161612e747874220d0a436f6e74656e");
body.append("742d547970653a20746578742f706c61");
body.append("696e0d0a0d0a61616161616161616161");
body.append("61616161616161616161616161616161");
body.append("61616161616161616161616161616161");
body.append("61616161616161616161616161616161");
body.append("0d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d39");
body.append("3433383332353432363038370d0a436f");
body.append("6e74656e742d446973706f736974696f");
body.append("6e3a20666f726d2d646174613b206e61");
body.append("6d653d226c61726765496d6167654669");
body.append("6c65223b2066696c656e616d653d2261");
body.append("61612e747874220d0a436f6e74656e74");
body.append("2d547970653a20746578742f706c6169");
body.append("6e0d0a0d0a6161616161616161616161");
body.append("61616161616161616161616161616161");
body.append("61616161616161616161616161616161");
body.append("6161616161616161616161616161610d");
body.append("0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d3934");
body.append("33383332353432363038372d2d");
return body.toString();
}
private String getTestTinyBody()
{
StringBuffer body = new StringBuffer("");
body.append("123400042d2d0d0a");
return body.toString();
}
// TODO: char array instead of string?
private String readResponse(Socket _client) throws IOException
{
ByteArrayOutputStream bout = new ByteArrayOutputStream();
try
{
IO.copy(_client.getInputStream(),bout);
}
catch(SocketTimeoutException e)
{
LOG.ignore(e);
}
return bout.toString("utf-8");
}
public static class Handler extends AbstractHandler
{
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
baseRequest.setHandled(true);
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("text/plain");
response.getWriter().println("success");
}
}
}

View File

@ -1,608 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ajp;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.ByteArrayBuffer;
import org.eclipse.jetty.io.ByteArrayEndPoint;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.SimpleBuffers;
import org.eclipse.jetty.util.TypeUtil;
import org.junit.Test;
public class TestAjpParser
{
@Test
public void testPacket1() throws Exception
{
String packet = "123401070202000f77696474683d20485454502f312e300000122f636f6e74726f6c2f70726f647563742f2200000e3230382e32372e3230332e31323800ffff000c7777772e756c74612e636f6d000050000005a006000a6b6565702d616c69766500a00b000c7777772e756c74612e636f6d00a00e002b4d6f7a696c6c612f342e302028636f6d70617469626c653b20426f726465724d616e6167657220332e302900a0010043696d6167652f6769662c20696d6167652f782d786269746d61702c20696d6167652f6a7065672c20696d6167652f706a7065672c20696d6167652f706d672c202a2f2a00a008000130000600067570726f64310008000a4145533235362d53484100ff";
byte[] src = TypeUtil.fromHexString(packet);
ByteArrayBuffer buffer= new ByteArrayBuffer(Ajp13Packet.MAX_PACKET_SIZE);
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
EndPoint endp = new ByteArrayEndPoint(src,Ajp13Packet.MAX_PACKET_SIZE);
Ajp13Parser parser = new Ajp13Parser(buffers,endp);
parser.setEventHandler(new EH());
parser.setGenerator(new Ajp13Generator(buffers,endp));
parser.parseAvailable();
assertTrue(true);
}
@Test
public void testPacket2() throws Exception
{
String packet="1234020102020008485454502f312e3100000f2f6363632d7777777777772f61616100000c38382e3838382e38382e383830ffff00116363632e6363636363636363632e636f6d0001bb010009a00b00116363632e6363636363636363632e636f6d00a00e005a4d6f7a696c6c612f352e30202857696e646f77733b20553b2057696e646f7773204e5420352e313b20656e2d55533b2072763a312e382e312e3129204765636b6f2f32303036313230342046697265666f782f322e302e302e3100a0010063746578742f786d6c2c6170706c69636174696f6e2f786d6c2c6170706c69636174696f6e2f7868746d6c2b786d6c2c746578742f68746d6c3b713d302e392c746578742f706c61696e3b713d302e382c696d6167652f706e672c2a2f2a3b713d302e3500a004000e656e2d75732c656e3b713d302e3500a003000c677a69702c6465666c61746500a002001e49534f2d383835392d312c7574662d383b713d302e372c2a3b713d302e3700000a4b6565702d416c69766500000333303000a006000a6b6565702d616c69766500000c4d61782d466f7277617264730000023130000800124448452d5253412d4145533235362d5348410009004039324643303544413043444141443232303137413743443141453939353132413330443938363838423843433041454643364231363035323543433232353341000b0100ff";
byte[] src=TypeUtil.fromHexString(packet);
ByteArrayBuffer buffer=new ByteArrayBuffer(Ajp13Packet.MAX_PACKET_SIZE);
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
EndPoint endp=new ByteArrayEndPoint(src,Ajp13Packet.MAX_PACKET_SIZE);
Ajp13Parser parser = new Ajp13Parser(buffers,endp);
parser.setEventHandler(new EH());
parser.setGenerator(new Ajp13Generator(buffers,endp));
parser.parse();
assertTrue(true);
}
@Test
public void testPacket3() throws Exception
{
String packet="1234028f02020008485454502f312e3100000d2f666f726d746573742e6a737000000d3139322e3136382e342e31383000ffff00107777772e777265636b6167652e6f726700005000000aa0010063746578742f786d6c2c6170706c69636174696f6e2f786d6c2c6170706c69636174696f6e2f7868746d6c2b786d6c2c746578742f68746d6c3b713d302e392c746578742f706c61696e3b713d302e382c696d6167652f706e672c2a2f2a3b713d302e3500a00200075554462d382c2a00a003000c677a69702c6465666c61746500a004000e656e2d67622c656e3b713d302e3500a006000a6b6565702d616c69766500a00900f95048505345535349443d37626361383232616638333466316465373663633630336366636435313938633b20667041757468436f6f6b69653d433035383430394537393344364245434633324230353234344242303039343230383344443645443533304230454637464137414544413745453231313538333745363033454435364332364446353531383635333335423433374531423637414641343533364345304546323342333642323133374243423932333943363631433131443330393842333938414546334546334146454344423746353842443b204a53455353494f4e49443d7365366331623864663432762e6a657474793300a00b00107777772e777265636b6167652e6f726700000a6b6565702d616c69766500000333303000a00e00654d6f7a696c6c612f352e3020285831313b20553b204c696e7578207838365f36343b20656e2d55533b2072763a312e382e302e3929204765636b6f2f3230303631323035202844656269616e2d312e382e302e392d3129204570697068616e792f322e313400a008000130000600066a657474793300ff";
byte[] src=TypeUtil.fromHexString(packet);
ByteArrayBuffer buffer=new ByteArrayBuffer(Ajp13Packet.MAX_PACKET_SIZE);
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
EndPoint endp=new ByteArrayEndPoint(src,Ajp13Packet.MAX_PACKET_SIZE);
Ajp13Parser parser = new Ajp13Parser(buffers,endp);
parser.setEventHandler(new EH());
parser.setGenerator(new Ajp13Generator(buffers,endp));
parser.parse();
assertTrue(true);
}
@Test
public void testSSLPacketWithIntegerKeySize() throws Exception
{
String packet = "1234025002020008485454502f312e3100000f2f746573742f64756d702f696e666f00000e3139322e3136382e3130302e343000ffff000c776562746964652d746573740001bb01000ca00b000c776562746964652d7465737400a00e005a4d6f7a696c6c612f352e30202857696e646f77733b20553b2057696e646f7773204e5420352e313b20656e2d55533b2072763a312e382e312e3129204765636b6f2f32303036313230342046697265666f782f322e302e302e3100a0010063746578742f786d6c2c6170706c69636174696f6e2f786d6c2c6170706c69636174696f6e2f7868746d6c2b786d6c2c746578742f68746d6c3b713d302e392c746578742f706c61696e3b713d302e382c696d6167652f706e672c2a2f2a3b713d302e3500a004000e656e2d75732c656e3b713d302e3500a003000c677a69702c6465666c61746500a002001e49534f2d383835392d312c7574662d383b713d302e372c2a3b713d302e3700000a4b6565702d416c69766500000333303000a006000a6b6565702d616c69766500a00d001a68747470733a2f2f776562746964652d746573742f746573742f00a00900174a53455353494f4e49443d69326c6e307539773573387300000d43616368652d436f6e74726f6c0000096d61782d6167653d3000000c4d61782d466f7277617264730000023130000800124448452d5253412d4145533235362d5348410009004032413037364245323330433238393130383941414132303631344139384441443131314230323132343030374130363642454531363742303941464337383942000b0100ff";
byte[] src = TypeUtil.fromHexString(packet);
ByteArrayBuffer buffer= new ByteArrayBuffer(Ajp13Packet.MAX_PACKET_SIZE);
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
EndPoint endp = new ByteArrayEndPoint(src,Ajp13Packet.MAX_PACKET_SIZE);
Ajp13Parser parser = new Ajp13Parser(buffers,endp);
parser.setEventHandler(new EH());
parser.setGenerator(new Ajp13Generator(buffers,endp));
parser.parseAvailable();
assertTrue(true);
}
@Test
public void testSSLPacketWithStringKeySize() throws Exception
{
String packet = "1234025002020008485454502f312e3100000f2f746573742f64756d702f696e666f00000e3139322e3136382e3130302e343000ffff000c776562746964652d746573740001bb01000ca00b000c776562746964652d7465737400a00e005a4d6f7a696c6c612f352e30202857696e646f77733b20553b2057696e646f7773204e5420352e313b20656e2d55533b2072763a312e382e312e3129204765636b6f2f32303036313230342046697265666f782f322e302e302e3100a0010063746578742f786d6c2c6170706c69636174696f6e2f786d6c2c6170706c69636174696f6e2f7868746d6c2b786d6c2c746578742f68746d6c3b713d302e392c746578742f706c61696e3b713d302e382c696d6167652f706e672c2a2f2a3b713d302e3500a004000e656e2d75732c656e3b713d302e3500a003000c677a69702c6465666c61746500a002001e49534f2d383835392d312c7574662d383b713d302e372c2a3b713d302e3700000a4b6565702d416c69766500000333303000a006000a6b6565702d616c69766500a00d001a68747470733a2f2f776562746964652d746573742f746573742f00a00900174a53455353494f4e49443d69326c6e307539773573387300000d43616368652d436f6e74726f6c0000096d61782d6167653d3000000c4d61782d466f7277617264730000023130000800124448452d5253412d4145533235362d5348410009004032413037364245323330433238393130383941414132303631344139384441443131314230323132343030374130363642454531363742303941464337383942000b000332353600ff";
byte[] src = TypeUtil.fromHexString(packet);
ByteArrayBuffer buffer= new ByteArrayBuffer(Ajp13Packet.MAX_PACKET_SIZE);
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
EndPoint endp = new ByteArrayEndPoint(src,Ajp13Packet.MAX_PACKET_SIZE);
Ajp13Parser parser = new Ajp13Parser(buffers,endp);
parser.setEventHandler(new EH());
parser.setGenerator(new Ajp13Generator(buffers,endp));
parser.parseAvailable();
assertTrue(true);
}
@Test
public void testSSLPacketFragment() throws Exception
{
String packet = "1234025002020008485454502f312e3100000f2f746573742f64756d702f696e666f00000e3139322e3136382e3130302e343000ffff000c776562746964652d746573740001bb01000ca00b000c776562746964652d7465737400a00e005a4d6f7a696c6c612f352e30202857696e646f77733b20553b2057696e646f7773204e5420352e313b20656e2d55533b2072763a312e382e312e3129204765636b6f2f32303036313230342046697265666f782f322e302e302e3100a0010063746578742f786d6c2c6170706c69636174696f6e2f786d6c2c6170706c69636174696f6e2f7868746d6c2b786d6c2c746578742f68746d6c3b713d302e392c746578742f706c61696e3b713d302e382c696d6167652f706e672c2a2f2a3b713d302e3500a004000e656e2d75732c656e3b713d302e3500a003000c677a69702c6465666c61746500a002001e49534f2d383835392d312c7574662d383b713d302e372c2a3b713d302e3700000a4b6565702d416c69766500000333303000a006000a6b6565702d616c69766500a00d001a68747470733a2f2f776562746964652d746573742f746573742f00a00900174a53455353494f4e49443d69326c6e307539773573387300000d43616368652d436f6e74726f6c0000096d61782d6167653d3000000c4d61782d466f7277617264730000023130000800124448452d5253412d4145533235362d5348410009004032413037364245323330433238393130383941414132303631344139384441443131314230323132343030374130363642454531363742303941464337383942000b0100ff";
byte[] src = TypeUtil.fromHexString(packet);
for (int f=1;f<src.length;f++)
{
byte[] frag0=new byte[src.length-f];
byte[] frag1=new byte[f];
System.arraycopy(src,0,frag0,0,src.length-f);
System.arraycopy(src,src.length-f,frag1,0,f);
ByteArrayBuffer buffer= new ByteArrayBuffer(Ajp13Packet.MAX_PACKET_SIZE);
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
ByteArrayEndPoint endp = new ByteArrayEndPoint(frag0,Ajp13Packet.MAX_PACKET_SIZE);
endp.setNonBlocking(true);
Ajp13Parser parser = new Ajp13Parser(buffers,endp);
parser.setEventHandler(new EH());
parser.setGenerator(new Ajp13Generator(buffers,endp));
parser.parseNext();
endp.setIn(new ByteArrayBuffer(frag1));
parser.parseAvailable();
}
assertTrue(true);
}
@Test
public void testPacketWithBody() throws Exception
{
String packet=getTestHeader();
byte[] src=TypeUtil.fromHexString(packet);
ByteArrayBuffer buffer=new ByteArrayBuffer(Ajp13Packet.MAX_PACKET_SIZE);
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
ByteArrayEndPoint endp=new ByteArrayEndPoint(src,Ajp13Packet.MAX_PACKET_SIZE);
endp.setNonBlocking(true);
final int count[]={0};
Ajp13Generator gen = new Ajp13Generator(buffers,endp)
{
public void getBodyChunk() throws IOException
{
count[0]++;
super.getBodyChunk();
}
};
Ajp13Parser parser = new Ajp13Parser(buffers,endp);
parser.setEventHandler(new EH());
parser.setGenerator(gen);
parser.parseNext();
assertEquals(1,parser.getState());
assertEquals(0,count[0]);
endp.setIn(new ByteArrayBuffer(TypeUtil.fromHexString(getTestShortBody())));
parser.parseNext();
assertEquals(1,parser.getState());
assertEquals(1,count[0]);
endp.setIn(new ByteArrayBuffer(TypeUtil.fromHexString(getTestTinyBody())));
parser.parseNext();
parser.parseNext();
assertEquals(0,parser.getState());
assertEquals(1,count[0]);
assertTrue(true);
}
@Test
public void testPacketWithChunkedBody() throws Exception
{
String packet="123400ff02040008485454502f312e3100000f2f746573742f64756d702f696e666f0000093132372e302e302e3100ffff00096c6f63616c686f7374000050000007a00e000d4a6176612f312e352e305f313100a00b00096c6f63616c686f737400a0010034746578742f68746d6c2c20696d6167652f6769662c20696d6167652f6a7065672c202a3b20713d2e322c202a2f2a3b20713d2e3200a006000a6b6565702d616c69766500a00700216170706c69636174696f6e2f782d7777772d666f726d2d75726c656e636f6465640000115472616e736665722d456e636f64696e670000076368756e6b656400000c4d61782d466f727761726473000002313000ff";
byte[] src=TypeUtil.fromHexString(packet);
ByteArrayBuffer buffer=new ByteArrayBuffer(Ajp13Packet.MAX_PACKET_SIZE);
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
ByteArrayEndPoint endp=new ByteArrayEndPoint(src,Ajp13Packet.MAX_PACKET_SIZE);
endp.setNonBlocking(true);
final int count[]={0};
Ajp13Generator gen = new Ajp13Generator(buffers,endp)
{
public void getBodyChunk() throws IOException
{
count[0]++;
super.getBodyChunk();
}
};
Ajp13Parser parser = new Ajp13Parser(buffers,endp);
parser.setEventHandler(new EH());
parser.setGenerator(gen);
parser.parseNext();
assertEquals(1,parser.getState());
assertEquals(1,count[0]);
endp.setIn(new ByteArrayBuffer(TypeUtil.fromHexString("1234007e007c7468656e616d653d746865253230717569636b25323062726f776e253230666f782532306a756d70732532306f766572253230746f2532307468652532306c617a79253230646f67253230544845253230515549434b25323042524f574e253230464f582532304a554d50532532304f564552253230544f25323054")));
while (parser.parseNext()>0);
assertEquals(1,parser.getState());
assertEquals(2,count[0]);
endp.setIn(new ByteArrayBuffer(TypeUtil.fromHexString("12340042004048452532304c415a59253230444f472532302676616c75656f66323d6162636465666768696a6b6c6d6e6f707172737475767778797a31323334353637383930")));
while (parser.parseNext()>0);
assertEquals(1,parser.getState());
assertEquals(3,count[0]);
endp.setIn(new ByteArrayBuffer(TypeUtil.fromHexString("123400020000")));
while (parser.getState()!=0 && parser.parseNext()>0);
assertEquals(0,parser.getState());
assertEquals(3,count[0]);
assertTrue(true);
}
@Test
public void testPacketFragment() throws Exception
{
String packet = "123401070202000f77696474683d20485454502f312e300000122f636f6e74726f6c2f70726f647563742f2200000e3230382e32372e3230332e31323800ffff000c7777772e756c74612e636f6d000050000005a006000a6b6565702d616c69766500a00b000c7777772e756c74612e636f6d00a00e002b4d6f7a696c6c612f342e302028636f6d70617469626c653b20426f726465724d616e6167657220332e302900a0010043696d6167652f6769662c20696d6167652f782d786269746d61702c20696d6167652f6a7065672c20696d6167652f706a7065672c20696d6167652f706d672c202a2f2a00a008000130000600067570726f64310008000a4145533235362d53484100ff";
byte[] src = TypeUtil.fromHexString(packet);
for (int f=1;f<src.length;f++)
{
byte[] frag0=new byte[src.length-f];
byte[] frag1=new byte[f];
System.arraycopy(src,0,frag0,0,src.length-f);
System.arraycopy(src,src.length-f,frag1,0,f);
ByteArrayBuffer buffer= new ByteArrayBuffer(Ajp13Packet.MAX_PACKET_SIZE);
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
ByteArrayEndPoint endp = new ByteArrayEndPoint(frag0,Ajp13Packet.MAX_PACKET_SIZE);
endp.setNonBlocking(true);
Ajp13Parser parser = new Ajp13Parser(buffers,endp);
parser.setEventHandler(new EH());
parser.setGenerator(new Ajp13Generator(buffers,endp));
parser.parseNext();
endp.setIn(new ByteArrayBuffer(frag1));
parser.parseAvailable();
}
assertTrue(true);
}
@Test
public void testPacketFragmentWithBody() throws Exception
{
String packet = getTestHeader()+getTestBody();
byte[] src = TypeUtil.fromHexString(packet);
for (int f=1;f<src.length;f++)
{
byte[] frag0=new byte[src.length-f];
byte[] frag1=new byte[f];
System.arraycopy(src,0,frag0,0,src.length-f);
System.arraycopy(src,src.length-f,frag1,0,f);
ByteArrayBuffer buffer= new ByteArrayBuffer(Ajp13Packet.MAX_PACKET_SIZE);
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
ByteArrayEndPoint endp = new ByteArrayEndPoint(frag0,Ajp13Packet.MAX_PACKET_SIZE);
endp.setNonBlocking(true);
Ajp13Parser parser = new Ajp13Parser(buffers,endp);
parser.setEventHandler(new EH());
parser.setGenerator(new Ajp13Generator(buffers,endp));
parser.parseNext();
endp.setIn(new ByteArrayBuffer(frag1));
parser.parseAvailable();
}
assertTrue(true);
}
private String getTestHeader()
{
StringBuffer header = new StringBuffer("");
header.append("1234026902040008485454502f31");
header.append("2e310000162f61646d696e2f496d6167");
header.append("6555706c6f61642e68746d00000a3130");
header.append("2e34382e31302e3100ffff000a31302e");
header.append("34382e31302e3200005000000da00b00");
header.append("0a31302e34382e31302e3200a00e005a");
header.append("4d6f7a696c6c612f352e30202857696e");
header.append("646f77733b20553b2057696e646f7773");
header.append("204e5420352e313b20656e2d55533b20");
header.append("72763a312e382e312e3129204765636b");
header.append("6f2f3230303631323034204669726566");
header.append("6f782f322e302e302e3100a001006374");
header.append("6578742f786d6c2c6170706c69636174");
header.append("696f6e2f786d6c2c6170706c69636174");
header.append("696f6e2f7868746d6c2b786d6c2c7465");
header.append("78742f68746d6c3b713d302e392c7465");
header.append("78742f706c61696e3b713d302e382c69");
header.append("6d6167652f706e672c2a2f2a3b713d30");
header.append("2e3500a004000e656e2d75732c656e3b");
header.append("713d302e3500a003000c677a69702c64");
header.append("65666c61746500a002001e49534f2d38");
header.append("3835392d312c7574662d383b713d302e");
header.append("372c2a3b713d302e3700000a4b656570");
header.append("2d416c69766500000333303000a00600");
header.append("0a6b6565702d616c69766500a00d003f");
header.append("687474703a2f2f31302e34382e31302e");
header.append("322f61646d696e2f496d61676555706c");
header.append("6f61642e68746d3f6964303d4974656d");
header.append("266964313d32266964323d696d673200");
header.append("a00900174a53455353494f4e49443d75");
header.append("383977733070696168746d00a0070046");
header.append("6d756c7469706172742f666f726d2d64");
header.append("6174613b20626f756e646172793d2d2d");
header.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
header.append("2d2d2d2d2d2d2d2d2d39343338333235");
header.append("34323630383700a00800033735390000");
header.append("0c4d61782d466f727761726473000002");
header.append("3130000500176964303d4974656d2669");
header.append("64313d32266964323d696d673200ff");
return header.toString();
}
private String getTestBody()
{
StringBuffer body = new StringBuffer("");
body.append("123402f902f72d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d3934333833323534323630");
body.append("38370d0a436f6e74656e742d44697370");
body.append("6f736974696f6e3a20666f726d2d6461");
body.append("74613b206e616d653d227265636f7264");
body.append("4964220d0a0d0a320d0a2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d393433383332353432");
body.append("363038370d0a436f6e74656e742d4469");
body.append("73706f736974696f6e3a20666f726d2d");
body.append("646174613b206e616d653d226e616d65");
body.append("220d0a0d0a4974656d0d0a2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d3934333833323534");
body.append("32363038370d0a436f6e74656e742d44");
body.append("6973706f736974696f6e3a20666f726d");
body.append("2d646174613b206e616d653d22746e49");
body.append("6d674964220d0a0d0a696d67320d0a2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d39343338");
body.append("3332353432363038370d0a436f6e7465");
body.append("6e742d446973706f736974696f6e3a20");
body.append("666f726d2d646174613b206e616d653d");
body.append("227468756d624e61696c496d61676546");
body.append("696c65223b2066696c656e616d653d22");
body.append("6161612e747874220d0a436f6e74656e");
body.append("742d547970653a20746578742f706c61");
body.append("696e0d0a0d0a61616161616161616161");
body.append("61616161616161616161616161616161");
body.append("61616161616161616161616161616161");
body.append("61616161616161616161616161616161");
body.append("0d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d39");
body.append("3433383332353432363038370d0a436f");
body.append("6e74656e742d446973706f736974696f");
body.append("6e3a20666f726d2d646174613b206e61");
body.append("6d653d226c61726765496d6167654669");
body.append("6c65223b2066696c656e616d653d2261");
body.append("61612e747874220d0a436f6e74656e74");
body.append("2d547970653a20746578742f706c6169");
body.append("6e0d0a0d0a6161616161616161616161");
body.append("61616161616161616161616161616161");
body.append("61616161616161616161616161616161");
body.append("6161616161616161616161616161610d");
body.append("0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d3934");
body.append("33383332353432363038372d2d0d0a");
return body.toString();
}
private String getTestShortBody()
{
StringBuffer body = new StringBuffer("");
body.append("123402f702f52d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d3934333833323534323630");
body.append("38370d0a436f6e74656e742d44697370");
body.append("6f736974696f6e3a20666f726d2d6461");
body.append("74613b206e616d653d227265636f7264");
body.append("4964220d0a0d0a320d0a2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d393433383332353432");
body.append("363038370d0a436f6e74656e742d4469");
body.append("73706f736974696f6e3a20666f726d2d");
body.append("646174613b206e616d653d226e616d65");
body.append("220d0a0d0a4974656d0d0a2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d3934333833323534");
body.append("32363038370d0a436f6e74656e742d44");
body.append("6973706f736974696f6e3a20666f726d");
body.append("2d646174613b206e616d653d22746e49");
body.append("6d674964220d0a0d0a696d67320d0a2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d39343338");
body.append("3332353432363038370d0a436f6e7465");
body.append("6e742d446973706f736974696f6e3a20");
body.append("666f726d2d646174613b206e616d653d");
body.append("227468756d624e61696c496d61676546");
body.append("696c65223b2066696c656e616d653d22");
body.append("6161612e747874220d0a436f6e74656e");
body.append("742d547970653a20746578742f706c61");
body.append("696e0d0a0d0a61616161616161616161");
body.append("61616161616161616161616161616161");
body.append("61616161616161616161616161616161");
body.append("61616161616161616161616161616161");
body.append("0d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d39");
body.append("3433383332353432363038370d0a436f");
body.append("6e74656e742d446973706f736974696f");
body.append("6e3a20666f726d2d646174613b206e61");
body.append("6d653d226c61726765496d6167654669");
body.append("6c65223b2066696c656e616d653d2261");
body.append("61612e747874220d0a436f6e74656e74");
body.append("2d547970653a20746578742f706c6169");
body.append("6e0d0a0d0a6161616161616161616161");
body.append("61616161616161616161616161616161");
body.append("61616161616161616161616161616161");
body.append("6161616161616161616161616161610d");
body.append("0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d");
body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d3934");
body.append("33383332353432363038372d2d");
return body.toString();
}
private String getTestTinyBody()
{
StringBuffer body = new StringBuffer("");
body.append("123400042d2d0d0a");
return body.toString();
}
private static class EH implements Ajp13Parser.EventHandler
{
final boolean debug=false;
public void content(Buffer ref) throws IOException
{
if (debug) System.err.println(ref);
}
public void headerComplete() throws IOException
{
if (debug) System.err.println("--");
}
public void messageComplete(long contextLength) throws IOException
{
if (debug) System.err.println("==");
}
public void parsedHeader(Buffer name, Buffer value) throws IOException
{
if (debug) System.err.println(name+": "+value);
}
public void parsedMethod(Buffer method) throws IOException
{
if (debug) System.err.println(method);
}
public void parsedProtocol(Buffer protocol) throws IOException
{
if (debug) System.err.println(protocol);
}
public void parsedQueryString(Buffer value) throws IOException
{
if (debug) System.err.println("?"+value);
}
public void parsedRemoteAddr(Buffer addr) throws IOException
{
if (debug) System.err.println("addr="+addr);
}
public void parsedRemoteHost(Buffer host) throws IOException
{
if (debug) System.err.println("host="+host);
}
public void parsedRequestAttribute(String key, Buffer value) throws IOException
{
if (debug) System.err.println(key+":: "+value);
}
public void parsedServerName(Buffer name) throws IOException
{
if (debug) System.err.println("Server:: "+name);
}
public void parsedServerPort(int port) throws IOException
{
if (debug) System.err.println("Port:: "+port);
}
public void parsedSslSecure(boolean secure) throws IOException
{
if (debug) System.err.println("Secure:: "+secure);
}
public void parsedUri(Buffer uri) throws IOException
{
if (debug) System.err.println("URI:: "+uri);
}
public void startForwardRequest() throws IOException
{
if (debug) System.err.println("..");
}
public void parsedAuthorizationType(Buffer authType) throws IOException
{
if (debug) System.err.println("auth:: "+authType);
}
public void parsedRemoteUser(Buffer remoteUser) throws IOException
{
if (debug) System.err.println("user:: "+remoteUser);
}
public void parsedServletPath(Buffer servletPath) throws IOException
{
if (debug) System.err.println("servletPath:: "+servletPath);
}
public void parsedContextPath(Buffer context) throws IOException
{
if (debug) System.err.println("Context:: "+context);
}
public void parsedSslCert(Buffer sslCert) throws IOException
{
if (debug) System.err.println("sslCert:: "+sslCert);
}
public void parsedSslCipher(Buffer sslCipher) throws IOException
{
if (debug) System.err.println("sslCipher:: "+sslCipher);
}
public void parsedSslSession(Buffer sslSession) throws IOException
{
if (debug) System.err.println("sslSession:: "+sslSession);
}
public void parsedSslKeySize(int keySize) throws IOException
{
if (debug) System.err.println("sslkeysize:: "+keySize);
}
public void parsedRequestAttribute(String key, int value) throws IOException
{
if (debug) System.err.println(key+":: "+value);
}
}
}

45
jetty-ant/pom.xml Executable file
View File

@ -0,0 +1,45 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-ant</artifactId>
<packaging>jar</packaging>
<name>Jetty :: Ant Plugin</name>
<build>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ant</groupId>
<artifactId>ant</artifactId>
<version>1.6.5</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-security</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-plus</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-annotations</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,146 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ant;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import java.util.regex.Pattern;
import org.apache.tools.ant.AntClassLoader;
import org.eclipse.jetty.util.PatternMatcher;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;
public class AntWebInfConfiguration extends WebInfConfiguration
{
@Override
public void preConfigure(final WebAppContext context) throws Exception
{
// Look for a work directory
File work = findWorkDirectory(context);
if (work != null)
makeTempDirectory(work, context, false);
//Make a temp directory for the webapp if one is not already set
resolveTempDirectory(context);
//Extract webapp if necessary
unpack (context);
//Apply an initial ordering to the jars which governs which will be scanned for META-INF
//info and annotations. The ordering is based on inclusion patterns.
String tmp = (String)context.getAttribute(WEBINF_JAR_PATTERN);
Pattern webInfPattern = (tmp==null?null:Pattern.compile(tmp));
tmp = (String)context.getAttribute(CONTAINER_JAR_PATTERN);
Pattern containerPattern = (tmp==null?null:Pattern.compile(tmp));
//Apply ordering to container jars - if no pattern is specified, we won't
//match any of the container jars
PatternMatcher containerJarNameMatcher = new PatternMatcher ()
{
public void matched(URI uri) throws Exception
{
context.getMetaData().addContainerJar(Resource.newResource(uri));
}
};
ClassLoader loader = context.getClassLoader();
if (loader != null)
{
loader = loader.getParent();
if (loader != null)
{
URI[] containerUris = null;
if (loader instanceof URLClassLoader)
{
URL[] urls = ((URLClassLoader)loader).getURLs();
if (urls != null)
{
containerUris = new URI[urls.length];
int i=0;
for (URL u : urls)
{
try
{
containerUris[i] = u.toURI();
}
catch (URISyntaxException e)
{
containerUris[i] = new URI(u.toString().replaceAll(" ", "%20"));
}
i++;
}
}
}
else if (loader instanceof AntClassLoader)
{
AntClassLoader antLoader = (AntClassLoader)loader;
String[] paths = antLoader.getClasspath().split(new String(new char[]{File.pathSeparatorChar}));
if (paths != null)
{
containerUris = new URI[paths.length];
int i=0;
for (String p:paths)
{
File f = new File(p);
containerUris[i] = f.toURI();
i++;
}
}
}
containerJarNameMatcher.match(containerPattern, containerUris, false);
}
}
//Apply ordering to WEB-INF/lib jars
PatternMatcher webInfJarNameMatcher = new PatternMatcher ()
{
@Override
public void matched(URI uri) throws Exception
{
context.getMetaData().addWebInfJar(Resource.newResource(uri));
}
};
List<Resource> jars = findJars(context);
//Convert to uris for matching
URI[] uris = null;
if (jars != null)
{
uris = new URI[jars.size()];
int i=0;
for (Resource r: jars)
{
uris[i++] = r.getURI();
}
}
webInfJarNameMatcher.match(webInfPattern, uris, true); //null is inclusive, no pattern == all jars match
}
}

View File

@ -0,0 +1,136 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Sabre Holdings.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ant;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Iterator;
import java.util.List;
import org.apache.tools.ant.AntClassLoader;
import org.eclipse.jetty.ant.utils.TaskLog;
import org.eclipse.jetty.plus.webapp.PlusConfiguration;
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.webapp.Descriptor;
import org.eclipse.jetty.webapp.StandardDescriptorProcessor;
import org.eclipse.jetty.webapp.WebAppClassLoader;
import org.eclipse.jetty.webapp.WebXmlConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.xml.XmlParser.Node;
/**
* This configuration object provides additional way to inject application
* properties into the configured web application. The list of classpath files,
* the application base directory and web.xml file could be specified in this
* way.
*
* @author Jakub Pawlowicz
* @author Athena Yao
*/
public class AntWebXmlConfiguration extends WebXmlConfiguration
{
private static final Logger LOG = Log.getLogger(WebXmlConfiguration.class);
/** List of classpath files. */
private List classPathFiles;
/** Web application root directory. */
private File webAppBaseDir;
/** Web application web.xml file. */
private File webXmlFile;
private File webDefaultXmlFile;
public AntWebXmlConfiguration() throws ClassNotFoundException
{
}
public File getWebDefaultXmlFile()
{
return this.webDefaultXmlFile;
}
public void setWebDefaultXmlFile(File webDefaultXmlfile)
{
this.webDefaultXmlFile = webDefaultXmlfile;
}
public void setClassPathFiles(List classPathFiles)
{
this.classPathFiles = classPathFiles;
}
public void setWebAppBaseDir(File webAppBaseDir)
{
this.webAppBaseDir = webAppBaseDir;
}
public void setWebXmlFile(File webXmlFile)
{
this.webXmlFile = webXmlFile;
if (webXmlFile.exists())
{
TaskLog.log("web.xml file = " + webXmlFile);
}
}
/**
* Adds classpath files into web application classloader, and
* sets web.xml and base directory for the configured web application.
*
* @see WebXmlConfiguration#configure(WebAppContext)
*/
public void configure(WebAppContext context) throws Exception
{
if (context.isStarted())
{
TaskLog.log("Cannot configure webapp after it is started");
return;
}
if (webXmlFile.exists())
{
context.setDescriptor(webXmlFile.getCanonicalPath());
}
super.configure(context);
Iterator filesIterator = classPathFiles.iterator();
while (filesIterator.hasNext())
{
File classPathFile = (File) filesIterator.next();
if (classPathFile.exists())
{
((WebAppClassLoader) context.getClassLoader())
.addClassPath(classPathFile.getCanonicalPath());
}
}
}
}

View File

@ -0,0 +1,328 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Sabre Holdings.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ant;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.Property;
import org.eclipse.jetty.ant.types.Connectors;
import org.eclipse.jetty.ant.types.LoginServices;
import org.eclipse.jetty.ant.types.SystemProperties;
import org.eclipse.jetty.ant.types.WebApp;
import org.eclipse.jetty.ant.utils.ServerProxy;
import org.eclipse.jetty.ant.utils.TaskLog;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.util.Scanner;
/**
* Ant task for running a Jetty server.
*
* @author Jakub Pawlowicz
*/
public class JettyRunTask extends Task
{
/** Temporary files directory. */
private File tempDirectory;
/** List of web applications to be deployed. */
private List webapps = new ArrayList();
/** Location of jetty.xml file. */
private File jettyXml;
/** List of server connectors. */
private Connectors connectors = null;
/** Server request logger object. */
private RequestLog requestLog;
/** List of login services. */
private LoginServices loginServices;
/** List of system properties to be set. */
private SystemProperties systemProperties;
/** Port Jetty will use for the default connector */
private int jettyPort = 8080;
public JettyRunTask()
{
TaskLog.setTask(this);
}
/**
* Creates a new <code>WebApp</code> Ant object.
*
*/
public void addWebApp(WebApp webapp)
{
webapps.add(webapp);
}
/**
* Adds a new Ant's connector tag object if it have not been created yet.
*/
public void addConnectors(Connectors connectors)
{
if (this.connectors != null)
{
throw new BuildException("Only one <connectors> tag is allowed!");
}
this.connectors = connectors;
}
/**
* @deprecated
*/
public void addUserRealms(Object o)
{
TaskLog.log("User realms are deprecated.");
}
public void addLoginServices(LoginServices services)
{
if (this.loginServices != null )
{
throw new BuildException("Only one <loginServices> tag is allowed!");
}
this.loginServices = services;
}
public void addSystemProperties(SystemProperties systemProperties)
{
if (this.systemProperties != null)
{
throw new BuildException("Only one <systemProperties> tag is allowed!");
}
this.systemProperties = systemProperties;
}
public File getTempDirectory()
{
return tempDirectory;
}
public void setTempDirectory(File tempDirectory)
{
this.tempDirectory = tempDirectory;
}
public File getJettyXml()
{
return jettyXml;
}
public void setJettyXml(File jettyXml)
{
this.jettyXml = jettyXml;
}
public void setRequestLog(String className)
{
try
{
this.requestLog = (RequestLog) Class.forName(className).newInstance();
}
catch (InstantiationException e)
{
throw new BuildException("Request logger instantiation exception: " + e);
}
catch (IllegalAccessException e)
{
throw new BuildException("Request logger instantiation exception: " + e);
}
catch (ClassNotFoundException e)
{
throw new BuildException("Unknown request logger class: " + className);
}
}
public String getRequestLog()
{
if (requestLog != null)
{
return requestLog.getClass().getName();
}
return "";
}
/**
* Sets the port Jetty uses for the default connector.
*
* @param jettyPort The port Jetty will use for the default connector
*/
public void setJettyPort(final int jettyPort)
{
this.jettyPort = jettyPort;
}
/**
* Executes this Ant task. The build flow is being stopped until Jetty
* server stops.
*
* @throws BuildException
*/
public void execute() throws BuildException
{
TaskLog.log("Configuring Jetty for project: " + getProject().getName());
WebApplicationProxyImpl.setBaseTempDirectory(tempDirectory);
setSystemProperties();
List connectorsList = null;
if (connectors != null)
{
connectorsList = connectors.getConnectors();
}
else
{
connectorsList = new Connectors(jettyPort,30000).getDefaultConnectors();
}
List loginServicesList = (loginServices != null?loginServices.getLoginServices():new ArrayList());
ServerProxy server = new ServerProxyImpl(connectorsList,loginServicesList,requestLog,jettyXml);
try
{
Iterator iterator = webapps.iterator();
while (iterator.hasNext())
{
WebApp webAppConfiguration = (WebApp)iterator.next();
WebApplicationProxyImpl webApp = new WebApplicationProxyImpl(webAppConfiguration.getName());
webApp.setSourceDirectory(webAppConfiguration.getWarFile());
webApp.setContextPath(webAppConfiguration.getContextPath());
webApp.setWebXml(webAppConfiguration.getWebXmlFile());
webApp.setJettyEnvXml(webAppConfiguration.getJettyEnvXml());
webApp.setClassPathFiles(webAppConfiguration.getClassPathFiles());
webApp.setLibrariesConfiguration(webAppConfiguration.getLibrariesConfiguration());
webApp.setExtraScanTargetsConfiguration(webAppConfiguration.getScanTargetsConfiguration());
webApp.setContextHandlers(webAppConfiguration.getContextHandlers());
webApp.setAttributes(webAppConfiguration.getAttributes());
webApp.setWebDefaultXmlFile(webAppConfiguration.getWebDefaultXmlFile());
server.addWebApplication(webApp,webAppConfiguration.getScanIntervalSeconds());
}
}
catch (Exception e)
{
throw new BuildException(e);
}
server.start();
}
/**
* Starts a new thread which scans project files and automatically reloads a
* container on any changes.
*
* @param scanIntervalSeconds
*
* @param webapp
* @param appContext
*/
static void startScanner(final WebApplicationProxyImpl webApp, int scanIntervalSeconds) throws Exception
{
List scanList = new ArrayList();
scanList.add(webApp.getWebXmlFile());
scanList.addAll(webApp.getLibraries());
scanList.addAll(webApp.getExtraScanTargets());
Scanner.Listener changeListener = new Scanner.BulkListener()
{
public void filesChanged(List changedFiles)
{
if (hasAnyFileChanged(changedFiles))
{
try
{
webApp.stop();
webApp.applyConfiguration();
webApp.start();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
/**
* Checks if any file in this particular application has changed.
* This is not that easy, because some applications may use the same
* class'es directory.
*
* @param changedFiles list of changed files.
* @return true if any of passed files has changed, false otherwise.
*/
private boolean hasAnyFileChanged(List changedFiles)
{
Iterator changes = changedFiles.iterator();
while (changes.hasNext())
{
String className = (String) changes.next();
if (webApp.isFileScanned(className))
{
return true;
}
}
return false;
}
};
TaskLog.log("Web application '" + webApp.getName() + "': starting scanner at interval of "
+ scanIntervalSeconds + " seconds.");
Scanner scanner = new Scanner();
scanner.setScanInterval(scanIntervalSeconds);
scanner.addListener(changeListener);
scanner.setScanDirs(scanList);
scanner.setReportExistingFilesOnStartup(false);
scanner.start();
}
/**
* Sets the system properties.
*/
private void setSystemProperties()
{
if (systemProperties != null)
{
Iterator propertiesIterator = systemProperties.getSystemProperties().iterator();
while (propertiesIterator.hasNext())
{
Property property = ((Property) propertiesIterator.next());
SystemProperties.setIfNotSetAlready(property);
}
}
}
}

View File

@ -0,0 +1,255 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Sabre Holdings.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ant;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.jetty.ant.types.Connectors.Connector;
import org.eclipse.jetty.ant.utils.ServerProxy;
import org.eclipse.jetty.ant.utils.TaskLog;
import org.eclipse.jetty.ant.utils.WebApplicationProxy;
import org.eclipse.jetty.security.LoginService;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.server.SelectChannelConnector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.RequestLogHandler;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.xml.XmlConfiguration;
import org.xml.sax.SAXException;
/**
* A proxy class for interaction with Jetty server object. Used to have some
* level of abstraction over standard Jetty classes.
*
* @author Jakub Pawlowicz
*/
public class ServerProxyImpl implements ServerProxy
{
/** Proxied Jetty server object. */
private Server server;
/** Collection of context handlers (web application contexts). */
private ContextHandlerCollection contexts;
/** Location of jetty.xml file. */
private File jettyXml;
/** List of connectors. */
private List connectors;
/** Request logger. */
private RequestLog requestLog;
/** User realms. */
private List loginServices;
/** List of added web applications. */
private Map webApplications = new HashMap();
/**
* Default constructor. Creates a new Jetty server with a standard connector
* listening on a given port.
*
* @param connectors
* @param loginServicesList
* @param requestLog
* @param jettyXml
*/
public ServerProxyImpl(List connectors, List loginServicesList, RequestLog requestLog,
File jettyXml)
{
server = new Server();
server.setStopAtShutdown(true);
this.connectors = connectors;
this.loginServices = loginServicesList;
this.requestLog = requestLog;
this.jettyXml = jettyXml;
configure();
}
/**
* @see org.eclipse.jetty.ant.utils.ServerProxy#addWebApplication(WebApplicationProxy,
* int)
*/
public void addWebApplication(WebApplicationProxy webApp, int scanIntervalSeconds)
{
webApp.createApplicationContext(contexts);
if (scanIntervalSeconds > 0)
{
webApplications.put(webApp, new Integer(scanIntervalSeconds));
}
}
/**
* Configures Jetty server before adding any web applications to it.
*/
private void configure()
{
// Applies external configuration via jetty.xml
applyJettyXml();
// Configures connectors for this server instance.
Iterator<Connector> connectorIterator = connectors.iterator();
while (connectorIterator.hasNext())
{
Connector jettyConnector = (Connector) connectorIterator.next();
SelectChannelConnector jc = new SelectChannelConnector(server);
jc.setPort(jettyConnector.getPort());
jc.setIdleTimeout(jettyConnector.getMaxIdleTime());
server.addConnector(jc);
}
// Configures login services
Iterator servicesIterator = loginServices.iterator();
while (servicesIterator.hasNext())
{
LoginService service = (LoginService) servicesIterator.next();
server.addBean(service);
}
// Does not cache resources, to prevent Windows from locking files
Resource.setDefaultUseCaches(false);
// Set default server handlers
configureHandlers();
}
private void configureHandlers()
{
RequestLogHandler requestLogHandler = new RequestLogHandler();
if (requestLog != null)
{
requestLogHandler.setRequestLog(requestLog);
}
contexts = (ContextHandlerCollection) server
.getChildHandlerByClass(ContextHandlerCollection.class);
if (contexts == null)
{
contexts = new ContextHandlerCollection();
HandlerCollection handlers = (HandlerCollection) server
.getChildHandlerByClass(HandlerCollection.class);
if (handlers == null)
{
handlers = new HandlerCollection();
server.setHandler(handlers);
handlers.setHandlers(new Handler[] { contexts, new DefaultHandler(),
requestLogHandler });
}
else
{
handlers.addHandler(contexts);
}
}
}
/**
* Applies jetty.xml configuration to the Jetty server instance.
*/
private void applyJettyXml()
{
if (jettyXml != null && jettyXml.exists())
{
TaskLog.log("Configuring jetty from xml configuration file = "
+ jettyXml.getAbsolutePath());
XmlConfiguration configuration;
try
{
configuration = new XmlConfiguration(Resource.toURL(jettyXml));
configuration.configure(server);
}
catch (MalformedURLException e)
{
throw new RuntimeException(e);
}
catch (SAXException e)
{
throw new RuntimeException(e);
}
catch (IOException e)
{
throw new RuntimeException(e);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
}
/**
* @see org.eclipse.jetty.ant.utils.ServerProxy#start()
*/
public void start()
{
try
{
server.start();
startScanners();
server.join();
}
catch (InterruptedException e)
{
new RuntimeException(e);
}
catch (Exception e)
{
new RuntimeException(e);
}
}
/**
* Starts web applications' scanners.
*/
private void startScanners() throws Exception
{
Iterator i = webApplications.keySet().iterator();
while (i.hasNext())
{
WebApplicationProxyImpl webApp = (WebApplicationProxyImpl) i.next();
Integer scanIntervalSeconds = (Integer) webApplications.get(webApp);
JettyRunTask.startScanner(webApp, scanIntervalSeconds.intValue());
}
}
/**
* @see org.eclipse.jetty.ant.utils.ServerProxy#getProxiedObject()
*/
public Object getProxiedObject()
{
return server;
}
}

View File

@ -0,0 +1,542 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Sabre Holdings.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ant;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Iterator;
import java.util.List;
import javax.servlet.Servlet;
import org.apache.tools.ant.AntClassLoader;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.ant.types.Attribute;
import org.eclipse.jetty.ant.types.FileMatchingConfiguration;
import org.eclipse.jetty.ant.utils.TaskLog;
import org.eclipse.jetty.ant.utils.WebApplicationProxy;
import org.eclipse.jetty.plus.webapp.EnvConfiguration;
import org.eclipse.jetty.plus.webapp.PlusConfiguration;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.server.HandlerContainer;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.servlet.Holder;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.FragmentConfiguration;
import org.eclipse.jetty.webapp.JettyWebXmlConfiguration;
import org.eclipse.jetty.webapp.MetaInfConfiguration;
import org.eclipse.jetty.webapp.TagLibConfiguration;
import org.eclipse.jetty.webapp.WebAppClassLoader;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;
import org.eclipse.jetty.webapp.WebXmlConfiguration;
/**
* An abstraction layer over Jetty WebAppContext.
*
* @author Jakub Pawlowicz
*/
public class WebApplicationProxyImpl implements WebApplicationProxy
{
/** Common root temp directory for all web applications. */
static File baseTempDirectory = new File(".");
/** Name of this web application. */
private String name;
/** Location of WAR file (either expanded or not). */
private File warFile;
/** Application context path. */
private String contextPath;
/** Location of web.xml file. */
private File webXmlFile;
/** Location of jetty-env.xml file. */
private File jettyEnvXml;
/** List of classpath files. */
private List classPathFiles;
/** Jetty6 Web Application Context. */
private WebAppContext webAppContext;
/** Extra scan targets. */
private FileMatchingConfiguration extraScanTargetsConfiguration;
/** Extra context handlers. */
private List contextHandlers;
private List attributes;
Configuration[] configurations;
private FileMatchingConfiguration librariesConfiguration;
public static void setBaseTempDirectory(File tempDirectory)
{
baseTempDirectory = tempDirectory;
}
public static class AntServletHolder extends ServletHolder
{
public AntServletHolder()
{
super();
}
public AntServletHolder(Class<? extends Servlet> servlet)
{
super(servlet);
}
public AntServletHolder(Servlet servlet)
{
super(servlet);
}
public AntServletHolder(String name, Class<? extends Servlet> servlet)
{
super(name, servlet);
}
public AntServletHolder(String name, Servlet servlet)
{
super(name, servlet);
}
@Override
protected void initJspServlet() throws Exception
{
//super.initJspServlet();
ContextHandler ch = ((ContextHandler.Context)getServletHandler().getServletContext()).getContextHandler();
/* Set the webapp's classpath for Jasper */
ch.setAttribute("org.apache.catalina.jsp_classpath", ch.getClassPath());
/* Set the system classpath for Jasper */
String sysClassPath = getSystemClassPath(ch.getClassLoader().getParent());
setInitParameter("com.sun.appserv.jsp.classpath", sysClassPath);
/* Set up other classpath attribute */
if ("?".equals(getInitParameter("classpath")))
{
String classpath = ch.getClassPath();
if (classpath != null)
setInitParameter("classpath", classpath);
}
}
protected String getSystemClassPath (ClassLoader loader) throws Exception
{
StringBuilder classpath=new StringBuilder();
while (loader != null)
{
if (loader instanceof URLClassLoader)
{
URL[] urls = ((URLClassLoader)loader).getURLs();
if (urls != null)
{
for (int i=0;i<urls.length;i++)
{
Resource resource = Resource.newResource(urls[i]);
File file=resource.getFile();
if (file!=null && file.exists())
{
if (classpath.length()>0)
classpath.append(File.pathSeparatorChar);
classpath.append(file.getAbsolutePath());
}
}
}
}
else if (loader instanceof AntClassLoader)
{
classpath.append(((AntClassLoader)loader).getClasspath());
}
loader = loader.getParent();
}
return classpath.toString();
}
}
public static class AntServletHandler extends ServletHandler
{
@Override
public ServletHolder newServletHolder(Holder.Source source)
{
return new AntServletHolder();
}
}
public static class AntWebAppContext extends WebAppContext
{
public AntWebAppContext()
{
super();
}
public AntWebAppContext(HandlerContainer parent, String webApp, String contextPath)
{
super(parent, webApp, contextPath);
}
public AntWebAppContext(SessionHandler sessionHandler, SecurityHandler securityHandler, ServletHandler servletHandler, ErrorHandler errorHandler)
{
super(sessionHandler, securityHandler, servletHandler, errorHandler);
}
public AntWebAppContext(String webApp, String contextPath)
{
super(webApp, contextPath);
}
@Override
protected ServletHandler newServletHandler()
{
return new AntServletHandler();
}
}
/**
* Default constructor. Takes application name as an argument
*
* @param name web application name.
*/
public WebApplicationProxyImpl(String name) throws Exception
{
this.name = name;
TaskLog.log("\nConfiguring Jetty for web application: " + name);
this.configurations = new Configuration[]
{ new AntWebInfConfiguration(),
new AntWebXmlConfiguration(),
new MetaInfConfiguration(),
new FragmentConfiguration(),
new EnvConfiguration(),
new PlusConfiguration(),
new AnnotationConfiguration(),
new JettyWebXmlConfiguration(),
new TagLibConfiguration() };
}
public List getClassPathFiles()
{
return classPathFiles;
}
public String getContextPath()
{
return contextPath;
}
public String getName()
{
return name;
}
public File getSourceDirectory()
{
return warFile;
}
public File getWebXmlFile()
{
return webXmlFile;
}
public void setSourceDirectory(File warFile)
{
this.warFile = warFile;
TaskLog.log("Webapp source directory = " + warFile);
}
public void setContextPath(String contextPath)
{
if (!contextPath.startsWith("/"))
{
contextPath = "/" + contextPath;
}
this.contextPath = contextPath;
TaskLog.log("Context path = " + contextPath);
}
public void setWebXml(File webXmlFile)
{
this.webXmlFile = webXmlFile;
}
public void setJettyEnvXml(File jettyEnvXml)
{
this.jettyEnvXml = jettyEnvXml;
if (this.jettyEnvXml != null)
{
TaskLog.log("jetty-env.xml file: = " + jettyEnvXml.getAbsolutePath());
}
}
public void setClassPathFiles(List classPathFiles)
{
this.classPathFiles = classPathFiles;
TaskLog.log("Classpath = " + classPathFiles);
}
/**
* Checks if a given file is scanned according to the internal
* configuration. This may be difficult due to use of 'includes' and
* 'excludes' statements.
*
* @param pathToFile a fully qualified path to file.
* @return true if file is being scanned, false otherwise.
*/
public boolean isFileScanned(String pathToFile)
{
return librariesConfiguration.isIncluded(pathToFile)
|| extraScanTargetsConfiguration.isIncluded(pathToFile);
}
public void setLibrariesConfiguration(FileMatchingConfiguration classesConfiguration)
{
TaskLog.log("Default scanned paths = " + classesConfiguration.getBaseDirectories());
this.librariesConfiguration = classesConfiguration;
}
public List getLibraries()
{
return librariesConfiguration.getBaseDirectories();
}
public void setExtraScanTargetsConfiguration(
FileMatchingConfiguration extraScanTargetsConfiguration)
{
this.extraScanTargetsConfiguration = extraScanTargetsConfiguration;
TaskLog.log("Extra scan targets = " + extraScanTargetsConfiguration.getBaseDirectories());
}
public void setAttributes(List attributes)
{
this.attributes = attributes;
}
public List getExtraScanTargets()
{
return extraScanTargetsConfiguration.getBaseDirectories();
}
public List getContextHandlers()
{
return contextHandlers;
}
public void setContextHandlers(List contextHandlers)
{
this.contextHandlers = contextHandlers;
}
/**
* @see WebApplicationProxy#getProxiedObject()
*/
public Object getProxiedObject()
{
return webAppContext;
}
/**
* @see WebApplicationProxy#start()
*/
public void start()
{
try
{
TaskLog.logWithTimestamp("Starting web application " + name + " ...\n");
webAppContext.start();
}
catch (Exception e)
{
TaskLog.log(e.toString());
}
}
/**
* @see WebApplicationProxy#stop()
*/
public void stop()
{
try
{
TaskLog.logWithTimestamp("Stopping web application " + name + " ...");
Thread.currentThread().sleep(500L);
webAppContext.stop();
}
catch (InterruptedException e)
{
TaskLog.log(e.toString());
}
catch (Exception e)
{
TaskLog.log(e.toString());
}
}
/**
* @see WebApplicationProxy#createApplicationContext(org.eclipse.jetty.server.handler.ContextHandlerCollection)
*/
public void createApplicationContext(ContextHandlerCollection contexts)
{
webAppContext = new AntWebAppContext(contexts, warFile.getAbsolutePath(), contextPath);
webAppContext.setDisplayName(name);
configurePaths();
if ( !attributes.isEmpty() )
{
for ( Iterator i = attributes.iterator(); i.hasNext(); )
{
Attribute attr = (Attribute) i.next();
webAppContext.setAttribute(attr.getName(),attr.getValue());
}
}
configureHandlers(contexts);
applyConfiguration();
}
private void configureHandlers(ContextHandlerCollection contexts)
{
// adding extra context handlers
Iterator handlersIterator = contextHandlers.iterator();
while (handlersIterator.hasNext())
{
ContextHandler contextHandler = (ContextHandler) handlersIterator.next();
contexts.addHandler(contextHandler);
}
}
private void configurePaths()
{
// configuring temp directory
File tempDir = new File(baseTempDirectory, contextPath);
if (!tempDir.exists())
{
tempDir.mkdirs();
}
webAppContext.setTempDirectory(tempDir);
tempDir.deleteOnExit();
TaskLog.log("Temp directory = " + tempDir.getAbsolutePath());
// configuring WAR directory for packaged web applications
if (warFile.isFile())
{
warFile = new File(tempDir, "webapp");
webXmlFile = new File(new File(warFile, "WEB-INF"), "web.xml");
}
}
/**
* Applies web application configuration at the end of configuration process
* or after application restart.
*/
void applyConfiguration()
{
for (int i = 0; i < configurations.length; i++)
{
if (configurations[i] instanceof EnvConfiguration)
{
try
{
if (jettyEnvXml != null && jettyEnvXml.exists())
{
((EnvConfiguration) configurations[i]).setJettyEnvXml(Resource.toURL(jettyEnvXml));
}
}
catch (MalformedURLException e)
{
throw new RuntimeException(e);
}
}
else if (configurations[i] instanceof AntWebXmlConfiguration)
{
((AntWebXmlConfiguration) configurations[i]).setClassPathFiles(classPathFiles);
((AntWebXmlConfiguration) configurations[i]).setWebAppBaseDir(warFile);
((AntWebXmlConfiguration) configurations[i]).setWebXmlFile(webXmlFile);
((AntWebXmlConfiguration) configurations[i]).setWebDefaultXmlFile(webDefaultXmlFile);
}
}
try
{
ClassLoader loader = new WebAppClassLoader(this.getClass().getClassLoader(),
webAppContext);
webAppContext.setParentLoaderPriority(true);
webAppContext.setClassLoader(loader);
if (webDefaultXmlFile != null)
webAppContext.setDefaultsDescriptor(webDefaultXmlFile.getCanonicalPath());
}
catch (IOException e)
{
TaskLog.log(e.toString());
}
webAppContext.setConfigurations(configurations);
}
private File webDefaultXmlFile;
public File getWebDefaultXmlFile()
{
return this.webDefaultXmlFile;
}
public void setWebDefaultXmlFile(File webDefaultXmlfile)
{
this.webDefaultXmlFile = webDefaultXmlfile;
}
}

View File

@ -0,0 +1,47 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ant.types;
public class Attribute
{
String name;
String value;
public void setName(String name)
{
this.name = name;
}
public void setValue(String value)
{
this.value = value;
}
public String getName()
{
return name;
}
public String getValue()
{
return value;
}
}

View File

@ -0,0 +1,38 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ant.types;
import java.util.ArrayList;
import java.util.List;
public class Attributes
{
List _attributes = new ArrayList();
public void addAttribute(Attribute attr )
{
_attributes.add(attr);
}
public List getAttributes()
{
return _attributes;
}
}

View File

@ -0,0 +1,116 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Sabre Holdings.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ant.types;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.SelectChannelConnector;
/**
* Specifies a jetty configuration <connectors/> element for Ant build file.
*
* @author Jakub Pawlowicz
*/
public class Connectors
{
private List<Connector> connectors = new ArrayList<Connector>();
private List<Connector> defaultConnectors = new ArrayList<Connector>();
/**
* Default constructor.
*/
public Connectors() {
this(8080, 30000);
}
/**
* Constructor.
*
* @param port The port that the default connector will listen on
* @param maxIdleTime The maximum idle time for the default connector
*/
public Connectors(int port, int maxIdleTime)
{
defaultConnectors.add(new Connector(port, maxIdleTime));
}
/**
* Adds a connector to the list of connectors to deploy.
*
* @param connector A connector to add to the list
*/
public void add(Connector connector)
{
connectors.add(connector);
}
/**
* Returns the list of known connectors to deploy.
*
* @return The list of known connectors
*/
public List<Connector> getConnectors()
{
return connectors;
}
/**
* Gets the default list of connectors to deploy when no connectors
* were explicitly added to the list.
*
* @return The list of default connectors
*/
public List<Connector> getDefaultConnectors()
{
return defaultConnectors;
}
public class Connector
{
private int port;
private int maxIdleTime;
public Connector(int port, int maxIdleTime)
{
this.port = port;
this.maxIdleTime = maxIdleTime;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public int getMaxIdleTime() {
return maxIdleTime;
}
public void setMaxIdleTime(int maxIdleTime) {
this.maxIdleTime = maxIdleTime;
}
}
}

View File

@ -0,0 +1,46 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Sabre Holdings.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ant.types;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.server.handler.ContextHandler;
/**
* Specifies <contextHandlers/> element in web app configuration.
*
* @author Jakub Pawlowicz
*/
public class ContextHandlers
{
private List contextHandlers = new ArrayList();
public void add(ContextHandler handler)
{
contextHandlers.add(handler);
}
public List getContextHandlers()
{
return contextHandlers;
}
}

View File

@ -0,0 +1,99 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Sabre Holdings.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ant.types;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.tools.ant.DirectoryScanner;
/**
* Describes set of files matched by <fileset/> elements in ant configuration
* file. It is used to group application classes, libraries, and scannedTargets
* elements.
*
* @author Jakub Pawlowicz
*/
public class FileMatchingConfiguration
{
private List directoryScanners;
public FileMatchingConfiguration()
{
this.directoryScanners = new ArrayList();
}
/**
* @param directoryScanner new directory scanner retrieved from the
* <fileset/> element.
*/
public void addDirectoryScanner(DirectoryScanner directoryScanner)
{
this.directoryScanners.add(directoryScanner);
}
/**
* @return a list of base directories denoted by a list of directory
* scanners.
*/
public List getBaseDirectories()
{
List baseDirs = new ArrayList();
Iterator scanners = directoryScanners.iterator();
while (scanners.hasNext())
{
DirectoryScanner scanner = (DirectoryScanner) scanners.next();
baseDirs.add(scanner.getBasedir());
}
return baseDirs;
}
/**
* Checks if passed file is scanned by any of the directory scanners.
*
* @param pathToFile a fully qualified path to tested file.
* @return true if so, false otherwise.
*/
public boolean isIncluded(String pathToFile)
{
Iterator scanners = directoryScanners.iterator();
while (scanners.hasNext())
{
DirectoryScanner scanner = (DirectoryScanner) scanners.next();
scanner.scan();
String[] includedFiles = scanner.getIncludedFiles();
for (int i = 0; i < includedFiles.length; i++)
{
File includedFile = new File(scanner.getBasedir(), includedFiles[i]);
if (pathToFile.equalsIgnoreCase(includedFile.getAbsolutePath()))
{
return true;
}
}
}
return false;
}
}

View File

@ -0,0 +1,46 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Sabre Holdings.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ant.types;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.security.LoginService;
/**
* Specifies a jetty configuration <loginServices/> element for Ant build file.
*
* @author Jakub Pawlowicz
*/
public class LoginServices
{
private List loginServices = new ArrayList();
public void add(LoginService service)
{
loginServices.add(service);
}
public List getLoginServices()
{
return loginServices;
}
}

View File

@ -0,0 +1,66 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Sabre Holdings.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ant.types;
import java.util.ArrayList;
import java.util.List;
import org.apache.tools.ant.taskdefs.Property;
import org.eclipse.jetty.ant.utils.TaskLog;
/**
* Ant <systemProperties/> tag definition.
*
* @author Jakub Pawlowicz
*/
public class SystemProperties
{
private List systemProperties = new ArrayList();
public List getSystemProperties()
{
return systemProperties;
}
public void addSystemProperty(Property property)
{
systemProperties.add(property);
}
/**
* Set a System.property with this value if it is not already set.
*
* @returns true if property has been set
*/
public static boolean setIfNotSetAlready(Property property)
{
if (System.getProperty(property.getName()) == null)
{
System.setProperty(property.getName(), (property.getValue() == null ? "" : property
.getValue()));
TaskLog.log("Setting property '" + property.getName() + "' to value '"
+ property.getValue() + "'");
return true;
}
return false;
}
}

View File

@ -0,0 +1,296 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Sabre Holdings.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ant.types;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.FileSet;
/**
* Ant's WebApp object definition.
*
* @author Jakub Pawlowicz
*/
public class WebApp
{
/** List of web application libraries. */
private List libraries = new ArrayList();
/** List of web application class directories. */
private List classes = new ArrayList();
/** Reference to Ant project variable. */
private Project project;
/** Application context path. */
private String contextPath;
/** Application name. */
private String name;
/** Application war file (either exploded or not). */
private File warFile;
/** Location of application web.xml file. */
private File webXmlFile;
/** Location of jetty-env.xml file. */
private File jettyEnvXml;
/** List of extra scan targets for this web application. */
private FileSet scanTargets;
/** List of the attributes to set to webapp context */
private Attributes attributes;
/** List of optional context handlers. */
private ContextHandlers contextHandlers;
private File webDefaultXmlFile;
/**
* Length of interval in which application will be scanned for changes (0
* means scanner wouldn't be created).
*/
private int scanIntervalSeconds = 0;
public WebApp(Project project)
{
this.project = project;
}
public File getWebDefaultXmlFile()
{
return this.webDefaultXmlFile;
}
public void setWebDefaultXmlFile(File webDefaultXmlfile)
{
this.webDefaultXmlFile = webDefaultXmlfile;
}
public void addLib(FileSet lib)
{
libraries.add(lib);
}
public List getLibraries()
{
return libraries;
}
public void addClasses(FileSet classes)
{
this.classes.add(classes);
}
public List getClasses()
{
return classes;
}
public File getWarFile()
{
return warFile;
}
public void setWarFile(File warFile)
{
this.warFile = warFile;
}
public String getContextPath()
{
return contextPath;
}
public void setContextPath(String contextPath)
{
this.contextPath = contextPath;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
/**
* @return a list of classpath files (libraries and class directories).
*/
public List getClassPathFiles()
{
List classPathFiles = new ArrayList();
Iterator classesIterator = classes.iterator();
while (classesIterator.hasNext())
{
FileSet clazz = (FileSet) classesIterator.next();
classPathFiles.add(clazz.getDirectoryScanner(project).getBasedir());
}
Iterator iterator = libraries.iterator();
while (iterator.hasNext())
{
FileSet library = (FileSet) iterator.next();
String[] includedFiles = library.getDirectoryScanner(project).getIncludedFiles();
File baseDir = library.getDirectoryScanner(project).getBasedir();
for (int i = 0; i < includedFiles.length; i++)
{
classPathFiles.add(new File(baseDir, includedFiles[i]));
}
}
return classPathFiles;
}
/**
* @return a <code>FileMatchingConfiguration</code> object describing the
* configuration of all libraries added to this particular web app
* (both classes and libraries).
*/
public FileMatchingConfiguration getLibrariesConfiguration()
{
FileMatchingConfiguration config = new FileMatchingConfiguration();
Iterator classesIterator = classes.iterator();
while (classesIterator.hasNext())
{
FileSet clazz = (FileSet) classesIterator.next();
config.addDirectoryScanner(clazz.getDirectoryScanner(project));
}
Iterator librariesIterator = libraries.iterator();
while (librariesIterator.hasNext())
{
FileSet library = (FileSet) librariesIterator.next();
config.addDirectoryScanner(library.getDirectoryScanner(project));
}
return config;
}
public FileMatchingConfiguration getScanTargetsConfiguration()
{
FileMatchingConfiguration configuration = new FileMatchingConfiguration();
if (scanTargets != null)
{
configuration.addDirectoryScanner(scanTargets.getDirectoryScanner(project));
}
return configuration;
}
/**
* @return location of web.xml file (either inside WAR or on the external
* location).
*/
public File getWebXmlFile()
{
if (webXmlFile == null)
{
File webInf = new File(warFile, "WEB-INF");
return new File(webInf, "web.xml");
}
return webXmlFile;
}
public void setWebXmlFile(File webXmlFile)
{
this.webXmlFile = webXmlFile;
}
public void addScanTargets(FileSet scanTargets)
{
if (this.scanTargets != null)
{
throw new BuildException("Only one <scanTargets> tag is allowed!");
}
this.scanTargets = scanTargets;
}
public void addContextHandlers(ContextHandlers contextHandlers)
{
if (this.contextHandlers != null)
{
throw new BuildException("Only one <contextHandlers> tag is allowed!");
}
this.contextHandlers = contextHandlers;
}
public void addAttributes(Attributes attributes)
{
if (this.attributes != null)
{
throw new BuildException("Only one <attributes> tag is allowed!");
}
this.attributes = attributes;
}
public int getScanIntervalSeconds()
{
return scanIntervalSeconds;
}
public void setScanIntervalSeconds(int scanIntervalSeconds)
{
this.scanIntervalSeconds = scanIntervalSeconds;
}
public File getJettyEnvXml()
{
return jettyEnvXml;
}
public void setJettyEnvXml(File jettyEnvXml)
{
this.jettyEnvXml = jettyEnvXml;
}
public List getContextHandlers()
{
return (contextHandlers != null ? contextHandlers.getContextHandlers() : new ArrayList());
}
public List getAttributes()
{
return (attributes != null ? attributes.getAttributes() : new ArrayList());
}
}

View File

@ -0,0 +1,40 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Sabre Holdings.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ant.utils;
public interface ServerProxy
{
/**
* Adds a new web application to this server.
*
* @param webApp a WebApplicationProxy object.
* @param scanIntervalSeconds
*/
public void addWebApplication(WebApplicationProxy webApp, int scanIntervalSeconds);
/**
* Starts this server.
*/
public void start();
public Object getProxiedObject();
}

View File

@ -0,0 +1,54 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Sabre Holdings.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ant.utils;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.tools.ant.Task;
/**
* Provides logging functionality for classes without access to the Ant project
* variable.
*
* @author Jakub Pawlowicz
*/
public class TaskLog
{
private static Task task;
private static SimpleDateFormat format = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss.SSS");
public static void setTask(Task task)
{
TaskLog.task = task;
}
public static void log(String message)
{
task.log(message);
}
public static void logWithTimestamp(String message)
{
task.log(format.format(new Date()) + ": " + message);
}
}

View File

@ -0,0 +1,47 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Sabre Holdings.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ant.utils;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
public interface WebApplicationProxy
{
public Object getProxiedObject();
/**
* Starts this web application context.
*/
public void start();
/**
* Stops this web application context.
*/
public void stop();
/**
* Creates a new Jetty web application context from this object.
*
* @param contexts collection of context this application should be added
* to.
*/
public void createApplicationContext(ContextHandlerCollection contexts);
}

View File

@ -0,0 +1 @@
jetty=org.eclipse.jetty.ant.JettyRunTask

View File

@ -0,0 +1,43 @@
<!-- =======================================================================================-->
<!-- Build file for running the test-jetty-webapp from the jetty distro. -->
<!-- -->
<!-- You will need to have a full jetty-distribution available unpacked on your local file -->
<!-- system. We will refer to the top level directory of this distribution as $JETTY_HOME. -->
<!-- -->
<!-- To use: -->
<!-- * mkdir test-jetty-ant -->
<!-- * cp this file to test-jetty-ant -->
<!-- * cd test-jetty-ant; mkdir jetty-lib; mkdir war; mkdir jetty-temp -->
<!-- * copy all jars from $JETTY_HOME/lib and all subdirs flatly into ./jetty-lib -->
<!-- * unjar the test.war from $JETTY_HOME/webapps dir into ./war -->
<!-- * cp $JETTY_HOME/etc/webdefaults.xml to . -->
<!-- * cp $JETTY_HOME/etc/realm.properties to . -->
<!-- -->
<!-- To run: -->
<!-- ant jetty.run -->
<!-- =======================================================================================-->
<project name="Jetty-Ant integration test" basedir=".">
<path id="jetty.plugin.classpath">
<fileset dir="jetty-lib" includes="*.jar"/>
</path>
<taskdef classpathref="jetty.plugin.classpath" resource="tasks.properties" loaderref="jetty.loader" />
<typedef name="hashLoginService" classname="org.eclipse.jetty.security.HashLoginService"
classpathref="jetty.plugin.classpath" loaderref="jetty.loader" />
<target name="jetty.run">
<jetty tempDirectory="jetty-temp">
<loginServices>
<hashLoginService name="Test Realm" config="realm.properties"/>
</loginServices>
<webApp name="test"
warfile="war"
webDefaultXmlFile="webdefault.xml"
contextpath="/test" >
<attributes>
<attribute name="org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern" value=".*/.*jsp-api-[^/]*\.jar$|.*/.*jsp-[^/]*\.jar$|.*/.*taglibs[^/]*\.jar$"/>
</attributes>
</webApp>
</jetty>
</target>
</project>

View File

@ -0,0 +1,28 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.ant;
import junit.framework.TestCase;
public class JettyRunTaskTest extends TestCase
{
public void testInit()
{
}
}

View File

@ -354,11 +354,6 @@
<artifactId>jetty-rewrite</artifactId> <artifactId>jetty-rewrite</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-ajp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-annotations</artifactId> <artifactId>jetty-annotations</artifactId>

View File

@ -40,7 +40,7 @@ import org.eclipse.jetty.plus.jaas.callback.RequestParameterCallback;
import org.eclipse.jetty.security.DefaultIdentityService; import org.eclipse.jetty.security.DefaultIdentityService;
import org.eclipse.jetty.security.IdentityService; import org.eclipse.jetty.security.IdentityService;
import org.eclipse.jetty.security.LoginService; import org.eclipse.jetty.security.LoginService;
import org.eclipse.jetty.server.AbstractHttpConnection; import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.Loader;
@ -210,8 +210,11 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
} }
else if (callback instanceof RequestParameterCallback) else if (callback instanceof RequestParameterCallback)
{ {
AbstractHttpConnection connection = AbstractHttpConnection.getCurrentConnection(); HttpChannel channel = HttpChannel.getCurrentHttpChannel();
Request request = (connection == null? null : connection.getRequest());
if (channel == null)
return;
Request request = channel.getRequest();
if (request != null) if (request != null)
{ {

View File

@ -19,6 +19,10 @@
package org.eclipse.jetty.websocket.client; package org.eclipse.jetty.websocket.client;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
@ -30,6 +34,7 @@ import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.websocket.api.Extension;
import org.eclipse.jetty.websocket.api.ExtensionRegistry; import org.eclipse.jetty.websocket.api.ExtensionRegistry;
import org.eclipse.jetty.websocket.api.WebSocketPolicy; import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.client.internal.ConnectionManager; import org.eclipse.jetty.websocket.client.internal.ConnectionManager;
@ -37,6 +42,8 @@ import org.eclipse.jetty.websocket.client.internal.IWebSocketClient;
import org.eclipse.jetty.websocket.driver.EventMethodsCache; import org.eclipse.jetty.websocket.driver.EventMethodsCache;
import org.eclipse.jetty.websocket.driver.WebSocketEventDriver; import org.eclipse.jetty.websocket.driver.WebSocketEventDriver;
import org.eclipse.jetty.websocket.extensions.WebSocketExtensionRegistry; import org.eclipse.jetty.websocket.extensions.WebSocketExtensionRegistry;
import org.eclipse.jetty.websocket.io.WebSocketSession;
import org.eclipse.jetty.websocket.protocol.ExtensionConfig;
public class WebSocketClientFactory extends AggregateLifeCycle public class WebSocketClientFactory extends AggregateLifeCycle
{ {
@ -47,9 +54,10 @@ public class WebSocketClientFactory extends AggregateLifeCycle
private final ScheduledExecutorService scheduler; private final ScheduledExecutorService scheduler;
private final EventMethodsCache methodsCache; private final EventMethodsCache methodsCache;
private final WebSocketPolicy policy; private final WebSocketPolicy policy;
private final ExtensionRegistry extensionRegistry; private final WebSocketExtensionRegistry extensionRegistry;
private SocketAddress bindAddress; private SocketAddress bindAddress;
private final Queue<WebSocketSession> sessions = new ConcurrentLinkedQueue<>();
private ConnectionManager connectionManager; private ConnectionManager connectionManager;
public WebSocketClientFactory() public WebSocketClientFactory()
@ -69,6 +77,7 @@ public class WebSocketClientFactory extends AggregateLifeCycle
public WebSocketClientFactory(Executor executor, ScheduledExecutorService scheduler, SslContextFactory sslContextFactory) public WebSocketClientFactory(Executor executor, ScheduledExecutorService scheduler, SslContextFactory sslContextFactory)
{ {
LOG.debug("new WebSocketClientFactory()");
if (executor == null) if (executor == null)
{ {
throw new IllegalArgumentException("Executor is required"); throw new IllegalArgumentException("Executor is required");
@ -101,6 +110,20 @@ public class WebSocketClientFactory extends AggregateLifeCycle
this(new QueuedThreadPool(),Executors.newSingleThreadScheduledExecutor(),sslContextFactory); this(new QueuedThreadPool(),Executors.newSingleThreadScheduledExecutor(),sslContextFactory);
} }
@Override
protected void doStart() throws Exception
{
super.doStart();
LOG.debug("doStart()");
}
@Override
protected void doStop() throws Exception
{
super.doStop();
LOG.debug("doStop()");
}
/** /**
* The address to bind local physical (outgoing) TCP Sockets to. * The address to bind local physical (outgoing) TCP Sockets to.
* *
@ -142,6 +165,26 @@ public class WebSocketClientFactory extends AggregateLifeCycle
return scheduler; return scheduler;
} }
public List<Extension> initExtensions(List<ExtensionConfig> requested)
{
List<Extension> extensions = new ArrayList<Extension>();
for (ExtensionConfig cfg : requested)
{
Extension extension = extensionRegistry.newInstance(cfg);
if (extension == null)
{
continue;
}
LOG.debug("added {}",extension);
extensions.add(extension);
}
LOG.debug("extensions={}",extensions);
return extensions;
}
public WebSocketClient newWebSocketClient(Object websocketPojo) public WebSocketClient newWebSocketClient(Object websocketPojo)
{ {
LOG.debug("Creating new WebSocket for {}",websocketPojo); LOG.debug("Creating new WebSocket for {}",websocketPojo);
@ -149,6 +192,33 @@ public class WebSocketClientFactory extends AggregateLifeCycle
return new IWebSocketClient(this,websocket); return new IWebSocketClient(this,websocket);
} }
public boolean sessionClosed(WebSocketSession session)
{
return isRunning() && sessions.remove(session);
}
public boolean sessionOpened(WebSocketSession session)
{
if (LOG.isDebugEnabled())
{
LOG.debug("Session Opened: {}",session);
}
// FIXME: what is going on?
// if (!isRunning())
// {
// LOG.debug("Factory.isRunning: {}",this.isRunning());
// LOG.debug("Factory.isStarted: {}",this.isStarted());
// LOG.debug("Factory.isStarting: {}",this.isStarting());
// LOG.debug("Factory.isStopped: {}",this.isStopped());
// LOG.debug("Factory.isStopping: {}",this.isStopping());
// LOG.warn("Factory is not running");
// return false;
// }
boolean ret = sessions.offer(session);
session.onConnect();
return ret;
}
/** /**
* @param bindAddress * @param bindAddress
* the address to bind the socket channel to * the address to bind the socket channel to

View File

@ -57,6 +57,8 @@ public class IWebSocketClient extends FutureCallback<UpgradeResponse> implements
public IWebSocketClient(WebSocketClientFactory factory, WebSocketEventDriver websocket) public IWebSocketClient(WebSocketClientFactory factory, WebSocketEventDriver websocket)
{ {
this.factory = factory; this.factory = factory;
LOG.debug("factory.isRunning(): {}",factory.isRunning());
LOG.debug("factory.isStarted(): {}",factory.isStarted());
this.policy = factory.getPolicy(); this.policy = factory.getPolicy();
this.websocket = websocket; this.websocket = websocket;
this.upgradeRequest = new ClientUpgradeRequest(); this.upgradeRequest = new ClientUpgradeRequest();
@ -210,9 +212,8 @@ public class IWebSocketClient extends FutureCallback<UpgradeResponse> implements
return websocketUri; return websocketUri;
} }
public void setUpgradeResponse(UpgradeResponse response) public void setUpgradeResponse(ClientUpgradeResponse response)
{ {
// TODO Auto-generated method stub this.upgradeResponse = response;
} }
} }

View File

@ -25,7 +25,6 @@ import java.util.regex.Pattern;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.Utf8LineParser; import org.eclipse.jetty.util.Utf8LineParser;
import org.eclipse.jetty.websocket.api.UpgradeException; import org.eclipse.jetty.websocket.api.UpgradeException;
import org.eclipse.jetty.websocket.api.UpgradeResponse;
import org.eclipse.jetty.websocket.client.internal.ClientUpgradeResponse; import org.eclipse.jetty.websocket.client.internal.ClientUpgradeResponse;
/** /**
@ -58,7 +57,7 @@ public class HttpResponseHeaderParser
return (state == State.END); return (state == State.END);
} }
public UpgradeResponse parse(ByteBuffer buf) throws UpgradeException public ClientUpgradeResponse parse(ByteBuffer buf) throws UpgradeException
{ {
while (!isDone() && (buf.remaining() > 0)) while (!isDone() && (buf.remaining() > 0))
{ {

View File

@ -22,6 +22,7 @@ import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@ -36,10 +37,17 @@ import org.eclipse.jetty.util.QuotedStringTokenizer;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.Extension;
import org.eclipse.jetty.websocket.api.UpgradeException; import org.eclipse.jetty.websocket.api.UpgradeException;
import org.eclipse.jetty.websocket.api.UpgradeResponse; import org.eclipse.jetty.websocket.api.UpgradeResponse;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.client.internal.ClientUpgradeRequest; import org.eclipse.jetty.websocket.client.internal.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.internal.ClientUpgradeResponse;
import org.eclipse.jetty.websocket.client.internal.IWebSocketClient; import org.eclipse.jetty.websocket.client.internal.IWebSocketClient;
import org.eclipse.jetty.websocket.driver.WebSocketEventDriver;
import org.eclipse.jetty.websocket.io.IncomingFrames;
import org.eclipse.jetty.websocket.io.OutgoingFrames;
import org.eclipse.jetty.websocket.io.WebSocketSession;
import org.eclipse.jetty.websocket.protocol.AcceptHash; import org.eclipse.jetty.websocket.protocol.AcceptHash;
import org.eclipse.jetty.websocket.protocol.ExtensionConfig; import org.eclipse.jetty.websocket.protocol.ExtensionConfig;
@ -176,14 +184,14 @@ public class UpgradeConnection extends AbstractConnection
{ {
LOG.debug("Filled {} bytes - {}",filled,BufferUtil.toDetailString(buffer)); LOG.debug("Filled {} bytes - {}",filled,BufferUtil.toDetailString(buffer));
} }
UpgradeResponse resp = parser.parse(buffer); ClientUpgradeResponse resp = parser.parse(buffer);
if (resp != null) if (resp != null)
{ {
// Got a response! // Got a response!
client.setUpgradeResponse(resp); client.setUpgradeResponse(resp);
validateResponse(resp); validateResponse(resp);
notifyConnect(); notifyConnect();
upgradeConnection(); upgradeConnection(resp);
return false; // do no more reading return false; // do no more reading
} }
} }
@ -205,12 +213,72 @@ public class UpgradeConnection extends AbstractConnection
} }
} }
private void upgradeConnection() private void upgradeConnection(ClientUpgradeResponse response)
{ {
EndPoint endp = getEndPoint(); EndPoint endp = getEndPoint();
Executor executor = getExecutor(); Executor executor = getExecutor();
WebSocketClientConnection conn = new WebSocketClientConnection(endp,executor,client); WebSocketClientConnection connection = new WebSocketClientConnection(endp,executor,client);
endp.setConnection(conn);
// Initialize / Negotiate Extensions
WebSocketEventDriver websocket = client.getWebSocket();
WebSocketPolicy policy = client.getPolicy();
String acceptedSubProtocol = response.getAcceptedSubProtocol();
WebSocketSession session = new WebSocketSession(websocket,connection,policy,acceptedSubProtocol);
connection.setSession(session);
List<Extension> extensions = client.getFactory().initExtensions(response.getExtensions());
// Start with default routing.
IncomingFrames incoming = session;
OutgoingFrames outgoing = connection;
// Connect extensions
if (extensions != null)
{
Iterator<Extension> extIter;
// Connect outgoings
extIter = extensions.iterator();
while (extIter.hasNext())
{
Extension ext = extIter.next();
ext.setNextOutgoingFrames(outgoing);
outgoing = ext;
// Handle RSV reservations
if (ext.useRsv1())
{
connection.getGenerator().setRsv1InUse(true);
connection.getParser().setRsv1InUse(true);
}
if (ext.useRsv2())
{
connection.getGenerator().setRsv2InUse(true);
connection.getParser().setRsv2InUse(true);
}
if (ext.useRsv3())
{
connection.getGenerator().setRsv3InUse(true);
connection.getParser().setRsv3InUse(true);
}
}
// Connect incomings
Collections.reverse(extensions);
extIter = extensions.iterator();
while (extIter.hasNext())
{
Extension ext = extIter.next();
ext.setNextIncomingFrames(incoming);
incoming = ext;
}
}
// configure session for outgoing flows
session.setOutgoing(outgoing);
// configure connection for incoming flows
connection.getParser().setIncomingFramesHandler(incoming);
// Now swap out the connection
endp.setConnection(connection);
} }
private void validateResponse(UpgradeResponse response) private void validateResponse(UpgradeResponse response)

View File

@ -21,17 +21,25 @@ package org.eclipse.jetty.websocket.client.internal.io;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.websocket.client.WebSocketClientFactory;
import org.eclipse.jetty.websocket.client.internal.IWebSocketClient; import org.eclipse.jetty.websocket.client.internal.IWebSocketClient;
import org.eclipse.jetty.websocket.io.AbstractWebSocketConnection; import org.eclipse.jetty.websocket.io.AbstractWebSocketConnection;
/**
* Client side WebSocket physical connection.
*/
public class WebSocketClientConnection extends AbstractWebSocketConnection public class WebSocketClientConnection extends AbstractWebSocketConnection
{ {
private final WebSocketClientFactory factory;
private final IWebSocketClient client; private final IWebSocketClient client;
private boolean connected;
public WebSocketClientConnection(EndPoint endp, Executor executor, IWebSocketClient client) public WebSocketClientConnection(EndPoint endp, Executor executor, IWebSocketClient client)
{ {
super(endp,executor,client.getFactory().getScheduler(),client.getPolicy(),client.getFactory().getBufferPool()); super(endp,executor,client.getFactory().getScheduler(),client.getPolicy(),client.getFactory().getBufferPool());
this.client = client; this.client = client;
this.factory = client.getFactory();
this.connected = false;
} }
public IWebSocketClient getClient() public IWebSocketClient getClient()
@ -39,9 +47,21 @@ public class WebSocketClientConnection extends AbstractWebSocketConnection
return client; return client;
} }
@Override
public void onClose()
{
super.onClose();
factory.sessionClosed(getSession());
}
@Override @Override
public void onOpen() public void onOpen()
{ {
if (!connected)
{
factory.sessionOpened(getSession());
connected = true;
}
super.onOpen(); super.onOpen();
} }
} }

View File

@ -22,78 +22,115 @@ import static org.hamcrest.Matchers.*;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.Exchanger;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.eclipse.jetty.util.BlockingArrayQueue; import org.eclipse.jetty.util.BlockingArrayQueue;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.WebSocketAdapter; import org.eclipse.jetty.websocket.api.WebSocketAdapter;
import org.eclipse.jetty.websocket.api.WebSocketConnection; import org.eclipse.jetty.websocket.api.WebSocketConnection;
import org.junit.Assert; import org.junit.Assert;
/**
* Testing Socket used on client side WebSocket testing.
*/
public class TrackingSocket extends WebSocketAdapter public class TrackingSocket extends WebSocketAdapter
{ {
public AtomicBoolean open = new AtomicBoolean(false); private static final Logger LOG = Log.getLogger(TrackingSocket.class);
public AtomicInteger close = new AtomicInteger(-1);
public int closeCode = -1;
public Exchanger<String> messageExchanger;
public StringBuilder closeMessage = new StringBuilder(); public StringBuilder closeMessage = new StringBuilder();
public CountDownLatch openLatch = new CountDownLatch(1); public CountDownLatch openLatch = new CountDownLatch(1);
public CountDownLatch closeLatch = new CountDownLatch(1); public CountDownLatch closeLatch = new CountDownLatch(1);
public CountDownLatch dataLatch = new CountDownLatch(1); public CountDownLatch dataLatch = new CountDownLatch(1);
public BlockingQueue<String> messageQueue = new BlockingArrayQueue<String>(); public BlockingQueue<String> messageQueue = new BlockingArrayQueue<String>();
public void assertClose(int expectedStatusCode, String expectedReason) public void assertClose(int expectedStatusCode, String expectedReason) throws InterruptedException
{ {
assertCloseCode(expectedStatusCode); assertCloseCode(expectedStatusCode);
assertCloseReason(expectedReason); assertCloseReason(expectedReason);
} }
public void assertCloseCode(int expectedCode) public void assertCloseCode(int expectedCode) throws InterruptedException
{ {
Assert.assertThat("Close Code",close.get(),is(expectedCode)); Assert.assertThat("Was Closed",closeLatch.await(500,TimeUnit.MILLISECONDS),is(true));
Assert.assertThat("Close Code",closeCode,is(expectedCode));
} }
private void assertCloseReason(String expectedReason) private void assertCloseReason(String expectedReason)
{ {
Assert.assertThat("Close Reaosn",closeMessage.toString(),is(expectedReason)); Assert.assertThat("Close Reason",closeMessage.toString(),is(expectedReason));
} }
public void assertIsOpen() public void assertIsOpen() throws InterruptedException
{ {
assertWasOpened(); assertWasOpened();
assertNotClosed(); assertNotClosed();
} }
public void assertMessage(String string) public void assertMessage(String expected)
{ {
// TODO Auto-generated method stub String actual = messageQueue.poll();
Assert.assertEquals("Message",expected,actual);
} }
public void assertNotClosed() public void assertNotClosed()
{ {
Assert.assertThat("Close Code",close.get(),is(-1)); Assert.assertThat("Closed Latch",closeLatch.getCount(),greaterThanOrEqualTo(1L));
} }
public void assertNotOpened() public void assertNotOpened()
{ {
Assert.assertThat("Opened State",open.get(),is(false)); Assert.assertThat("Open Latch",openLatch.getCount(),greaterThanOrEqualTo(1L));
} }
public void assertWasOpened() public void assertWasOpened() throws InterruptedException
{ {
Assert.assertThat("Opened State",open.get(),is(true)); Assert.assertThat("Was Opened",openLatch.await(500,TimeUnit.MILLISECONDS),is(true));
}
public void awaitMessage(int expectedMessageCount, TimeUnit timeoutUnit, int timeoutDuration) throws TimeoutException
{
int startCount = messageQueue.size();
long msDur = TimeUnit.MILLISECONDS.convert(timeoutDuration,timeoutUnit);
long now = System.currentTimeMillis();
long expireOn = now + msDur;
LOG.debug("Now: {} - expireOn: {} ({} ms)",now,expireOn,msDur);
while (messageQueue.size() < (startCount + expectedMessageCount))
{
try
{
TimeUnit.MILLISECONDS.sleep(20);
}
catch (InterruptedException gnore)
{
/* ignore */
}
if (!LOG.isDebugEnabled() && (System.currentTimeMillis() > expireOn))
{
throw new TimeoutException(String.format("Timeout reading all %d expected messages. (managed to only read %d messages)",expectedMessageCount,
messageQueue.size()));
}
}
} }
@Override @Override
public void onWebSocketBinary(byte[] payload, int offset, int len) public void onWebSocketBinary(byte[] payload, int offset, int len)
{ {
LOG.debug("onWebSocketBinary()");
dataLatch.countDown(); dataLatch.countDown();
} }
@Override @Override
public void onWebSocketClose(int statusCode, String reason) public void onWebSocketClose(int statusCode, String reason)
{ {
LOG.debug("onWebSocketClose({},{})",statusCode,reason);
super.onWebSocketClose(statusCode,reason); super.onWebSocketClose(statusCode,reason);
close.set(statusCode); closeCode = statusCode;
closeMessage.append(reason); closeMessage.append(reason);
closeLatch.countDown(); closeLatch.countDown();
} }
@ -102,20 +139,31 @@ public class TrackingSocket extends WebSocketAdapter
public void onWebSocketConnect(WebSocketConnection connection) public void onWebSocketConnect(WebSocketConnection connection)
{ {
super.onWebSocketConnect(connection); super.onWebSocketConnect(connection);
open.set(true);
openLatch.countDown(); openLatch.countDown();
} }
@Override @Override
public void onWebSocketText(String message) public void onWebSocketText(String message)
{ {
LOG.debug("onWebSocketText({})",message);
messageQueue.offer(message);
dataLatch.countDown(); dataLatch.countDown();
messageQueue.add(message);
if (messageExchanger != null)
{
try
{
messageExchanger.exchange(message);
}
catch (InterruptedException e)
{
LOG.debug(e);
}
}
} }
public void waitForResponseMessage() public void waitForMessage(TimeUnit timeoutUnit, int timeoutDuration) throws InterruptedException
{ {
// TODO Auto-generated method stub Assert.assertThat("Message Received",dataLatch.await(timeoutDuration,timeoutUnit),is(true));
} }
} }

View File

@ -22,24 +22,20 @@ import static org.hamcrest.Matchers.*;
import java.net.ConnectException; import java.net.ConnectException;
import java.net.URI; import java.net.URI;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Exchanger; import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
import org.eclipse.jetty.util.FutureCallback; import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.websocket.api.StatusCode; import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.UpgradeException; import org.eclipse.jetty.websocket.api.UpgradeException;
import org.eclipse.jetty.websocket.api.UpgradeRequest; import org.eclipse.jetty.websocket.api.UpgradeRequest;
import org.eclipse.jetty.websocket.api.UpgradeResponse; import org.eclipse.jetty.websocket.api.UpgradeResponse;
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
import org.eclipse.jetty.websocket.api.WebSocketConnection;
import org.eclipse.jetty.websocket.api.WebSocketListener;
import org.eclipse.jetty.websocket.client.blockhead.BlockheadServer; import org.eclipse.jetty.websocket.client.blockhead.BlockheadServer;
import org.eclipse.jetty.websocket.client.blockhead.BlockheadServer.ServerConnection; import org.eclipse.jetty.websocket.client.blockhead.BlockheadServer.ServerConnection;
import org.eclipse.jetty.websocket.protocol.WebSocketFrame; import org.eclipse.jetty.websocket.protocol.WebSocketFrame;
@ -48,8 +44,9 @@ import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
@Ignore("work in progress") @RunWith(AdvancedRunner.class)
public class WebSocketClientTest public class WebSocketClientTest
{ {
private BlockheadServer server; private BlockheadServer server;
@ -149,9 +146,9 @@ public class WebSocketClientTest
final ServerConnection srvSock = server.accept(); final ServerConnection srvSock = server.accept();
srvSock.upgrade(); srvSock.upgrade();
UpgradeResponse resp = future.get(250,TimeUnit.MILLISECONDS); UpgradeResponse resp = future.get(500,TimeUnit.MILLISECONDS);
Assert.assertThat("Response",resp,notNullValue()); Assert.assertThat("Response",resp,notNullValue());
Assert.assertEquals("Response.success",resp.isSuccess(),is(true)); Assert.assertThat("Response.success",resp.isSuccess(),is(true));
cliSock.assertWasOpened(); cliSock.assertWasOpened();
cliSock.assertNotClosed(); cliSock.assertNotClosed();
@ -159,9 +156,9 @@ public class WebSocketClientTest
Assert.assertThat("Factory.sockets.size",factory.getConnectionManager().getClients().size(),is(1)); Assert.assertThat("Factory.sockets.size",factory.getConnectionManager().getClients().size(),is(1));
cliSock.getConnection().write(null,new FutureCallback<Void>(),"Hello World!"); cliSock.getConnection().write(null,new FutureCallback<Void>(),"Hello World!");
srvSock.echoMessage(); srvSock.echoMessage(1,TimeUnit.MILLISECONDS,500);
// wait for response from server // wait for response from server
cliSock.waitForResponseMessage(); cliSock.waitForMessage(TimeUnit.MILLISECONDS,500);
cliSock.assertMessage("Hello World!"); cliSock.assertMessage("Hello World!");
} }
@ -177,55 +174,29 @@ public class WebSocketClientTest
final ServerConnection srvSock = server.accept(); final ServerConnection srvSock = server.accept();
srvSock.upgrade(); srvSock.upgrade();
// Validate connect
UpgradeResponse resp = future.get(500,TimeUnit.MILLISECONDS);
Assert.assertThat("Response",resp,notNullValue());
Assert.assertThat("Response.success",resp.isSuccess(),is(true));
// Have server send initial message // Have server send initial message
srvSock.write(WebSocketFrame.text("Hello World")); srvSock.write(WebSocketFrame.text("Hello World"));
// Verify connect // Verify connect
future.get(500,TimeUnit.MILLISECONDS); future.get(500,TimeUnit.MILLISECONDS);
wsocket.assertWasOpened();
wsocket.awaitMessage(1,TimeUnit.MILLISECONDS,500);
wsocket.assertMessage("Hello world"); wsocket.assertMessage("Hello World");
} }
@Test @Test
public void testBlockReceiving() throws Exception public void testBlockReceiving() throws Exception
{ {
final AtomicBoolean open = new AtomicBoolean(false);
final AtomicInteger close = new AtomicInteger();
final CountDownLatch _latch = new CountDownLatch(1);
final StringBuilder closeMessage = new StringBuilder();
final Exchanger<String> exchanger = new Exchanger<String>(); final Exchanger<String> exchanger = new Exchanger<String>();
TrackingSocket tsocket = new TrackingSocket();
WebSocketListener socket = new WebSocketAdapter() tsocket.messageExchanger = exchanger;
{ WebSocketClient client = factory.newWebSocketClient(tsocket);
@Override
public void onWebSocketClose(int statusCode, String reason)
{
close.set(statusCode);
closeMessage.append(reason);
_latch.countDown();
}
@Override
public void onWebSocketConnect(WebSocketConnection connection)
{
open.set(true);
}
@Override
public void onWebSocketText(String message)
{
try
{
exchanger.exchange(message);
}
catch (InterruptedException e)
{
// e.printStackTrace();
}
}
};
WebSocketClient client = factory.newWebSocketClient(socket);
client.getPolicy().setIdleTimeout(60000); client.getPolicy().setIdleTimeout(60000);
URI wsUri = server.getWsUri(); URI wsUri = server.getWsUri();
@ -233,8 +204,9 @@ public class WebSocketClientTest
ServerConnection sconnection = server.accept(); ServerConnection sconnection = server.accept();
sconnection.setSoTimeout(60000); sconnection.setSoTimeout(60000);
sconnection.upgrade();
UpgradeResponse resp = future.get(250,TimeUnit.MILLISECONDS); future.get(500,TimeUnit.MILLISECONDS);
// define some messages to send server to client // define some messages to send server to client
byte[] send = new byte[] byte[] send = new byte[]
@ -300,18 +272,14 @@ public class WebSocketClientTest
Assert.assertEquals(m.get(),messages); Assert.assertEquals(m.get(),messages);
// Close with code // Close with code
start = System.currentTimeMillis(); sconnection.close(StatusCode.NORMAL);
sconnection.write(new byte[]
{ (byte)0x88, (byte)0x02, (byte)4, (byte)87 },0,4);
sconnection.flush();
_latch.await(10,TimeUnit.SECONDS); Assert.assertTrue("Client Socket Closed",tsocket.closeLatch.await(10,TimeUnit.SECONDS));
Assert.assertTrue((System.currentTimeMillis() - start) < 5000); tsocket.assertCloseCode(StatusCode.NORMAL);
Assert.assertEquals(1002,close.get());
Assert.assertEquals("Invalid close code 1111",closeMessage.toString());
} }
@Test @Test
@Ignore("Not working, it hangs")
public void testBlockSending() throws Exception public void testBlockSending() throws Exception
{ {
TrackingSocket wsocket = new TrackingSocket(); TrackingSocket wsocket = new TrackingSocket();
@ -324,7 +292,7 @@ public class WebSocketClientTest
final ServerConnection ssocket = server.accept(); final ServerConnection ssocket = server.accept();
ssocket.upgrade(); ssocket.upgrade();
UpgradeResponse resp = future.get(250,TimeUnit.MILLISECONDS); future.get(250,TimeUnit.MILLISECONDS);
final int messages = 200000; final int messages = 200000;
final AtomicLong totalB = new AtomicLong(); final AtomicLong totalB = new AtomicLong();
@ -408,6 +376,7 @@ public class WebSocketClientTest
} }
@Test(expected = ConnectException.class) @Test(expected = ConnectException.class)
@Ignore("Needs work in SelectManager to support this use case")
public void testConnectionRefused() throws Exception public void testConnectionRefused() throws Exception
{ {
TrackingSocket wsocket = new TrackingSocket(); TrackingSocket wsocket = new TrackingSocket();
@ -456,6 +425,7 @@ public class WebSocketClientTest
} }
@Test @Test
@Ignore("Work In Progress")
public void testIdle() throws Exception public void testIdle() throws Exception
{ {
TrackingSocket wsocket = new TrackingSocket(); TrackingSocket wsocket = new TrackingSocket();
@ -520,6 +490,7 @@ public class WebSocketClientTest
} }
@Test @Test
@Ignore("Work In Progress")
public void testNotIdle() throws Exception public void testNotIdle() throws Exception
{ {
TrackingSocket wsocket = new TrackingSocket(); TrackingSocket wsocket = new TrackingSocket();
@ -537,7 +508,7 @@ public class WebSocketClientTest
wsocket.assertIsOpen(); wsocket.assertIsOpen();
// Send some messages client to server // Send some messages from client to server
byte[] recv = new byte[1024]; byte[] recv = new byte[1024];
int len = -1; int len = -1;
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
@ -548,7 +519,7 @@ public class WebSocketClientTest
Assert.assertTrue(len > 0); Assert.assertTrue(len > 0);
} }
// Send some messages server to client // Send some messages from server to client
byte[] send = new byte[] byte[] send = new byte[]
{ (byte)0x81, (byte)0x02, (byte)'H', (byte)'i' }; { (byte)0x81, (byte)0x02, (byte)'H', (byte)'i' };
@ -567,11 +538,13 @@ public class WebSocketClientTest
ssocket.flush(); ssocket.flush();
wsocket.closeLatch.await(10,TimeUnit.SECONDS); wsocket.closeLatch.await(10,TimeUnit.SECONDS);
Assert.assertTrue((System.currentTimeMillis() - start) < 5000); long dur = (System.currentTimeMillis() - start);
Assert.assertThat("Overall duration",dur,lessThanOrEqualTo(5000L));
wsocket.assertClose(StatusCode.PROTOCOL,"Invalid close code 1111"); wsocket.assertClose(StatusCode.PROTOCOL,"Invalid close code 1111");
} }
@Test @Test
@Ignore("Test for is-open is broken")
public void testUpgradeThenTCPClose() throws Exception public void testUpgradeThenTCPClose() throws Exception
{ {
TrackingSocket wsocket = new TrackingSocket(); TrackingSocket wsocket = new TrackingSocket();
@ -587,9 +560,8 @@ public class WebSocketClientTest
wsocket.assertIsOpen(); wsocket.assertIsOpen();
ssocket.close(); ssocket.disconnect();
wsocket.openLatch.await(10,TimeUnit.SECONDS);
wsocket.assertCloseCode(StatusCode.NO_CLOSE); Assert.assertThat("Close should have been detected",wsocket.closeLatch.await(10,TimeUnit.SECONDS),is(true));
} }
} }

View File

@ -31,11 +31,36 @@ import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.net.SocketException; import java.net.SocketException;
import java.net.URI; import java.net.URI;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.StandardByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.Extension;
import org.eclipse.jetty.websocket.api.WebSocketException;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.extensions.WebSocketExtensionRegistry;
import org.eclipse.jetty.websocket.io.IncomingFrames;
import org.eclipse.jetty.websocket.io.OutgoingFrames;
import org.eclipse.jetty.websocket.protocol.AcceptHash; import org.eclipse.jetty.websocket.protocol.AcceptHash;
import org.eclipse.jetty.websocket.protocol.CloseInfo;
import org.eclipse.jetty.websocket.protocol.ExtensionConfig;
import org.eclipse.jetty.websocket.protocol.Generator;
import org.eclipse.jetty.websocket.protocol.OpCode;
import org.eclipse.jetty.websocket.protocol.Parser;
import org.eclipse.jetty.websocket.protocol.WebSocketFrame; import org.eclipse.jetty.websocket.protocol.WebSocketFrame;
import org.junit.Assert; import org.junit.Assert;
@ -46,26 +71,79 @@ import org.junit.Assert;
*/ */
public class BlockheadServer public class BlockheadServer
{ {
public static class ServerConnection public static class ServerConnection implements IncomingFrames, OutgoingFrames
{ {
private final Socket socket; private final Socket socket;
private final ByteBufferPool bufferPool;
private final WebSocketPolicy policy;
private final IncomingFramesCapture incomingFrames;
private final Parser parser;
private final Generator generator;
private final AtomicInteger parseCount;
private final WebSocketExtensionRegistry extensionRegistry;
/** Set to true to disable timeouts (for debugging reasons) */
private boolean debug = false;
private OutputStream out; private OutputStream out;
private InputStream in; private InputStream in;
private IncomingFrames incoming = this;
private OutgoingFrames outgoing = this;
public ServerConnection(Socket socket) public ServerConnection(Socket socket)
{ {
this.socket = socket; this.socket = socket;
this.incomingFrames = new IncomingFramesCapture();
this.policy = WebSocketPolicy.newServerPolicy();
this.bufferPool = new StandardByteBufferPool(policy.getBufferSize());
this.parser = new Parser(policy);
this.parseCount = new AtomicInteger(0);
this.generator = new Generator(policy,bufferPool,false);
this.extensionRegistry = new WebSocketExtensionRegistry(policy,bufferPool);
} }
public void close() throws IOException public void close() throws IOException
{ {
this.socket.close(); write(new WebSocketFrame(OpCode.CLOSE));
flush();
disconnect();
} }
public void echoMessage() public void close(int statusCode) throws IOException
{ {
// TODO Auto-generated method stub CloseInfo close = new CloseInfo(statusCode);
write(close.asFrame());
flush();
disconnect();
}
public void disconnect()
{
LOG.debug("disconnect");
IO.close(in);
IO.close(out);
if (socket != null)
{
try
{
socket.close();
}
catch (IOException ignore)
{
/* ignore */
}
}
}
public void echoMessage(int expectedFrames, TimeUnit timeoutUnit, int timeoutDuration) throws IOException, TimeoutException
{
LOG.debug("Echo Frames [expecting {}]",expectedFrames);
IncomingFramesCapture cap = readFrames(expectedFrames,timeoutUnit,timeoutDuration);
// now echo them back.
for (WebSocketFrame frame : cap.getFrames())
{
write(frame);
}
} }
public void flush() throws IOException public void flush() throws IOException
@ -91,6 +169,102 @@ public class BlockheadServer
return out; return out;
} }
@Override
public void incoming(WebSocketException e)
{
incomingFrames.incoming(e);
}
@Override
public void incoming(WebSocketFrame frame)
{
LOG.debug("incoming({})",frame);
int count = parseCount.incrementAndGet();
if ((count % 10) == 0)
{
LOG.info("Server parsed {} frames",count);
}
WebSocketFrame copy = new WebSocketFrame(frame);
incomingFrames.incoming(copy);
}
@Override
public <C> void output(C context, Callback<C> callback, WebSocketFrame frame) throws IOException
{
ByteBuffer buf = generator.generate(frame);
if (LOG.isDebugEnabled())
{
LOG.debug("writing out: {}",BufferUtil.toDetailString(buf));
}
BufferUtil.writeTo(buf,out);
out.flush();
if (frame.getOpCode() == OpCode.CLOSE)
{
disconnect();
}
}
public int read(ByteBuffer buf) throws IOException
{
int len = 0;
while ((in.available() > 0) && (buf.remaining() > 0))
{
buf.put((byte)in.read());
len++;
}
return len;
}
public IncomingFramesCapture readFrames(int expectedCount, TimeUnit timeoutUnit, int timeoutDuration) throws IOException, TimeoutException
{
LOG.debug("Read: waiting for {} frame(s) from server",expectedCount);
int startCount = incomingFrames.size();
ByteBuffer buf = bufferPool.acquire(policy.getBufferSize(),false);
BufferUtil.clearToFill(buf);
try
{
long msDur = TimeUnit.MILLISECONDS.convert(timeoutDuration,timeoutUnit);
long now = System.currentTimeMillis();
long expireOn = now + msDur;
LOG.debug("Now: {} - expireOn: {} ({} ms)",now,expireOn,msDur);
int len = 0;
while (incomingFrames.size() < (startCount + expectedCount))
{
BufferUtil.clearToFill(buf);
len = read(buf);
if (len > 0)
{
LOG.debug("Read {} bytes",len);
BufferUtil.flipToFlush(buf,0);
parser.parse(buf);
}
try
{
TimeUnit.MILLISECONDS.sleep(20);
}
catch (InterruptedException gnore)
{
/* ignore */
}
if (!debug && (System.currentTimeMillis() > expireOn))
{
incomingFrames.dump();
throw new TimeoutException(String.format("Timeout reading all %d expected frames. (managed to only read %d frame(s))",expectedCount,
incomingFrames.size()));
}
}
}
finally
{
bufferPool.release(buf);
}
return incomingFrames;
}
public String readRequest() throws IOException public String readRequest() throws IOException
{ {
LOG.debug("Reading client request"); LOG.debug("Reading client request");
@ -124,6 +298,12 @@ public class BlockheadServer
public void upgrade() throws IOException public void upgrade() throws IOException
{ {
List<ExtensionConfig> extensionConfigs = new ArrayList<>();
Pattern patExts = Pattern.compile("^Sec-WebSocket-Extensions: (.*)$",Pattern.CASE_INSENSITIVE);
Pattern patKey = Pattern.compile("^Sec-WebSocket-Key: (.*)$",Pattern.CASE_INSENSITIVE);
Matcher mat;
String key = "not sent"; String key = "not sent";
BufferedReader in = new BufferedReader(new InputStreamReader(getInputStream())); BufferedReader in = new BufferedReader(new InputStreamReader(getInputStream()));
for (String line = in.readLine(); line != null; line = in.readLine()) for (String line = in.readLine(); line != null; line = in.readLine())
@ -132,19 +312,103 @@ public class BlockheadServer
{ {
break; break;
} }
if (line.startsWith("Sec-WebSocket-Key:"))
// Check for extensions
mat = patExts.matcher(line);
if (mat.matches())
{ {
key = line.substring(18).trim(); // found extensions
String econf = mat.group(1);
ExtensionConfig config = ExtensionConfig.parse(econf);
extensionConfigs.add(config);
continue;
}
// Check for Key
mat = patKey.matcher(line);
if (mat.matches())
{
key = mat.group(1);
} }
} }
// Init extensions
List<Extension> extensions = new ArrayList<>();
for (ExtensionConfig config : extensionConfigs)
{
Extension ext = extensionRegistry.newInstance(config);
extensions.add(ext);
}
// Start with default routing
incoming = this;
outgoing = this;
// Connect extensions
if (!extensions.isEmpty())
{
Iterator<Extension> extIter;
// Connect outgoings
extIter = extensions.iterator();
while (extIter.hasNext())
{
Extension ext = extIter.next();
ext.setNextOutgoingFrames(outgoing);
outgoing = ext;
// Handle RSV reservations
if (ext.useRsv1())
{
generator.setRsv1InUse(true);
}
if (ext.useRsv2())
{
generator.setRsv2InUse(true);
}
if (ext.useRsv3())
{
generator.setRsv3InUse(true);
}
}
// Connect incomings
Collections.reverse(extensions);
extIter = extensions.iterator();
while (extIter.hasNext())
{
Extension ext = extIter.next();
ext.setNextIncomingFrames(incoming);
incoming = ext;
}
}
// Configure Parser
parser.setIncomingFramesHandler(incoming);
// Setup Response
StringBuilder resp = new StringBuilder(); StringBuilder resp = new StringBuilder();
resp.append("HTTP/1.1 101 Upgrade\r\n"); resp.append("HTTP/1.1 101 Upgrade\r\n");
resp.append("Sec-WebSocket-Accept: "); resp.append("Sec-WebSocket-Accept: ");
resp.append(AcceptHash.hashKey(key)); resp.append(AcceptHash.hashKey(key)).append("\r\n");
resp.append("\r\n"); if (!extensions.isEmpty())
{
// Respond to used extensions
resp.append("Sec-WebSocket-Extensions: ");
boolean delim = false;
for (Extension ext : extensions)
{
if (delim)
{
resp.append(", ");
}
resp.append(ext.getParameterizedName());
delim = true;
}
resp.append("\r\n");
}
resp.append("\r\n"); resp.append("\r\n");
// Write Response
write(resp.toString().getBytes()); write(resp.toString().getBytes());
} }
@ -163,10 +427,10 @@ public class BlockheadServer
getOutputStream().write(b); getOutputStream().write(b);
} }
public void write(WebSocketFrame frame) public void write(WebSocketFrame frame) throws IOException
{ {
// TODO Auto-generated method stub LOG.debug("write(Frame->{}) to {}",frame,outgoing);
outgoing.output(null,null,frame);
} }
} }

View File

@ -0,0 +1,140 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.websocket.client.blockhead;
import static org.hamcrest.Matchers.*;
import java.util.LinkedList;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.WebSocketException;
import org.eclipse.jetty.websocket.io.IncomingFrames;
import org.eclipse.jetty.websocket.protocol.OpCode;
import org.eclipse.jetty.websocket.protocol.WebSocketFrame;
import org.junit.Assert;
public class IncomingFramesCapture implements IncomingFrames
{
private static final Logger LOG = Log.getLogger(IncomingFramesCapture.class);
private LinkedList<WebSocketFrame> frames = new LinkedList<>();
private LinkedList<WebSocketException> errors = new LinkedList<>();
public void assertErrorCount(int expectedCount)
{
Assert.assertThat("Captured error count",errors.size(),is(expectedCount));
}
public void assertFrameCount(int expectedCount)
{
Assert.assertThat("Captured frame count",frames.size(),is(expectedCount));
}
public void assertHasErrors(Class<? extends WebSocketException> errorType, int expectedCount)
{
Assert.assertThat(errorType.getSimpleName(),getErrorCount(errorType),is(expectedCount));
}
public void assertHasFrame(byte op)
{
Assert.assertThat(OpCode.name(op),getFrameCount(op),greaterThanOrEqualTo(1));
}
public void assertHasFrame(byte op, int expectedCount)
{
Assert.assertThat(OpCode.name(op),getFrameCount(op),is(expectedCount));
}
public void assertHasNoFrames()
{
Assert.assertThat("Has no frames",frames.size(),is(0));
}
public void assertNoErrors()
{
Assert.assertThat("Has no errors",errors.size(),is(0));
}
public void dump()
{
System.err.printf("Captured %d incoming frames%n",frames.size());
for (int i = 0; i < frames.size(); i++)
{
WebSocketFrame frame = frames.get(i);
System.err.printf("[%3d] %s%n",i,frame);
System.err.printf(" %s%n",BufferUtil.toDetailString(frame.getPayload()));
}
}
public int getErrorCount(Class<? extends WebSocketException> errorType)
{
int count = 0;
for (WebSocketException error : errors)
{
if (errorType.isInstance(error))
{
count++;
}
}
return count;
}
public LinkedList<WebSocketException> getErrors()
{
return errors;
}
public int getFrameCount(byte op)
{
int count = 0;
for (WebSocketFrame frame : frames)
{
if (frame.getOpCode() == op)
{
count++;
}
}
return count;
}
public LinkedList<WebSocketFrame> getFrames()
{
return frames;
}
@Override
public void incoming(WebSocketException e)
{
LOG.debug(e);
errors.add(e);
}
@Override
public void incoming(WebSocketFrame frame)
{
WebSocketFrame copy = new WebSocketFrame(frame);
frames.add(copy);
}
public int size()
{
return frames.size();
}
}

View File

@ -1,8 +1,9 @@
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
# org.eclipse.jetty.LEVEL=DEBUG # org.eclipse.jetty.LEVEL=DEBUG
# org.eclipse.jetty.io.ChannelEndPoint.LEVEL=INFO # org.eclipse.jetty.io.ChannelEndPoint.LEVEL=INFO
# org.eclipse.jetty.websocket.LEVEL=WARN org.eclipse.jetty.websocket.LEVEL=WARN
org.eclipse.jetty.websocket.LEVEL=DEBUG # org.eclipse.jetty.websocket.LEVEL=DEBUG
# org.eclipse.jetty.websocket.client.TrackingSocket.LEVEL=DEBUG
# See the read/write traffic # See the read/write traffic
# org.eclipse.jetty.websocket.io.Frames.LEVEL=DEBUG # org.eclipse.jetty.websocket.io.Frames.LEVEL=DEBUG
# org.eclipse.jetty.websocket.io.LEVEL=DEBUG # org.eclipse.jetty.websocket.io.LEVEL=DEBUG

View File

@ -224,6 +224,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
@Override @Override
public void onFillable() public void onFillable()
{ {
LOG.debug("{} onFillable()",policy.getBehavior());
ByteBuffer buffer = bufferPool.acquire(policy.getBufferSize(),false); ByteBuffer buffer = bufferPool.acquire(policy.getBufferSize(),false);
BufferUtil.clear(buffer); BufferUtil.clear(buffer);
boolean readMore = false; boolean readMore = false;
@ -251,6 +252,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
public void onOpen() public void onOpen()
{ {
super.onOpen(); super.onOpen();
LOG.debug("fillInterested");
fillInterested(); fillInterested();
} }

14
pom.xml
View File

@ -351,6 +351,7 @@
</repository> </repository>
</repositories> </repositories>
<modules> <modules>
<module>jetty-ant</module>
<module>jetty-util</module> <module>jetty-util</module>
<module>jetty-jmx</module> <module>jetty-jmx</module>
<module>jetty-io</module> <module>jetty-io</module>
@ -375,15 +376,19 @@
<!--<module>jetty-client</module>--> <!--<module>jetty-client</module>-->
<!--<module>jetty-proxy</module>--> <!--<module>jetty-proxy</module>-->
<!-- Not ready to bring in yet module>jetty-maven-plugin</module>
<module>jetty-jspc-maven-plugin</module-->
<module>jetty-deploy</module> <module>jetty-deploy</module>
<module>jetty-start</module> <module>jetty-start</module>
<module>jetty-plugins</module> <module>jetty-plugins</module>
<module>jetty-plus</module>
<module>jetty-annotations</module>
<module>jetty-jndi</module>
<!-- <!--
<module>jetty-jaspi</module> <module>jetty-jaspi</module>
<module>jetty-ajp</module>
<module>jetty-jndi</module>
<module>jetty-annotations</module>
<module>jetty-plus</module>
<module>jetty-rewrite</module> <module>jetty-rewrite</module>
<module>jetty-policy</module> <module>jetty-policy</module>
<module>jetty-monitor</module> <module>jetty-monitor</module>
@ -650,6 +655,7 @@
<exclude>jetty-util/src/main/java/org/eclipse/jetty/util/security/UnixCrypt.java</exclude> <exclude>jetty-util/src/main/java/org/eclipse/jetty/util/security/UnixCrypt.java</exclude>
<exclude>jetty-policy/src/main/java/org/eclipse/jetty/policy/loader/DefaultPolicyLoader.java</exclude> <exclude>jetty-policy/src/main/java/org/eclipse/jetty/policy/loader/DefaultPolicyLoader.java</exclude>
<exclude>jetty-policy/src/main/java/org/eclipse/jetty/policy/loader/PolicyFileScanner.java</exclude> <exclude>jetty-policy/src/main/java/org/eclipse/jetty/policy/loader/PolicyFileScanner.java</exclude>
<exlcude>jetty-ant/**</exlcude> <!-- short term, need to add support to accept additional copyrights -->
</excludes> </excludes>
</configuration> </configuration>
<executions> <executions>