Merge branch 'jetty-9' of ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project into jetty-9

This commit is contained in:
Thomas Becker 2012-08-17 17:35:33 +02:00
commit 095a15f9e8
39 changed files with 917 additions and 181 deletions

15
header-template.txt Normal file
View File

@ -0,0 +1,15 @@
========================================================================
Copyright (c) ${copyright-range} 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.
========================================================================

View File

@ -450,7 +450,7 @@ public class HttpFields implements Iterable<HttpFields.Field>
}
return new Enumeration<String>()
{
{
Field f = field;
@Override
@ -467,7 +467,7 @@ public class HttpFields implements Iterable<HttpFields.Field>
f = f._next;
return n.getValue();
}
};
};
}
/* -------------------------------------------------------------- */
@ -1262,5 +1262,36 @@ public class HttpFields implements Iterable<HttpFields.Field>
{
return ("[" + getName() + "=" + _value + (_next == null ? "" : "->") + "]");
}
/* ------------------------------------------------------------ */
public boolean contains(String value)
{
if (_value==null)
return false;
if (value.equalsIgnoreCase(_value))
return true;
String[] split = _value.split("\\s*,\\s*");
for (String s : split)
{
if (value.equalsIgnoreCase(s))
return true;
}
if (_next!=null)
return _next.contains(value);
return false;
}
}
/* ------------------------------------------------------------ */
public boolean contains(HttpHeader header, String value)
{
Field field = getField(header);
if (field==null)
return false;
return field.contains(value);
}
}

View File

@ -62,7 +62,6 @@ public class HttpParser
private HttpHeaderValue _value;
private String _valueString;
private int _responseStatus;
private boolean _persistent;
/* ------------------------------------------------------------------------------- */
private State _state=State.START;
@ -186,12 +185,6 @@ public class HttpParser
return _state == state;
}
/* ------------------------------------------------------------------------------- */
public boolean isPersistent()
{
return _persistent;
}
/* ------------------------------------------------------------------------------- */
/* Quick lookahead for the start state looking for a request method or a HTTP version,
* otherwise skip white space until something else to parse.
@ -218,7 +211,6 @@ public class HttpParser
if (_version!=null)
{
buffer.position(buffer.position()+_version.asString().length()+1);
_persistent=_version.getVerion()>=HttpVersion.HTTP_1_1.getVerion();
_state=State.SPACE1;
return;
}
@ -309,7 +301,6 @@ public class HttpParser
badMessage(buffer, "Unknown Version");
return true;
}
_persistent=_version.getVerion()>=HttpVersion.HTTP_1_1.getVerion();
_state=State.SPACE1;
}
else if (ch < HttpTokens.SPACE && ch>=0)
@ -377,10 +368,9 @@ public class HttpParser
_uri=_utf8.toString();
_utf8.reset();
return_from_parse|=_requestHandler.startRequest(_method,_methodString,_uri,null);
_persistent=false;
_state=State.END;
BufferUtil.clear(buffer);
return_from_parse|=_handler.headerComplete(false,_persistent);
return_from_parse|=_handler.headerComplete();
return_from_parse|=_handler.messageComplete(_contentPosition);
}
else
@ -410,7 +400,6 @@ public class HttpParser
_string.setLength(0);
buffer.position(buffer.position()+_version.asString().length()-1);
_eol=buffer.get();
_persistent=_version.getVerion()>=HttpVersion.HTTP_1_1.getVerion();
_state=State.HEADER;
return_from_parse|=_requestHandler.startRequest(_method,_methodString, _uri, _version);
}
@ -429,10 +418,9 @@ public class HttpParser
{
// HTTP/0.9
return_from_parse|=_requestHandler.startRequest(_method,_methodString, _uri, null);
_persistent=false;
_state=State.END;
BufferUtil.clear(buffer);
return_from_parse|=_handler.headerComplete(false,_persistent);
return_from_parse|=_handler.headerComplete();
return_from_parse|=_handler.messageComplete(_contentPosition);
}
}
@ -450,7 +438,6 @@ public class HttpParser
}
_eol=ch;
_persistent=_version.getVerion()>=HttpVersion.HTTP_1_1.getVerion();
_state=State.HEADER;
return_from_parse|=_requestHandler.startRequest(_method,_methodString, _uri, _version);
continue;
@ -568,37 +555,6 @@ public class HttpParser
}
}
break;
case CONNECTION:
switch(_value==null?HttpHeaderValue.UNKNOWN:_value)
{
case CLOSE:
_persistent=false;
break;
case KEEP_ALIVE:
_persistent=true;
break;
default: // No match, may be multi valued
{
for (String v : _valueString.toString().split(","))
{
HttpHeaderValue val=HttpHeaderValue.CACHE.get(v.trim());
switch(val==null?HttpHeaderValue.UNKNOWN:val)
{
case CLOSE:
_persistent=false;
break;
case KEEP_ALIVE:
_persistent=true;
break;
}
}
break;
}
}
}
}
@ -634,24 +590,23 @@ public class HttpParser
{
case EOF_CONTENT:
_state=State.EOF_CONTENT;
_persistent=false;
return_from_parse|=_handler.headerComplete(true,_persistent);
return_from_parse|=_handler.headerComplete();
break;
case CHUNKED_CONTENT:
_state=State.CHUNKED_CONTENT;
return_from_parse|=_handler.headerComplete(true,_persistent);
return_from_parse|=_handler.headerComplete();
break;
case NO_CONTENT:
return_from_parse|=_handler.headerComplete(false,_persistent);
return_from_parse|=_handler.headerComplete();
_state=State.END;
return_from_parse|=_handler.messageComplete(_contentPosition);
break;
default:
_state=State.CONTENT;
return_from_parse|=_handler.headerComplete(true,_persistent);
return_from_parse|=_handler.headerComplete();
break;
}
}
@ -1103,7 +1058,6 @@ public class HttpParser
private void badMessage(ByteBuffer buffer, String reason)
{
BufferUtil.clear(buffer);
_persistent=false;
_state=State.END;
_handler.badMessage(400, reason);
}
@ -1111,8 +1065,6 @@ public class HttpParser
/* ------------------------------------------------------------------------------- */
public void inputShutdown()
{
_persistent=false;
// was this unexpected?
switch(_state)
{
@ -1139,15 +1091,18 @@ public class HttpParser
{
if (_state!=State.END && _state!=State.CLOSED)
LOG.warn("Closing {}",this);
_persistent=false;
reset();
_state=State.CLOSED;
_endOfContent=EndOfContent.UNKNOWN_CONTENT;
_contentPosition=0;
_responseStatus=0;
_contentChunk=null;
}
/* ------------------------------------------------------------------------------- */
public void reset()
{
// reset state
_state=_persistent?State.START:State.CLOSED;
_state=State.START;
_endOfContent=EndOfContent.UNKNOWN_CONTENT;
_contentPosition=0;
_responseStatus=0;
@ -1159,19 +1114,16 @@ public class HttpParser
{
this._state=state;
_endOfContent=EndOfContent.UNKNOWN_CONTENT;
if (state==State.CLOSED)
_persistent=false;
}
/* ------------------------------------------------------------------------------- */
@Override
public String toString()
{
return String.format("%s{s=%s,c=%d,p=%b}",
return String.format("%s{s=%s,c=%d}",
getClass().getSimpleName(),
_state,
_contentLength,
_persistent);
_contentLength);
}
/* ------------------------------------------------------------ */
@ -1185,7 +1137,7 @@ public class HttpParser
{
public boolean content(ByteBuffer ref);
public boolean headerComplete(boolean hasBody,boolean persistent);
public boolean headerComplete();
public boolean messageComplete(long contentLength);

View File

@ -112,10 +112,9 @@ public class HttpTester
}
@Override
public boolean headerComplete(boolean hasBody, boolean persistent)
public boolean headerComplete()
{
if (hasBody)
_content=new ByteArrayOutputStream();
_content=new ByteArrayOutputStream();
return false;
}

View File

@ -587,6 +587,55 @@ public class HttpURI
return new String(_raw,_path,length,_charset);
return new String(bytes,0,n,_charset);
}
public String getDecodedPath(String encoding)
{
if (_path==_param)
return null;
int length = _param-_path;
byte[] bytes=null;
int n=0;
for (int i=_path;i<_param;i++)
{
byte b = _raw[i];
if (b=='%')
{
if ((i+2)>=_param)
throw new IllegalArgumentException("Bad % encoding: "+this);
b=(byte)(0xff&TypeUtil.parseInt(_raw,i+1,2,16));
i+=2;
}
else if (bytes==null)
{
n++;
continue;
}
if (bytes==null)
{
bytes=new byte[length];
System.arraycopy(_raw,_path,bytes,0,n);
}
bytes[n++]=b;
}
if (bytes==null)
return StringUtil.toString(_raw,_path,_param-_path,encoding);
return StringUtil.toString(bytes,0,n,encoding);
}
public String getPathAndParam()
{

View File

@ -436,4 +436,25 @@ public class HttpFieldsTest
}
@Test
public void testContains() throws Exception
{
HttpFields header = new HttpFields();
header.add("0", "");
header.add("1", ",");
header.add("2", ",,");
header.add("3", "abc");
header.add("4", "def");
header.add("5", "abc,def,hig");
header.add("6", "abc");
header.add("6", "def");
header.add("6", "hig");
for (int i=0;i<7;i++)
{
assertFalse(""+i,header.getField(""+i).contains("xyz"));
assertEquals(""+i,i>=4,header.getField(""+i).contains("def"));
}
}
}

View File

@ -60,7 +60,7 @@ public class HttpGeneratorServerTest
}
@Override
public boolean headerComplete(boolean hasBody,boolean persistent)
public boolean headerComplete()
{
_content= null;
return false;

View File

@ -735,7 +735,7 @@ public class HttpParserTest
}
@Override
public boolean headerComplete(boolean hasBody,boolean persistent)
public boolean headerComplete()
{
//System.err.println("headerComplete");
_content= null;

View File

@ -23,16 +23,20 @@ import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import org.eclipse.jetty.security.authentication.DeferredAuthentication;
import org.eclipse.jetty.server.Authentication;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandler.Context;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.server.session.AbstractSessionManager;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -285,6 +289,33 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
getInitParameter(name)==null)
setInitParameter(name,context.getInitParameter(name));
}
//register a session listener to handle securing sessions when authentication is performed
context.getContextHandler().addEventListener(new HttpSessionListener()
{
public void sessionDestroyed(HttpSessionEvent se)
{
}
public void sessionCreated(HttpSessionEvent se)
{
//if current request is authenticated, then as we have just created the session, mark it as secure, as it has not yet been returned to a user
HttpChannel channel = HttpChannel.getCurrentHttpChannel();
if (channel == null)
return;
Request request = channel.getRequest();
if (request == null)
return;
if (request.isSecure())
{
se.getSession().setAttribute(AbstractSessionManager.SESSION_KNOWN_ONLY_TO_AUTHENTICATED, Boolean.TRUE);
}
}
});
}
// complicated resolution of login and identity service to handle

View File

@ -83,7 +83,7 @@ public class BasicAuthenticator extends LoginAuthenticator
UserIdentity user = _loginService.login(username,password);
if (user!=null)
{
renewSessionOnAuthentication(request,response);
renewSession(request,response);
return new UserAuthentication(getAuthMethod(),user);
}
}

View File

@ -119,7 +119,7 @@ public class ClientCertAuthenticator extends LoginAuthenticator
UserIdentity user = _loginService.login(username,credential);
if (user!=null)
{
renewSessionOnAuthentication(request,response);
renewSession(request,response);
return new UserAuthentication(getAuthMethod(),user);
}
}

View File

@ -183,7 +183,7 @@ public class DigestAuthenticator extends LoginAuthenticator
UserIdentity user = _loginService.login(digest.username,digest);
if (user!=null)
{
renewSessionOnAuthentication(request,response);
renewSession(request,response);
return new UserAuthentication(getAuthMethod(),user);
}
}

View File

@ -189,8 +189,8 @@ public class FormAuthenticator extends LoginAuthenticator
if (!mandatory)
return _deferred;
if (isLoginOrErrorPage(URIUtil.addPaths(request.getServletPath(),request.getPathInfo())))
return Authentication.NOT_CHECKED;
if (isLoginOrErrorPage(URIUtil.addPaths(request.getServletPath(),request.getPathInfo())) &&!DeferredAuthentication.isDeferred(response))
return _deferred;
HttpSession session = request.getSession(true);
@ -205,7 +205,7 @@ public class FormAuthenticator extends LoginAuthenticator
UserIdentity user = _loginService.login(username,password);
if (user!=null)
{
session=renewSessionOnAuthentication(request,response);
session=renewSession(request,response);
// Redirect to original request
String nuri;

View File

@ -13,10 +13,6 @@
package org.eclipse.jetty.security.authentication;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@ -24,10 +20,10 @@ import javax.servlet.http.HttpSession;
import org.eclipse.jetty.security.Authenticator;
import org.eclipse.jetty.security.IdentityService;
import org.eclipse.jetty.security.LoginService;
import org.eclipse.jetty.server.session.AbstractSessionManager;
public abstract class LoginAuthenticator implements Authenticator
{
public final static String SESSION_SECURED="org.eclipse.jetty.security.secured";
protected final DeferredAuthentication _deferred=new DeferredAuthentication(this);
protected LoginService _loginService;
protected IdentityService _identityService;
@ -53,34 +49,29 @@ public abstract class LoginAuthenticator implements Authenticator
return _loginService;
}
/* ------------------------------------------------------------ */
/** Change the session when the request is authenticated for the first time
/** Change the session id.
* The session is changed to a new instance with a new ID if and only if:<ul>
* <li>A session exists.
* <li>The {@link AuthConfiguration#isSessionRenewedOnAuthentication()} returns true.
* <li>The session ID has been given to unauthenticated responses
* </ul>
* @param request
* @param response
* @return The new session.
*/
protected HttpSession renewSessionOnAuthentication(HttpServletRequest request, HttpServletResponse response)
protected HttpSession renewSession(HttpServletRequest request, HttpServletResponse response)
{
HttpSession httpSession = request.getSession(false);
if (_renewSession && httpSession!=null && httpSession.getAttribute(SESSION_SECURED)==null)
//if we should renew sessions, and there is an existing session that may have been seen by non-authenticated users
//(indicated by SESSION_SECURED not being set on the session) then we should change id
if (_renewSession && httpSession!=null && httpSession.getAttribute(AbstractSessionManager.SESSION_KNOWN_ONLY_TO_AUTHENTICATED)!=Boolean.TRUE)
{
synchronized (this)
{
Map<String,Object> attributes = new HashMap<String, Object>();
for (Enumeration<String> e=httpSession.getAttributeNames();e.hasMoreElements();)
{
String name=e.nextElement();
attributes.put(name,httpSession.getAttribute(name));
httpSession.removeAttribute(name);
}
httpSession.invalidate();
httpSession = request.getSession(true);
httpSession.setAttribute(SESSION_SECURED,Boolean.TRUE);
for (Map.Entry<String, Object> entry: attributes.entrySet())
httpSession.setAttribute(entry.getKey(),entry.getValue());
httpSession = AbstractSessionManager.renewSession(request, httpSession,true);
}
}
return httpSession;
}
}

View File

@ -29,6 +29,7 @@ import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.server.Authentication;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.server.UserIdentity.Scope;
import org.eclipse.jetty.server.session.AbstractSessionManager;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -102,7 +103,7 @@ public class SessionAuthentication implements Authentication.User, Serializable,
if (security!=null)
security.logout(this);
if (_session!=null)
_session.removeAttribute(LoginAuthenticator.SESSION_SECURED);
_session.removeAttribute(AbstractSessionManager.SESSION_KNOWN_ONLY_TO_AUTHENTICATED);
}
@Override

View File

@ -500,14 +500,17 @@ public abstract class HttpChannel
}
@Override
public boolean headerComplete(boolean hasBody,boolean persistent)
public boolean headerComplete()
{
_requests++;
boolean persistent;
switch (_version)
{
case HTTP_0_9:
persistent=false;
break;
case HTTP_1_0:
persistent=_request.getHttpFields().contains(HttpHeader.CONNECTION,HttpHeaderValue.KEEP_ALIVE.asString());
if (persistent)
_response.getHttpFields().add(HttpHeader.CONNECTION,HttpHeaderValue.KEEP_ALIVE);
@ -516,7 +519,8 @@ public abstract class HttpChannel
break;
case HTTP_1_1:
persistent=!_request.getHttpFields().contains(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE.asString());
if (!persistent)
_response.getHttpFields().add(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE);
@ -537,7 +541,10 @@ public abstract class HttpChannel
break;
default:
throw new IllegalStateException();
}
_request.setPersistent(persistent);
// Either handle now or wait for first content/message complete
if (_expect100Continue)

View File

@ -252,16 +252,19 @@ public class HttpConnection extends AbstractConnection
// Parse the buffer
if (_parser.parseNext(_requestBuffer))
{
// reset header count
_headerBytes=0;
// For most requests, there will not be a body, so we can try to recycle the buffer now
releaseRequestBuffer();
_headerBytes=0;
if (!_channel.getRequest().isPersistent())
_generator.setPersistent(false);
// The parser returned true, which indicates the channel is ready
// to handle a request. Call the channel and this will either handle the
// request/response to completion OR if the request suspends, the channel
// will be left in !idle state so our outer loop will exit.
if (!_parser.isPersistent())
_generator.setPersistent(false);
_channel.handle();
// Return if the channel is still processing the request

View File

@ -159,6 +159,7 @@ public class Request implements HttpServletRequest
private SessionManager _sessionManager;
private long _timeStamp;
private long _dispatchTime;
private boolean _persistent;
private HttpURI _uri;
@ -184,7 +185,19 @@ public class Request implements HttpServletRequest
{
return _in;
}
/* ------------------------------------------------------------ */
public boolean isPersistent()
{
return _persistent;
}
/* ------------------------------------------------------------ */
public void setPersistent(boolean persistent)
{
_persistent = persistent;
}
/* ------------------------------------------------------------ */
public void addEventListener(final EventListener listener)
{

View File

@ -37,6 +37,7 @@ import org.eclipse.jetty.util.ByteArrayISO8859Writer;
public class ErrorHandler extends AbstractHandler
{
boolean _showStacks=true;
boolean _showMessageInTitle=true;
String _cacheControl="must-revalidate,no-cache,no-store";
/* ------------------------------------------------------------ */
@ -86,12 +87,16 @@ public class ErrorHandler extends AbstractHandler
/* ------------------------------------------------------------ */
protected void writeErrorPageHead(HttpServletRequest request, Writer writer, int code, String message)
throws IOException
{
{
writer.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\"/>\n");
writer.write("<title>Error ");
writer.write(Integer.toString(code));
writer.write(' ');
write(writer,message);
if (_showMessageInTitle)
{
writer.write(' ');
write(writer,message);
}
writer.write("</title>\n");
}
@ -175,6 +180,22 @@ public class ErrorHandler extends AbstractHandler
{
_showStacks = showStacks;
}
/* ------------------------------------------------------------ */
/**
* @param showMessageInTitle if true, the error message appears in page title
*/
public void setShowMessageInTitle(boolean showMessageInTitle)
{
_showMessageInTitle = showMessageInTitle;
}
/* ------------------------------------------------------------ */
public boolean getShowMessageInTitle()
{
return _showMessageInTitle;
}
/* ------------------------------------------------------------ */
protected void write(Writer writer,String string)

View File

@ -20,6 +20,7 @@ import java.util.Collections;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.HashSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -69,6 +70,8 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement
new HashSet<SessionTrackingMode>(
Arrays.asList(new SessionTrackingMode[]{SessionTrackingMode.COOKIE,SessionTrackingMode.URL})));
public final static String SESSION_KNOWN_ONLY_TO_AUTHENTICATED="org.eclipse.jetty.security.sessionKnownOnlytoAuthenticated";
/* ------------------------------------------------------------ */
public final static int __distantFuture=60*60*24*7*52*20;
@ -121,6 +124,28 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement
protected final CounterStatistic _sessionsStats = new CounterStatistic();
protected final SampleStatistic _sessionTimeStats = new SampleStatistic();
/* ------------------------------------------------------------ */
public static HttpSession renewSession (HttpServletRequest request, HttpSession httpSession, boolean authenticated)
{
Map<String,Object> attributes = new HashMap<String, Object>();
for (Enumeration<String> e=httpSession.getAttributeNames();e.hasMoreElements();)
{
String name=e.nextElement();
attributes.put(name,httpSession.getAttribute(name));
httpSession.removeAttribute(name);
}
httpSession.invalidate();
httpSession = request.getSession(true);
if (authenticated)
httpSession.setAttribute(SESSION_KNOWN_ONLY_TO_AUTHENTICATED, Boolean.TRUE);
for (Map.Entry<String, Object> entry: attributes.entrySet())
httpSession.setAttribute(entry.getKey(),entry.getValue());
return httpSession;
}
/* ------------------------------------------------------------ */
public AbstractSessionManager()
{

View File

@ -121,6 +121,19 @@ public class HttpConnectionTest
System.err.println(response);
}
}
@Test
public void testNoPath() throws Exception
{
String response=connector.getResponses("GET http://localhost:80 HTTP/1.1\n"+
"Host: localhost:80\n"+
"\n");
int offset=0;
offset = checkContains(response,offset,"HTTP/1.1 200");
checkContains(response,offset,"pathInfo=/");
}
@Test
public void testEmpty() throws Exception
@ -183,9 +196,15 @@ public class HttpConnectionTest
response=connector.getResponses("GET % HTTP/1.1\n"+
"Host: localhost\n"+
"Connection: close\n"+
"Connection: close\n"+
"\015\012");
checkContains(response,0,"HTTP/1.1 400");
checkContains(response,0,"HTTP/1.1 200"); //now fallback to iso-8859-1
response=connector.getResponses("GET /bad/utf8%c1 HTTP/1.1\n"+
"Host: localhost\n"+
"Connection: close\n"+
"\015\012");
checkContains(response,0,"HTTP/1.1 200"); //now fallback to iso-8859-1
}
@Test

View File

@ -182,10 +182,11 @@ public class HttpURITest
private final String[][] encoding_tests=
{
/* 0*/ {"/path/info","/path/info"},
/* 1*/ {"/path/%69nfo","/path/info"},
/* 2*/ {"http://host/path/%69nfo","/path/info"},
/* 3*/ {"http://host/path/%69nf%c2%a4","/path/inf\u00a4"},
/* 0*/ {"/path/info","/path/info", "UTF-8"},
/* 1*/ {"/path/%69nfo","/path/info", "UTF-8"},
/* 2*/ {"http://host/path/%69nfo","/path/info", "UTF-8"},
/* 3*/ {"http://host/path/%69nf%c2%a4","/path/inf\u00a4", "UTF-8"},
/* 4*/ {"http://host/path/%E5", "/path/\u00e5", "ISO-8859-1"}
};
@Test
@ -196,7 +197,7 @@ public class HttpURITest
for (int t=0;t<encoding_tests.length;t++)
{
uri.parse(encoding_tests[t][0]);
assertEquals(""+t,encoding_tests[t][1],uri.getDecodedPath());
assertEquals(""+t,encoding_tests[t][1],uri.getDecodedPath(encoding_tests[t][2]));
}
}

View File

@ -47,7 +47,9 @@ import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.session.HashSessionIdManager;
import org.eclipse.jetty.server.session.HashSessionManager;
import org.eclipse.jetty.server.session.HashedSession;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
@ -585,6 +587,7 @@ public class ResponseTest
{
server.setHandler(new AbstractHandler()
{
@Override
public void handle(String string, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
response.setStatus(200);
@ -607,14 +610,14 @@ public class ResponseTest
LineNumberReader reader = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
String line = reader.readLine();
assertTrue(line!=null && line.startsWith("HTTP/1.1 200 OK"));
Assert.assertThat(line,Matchers.startsWith("HTTP/1.1 200 OK"));
// look for blank line
while (line!=null && line.length()>0)
line = reader.readLine();
// Read the first line of the GET
line = reader.readLine();
assertTrue(line!=null && line.startsWith("HTTP/1.1 200 OK"));
Assert.assertThat(line,Matchers.startsWith("HTTP/1.1 200 OK"));
String last=null;
while (line!=null)

View File

@ -1305,7 +1305,7 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
@Override
public String toString()
{
return String.format("DATA bytes @%x available=%d consumed=%d on %s",dataInfo.hashCode(),dataInfo.available(),dataInfo.consumed(),getStream());
return String.format("DATA bytes @%x available=%d consumed=%d on %s", dataInfo.hashCode(), dataInfo.available(), dataInfo.consumed(), getStream());
}
}

View File

@ -16,10 +16,10 @@ package org.eclipse.jetty.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/* ------------------------------------------------------------ */
/** AttributesMap.
@ -33,7 +33,7 @@ public class AttributesMap implements Attributes
/* ------------------------------------------------------------ */
public AttributesMap()
{
_map=new HashMap<String,Object>();
_map=new ConcurrentHashMap<String,Object>();
}
/* ------------------------------------------------------------ */
@ -45,13 +45,14 @@ public class AttributesMap implements Attributes
/* ------------------------------------------------------------ */
public AttributesMap(AttributesMap map)
{
_map=new HashMap<String,Object>(map._map);
_map=new ConcurrentHashMap<String,Object>(map._map);
}
/* ------------------------------------------------------------ */
/*
* @see org.eclipse.jetty.util.Attributes#removeAttribute(java.lang.String)
*/
@Override
public void removeAttribute(String name)
{
_map.remove(name);
@ -61,6 +62,7 @@ public class AttributesMap implements Attributes
/*
* @see org.eclipse.jetty.util.Attributes#setAttribute(java.lang.String, java.lang.Object)
*/
@Override
public void setAttribute(String name, Object attribute)
{
if (attribute==null)
@ -73,6 +75,7 @@ public class AttributesMap implements Attributes
/*
* @see org.eclipse.jetty.util.Attributes#getAttribute(java.lang.String)
*/
@Override
public Object getAttribute(String name)
{
return _map.get(name);
@ -82,6 +85,7 @@ public class AttributesMap implements Attributes
/*
* @see org.eclipse.jetty.util.Attributes#getAttributeNames()
*/
@Override
public Enumeration<String> getAttributeNames()
{
return Collections.enumeration(_map.keySet());
@ -120,6 +124,7 @@ public class AttributesMap implements Attributes
/*
* @see org.eclipse.jetty.util.Attributes#clear()
*/
@Override
public void clearAttributes()
{
_map.clear();

View File

@ -350,7 +350,7 @@ public class StdErrLog extends AbstractLogger
this._level = LEVEL_DEBUG;
for (Logger log : Log.getLoggers().values())
{
{
if (log.getName().startsWith(getName()) && log instanceof StdErrLog)
((StdErrLog)log).setLevel(LEVEL_DEBUG);
}

View File

@ -0,0 +1,43 @@
//========================================================================
//Copyright 2012 Mort Bay Consulting Pty. Ltd.
//------------------------------------------------------------------------
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//http://www.apache.org/licenses/LICENSE-2.0
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
//========================================================================
package org.eclipse.jetty.util.preventers;
import java.awt.Toolkit;
/**
* AWTLeakPreventer
*
* See https://issues.jboss.org/browse/AS7-3733
*
* The java.awt.Toolkit class has a static field that is the default toolkit.
* Creating the default toolkit causes the creation of an EventQueue, which has a
* classloader field initialized by the thread context class loader.
*
*/
public class AWTLeakPreventer extends AbstractLeakPreventer
{
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.util.preventers.AbstractLeakPreventer#prevent(java.lang.ClassLoader)
*/
@Override
public void prevent(ClassLoader loader)
{
LOG.debug("Pinning classloader for java.awt.EventQueue using "+loader);
Toolkit.getDefaultToolkit();
}
}

View File

@ -0,0 +1,57 @@
// ========================================================================
// Copyright (c) 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.util.preventers;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* AbstractLeakPreventer
*
* Abstract base class for code that seeks to avoid pinning of webapp classloaders by using the jetty classloader to
* proactively call the code that pins them (generally pinned as static data members, or as static
* data members that are daemon threads (which use the context classloader)).
*
* Instances of subclasses of this class should be set with Server.addBean(), which will
* ensure that they are called when the Server instance starts up, which will have the jetty
* classloader in scope.
*
*/
public abstract class AbstractLeakPreventer extends AbstractLifeCycle
{
protected static final Logger LOG = Log.getLogger(AbstractLeakPreventer.class);
/* ------------------------------------------------------------ */
abstract public void prevent(ClassLoader loader);
/* ------------------------------------------------------------ */
@Override
protected void doStart() throws Exception
{
ClassLoader loader = Thread.currentThread().getContextClassLoader();
try
{
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
prevent(getClass().getClassLoader());
super.doStart();
}
finally
{
Thread.currentThread().setContextClassLoader(loader);
}
}
}

View File

@ -0,0 +1,36 @@
// ========================================================================
// Copyright (c) 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.util.preventers;
import javax.imageio.ImageIO;
/**
* AppContextLeakPreventer
*
* Cause the classloader that is pinned by AppContext.getAppContext() to be
* a container or system classloader, not a webapp classloader.
*
* Inspired by Tomcat JreMemoryLeakPrevention.
*/
public class AppContextLeakPreventer extends AbstractLeakPreventer
{
/* ------------------------------------------------------------ */
@Override
public void prevent(ClassLoader loader)
{
LOG.debug("Pinning classloader for AppContext.getContext() with "+loader);
ImageIO.getUseCache();
}
}

View File

@ -0,0 +1,52 @@
//========================================================================
//Copyright 2012 Mort Bay Consulting Pty. Ltd.
//------------------------------------------------------------------------
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//http://www.apache.org/licenses/LICENSE-2.0
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
//========================================================================
package org.eclipse.jetty.util.preventers;
import javax.xml.parsers.DocumentBuilderFactory;
/**
* DOMLeakPreventer
*
* See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6916498
*
* Prevent the RuntimeException that is a static member of AbstractDOMParser
* from pinning a webapp classloader by causing it to be set here by a non-webapp classloader.
*
* Note that according to the bug report, a heap dump may not identify the GCRoot, making
* it difficult to identify the cause of the leak.
*
*/
public class DOMLeakPreventer extends AbstractLeakPreventer
{
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.util.preventers.AbstractLeakPreventer#prevent(java.lang.ClassLoader)
*/
@Override
public void prevent(ClassLoader loader)
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try
{
factory.newDocumentBuilder();
}
catch (Exception e)
{
LOG.warn(e);
}
}
}

View File

@ -0,0 +1,37 @@
// ========================================================================
// Copyright (c) 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.util.preventers;
import java.sql.DriverManager;
/**
* DriverManagerLeakPreventer
*
* Cause DriverManager.getCallerClassLoader() to be called, which will pin the classloader.
*
* Inspired by Tomcat JreMemoryLeakPrevention.
*/
public class DriverManagerLeakPreventer extends AbstractLeakPreventer
{
/* ------------------------------------------------------------ */
@Override
public void prevent(ClassLoader loader)
{
LOG.debug("Pinning DriverManager classloader with "+loader);
DriverManager.getDrivers();
}
}

View File

@ -0,0 +1,60 @@
//========================================================================
//Copyright 2012 Mort Bay Consulting Pty. Ltd.
//------------------------------------------------------------------------
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//http://www.apache.org/licenses/LICENSE-2.0
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
//========================================================================
package org.eclipse.jetty.util.preventers;
import java.lang.reflect.Method;
/**
* GCThreadLeakPreventer
*
* Prevents a call to sun.misc.GC.requestLatency pinning a webapp classloader
* by calling it with a non-webapp classloader. The problem appears to be that
* when this method is called, a daemon thread is created which takes the
* context classloader. A known caller of this method is the RMI impl. See
* http://stackoverflow.com/questions/6626680/does-java-garbage-collection-log-entry-full-gc-system-mean-some-class-called
*
* This preventer will start the thread with the longest possible interval, although
* subsequent calls can vary that. Recommend to only use this class if you're doing
* RMI.
*
* Inspired by Tomcat JreMemoryLeakPrevention.
*
*/
public class GCThreadLeakPreventer extends AbstractLeakPreventer
{
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.util.preventers.AbstractLeakPreventer#prevent(java.lang.ClassLoader)
*/
@Override
public void prevent(ClassLoader loader)
{
try
{
Class clazz = Class.forName("sun.misc.GC");
Method requestLatency = clazz.getMethod("requestLatency", new Class[] {long.class});
requestLatency.invoke(null, Long.valueOf(Long.MAX_VALUE-1));
}
catch (ClassNotFoundException e)
{
LOG.ignore(e);
}
catch (Exception e)
{
LOG.warn(e);
}
}
}

View File

@ -0,0 +1,45 @@
//========================================================================
//Copyright 2012 Mort Bay Consulting Pty. Ltd.
//------------------------------------------------------------------------
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//http://www.apache.org/licenses/LICENSE-2.0
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
//========================================================================
package org.eclipse.jetty.util.preventers;
/**
* Java2DLeakPreventer
*
* Prevent pinning of webapp classloader by pre-loading sun.java2d.Disposer class
* before webapp classloaders are created.
*
* See https://issues.apache.org/bugzilla/show_bug.cgi?id=51687
*
*/
public class Java2DLeakPreventer extends AbstractLeakPreventer
{
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.util.preventers.AbstractLeakPreventer#prevent(java.lang.ClassLoader)
*/
@Override
public void prevent(ClassLoader loader)
{
try
{
Class.forName("sun.java2d.Disposer", true, loader);
}
catch (ClassNotFoundException e)
{
LOG.ignore(e);
}
}
}

View File

@ -0,0 +1,47 @@
//========================================================================
//Copyright 2012 Mort Bay Consulting Pty. Ltd.
//------------------------------------------------------------------------
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//http://www.apache.org/licenses/LICENSE-2.0
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
//========================================================================
package org.eclipse.jetty.util.preventers;
/**
* LDAPLeakPreventer
*
* If com.sun.jndi.LdapPoolManager class is loaded and the system property
* com.sun.jndi.ldap.connect.pool.timeout is set to a nonzero value, a daemon
* thread is started which can pin a webapp classloader if it is the first to
* load the LdapPoolManager.
*
* Inspired by Tomcat JreMemoryLeakPrevention
*
*/
public class LDAPLeakPreventer extends AbstractLeakPreventer
{
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.util.preventers.AbstractLeakPreventer#prevent(java.lang.ClassLoader)
*/
@Override
public void prevent(ClassLoader loader)
{
try
{
Class.forName("com.sun.jndi.LdapPoolManager", true, loader);
}
catch (ClassNotFoundException e)
{
LOG.ignore(e);
}
}
}

View File

@ -0,0 +1,45 @@
//========================================================================
//Copyright 2012 Mort Bay Consulting Pty. Ltd.
//------------------------------------------------------------------------
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//http://www.apache.org/licenses/LICENSE-2.0
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
//========================================================================
package org.eclipse.jetty.util.preventers;
/**
* LoginConfigurationLeakPreventer
*
* The javax.security.auth.login.Configuration class keeps a static reference to the
* thread context classloader. We prevent a webapp context classloader being used for
* that by invoking the classloading here.
*
* Inspired by Tomcat JreMemoryLeakPrevention
*/
public class LoginConfigurationLeakPreventer extends AbstractLeakPreventer
{
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.util.preventers.AbstractLeakPreventer#prevent(java.lang.ClassLoader)
*/
@Override
public void prevent(ClassLoader loader)
{
try
{
Class.forName("javax.security.auth.login.Configuration", true, loader);
}
catch (ClassNotFoundException e)
{
LOG.warn(e);
}
}
}

View File

@ -0,0 +1,40 @@
//========================================================================
//Copyright 2012 Mort Bay Consulting Pty. Ltd.
//------------------------------------------------------------------------
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//http://www.apache.org/licenses/LICENSE-2.0
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
//========================================================================
package org.eclipse.jetty.util.preventers;
import java.security.Security;
/**
* SecurityProviderLeakPreventer
*
* Some security providers, such as sun.security.pkcs11.SunPKCS11 start a deamon thread,
* which will use the thread context classloader. Load them here to ensure the classloader
* is not a webapp classloader.
*
* Inspired by Tomcat JreMemoryLeakPrevention
*/
public class SecurityProviderLeakPreventer extends AbstractLeakPreventer
{
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.util.preventers.AbstractLeakPreventer#prevent(java.lang.ClassLoader)
*/
@Override
public void prevent(ClassLoader loader)
{
Security.getProviders();
}
}

View File

@ -19,6 +19,7 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@ -108,7 +109,7 @@ class JarFileResource extends JarResource
/* ------------------------------------------------------------ */
/**
* Returns true if the respresenetd resource exists.
* Returns true if the represented resource exists.
*/
@Override
public boolean exists()
@ -240,68 +241,102 @@ class JarFileResource extends JarResource
@Override
public synchronized String[] list()
{
if(isDirectory() && _list==null)
if (isDirectory() && _list==null)
{
ArrayList<String> list = new ArrayList<>(32);
List<String> list = null;
try
{
list = listEntries();
}
catch (Exception e)
{
//Sun's JarURLConnection impl for jar: protocol will close a JarFile in its connect() method if
//useCaches == false (eg someone called URLConnection with defaultUseCaches==true).
//As their sun.net.www.protocol.jar package caches JarFiles and/or connections, we can wind up in
//the situation where the JarFile we have remembered in our _jarFile member has actually been closed
//by other code.
//So, do one retry to drop a connection and get a fresh JarFile
LOG.warn("Retrying list:"+e);
LOG.debug(e);
release();
list = listEntries();
}
checkConnection();
JarFile jarFile=_jarFile;
if(jarFile==null)
if (list != null)
{
try
{
JarURLConnection jc=(JarURLConnection)((new URL(_jarUrl)).openConnection());
jc.setUseCaches(getUseCaches());
jarFile=jc.getJarFile();
}
catch(Exception e)
{
LOG.ignore(e);
}
if(jarFile==null)
throw new IllegalStateException();
}
Enumeration<JarEntry> e=jarFile.entries();
String dir=_urlString.substring(_urlString.indexOf("!/")+2);
while(e.hasMoreElements())
{
JarEntry entry = e.nextElement();
String name=entry.getName().replace('\\','/');
if(!name.startsWith(dir) || name.length()==dir.length())
{
continue;
}
String listName=name.substring(dir.length());
int dash=listName.indexOf('/');
if (dash>=0)
{
//when listing jar:file urls, you get back one
//entry for the dir itself, which we ignore
if (dash==0 && listName.length()==1)
continue;
//when listing jar:file urls, all files and
//subdirs have a leading /, which we remove
if (dash==0)
listName=listName.substring(dash+1, listName.length());
else
listName=listName.substring(0,dash+1);
if (list.contains(listName))
continue;
}
list.add(listName);
}
_list=new String[list.size()];
list.toArray(_list);
_list=new String[list.size()];
list.toArray(_list);
}
}
return _list;
}
/* ------------------------------------------------------------ */
private List<String> listEntries ()
{
checkConnection();
ArrayList<String> list = new ArrayList<String>(32);
JarFile jarFile=_jarFile;
if(jarFile==null)
{
try
{
JarURLConnection jc=(JarURLConnection)((new URL(_jarUrl)).openConnection());
jc.setUseCaches(getUseCaches());
jarFile=jc.getJarFile();
}
catch(Exception e)
{
e.printStackTrace();
LOG.ignore(e);
}
if(jarFile==null)
throw new IllegalStateException();
}
Enumeration e=jarFile.entries();
String dir=_urlString.substring(_urlString.indexOf("!/")+2);
while(e.hasMoreElements())
{
JarEntry entry = (JarEntry) e.nextElement();
String name=entry.getName().replace('\\','/');
if(!name.startsWith(dir) || name.length()==dir.length())
{
continue;
}
String listName=name.substring(dir.length());
int dash=listName.indexOf('/');
if (dash>=0)
{
//when listing jar:file urls, you get back one
//entry for the dir itself, which we ignore
if (dash==0 && listName.length()==1)
continue;
//when listing jar:file urls, all files and
//subdirs have a leading /, which we remove
if (dash==0)
listName=listName.substring(dash+1, listName.length());
else
listName=listName.substring(0,dash+1);
if (list.contains(listName))
continue;
}
list.add(listName);
}
return list;
}
/* ------------------------------------------------------------ */
/**
* Return the length of the resource

View File

@ -77,18 +77,28 @@ public class StdErrLogTest
log.debug("YOU SHOULD NOT SEE THIS!",null,null);
// Test for backward compat with old (now deprecated) method
Logger before = log.getLogger("before");
log.setDebugEnabled(true);
Logger after = log.getLogger("after");
before.debug("testing {} {}","test","debug-before");
log.debug("testing {} {}","test","debug-deprecated");
after.debug("testing {} {}","test","debug-after");
log.setDebugEnabled(false);
before.debug("testing {} {}","test","debug-before-false");
log.debug("testing {} {}","test","debug-deprecated-false");
after.debug("testing {} {}","test","debug-after-false");
output.assertContains("DBUG:xxx:tname: testing test debug");
output.assertContains("INFO:xxx:tname: testing test info");
output.assertContains("WARN:xxx:tname: testing test warn");
output.assertNotContains("YOU SHOULD NOT SEE THIS!");
output.assertContains("DBUG:xxx:tname: testing test debug-deprecated");
output.assertContains("DBUG:x.before:tname:testing test debug-before");
output.assertNotContains("DBUG:xxx:tname: testing test debug-depdeprecated-false");
output.assertContains("DBUG:x.after:testing test debug-after");
output.assertNotContains("DBUG:x.before:tname:testing test debug-before-false");
output.assertNotContains("DBUG:xxx:tname:testing test debug-deprecated-false");
output.assertNotContains("DBUG:x.after:tname:testing test debug-after-false");
}
@Test

44
pom.xml
View File

@ -51,7 +51,7 @@
</goals>
<configuration>
<resourceBundles>
<resourceBundle>org.eclipse.jetty.toolchain:jetty-artifact-remote-resources:1.0</resourceBundle>
<resourceBundle>org.eclipse.jetty.toolchain:jetty-artifact-remote-resources:1.1</resourceBundle>
</resourceBundles>
</configuration>
</execution>
@ -623,5 +623,47 @@
</plugins>
</build>
</profile>
<profile>
<id>license-check</id>
<build>
<plugins>
<plugin>
<inherited>false</inherited>
<groupId>com.mycila.maven-license-plugin</groupId>
<artifactId>maven-license-plugin</artifactId>
<version>1.10.b1</version>
<configuration>
<header>header-template.txt</header>
<failIfMissing>true</failIfMissing>
<aggregate>true</aggregate>
<strictCheck>true</strictCheck>
<properties>
<copyright-range>${project.inceptionYear}-2012</copyright-range>
</properties>
<mapping>
<java>DOUBLESLASH_STYLE</java>
</mapping>
<includes>
<include>**/*.java</include>
</includes>
<excludes>
<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/PolicyFileScanner.java</exclude>
</excludes>
</configuration>
<executions>
<execution>
<id>check-headers</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>