Merge branch 'jetty-9' of ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project into jetty-9
This commit is contained in:
commit
71dd5322c7
|
@ -236,10 +236,8 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
_constraintMap.clear();
|
||||
_constraintMappings.clear();
|
||||
_roles.clear();
|
||||
super.doStop();
|
||||
_constraintMap.clear();
|
||||
}
|
||||
|
||||
protected void processConstraintMapping(ConstraintMapping mapping)
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.eclipse.jetty.server.Authentication.User;
|
|||
import org.eclipse.jetty.server.HttpChannel;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
import org.eclipse.jetty.server.session.HashedSession;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
|
@ -139,6 +140,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String getAuthMethod()
|
||||
{
|
||||
return Constraint.__FORM_AUTH;
|
||||
|
@ -182,6 +184,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException
|
||||
{
|
||||
HttpServletRequest request = (HttpServletRequest)req;
|
||||
|
@ -206,31 +209,36 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
{
|
||||
final String username = request.getParameter(__J_USERNAME);
|
||||
final String password = request.getParameter(__J_PASSWORD);
|
||||
|
||||
|
||||
UserIdentity user = _loginService.login(username,password);
|
||||
LOG.debug("jsecuritycheck {} {}",username,user);
|
||||
if (user!=null)
|
||||
{
|
||||
session=renewSession(request,response);
|
||||
|
||||
// Redirect to original request
|
||||
String nuri;
|
||||
FormAuthentication form_auth;
|
||||
synchronized(session)
|
||||
{
|
||||
nuri = (String) session.getAttribute(__J_URI);
|
||||
}
|
||||
|
||||
if (nuri == null || nuri.length() == 0)
|
||||
{
|
||||
nuri = request.getContextPath();
|
||||
if (nuri.length() == 0)
|
||||
nuri = URIUtil.SLASH;
|
||||
if (nuri == null || nuri.length() == 0)
|
||||
{
|
||||
nuri = request.getContextPath();
|
||||
if (nuri.length() == 0)
|
||||
nuri = URIUtil.SLASH;
|
||||
}
|
||||
|
||||
Authentication cached=new SessionAuthentication(getAuthMethod(),user,password);
|
||||
session.setAttribute(SessionAuthentication.__J_AUTHENTICATED, cached);
|
||||
form_auth = new FormAuthentication(getAuthMethod(),user);
|
||||
}
|
||||
LOG.debug("authenticated {}->{}",form_auth,nuri);
|
||||
|
||||
response.setContentLength(0);
|
||||
response.sendRedirect(response.encodeRedirectURL(nuri));
|
||||
|
||||
Authentication cached=new SessionAuthentication(getAuthMethod(),user,password);
|
||||
session.setAttribute(SessionAuthentication.__J_AUTHENTICATED, cached);
|
||||
return new FormAuthentication(getAuthMethod(),user);
|
||||
return form_auth;
|
||||
}
|
||||
|
||||
// not authenticated
|
||||
|
@ -238,11 +246,13 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
LOG.debug("Form authentication FAILED for " + StringUtil.printable(username));
|
||||
if (_formErrorPage == null)
|
||||
{
|
||||
LOG.debug("auth failed {}->403",username);
|
||||
if (response != null)
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN);
|
||||
}
|
||||
else if (_dispatch)
|
||||
{
|
||||
LOG.debug("auth failed {}=={}",username,_formErrorPage);
|
||||
RequestDispatcher dispatcher = request.getRequestDispatcher(_formErrorPage);
|
||||
response.setHeader(HttpHeader.CACHE_CONTROL.asString(),HttpHeaderValue.NO_CACHE.asString());
|
||||
response.setDateHeader(HttpHeader.EXPIRES.asString(),1);
|
||||
|
@ -250,6 +260,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
}
|
||||
else
|
||||
{
|
||||
LOG.debug("auth failed {}->{}",username,_formErrorPage);
|
||||
response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(request.getContextPath(),_formErrorPage)));
|
||||
}
|
||||
|
||||
|
@ -265,43 +276,51 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
_loginService!=null &&
|
||||
!_loginService.validate(((Authentication.User)authentication).getUserIdentity()))
|
||||
{
|
||||
|
||||
LOG.debug("auth revoked {}",authentication);
|
||||
session.removeAttribute(SessionAuthentication.__J_AUTHENTICATED);
|
||||
}
|
||||
else
|
||||
{
|
||||
String j_uri=(String)session.getAttribute(__J_URI);
|
||||
if (j_uri!=null)
|
||||
synchronized (session)
|
||||
{
|
||||
MultiMap j_post = (MultiMap)session.getAttribute(__J_POST);
|
||||
if (j_post!=null)
|
||||
String j_uri=(String)session.getAttribute(__J_URI);
|
||||
if (j_uri!=null)
|
||||
{
|
||||
StringBuffer buf = request.getRequestURL();
|
||||
if (request.getQueryString() != null)
|
||||
buf.append("?").append(request.getQueryString());
|
||||
|
||||
if (j_uri.equals(buf.toString()))
|
||||
LOG.debug("auth retry {}->{}",authentication,j_uri);
|
||||
MultiMap<String> j_post = (MultiMap<String>)session.getAttribute(__J_POST);
|
||||
if (j_post!=null)
|
||||
{
|
||||
// This is a retry of an original POST request
|
||||
// so restore method and parameters
|
||||
LOG.debug("auth rePOST {}->{}",authentication,j_uri);
|
||||
StringBuffer buf = request.getRequestURL();
|
||||
if (request.getQueryString() != null)
|
||||
buf.append("?").append(request.getQueryString());
|
||||
|
||||
session.removeAttribute(__J_POST);
|
||||
Request base_request = HttpChannel.getCurrentHttpChannel().getRequest();
|
||||
base_request.setMethod(HttpMethod.POST,HttpMethod.POST.asString());
|
||||
base_request.setParameters(j_post);
|
||||
if (j_uri.equals(buf.toString()))
|
||||
{
|
||||
// This is a retry of an original POST request
|
||||
// so restore method and parameters
|
||||
|
||||
session.removeAttribute(__J_POST);
|
||||
Request base_request = HttpChannel.getCurrentHttpChannel().getRequest();
|
||||
base_request.setMethod(HttpMethod.POST,HttpMethod.POST.asString());
|
||||
base_request.setParameters(j_post);
|
||||
}
|
||||
}
|
||||
else
|
||||
session.removeAttribute(__J_URI);
|
||||
}
|
||||
else
|
||||
session.removeAttribute(__J_URI);
|
||||
|
||||
}
|
||||
LOG.debug("auth {}",authentication);
|
||||
return authentication;
|
||||
}
|
||||
}
|
||||
|
||||
// if we can't send challenge
|
||||
if (DeferredAuthentication.isDeferred(response))
|
||||
{
|
||||
LOG.debug("auth deferred {}",session.getId());
|
||||
return Authentication.UNAUTHENTICATED;
|
||||
}
|
||||
|
||||
// remember the current URI
|
||||
synchronized (session)
|
||||
|
@ -318,7 +337,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
{
|
||||
Request base_request = (req instanceof Request)?(Request)req:HttpChannel.getCurrentHttpChannel().getRequest();
|
||||
base_request.extractParameters();
|
||||
session.setAttribute(__J_POST, new MultiMap(base_request.getParameters()));
|
||||
session.setAttribute(__J_POST, new MultiMap<String>(base_request.getParameters()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -326,6 +345,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
// send the the challenge
|
||||
if (_dispatch)
|
||||
{
|
||||
LOG.debug("challenge {}=={}",session.getId(),_formLoginPage);
|
||||
RequestDispatcher dispatcher = request.getRequestDispatcher(_formLoginPage);
|
||||
response.setHeader(HttpHeader.CACHE_CONTROL.asString(),HttpHeaderValue.NO_CACHE.asString());
|
||||
response.setDateHeader(HttpHeader.EXPIRES.asString(),1);
|
||||
|
@ -333,11 +353,10 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
}
|
||||
else
|
||||
{
|
||||
LOG.debug("challenge {}->{}",session.getId(),_formLoginPage);
|
||||
response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(request.getContextPath(),_formLoginPage)));
|
||||
}
|
||||
return Authentication.SEND_CONTINUE;
|
||||
|
||||
|
||||
}
|
||||
catch (IOException | ServletException e)
|
||||
{
|
||||
|
@ -366,6 +385,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public boolean secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, User validatedUser) throws ServerAuthException
|
||||
{
|
||||
return true;
|
||||
|
|
|
@ -26,9 +26,15 @@ 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;
|
||||
import org.eclipse.jetty.server.session.HashSessionManager;
|
||||
import org.eclipse.jetty.server.session.HashedSession;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public abstract class LoginAuthenticator implements Authenticator
|
||||
{
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(LoginAuthenticator.class);
|
||||
|
||||
protected final DeferredAuthentication _deferred=new DeferredAuthentication(this);
|
||||
protected LoginService _loginService;
|
||||
protected IdentityService _identityService;
|
||||
|
@ -67,14 +73,19 @@ public abstract class LoginAuthenticator implements Authenticator
|
|||
protected HttpSession renewSession(HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
HttpSession httpSession = request.getSession(false);
|
||||
|
||||
//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)
|
||||
|
||||
if (_renewSession && httpSession!=null)
|
||||
{
|
||||
synchronized (this)
|
||||
synchronized (httpSession)
|
||||
{
|
||||
httpSession = AbstractSessionManager.renewSession(request, httpSession,true);
|
||||
//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 (httpSession.getAttribute(AbstractSessionManager.SESSION_KNOWN_ONLY_TO_AUTHENTICATED)!=Boolean.TRUE)
|
||||
{
|
||||
HttpSession newSession = AbstractSessionManager.renewSession(request, httpSession,true);
|
||||
LOG.debug("renew {}->{}",httpSession.getId(),newSession.getId());
|
||||
httpSession=newSession;
|
||||
}
|
||||
}
|
||||
}
|
||||
return httpSession;
|
||||
|
|
|
@ -114,23 +114,27 @@ public class SessionAuthentication implements Authentication.User, Serializable,
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "Session"+super.toString();
|
||||
return String.format("%s@%x{%s,%s}",this.getClass().getSimpleName(),hashCode(),_session==null?"-":_session.getId(),_userIdentity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionWillPassivate(HttpSessionEvent se)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionDidActivate(HttpSessionEvent se)
|
||||
{
|
||||
if (_session==null)
|
||||
_session=se.getSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void valueBound(HttpSessionBindingEvent event)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void valueUnbound(HttpSessionBindingEvent event)
|
||||
{
|
||||
doLogout();
|
||||
|
|
|
@ -34,6 +34,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.eclipse.jetty.security.authentication.BasicAuthenticator;
|
||||
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
||||
import org.eclipse.jetty.security.authentication.LoginAuthenticator;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
|
@ -44,6 +45,7 @@ import org.eclipse.jetty.server.handler.ContextHandler;
|
|||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||
import org.eclipse.jetty.server.session.SessionHandler;
|
||||
import org.eclipse.jetty.util.B64Code;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.eclipse.jetty.util.security.Password;
|
||||
import org.junit.After;
|
||||
|
@ -777,9 +779,8 @@ public class ConstraintTest
|
|||
_security.setHandler(check);
|
||||
_security.setAuthenticator(new BasicAuthenticator());
|
||||
_security.setStrict(false);
|
||||
_server.start();
|
||||
|
||||
System.out.println(_server.dump());
|
||||
_server.start();
|
||||
|
||||
String response;
|
||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n\r\n", 100000, TimeUnit.MILLISECONDS);
|
||||
|
@ -792,40 +793,12 @@ public class ConstraintTest
|
|||
|
||||
_server.stop();
|
||||
|
||||
/*
|
||||
* FIXME: this seems to indicate there is an issue with the way the server is stopping and starting now
|
||||
*
|
||||
* Note that ConstraintSecurityHandler loses all of its brains when the server starts and stops, but that
|
||||
* change was made in 2/2011 and this wasn't exposed til now, which seems to indicate that previously
|
||||
* when the server stopped that doStop() didn't make it down to the constraint handler...and now it does.
|
||||
*
|
||||
* also, seems to be an issue in local connector, I had to add a new one for it to be able to work here as well
|
||||
* so issues in stop/start there as well
|
||||
*/
|
||||
|
||||
_connector = new LocalConnector(_server);
|
||||
_server.setConnectors(new Connector[]{_connector});
|
||||
ContextHandler _context = new ContextHandler();
|
||||
SessionHandler _session = new SessionHandler();
|
||||
|
||||
_context.setContextPath("/ctx");
|
||||
_server.setHandler(_context);
|
||||
_context.setHandler(_session);
|
||||
|
||||
_security = new ConstraintSecurityHandler();
|
||||
_session.setHandler(_security);
|
||||
RequestHandler _handler = new RequestHandler();
|
||||
_security.setHandler(_handler);
|
||||
|
||||
RoleRefHandler roleref = new RoleRefHandler();
|
||||
roleref.setHandler(_security.getHandler());
|
||||
_security.setHandler(roleref);
|
||||
roleref.setHandler(check);
|
||||
|
||||
_security.setConstraintMappings(getConstraintMappings(),getKnownRoles());
|
||||
|
||||
_server.start();
|
||||
|
||||
System.out.println(_server.dump());
|
||||
_server.start();
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user2:password") + "\r\n" +
|
||||
|
@ -879,6 +852,7 @@ public class ConstraintTest
|
|||
}
|
||||
private class RequestHandler extends AbstractHandler
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
|
@ -910,16 +884,19 @@ public class ConstraintTest
|
|||
|
||||
UserIdentity.Scope scope = new UserIdentity.Scope()
|
||||
{
|
||||
@Override
|
||||
public String getContextPath()
|
||||
{
|
||||
return "/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return "someServlet";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getRoleRefMap()
|
||||
{
|
||||
Map<String, String> map = new HashMap<>();
|
||||
|
@ -943,6 +920,7 @@ public class ConstraintTest
|
|||
|
||||
private class RoleCheckHandler extends AbstractHandler
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException
|
||||
{
|
||||
((Request) request).setHandled(true);
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.Writer;
|
||||
|
||||
import org.eclipse.jetty.util.ByteArrayOutputStream2;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class EncodingHttpWriter extends HttpWriter
|
||||
{
|
||||
final Writer _converter;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public EncodingHttpWriter(HttpOutput out, String encoding)
|
||||
{
|
||||
super(out);
|
||||
try
|
||||
{
|
||||
_converter = new OutputStreamWriter(_bytes, encoding);
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void write (char[] s,int offset, int length) throws IOException
|
||||
{
|
||||
if (length==0)
|
||||
_out.checkAllWritten();
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
_bytes.reset();
|
||||
int chars = length>MAX_OUTPUT_CHARS?MAX_OUTPUT_CHARS:length;
|
||||
|
||||
_converter.write(s, offset, chars);
|
||||
_converter.flush();
|
||||
_bytes.writeTo(_out);
|
||||
length-=chars;
|
||||
offset+=chars;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -433,7 +433,23 @@ public abstract class HttpChannel
|
|||
else
|
||||
_uri.parse(uri);
|
||||
_request.setUri(_uri);
|
||||
_request.setPathInfo(_uri.getDecodedPath());
|
||||
|
||||
String path = null;
|
||||
try
|
||||
{
|
||||
path = _uri.getDecodedPath();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Failed UTF-8 decode for request path, trying ISO-8859-1");
|
||||
LOG.ignore(e);
|
||||
path = _uri.getDecodedPath(StringUtil.__ISO_8859_1);
|
||||
}
|
||||
String info=URIUtil.canonicalPath(path);
|
||||
|
||||
if (info==null)
|
||||
info="/";
|
||||
_request.setPathInfo(info);
|
||||
_version=version==null?HttpVersion.HTTP_0_9:version;
|
||||
_request.setHttpVersion(_version);
|
||||
|
||||
|
|
|
@ -40,13 +40,7 @@ public class HttpOutput extends ServletOutputStream
|
|||
{
|
||||
private final HttpChannel _channel;
|
||||
private boolean _closed;
|
||||
|
||||
// These are held here for reuse by Writer
|
||||
String _characterEncoding;
|
||||
Writer _converter;
|
||||
char[] _chars;
|
||||
ByteArrayOutputStream2 _bytes;
|
||||
long _written;
|
||||
private long _written;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public HttpOutput(HttpChannel channel)
|
||||
|
|
|
@ -19,61 +19,27 @@
|
|||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
|
||||
import org.eclipse.jetty.util.ByteArrayOutputStream2;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
||||
/** OutputWriter.
|
||||
* A writer that can wrap a {@link HttpOutput} stream and provide
|
||||
* character encodings.
|
||||
*
|
||||
* The UTF-8 encoding is done by this class and no additional
|
||||
* buffers or Writers are used.
|
||||
* The UTF-8 code was inspired by http://javolution.org
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class HttpWriter extends Writer
|
||||
public abstract class HttpWriter extends Writer
|
||||
{
|
||||
public static final int MAX_OUTPUT_CHARS = 512;
|
||||
|
||||
private static final int WRITE_CONV = 0;
|
||||
private static final int WRITE_ISO1 = 1;
|
||||
private static final int WRITE_UTF8 = 2;
|
||||
|
||||
final HttpOutput _out;
|
||||
int _writeMode;
|
||||
int _surrogate;
|
||||
final ByteArrayOutputStream2 _bytes;
|
||||
final char[] _chars;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public HttpWriter(HttpOutput out, String encoding)
|
||||
public HttpWriter(HttpOutput out)
|
||||
{
|
||||
_out=out;
|
||||
_surrogate=0; // AS lastUTF16CodePoint
|
||||
setCharacterEncoding(encoding);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setCharacterEncoding(String encoding)
|
||||
{
|
||||
if (encoding == null || StringUtil.__ISO_8859_1.equalsIgnoreCase(encoding))
|
||||
{
|
||||
_writeMode = WRITE_ISO1;
|
||||
}
|
||||
else if (StringUtil.__UTF8.equalsIgnoreCase(encoding))
|
||||
{
|
||||
_writeMode = WRITE_UTF8;
|
||||
}
|
||||
else
|
||||
{
|
||||
_writeMode = WRITE_CONV;
|
||||
if (_out._characterEncoding == null || !_out._characterEncoding.equalsIgnoreCase(encoding))
|
||||
_out._converter = null; // Set lazily in getConverter()
|
||||
}
|
||||
|
||||
_out._characterEncoding = encoding;
|
||||
if (_out._bytes==null)
|
||||
_out._bytes = new ByteArrayOutputStream2(MAX_OUTPUT_CHARS);
|
||||
_chars=new char[MAX_OUTPUT_CHARS];
|
||||
_bytes = new ByteArrayOutputStream2(MAX_OUTPUT_CHARS);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -101,202 +67,14 @@ public class HttpWriter extends Writer
|
|||
length -= MAX_OUTPUT_CHARS;
|
||||
}
|
||||
|
||||
if (_out._chars==null)
|
||||
{
|
||||
_out._chars = new char[MAX_OUTPUT_CHARS];
|
||||
}
|
||||
char[] chars = _out._chars;
|
||||
s.getChars(offset, offset + length, chars, 0);
|
||||
write(chars, 0, length);
|
||||
s.getChars(offset, offset + length, _chars, 0);
|
||||
write(_chars, 0, length);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void write (char[] s,int offset, int length) throws IOException
|
||||
{
|
||||
HttpOutput out = _out;
|
||||
if (length==0)
|
||||
out.checkAllWritten();
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
out._bytes.reset();
|
||||
int chars = length>MAX_OUTPUT_CHARS?MAX_OUTPUT_CHARS:length;
|
||||
|
||||
switch (_writeMode)
|
||||
{
|
||||
case WRITE_CONV:
|
||||
{
|
||||
Writer converter=getConverter();
|
||||
converter.write(s, offset, chars);
|
||||
converter.flush();
|
||||
}
|
||||
break;
|
||||
|
||||
case WRITE_ISO1:
|
||||
{
|
||||
byte[] buffer=out._bytes.getBuf();
|
||||
int bytes=out._bytes.getCount();
|
||||
|
||||
if (chars>buffer.length-bytes)
|
||||
chars=buffer.length-bytes;
|
||||
|
||||
for (int i = 0; i < chars; i++)
|
||||
{
|
||||
int c = s[offset+i];
|
||||
buffer[bytes++]=(byte)(c<256?c:'?'); // ISO-1 and UTF-8 match for 0 - 255
|
||||
}
|
||||
if (bytes>=0)
|
||||
out._bytes.setCount(bytes);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WRITE_UTF8:
|
||||
{
|
||||
byte[] buffer=out._bytes.getBuf();
|
||||
int bytes=out._bytes.getCount();
|
||||
|
||||
if (bytes+chars>buffer.length)
|
||||
chars=buffer.length-bytes;
|
||||
|
||||
for (int i = 0; i < chars; i++)
|
||||
{
|
||||
int code = s[offset+i];
|
||||
|
||||
// Do we already have a surrogate?
|
||||
if(_surrogate==0)
|
||||
{
|
||||
// No - is this char code a surrogate?
|
||||
if(Character.isHighSurrogate((char)code))
|
||||
{
|
||||
_surrogate=code; // UCS-?
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// else handle a low surrogate
|
||||
else if(Character.isLowSurrogate((char)code))
|
||||
{
|
||||
code = Character.toCodePoint((char)_surrogate, (char)code); // UCS-4
|
||||
}
|
||||
// else UCS-2
|
||||
else
|
||||
{
|
||||
code=_surrogate; // UCS-2
|
||||
_surrogate=0; // USED
|
||||
i--;
|
||||
}
|
||||
|
||||
if ((code & 0xffffff80) == 0)
|
||||
{
|
||||
// 1b
|
||||
if (bytes>=buffer.length)
|
||||
{
|
||||
chars=i;
|
||||
break;
|
||||
}
|
||||
buffer[bytes++]=(byte)(code);
|
||||
}
|
||||
else
|
||||
{
|
||||
if((code&0xfffff800)==0)
|
||||
{
|
||||
// 2b
|
||||
if (bytes+2>buffer.length)
|
||||
{
|
||||
chars=i;
|
||||
break;
|
||||
}
|
||||
buffer[bytes++]=(byte)(0xc0|(code>>6));
|
||||
buffer[bytes++]=(byte)(0x80|(code&0x3f));
|
||||
}
|
||||
else if((code&0xffff0000)==0)
|
||||
{
|
||||
// 3b
|
||||
if (bytes+3>buffer.length)
|
||||
{
|
||||
chars=i;
|
||||
break;
|
||||
}
|
||||
buffer[bytes++]=(byte)(0xe0|(code>>12));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|(code&0x3f));
|
||||
}
|
||||
else if((code&0xff200000)==0)
|
||||
{
|
||||
// 4b
|
||||
if (bytes+4>buffer.length)
|
||||
{
|
||||
chars=i;
|
||||
break;
|
||||
}
|
||||
buffer[bytes++]=(byte)(0xf0|(code>>18));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|(code&0x3f));
|
||||
}
|
||||
else if((code&0xf4000000)==0)
|
||||
{
|
||||
// 5b
|
||||
if (bytes+5>buffer.length)
|
||||
{
|
||||
chars=i;
|
||||
break;
|
||||
}
|
||||
buffer[bytes++]=(byte)(0xf8|(code>>24));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>18)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|(code&0x3f));
|
||||
}
|
||||
else if((code&0x80000000)==0)
|
||||
{
|
||||
// 6b
|
||||
if (bytes+6>buffer.length)
|
||||
{
|
||||
chars=i;
|
||||
break;
|
||||
}
|
||||
buffer[bytes++]=(byte)(0xfc|(code>>30));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>24)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>18)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|(code&0x3f));
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[bytes++]=(byte)('?');
|
||||
}
|
||||
|
||||
_surrogate=0; // USED
|
||||
|
||||
if (bytes==buffer.length)
|
||||
{
|
||||
chars=i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
out._bytes.setCount(bytes);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
out._bytes.writeTo(out);
|
||||
length-=chars;
|
||||
offset+=chars;
|
||||
}
|
||||
{
|
||||
throw new AbstractMethodError();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private Writer getConverter() throws IOException
|
||||
{
|
||||
if (_out._converter == null)
|
||||
_out._converter = new OutputStreamWriter(_out._bytes, _out._characterEncoding);
|
||||
return _out._converter;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
|
||||
import org.eclipse.jetty.util.ByteArrayOutputStream2;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class Iso88591HttpWriter extends HttpWriter
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
public Iso88591HttpWriter(HttpOutput out)
|
||||
{
|
||||
super(out);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void write (char[] s,int offset, int length) throws IOException
|
||||
{
|
||||
HttpOutput out = _out;
|
||||
if (length==0)
|
||||
out.checkAllWritten();
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
_bytes.reset();
|
||||
int chars = length>MAX_OUTPUT_CHARS?MAX_OUTPUT_CHARS:length;
|
||||
|
||||
byte[] buffer=_bytes.getBuf();
|
||||
int bytes=_bytes.getCount();
|
||||
|
||||
if (chars>buffer.length-bytes)
|
||||
chars=buffer.length-bytes;
|
||||
|
||||
for (int i = 0; i < chars; i++)
|
||||
{
|
||||
int c = s[offset+i];
|
||||
buffer[bytes++]=(byte)(c<256?c:'?');
|
||||
}
|
||||
if (bytes>=0)
|
||||
_bytes.setCount(bytes);
|
||||
|
||||
_bytes.writeTo(out);
|
||||
length-=chars;
|
||||
offset+=chars;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -802,25 +802,19 @@ public class Response implements HttpServletResponse
|
|||
setCharacterEncoding(encoding);
|
||||
}
|
||||
|
||||
/* construct Writer using correct encoding */
|
||||
// TODO switch on encoding here
|
||||
_writer = new PrintWriter(new HttpWriter(_out,encoding))
|
||||
if (encoding == null || StringUtil.__ISO_8859_1.equalsIgnoreCase(encoding))
|
||||
{
|
||||
public void close()
|
||||
{
|
||||
synchronized (lock)
|
||||
{
|
||||
try
|
||||
{
|
||||
out.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
setError();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
_writer = new PrintWriter(new Iso88591HttpWriter(_out));
|
||||
}
|
||||
else if (StringUtil.__UTF8.equalsIgnoreCase(encoding))
|
||||
{
|
||||
_writer = new PrintWriter(new Utf8HttpWriter(_out));
|
||||
}
|
||||
else
|
||||
{
|
||||
_writer = new PrintWriter(new EncodingHttpWriter(_out,encoding));
|
||||
}
|
||||
|
||||
}
|
||||
_outputState=OutputState.WRITER;
|
||||
return _writer;
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
|
||||
import org.eclipse.jetty.util.ByteArrayOutputStream2;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
||||
/** OutputWriter.
|
||||
* A writer that can wrap a {@link HttpOutput} stream and provide
|
||||
* character encodings.
|
||||
*
|
||||
* The UTF-8 encoding is done by this class and no additional
|
||||
* buffers or Writers are used.
|
||||
* The UTF-8 code was inspired by http://javolution.org
|
||||
*/
|
||||
public class Utf8HttpWriter extends HttpWriter
|
||||
{
|
||||
int _surrogate=0;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Utf8HttpWriter(HttpOutput out)
|
||||
{
|
||||
super(out);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void write (char[] s,int offset, int length) throws IOException
|
||||
{
|
||||
HttpOutput out = _out;
|
||||
if (length==0)
|
||||
out.checkAllWritten();
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
_bytes.reset();
|
||||
int chars = length>MAX_OUTPUT_CHARS?MAX_OUTPUT_CHARS:length;
|
||||
|
||||
byte[] buffer=_bytes.getBuf();
|
||||
int bytes=_bytes.getCount();
|
||||
|
||||
if (bytes+chars>buffer.length)
|
||||
chars=buffer.length-bytes;
|
||||
|
||||
for (int i = 0; i < chars; i++)
|
||||
{
|
||||
int code = s[offset+i];
|
||||
|
||||
// Do we already have a surrogate?
|
||||
if(_surrogate==0)
|
||||
{
|
||||
// No - is this char code a surrogate?
|
||||
if(Character.isHighSurrogate((char)code))
|
||||
{
|
||||
_surrogate=code; // UCS-?
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// else handle a low surrogate
|
||||
else if(Character.isLowSurrogate((char)code))
|
||||
{
|
||||
code = Character.toCodePoint((char)_surrogate, (char)code); // UCS-4
|
||||
}
|
||||
// else UCS-2
|
||||
else
|
||||
{
|
||||
code=_surrogate; // UCS-2
|
||||
_surrogate=0; // USED
|
||||
i--;
|
||||
}
|
||||
|
||||
if ((code & 0xffffff80) == 0)
|
||||
{
|
||||
// 1b
|
||||
if (bytes>=buffer.length)
|
||||
{
|
||||
chars=i;
|
||||
break;
|
||||
}
|
||||
buffer[bytes++]=(byte)(code);
|
||||
}
|
||||
else
|
||||
{
|
||||
if((code&0xfffff800)==0)
|
||||
{
|
||||
// 2b
|
||||
if (bytes+2>buffer.length)
|
||||
{
|
||||
chars=i;
|
||||
break;
|
||||
}
|
||||
buffer[bytes++]=(byte)(0xc0|(code>>6));
|
||||
buffer[bytes++]=(byte)(0x80|(code&0x3f));
|
||||
}
|
||||
else if((code&0xffff0000)==0)
|
||||
{
|
||||
// 3b
|
||||
if (bytes+3>buffer.length)
|
||||
{
|
||||
chars=i;
|
||||
break;
|
||||
}
|
||||
buffer[bytes++]=(byte)(0xe0|(code>>12));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|(code&0x3f));
|
||||
}
|
||||
else if((code&0xff200000)==0)
|
||||
{
|
||||
// 4b
|
||||
if (bytes+4>buffer.length)
|
||||
{
|
||||
chars=i;
|
||||
break;
|
||||
}
|
||||
buffer[bytes++]=(byte)(0xf0|(code>>18));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|(code&0x3f));
|
||||
}
|
||||
else if((code&0xf4000000)==0)
|
||||
{
|
||||
// 5b
|
||||
if (bytes+5>buffer.length)
|
||||
{
|
||||
chars=i;
|
||||
break;
|
||||
}
|
||||
buffer[bytes++]=(byte)(0xf8|(code>>24));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>18)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|(code&0x3f));
|
||||
}
|
||||
else if((code&0x80000000)==0)
|
||||
{
|
||||
// 6b
|
||||
if (bytes+6>buffer.length)
|
||||
{
|
||||
chars=i;
|
||||
break;
|
||||
}
|
||||
buffer[bytes++]=(byte)(0xfc|(code>>30));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>24)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>18)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
|
||||
buffer[bytes++]=(byte)(0x80|(code&0x3f));
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[bytes++]=(byte)('?');
|
||||
}
|
||||
|
||||
_surrogate=0; // USED
|
||||
|
||||
if (bytes==buffer.length)
|
||||
{
|
||||
chars=i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_bytes.setCount(bytes);
|
||||
|
||||
_bytes.writeTo(out);
|
||||
length-=chars;
|
||||
offset+=chars;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -164,13 +164,9 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
|
|||
private Object _requestAttributeListeners;
|
||||
private Map<String, Object> _managedAttributes;
|
||||
private String[] _protectedTargets;
|
||||
|
||||
private boolean _shutdown = false;
|
||||
|
||||
private boolean _available = true;
|
||||
private volatile int _availability; // 0=STOPPED, 1=AVAILABLE, 2=SHUTDOWN, 3=UNAVAILABLE
|
||||
|
||||
private final static int __STOPPED = 0, __AVAILABLE = 1, __SHUTDOWN = 2, __UNAVAILABLE = 3;
|
||||
|
||||
public enum Availability { AVAILABLE,SHUTDOWN,UNAVAILABLE};
|
||||
private volatile Availability _availability;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -629,12 +625,15 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
|
|||
/**
|
||||
* @return true if this context is accepting new requests
|
||||
*/
|
||||
@ManagedAttribute("false if this context is accepting new requests. true for graceful shutdown, which allows existing requests to complete")
|
||||
@ManagedAttribute("true for graceful shutdown, which allows existing requests to complete")
|
||||
public boolean isShutdown()
|
||||
{
|
||||
synchronized (this)
|
||||
switch(_availability)
|
||||
{
|
||||
return !_shutdown;
|
||||
case SHUTDOWN:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -644,13 +643,10 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
|
|||
* requests can complete, but no new requests are accepted.
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void shutdown()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
_shutdown = true;
|
||||
_availability = isRunning() ? __SHUTDOWN : __STOPPED;
|
||||
}
|
||||
_availability = isRunning() ? Availability.SHUTDOWN : Availability.UNAVAILABLE;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -659,10 +655,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
|
|||
*/
|
||||
public boolean isAvailable()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
return _available;
|
||||
}
|
||||
return _availability==Availability.AVAILABLE;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -673,8 +666,10 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
|
|||
{
|
||||
synchronized (this)
|
||||
{
|
||||
_available = available;
|
||||
_availability = isRunning()?(_shutdown?__SHUTDOWN:_available?__AVAILABLE:__UNAVAILABLE):__STOPPED;
|
||||
if (available && isRunning())
|
||||
_availability = Availability.AVAILABLE;
|
||||
else if (!available || !isRunning())
|
||||
_availability = Availability.UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -697,7 +692,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
|
|||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
_availability = __STOPPED;
|
||||
_availability = Availability.UNAVAILABLE;
|
||||
|
||||
if (_contextPath == null)
|
||||
throw new IllegalStateException("Null contextPath");
|
||||
|
@ -726,10 +721,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
|
|||
// defers the calling of super.doStart()
|
||||
startContext();
|
||||
|
||||
synchronized(this)
|
||||
{
|
||||
_availability = _shutdown?__SHUTDOWN:_available?__AVAILABLE:__UNAVAILABLE;
|
||||
}
|
||||
_availability = Availability.AVAILABLE;
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -806,7 +798,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
|
|||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
_availability = __STOPPED;
|
||||
_availability = Availability.UNAVAILABLE;
|
||||
|
||||
ClassLoader old_classloader = null;
|
||||
Thread current_thread = null;
|
||||
|
@ -867,10 +859,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
|
|||
|
||||
switch (_availability)
|
||||
{
|
||||
case __STOPPED:
|
||||
case __SHUTDOWN:
|
||||
return false;
|
||||
case __UNAVAILABLE:
|
||||
case SHUTDOWN:
|
||||
case UNAVAILABLE:
|
||||
baseRequest.setHandled(true);
|
||||
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
|
||||
return false;
|
||||
|
@ -1517,8 +1507,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
|
|||
b.append(s.charAt(0)).append('.');
|
||||
}
|
||||
}
|
||||
b.append(getClass().getSimpleName());
|
||||
b.append('{').append(getContextPath()).append(',').append(getBaseResource());
|
||||
b.append(getClass().getSimpleName()).append('@').append(Integer.toString(hashCode(),16));
|
||||
b.append('{').append(getContextPath()).append(',').append(getBaseResource()).append(',').append(_availability);
|
||||
|
||||
if (vhosts != null && vhosts.length > 0)
|
||||
b.append(',').append(vhosts[0]);
|
||||
|
|
|
@ -64,6 +64,7 @@ public class HandlerWrapper extends AbstractHandlerContainer
|
|||
/**
|
||||
* @return Returns the handlers.
|
||||
*/
|
||||
@Override
|
||||
public Handler[] getHandlers()
|
||||
{
|
||||
if (_handler==null)
|
||||
|
@ -114,6 +115,7 @@ public class HandlerWrapper extends AbstractHandlerContainer
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
if (_handler!=null && isStarted())
|
||||
|
|
|
@ -59,6 +59,7 @@ public class HotSwapHandler extends AbstractHandlerContainer
|
|||
/**
|
||||
* @return Returns the handlers.
|
||||
*/
|
||||
@Override
|
||||
public Handler[] getHandlers()
|
||||
{
|
||||
return new Handler[]
|
||||
|
@ -122,6 +123,7 @@ public class HotSwapHandler extends AbstractHandlerContainer
|
|||
/*
|
||||
* @see org.eclipse.jetty.server.server.EventHandler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
|
||||
*/
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
if (_handler != null && isStarted())
|
||||
|
|
|
@ -114,7 +114,7 @@ public abstract class ScopedHandler extends HandlerWrapper
|
|||
|
||||
super.doStart();
|
||||
|
||||
_nextScope= (ScopedHandler)getChildHandlerByClass(ScopedHandler.class);
|
||||
_nextScope= getChildHandlerByClass(ScopedHandler.class);
|
||||
|
||||
}
|
||||
finally
|
||||
|
@ -124,17 +124,19 @@ public abstract class ScopedHandler extends HandlerWrapper
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
*/
|
||||
@Override
|
||||
public final void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
if (_outerScope==null)
|
||||
doScope(target,baseRequest,request, response);
|
||||
else
|
||||
doHandle(target,baseRequest,request, response);
|
||||
if (isStarted())
|
||||
{
|
||||
if (_outerScope==null)
|
||||
doScope(target,baseRequest,request, response);
|
||||
else
|
||||
doHandle(target,baseRequest,request, response);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -111,6 +111,7 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
@Override
|
||||
public AbstractSession getSession()
|
||||
{
|
||||
return this;
|
||||
|
@ -124,8 +125,15 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
return _accessed;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
public Map<String,Object> getAttributeMap()
|
||||
{
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public Object getAttribute(String name)
|
||||
{
|
||||
synchronized (this)
|
||||
|
@ -147,6 +155,7 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@Override
|
||||
public Enumeration<String> getAttributeNames()
|
||||
{
|
||||
synchronized (this)
|
||||
|
@ -173,12 +182,14 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
@Override
|
||||
public long getCreationTime() throws IllegalStateException
|
||||
{
|
||||
return _created;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String getId() throws IllegalStateException
|
||||
{
|
||||
return _manager._nodeIdInSessionId?_nodeId:_clusterId;
|
||||
|
@ -197,6 +208,7 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
@Override
|
||||
public long getLastAccessedTime() throws IllegalStateException
|
||||
{
|
||||
checkValid();
|
||||
|
@ -204,6 +216,7 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
@Override
|
||||
public int getMaxInactiveInterval()
|
||||
{
|
||||
checkValid();
|
||||
|
@ -214,6 +227,7 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
/*
|
||||
* @see javax.servlet.http.HttpSession#getServletContext()
|
||||
*/
|
||||
@Override
|
||||
public ServletContext getServletContext()
|
||||
{
|
||||
return _manager._context;
|
||||
|
@ -221,6 +235,7 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
|
||||
/* ------------------------------------------------------------- */
|
||||
@Deprecated
|
||||
@Override
|
||||
public HttpSessionContext getSessionContext() throws IllegalStateException
|
||||
{
|
||||
checkValid();
|
||||
|
@ -233,6 +248,7 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
* {@link #getAttribute}
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public Object getValue(String name) throws IllegalStateException
|
||||
{
|
||||
return getAttribute(name);
|
||||
|
@ -244,6 +260,7 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
* {@link #getAttributeNames}
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public String[] getValueNames() throws IllegalStateException
|
||||
{
|
||||
synchronized(this)
|
||||
|
@ -309,6 +326,7 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
@Override
|
||||
public void invalidate() throws IllegalStateException
|
||||
{
|
||||
// remove session from context and invalidate other sessions with same ID.
|
||||
|
@ -372,6 +390,7 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
@Override
|
||||
public boolean isNew() throws IllegalStateException
|
||||
{
|
||||
checkValid();
|
||||
|
@ -384,12 +403,14 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
* {@link #setAttribute}
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public void putValue(java.lang.String name, java.lang.Object value) throws IllegalStateException
|
||||
{
|
||||
setAttribute(name,value);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void removeAttribute(String name)
|
||||
{
|
||||
setAttribute(name,null);
|
||||
|
@ -401,6 +422,7 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
* {@link #removeAttribute}
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public void removeValue(java.lang.String name) throws IllegalStateException
|
||||
{
|
||||
removeAttribute(name);
|
||||
|
@ -419,6 +441,7 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void setAttribute(String name, Object value)
|
||||
{
|
||||
Object old=null;
|
||||
|
@ -447,6 +470,7 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
@Override
|
||||
public void setMaxInactiveInterval(int secs)
|
||||
{
|
||||
_maxIdleMs=(long)secs*1000L;
|
||||
|
|
|
@ -69,7 +69,7 @@ public abstract class AbstractHttpTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
protected TestHttpResponse executeRequest() throws URISyntaxException, IOException
|
||||
protected SimpleHttpParser.TestHttpResponse executeRequest() throws URISyntaxException, IOException
|
||||
{
|
||||
Socket socket = new Socket("localhost", connector.getLocalPort());
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
|
||||
|
@ -84,12 +84,12 @@ public abstract class AbstractHttpTest
|
|||
return httpParser.readResponse(reader);
|
||||
}
|
||||
|
||||
protected void assertResponseBody(TestHttpResponse response, String expectedResponseBody)
|
||||
protected void assertResponseBody(SimpleHttpParser.TestHttpResponse response, String expectedResponseBody)
|
||||
{
|
||||
assertThat("response body is" + expectedResponseBody, response.getBody(), is(expectedResponseBody));
|
||||
}
|
||||
|
||||
protected void assertHeader(TestHttpResponse response, String headerName, String expectedValue)
|
||||
protected void assertHeader(SimpleHttpParser.TestHttpResponse response, String headerName, String expectedValue)
|
||||
{
|
||||
assertThat(headerName + "=" + expectedValue, response.getHeaders().get(headerName), is(expectedValue));
|
||||
}
|
||||
|
|
|
@ -132,6 +132,7 @@ public class HttpConnectionTest
|
|||
{
|
||||
String response=connector.getResponses("GET http://localhost:80 HTTP/1.1\n"+
|
||||
"Host: localhost:80\n"+
|
||||
"Connection: close\n"+
|
||||
"\n");
|
||||
|
||||
int offset=0;
|
||||
|
@ -198,18 +199,18 @@ public class HttpConnectionTest
|
|||
"Connection: close\n"+
|
||||
"\015\012");
|
||||
checkContains(response,0,"HTTP/1.1 400");
|
||||
|
||||
response=connector.getResponses("GET % HTTP/1.1\n"+
|
||||
|
||||
response=connector.getResponses("GET /foo/bar%c0%00 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
|
||||
|
||||
response=connector.getResponses("GET /bad/utf8%c1 HTTP/1.1\n"+
|
||||
"Host: localhost\n"+
|
||||
"Connection: close\n"+
|
||||
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
|
||||
checkContains(response,0,"HTTP/1.1 200"); //now fallback to iso-8859-1
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -28,6 +28,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.server.util.SimpleHttpParser;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
@ -65,7 +66,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new DoesNotSetHandledHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 404", response.getCode(), is("404"));
|
||||
}
|
||||
|
@ -76,7 +77,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new DoesNotSetHandledHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 500", response.getCode(), is("500"));
|
||||
}
|
||||
|
@ -119,7 +120,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new OnlySetHandledHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
assertHeader(response, "content-length", "0");
|
||||
|
@ -131,7 +132,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new OnlySetHandledHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 500", response.getCode(), is("500"));
|
||||
}
|
||||
|
@ -176,7 +177,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new SetHandledWriteSomeDataHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
assertHeader(response, "content-length", "6");
|
||||
|
@ -188,7 +189,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new SetHandledWriteSomeDataHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 500", response.getCode(), is("500"));
|
||||
}
|
||||
|
@ -240,7 +241,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new ExplicitFlushHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
|
@ -254,7 +255,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new ExplicitFlushHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
if ("HTTP/1.1".equals(httpVersion))
|
||||
|
@ -310,7 +311,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new SetHandledAndFlushWithoutContentHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
if ("HTTP/1.1".equals(httpVersion))
|
||||
|
@ -323,7 +324,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new SetHandledAndFlushWithoutContentHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
if ("HTTP/1.1".equals(httpVersion))
|
||||
|
@ -377,7 +378,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new WriteFlushWriteMoreHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
if ("HTTP/1.1".equals(httpVersion))
|
||||
|
@ -390,7 +391,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new WriteFlushWriteMoreHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
if ("HTTP/1.1".equals(httpVersion))
|
||||
|
@ -447,7 +448,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new OverflowHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
assertResponseBody(response, "foobar");
|
||||
|
@ -460,7 +461,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new OverflowHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
// response not committed when we throw, so 500 expected
|
||||
assertThat("response code is 500", response.getCode(), is("500"));
|
||||
|
@ -515,7 +516,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new SetContentLengthAndWriteThatAmountOfBytesHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
assertThat("response body is foo", response.getBody(), is("foo"));
|
||||
|
@ -528,7 +529,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new SetContentLengthAndWriteThatAmountOfBytesHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
//TODO: should we expect 500 here?
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
|
@ -585,7 +586,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new SetContentLengthAndWriteMoreBytesHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
// jetty truncates the body when content-length is reached.! This is correct and desired behaviour?
|
||||
|
@ -599,7 +600,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new SetContentLengthAndWriteMoreBytesHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
// TODO: we throw before response is committed. should we expect 500?
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
|
@ -656,7 +657,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new WriteAndSetContentLengthHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
//TODO: jetty ignores setContentLength and sends transfer-encoding header. Correct?
|
||||
|
@ -668,7 +669,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new WriteAndSetContentLengthHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
}
|
||||
|
@ -723,7 +724,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new WriteAndSetContentLengthTooSmallHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
assertResponseBody(response, "foobar");
|
||||
|
@ -738,7 +739,7 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new WriteAndSetContentLengthTooSmallHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat(response.getCode(), is("500"));
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.server.util.SimpleHttpParser;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
@ -57,7 +58,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new DoesNotSetHandledHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 404", response.getCode(), is("404"));
|
||||
}
|
||||
|
@ -68,7 +69,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new DoesNotSetHandledHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 500", response.getCode(), is("500"));
|
||||
}
|
||||
|
@ -94,7 +95,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new OnlySetHandledHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
assertHeader(response, "content-length", "0");
|
||||
|
@ -106,7 +107,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new OnlySetHandledHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 500", response.getCode(), is("500"));
|
||||
}
|
||||
|
@ -133,7 +134,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new SetHandledWriteSomeDataHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
assertHeader(response, "content-length", "6");
|
||||
|
@ -145,7 +146,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new SetHandledWriteSomeDataHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 500", response.getCode(), is("500"));
|
||||
}
|
||||
|
@ -172,7 +173,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new ExplicitFlushHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
|
@ -186,7 +187,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new ExplicitFlushHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
if ("HTTP/1.1".equals(httpVersion))
|
||||
|
@ -216,7 +217,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new SetHandledAndFlushWithoutContentHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
if ("HTTP/1.1".equals(httpVersion))
|
||||
|
@ -229,7 +230,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new SetHandledAndFlushWithoutContentHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
if ("HTTP/1.1".equals(httpVersion))
|
||||
|
@ -258,7 +259,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new WriteFlushWriteMoreHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
if ("HTTP/1.1".equals(httpVersion))
|
||||
|
@ -271,7 +272,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new WriteFlushWriteMoreHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
if ("HTTP/1.1".equals(httpVersion))
|
||||
|
@ -302,7 +303,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new OverflowHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
assertResponseBody(response, "foobar");
|
||||
|
@ -315,7 +316,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new OverflowHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
// response not committed when we throw, so 500 expected
|
||||
assertThat("response code is 500", response.getCode(), is("500"));
|
||||
|
@ -344,7 +345,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new SetContentLengthAndWriteThatAmountOfBytesHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
assertThat("response body is foo", response.getBody(), is("foo"));
|
||||
|
@ -358,7 +359,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new SetContentLengthAndWriteThatAmountOfBytesHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
//TODO: should we expect 500 here?
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
|
@ -389,7 +390,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new SetContentLengthAndWriteMoreBytesHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
// jetty truncates the body when content-length is reached.! This is correct and desired behaviour?
|
||||
|
@ -403,7 +404,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new SetContentLengthAndWriteMoreBytesHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
// TODO: we throw before response is committed. should we expect 500?
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
|
@ -434,7 +435,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new WriteAndSetContentLengthHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
//TODO: jetty ignores setContentLength and sends transfer-encoding header. Correct?
|
||||
|
@ -446,7 +447,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new WriteAndSetContentLengthHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
}
|
||||
|
@ -475,7 +476,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new WriteAndSetContentLengthTooSmallHandler(false));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat("response code is 200", response.getCode(), is("200"));
|
||||
assertResponseBody(response, "foobar");
|
||||
|
@ -490,7 +491,7 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
|
|||
server.setHandler(new WriteAndSetContentLengthTooSmallHandler(true));
|
||||
server.start();
|
||||
|
||||
TestHttpResponse response = executeRequest();
|
||||
SimpleHttpParser.TestHttpResponse response = executeRequest();
|
||||
|
||||
assertThat(response.getCode(), is("500"));
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ public class HttpWriterTest
|
|||
@Test
|
||||
public void testSimpleUTF8() throws Exception
|
||||
{
|
||||
HttpWriter _writer = new HttpWriter(_httpOut,StringUtil.__UTF8);
|
||||
HttpWriter _writer = new Utf8HttpWriter(_httpOut);
|
||||
_writer.write("Now is the time");
|
||||
assertArrayEquals("Now is the time".getBytes(StringUtil.__UTF8),BufferUtil.toArray(_bytes));
|
||||
}
|
||||
|
@ -127,15 +127,23 @@ public class HttpWriterTest
|
|||
@Test
|
||||
public void testUTF8() throws Exception
|
||||
{
|
||||
HttpWriter _writer = new HttpWriter(_httpOut,StringUtil.__UTF8);
|
||||
HttpWriter _writer = new Utf8HttpWriter(_httpOut);
|
||||
_writer.write("How now \uFF22rown cow");
|
||||
assertArrayEquals("How now \uFF22rown cow".getBytes(StringUtil.__UTF8),BufferUtil.toArray(_bytes));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUTF16() throws Exception
|
||||
{
|
||||
HttpWriter _writer = new EncodingHttpWriter(_httpOut,StringUtil.__UTF16);
|
||||
_writer.write("How now \uFF22rown cow");
|
||||
assertArrayEquals("How now \uFF22rown cow".getBytes(StringUtil.__UTF16),BufferUtil.toArray(_bytes));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotCESU8() throws Exception
|
||||
{
|
||||
HttpWriter _writer = new HttpWriter(_httpOut,StringUtil.__UTF8);
|
||||
HttpWriter _writer = new Utf8HttpWriter(_httpOut);
|
||||
String data="xxx\uD801\uDC00xxx";
|
||||
_writer.write(data);
|
||||
assertEquals("787878F0909080787878",TypeUtil.toHexString(BufferUtil.toArray(_bytes)));
|
||||
|
@ -151,7 +159,7 @@ public class HttpWriterTest
|
|||
@Test
|
||||
public void testMultiByteOverflowUTF8() throws Exception
|
||||
{
|
||||
HttpWriter _writer = new HttpWriter(_httpOut,StringUtil.__UTF8);
|
||||
HttpWriter _writer = new Utf8HttpWriter(_httpOut);
|
||||
final String singleByteStr = "a";
|
||||
final String multiByteDuplicateStr = "\uFF22";
|
||||
int remainSize = 1;
|
||||
|
@ -178,7 +186,7 @@ public class HttpWriterTest
|
|||
@Test
|
||||
public void testISO8859() throws Exception
|
||||
{
|
||||
HttpWriter _writer = new HttpWriter(_httpOut,StringUtil.__ISO_8859_1);
|
||||
HttpWriter _writer = new Iso88591HttpWriter(_httpOut);
|
||||
_writer.write("How now \uFF22rown cow");
|
||||
assertEquals("How now ?rown cow",new String(BufferUtil.toArray(_bytes),StringUtil.__ISO_8859_1));
|
||||
}
|
||||
|
@ -187,7 +195,7 @@ public class HttpWriterTest
|
|||
@Test
|
||||
public void testUTF16x2() throws Exception
|
||||
{
|
||||
HttpWriter _writer = new HttpWriter(_httpOut,StringUtil.__UTF8);
|
||||
HttpWriter _writer = new Utf8HttpWriter(_httpOut);
|
||||
|
||||
String source = "\uD842\uDF9F";
|
||||
|
||||
|
@ -210,7 +218,7 @@ public class HttpWriterTest
|
|||
@Test
|
||||
public void testMultiByteOverflowUTF16x2() throws Exception
|
||||
{
|
||||
HttpWriter _writer = new HttpWriter(_httpOut,StringUtil.__UTF8);
|
||||
HttpWriter _writer = new Utf8HttpWriter(_httpOut);
|
||||
|
||||
final String singleByteStr = "a";
|
||||
int remainSize = 1;
|
||||
|
@ -248,7 +256,7 @@ public class HttpWriterTest
|
|||
@Test
|
||||
public void testMultiByteOverflowUTF16x2_2() throws Exception
|
||||
{
|
||||
HttpWriter _writer = new HttpWriter(_httpOut,StringUtil.__UTF8);
|
||||
HttpWriter _writer = new Utf8HttpWriter(_httpOut);
|
||||
|
||||
final String singleByteStr = "a";
|
||||
int remainSize = 1;
|
||||
|
|
|
@ -58,6 +58,21 @@ public class LocalConnectorTest
|
|||
assertThat(response,containsString("pathInfo=/R1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStopStart() throws Exception
|
||||
{
|
||||
String response=_connector.getResponses("GET /R1 HTTP/1.0\r\n\r\n");
|
||||
assertThat(response,containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(response,containsString("pathInfo=/R1"));
|
||||
|
||||
_server.stop();
|
||||
_server.start();
|
||||
|
||||
response=_connector.getResponses("GET /R2 HTTP/1.0\r\n\r\n");
|
||||
assertThat(response,containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(response,containsString("pathInfo=/R2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTwoGETs() throws Exception
|
||||
{
|
||||
|
|
|
@ -1,60 +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.server;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class TestHttpResponse
|
||||
{
|
||||
private final String code;
|
||||
private final Map<String, String> headers;
|
||||
private final String body;
|
||||
|
||||
public TestHttpResponse(String code, Map<String, String> headers, String body)
|
||||
{
|
||||
this.code = code;
|
||||
this.headers = headers;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public String getCode()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
public Map<String, String> getHeaders()
|
||||
{
|
||||
return headers;
|
||||
}
|
||||
|
||||
public String getBody()
|
||||
{
|
||||
return body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "Response{" +
|
||||
"code='" + code + '\'' +
|
||||
", headers=" + headers +
|
||||
", body='" + body + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.server.handler;
|
|||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -33,7 +34,8 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Assert;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
|
@ -150,6 +152,60 @@ public class ContextHandlerTest
|
|||
Assert.assertEquals(fooA._scontext,foobarA._scontext.getContext("/foo/other"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifeCycle() throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
LocalConnector connector = new LocalConnector(server);
|
||||
server.setConnectors(new Connector[] { connector });
|
||||
ContextHandlerCollection contexts = new ContextHandlerCollection();
|
||||
server.setHandler(contexts);
|
||||
|
||||
ContextHandler root = new ContextHandler(contexts,"/");
|
||||
root.setHandler(new ContextPathHandler());
|
||||
ContextHandler foo = new ContextHandler(contexts,"/foo");
|
||||
foo.setHandler(new ContextPathHandler());
|
||||
ContextHandler foobar = new ContextHandler(contexts,"/foo/bar");
|
||||
foobar.setHandler(new ContextPathHandler());
|
||||
|
||||
// check that all contexts start normally
|
||||
server.start();
|
||||
assertThat(connector.getResponses("GET / HTTP/1.0\n\n"),Matchers.containsString("ctx=''"));
|
||||
assertThat(connector.getResponses("GET /foo/xxx HTTP/1.0\n\n"),Matchers.containsString("ctx='/foo'"));
|
||||
assertThat(connector.getResponses("GET /foo/bar/xxx HTTP/1.0\n\n"),Matchers.containsString("ctx='/foo/bar'"));
|
||||
|
||||
// If we stop foobar, then requests will be handled by foo
|
||||
foobar.stop();
|
||||
assertThat(connector.getResponses("GET / HTTP/1.0\n\n"),Matchers.containsString("ctx=''"));
|
||||
assertThat(connector.getResponses("GET /foo/xxx HTTP/1.0\n\n"),Matchers.containsString("ctx='/foo'"));
|
||||
assertThat(connector.getResponses("GET /foo/bar/xxx HTTP/1.0\n\n"),Matchers.containsString("ctx='/foo'"));
|
||||
|
||||
// If we shutdown foo then requests will be 503'd
|
||||
foo.shutdown();
|
||||
assertThat(connector.getResponses("GET / HTTP/1.0\n\n"),Matchers.containsString("ctx=''"));
|
||||
assertThat(connector.getResponses("GET /foo/xxx HTTP/1.0\n\n"),Matchers.containsString("503"));
|
||||
assertThat(connector.getResponses("GET /foo/bar/xxx HTTP/1.0\n\n"),Matchers.containsString("503"));
|
||||
|
||||
// If we stop foo then requests will be handled by root
|
||||
foo.stop();
|
||||
assertThat(connector.getResponses("GET / HTTP/1.0\n\n"),Matchers.containsString("ctx=''"));
|
||||
assertThat(connector.getResponses("GET /foo/xxx HTTP/1.0\n\n"),Matchers.containsString("ctx=''"));
|
||||
assertThat(connector.getResponses("GET /foo/bar/xxx HTTP/1.0\n\n"),Matchers.containsString("ctx=''"));
|
||||
|
||||
// If we start foo then foobar requests will be handled by foo
|
||||
foo.start();
|
||||
assertThat(connector.getResponses("GET / HTTP/1.0\n\n"),Matchers.containsString("ctx=''"));
|
||||
assertThat(connector.getResponses("GET /foo/xxx HTTP/1.0\n\n"),Matchers.containsString("ctx='/foo'"));
|
||||
assertThat(connector.getResponses("GET /foo/bar/xxx HTTP/1.0\n\n"),Matchers.containsString("ctx='/foo'"));
|
||||
|
||||
// If we start foobar then foobar requests will be handled by foobar
|
||||
foobar.start();
|
||||
assertThat(connector.getResponses("GET / HTTP/1.0\n\n"),Matchers.containsString("ctx=''"));
|
||||
assertThat(connector.getResponses("GET /foo/xxx HTTP/1.0\n\n"),Matchers.containsString("ctx='/foo'"));
|
||||
assertThat(connector.getResponses("GET /foo/bar/xxx HTTP/1.0\n\n"),Matchers.containsString("ctx='/foo/bar'"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testContextVirtualGetContext() throws Exception
|
||||
{
|
||||
|
@ -393,6 +449,7 @@ public class ContextHandlerTest
|
|||
return handled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(String s, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
|
@ -404,38 +461,19 @@ public class ContextHandlerTest
|
|||
handled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class WriterHandler extends AbstractHandler
|
||||
|
||||
private static final class ContextPathHandler extends AbstractHandler
|
||||
{
|
||||
volatile boolean error;
|
||||
volatile Throwable throwable;
|
||||
|
||||
|
||||
@Override
|
||||
public void handle(String s, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
error = false;
|
||||
throwable=null;
|
||||
|
||||
response.setStatus(200);
|
||||
response.setContentType("text/plain; charset=utf-8");
|
||||
response.setHeader("Connection","close");
|
||||
PrintWriter writer = response.getWriter();
|
||||
try
|
||||
{
|
||||
writer.write("Goodbye cruel world\n");
|
||||
writer.close();
|
||||
response.flushBuffer();
|
||||
//writer.write("speaking from the dead");
|
||||
writer.write("give the printwriter a chance"); //should create an error
|
||||
if (writer.checkError())
|
||||
writer.write("didn't take the chance, will throw now"); //write after an error
|
||||
}
|
||||
catch(Throwable th)
|
||||
{
|
||||
throwable=th;
|
||||
}
|
||||
error=writer.checkError();
|
||||
writer.println("ctx='"+request.getContextPath()+"'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,8 +27,6 @@ import java.util.Map;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.jetty.server.TestHttpResponse;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
@ -161,4 +159,43 @@ public class SimpleHttpParser
|
|||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
public static class TestHttpResponse
|
||||
{
|
||||
private final String code;
|
||||
private final Map<String, String> headers;
|
||||
private final String body;
|
||||
|
||||
public TestHttpResponse(String code, Map<String, String> headers, String body)
|
||||
{
|
||||
this.code = code;
|
||||
this.headers = headers;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public String getCode()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
public Map<String, String> getHeaders()
|
||||
{
|
||||
return headers;
|
||||
}
|
||||
|
||||
public String getBody()
|
||||
{
|
||||
return body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "Response{" +
|
||||
"code='" + code + '\'' +
|
||||
", headers=" + headers +
|
||||
", body='" + body + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,17 +93,17 @@ public class StdErrLogTest
|
|||
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: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");
|
||||
output.assertContains("DBUG:x.before:tname: testing test debug-before");
|
||||
output.assertContains("DBUG:xxx:tname: testing test debug-deprecated");
|
||||
output.assertContains("DBUG:x.after:tname: 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
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
package org.eclipse.jetty.websocket.client;
|
||||
|
||||
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.Executors;
|
||||
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.ssl.SslContextFactory;
|
||||
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.WebSocketPolicy;
|
||||
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.WebSocketEventDriver;
|
||||
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
|
||||
{
|
||||
|
@ -47,9 +54,10 @@ public class WebSocketClientFactory extends AggregateLifeCycle
|
|||
private final ScheduledExecutorService scheduler;
|
||||
private final EventMethodsCache methodsCache;
|
||||
private final WebSocketPolicy policy;
|
||||
private final ExtensionRegistry extensionRegistry;
|
||||
private final WebSocketExtensionRegistry extensionRegistry;
|
||||
private SocketAddress bindAddress;
|
||||
|
||||
private final Queue<WebSocketSession> sessions = new ConcurrentLinkedQueue<>();
|
||||
private ConnectionManager connectionManager;
|
||||
|
||||
public WebSocketClientFactory()
|
||||
|
@ -69,6 +77,7 @@ public class WebSocketClientFactory extends AggregateLifeCycle
|
|||
|
||||
public WebSocketClientFactory(Executor executor, ScheduledExecutorService scheduler, SslContextFactory sslContextFactory)
|
||||
{
|
||||
LOG.debug("new WebSocketClientFactory()");
|
||||
if (executor == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Executor is required");
|
||||
|
@ -101,6 +110,20 @@ public class WebSocketClientFactory extends AggregateLifeCycle
|
|||
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.
|
||||
*
|
||||
|
@ -142,6 +165,26 @@ public class WebSocketClientFactory extends AggregateLifeCycle
|
|||
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)
|
||||
{
|
||||
LOG.debug("Creating new WebSocket for {}",websocketPojo);
|
||||
|
@ -149,6 +192,33 @@ public class WebSocketClientFactory extends AggregateLifeCycle
|
|||
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
|
||||
* the address to bind the socket channel to
|
||||
|
|
|
@ -57,6 +57,8 @@ public class IWebSocketClient extends FutureCallback<UpgradeResponse> implements
|
|||
public IWebSocketClient(WebSocketClientFactory factory, WebSocketEventDriver websocket)
|
||||
{
|
||||
this.factory = factory;
|
||||
LOG.debug("factory.isRunning(): {}",factory.isRunning());
|
||||
LOG.debug("factory.isStarted(): {}",factory.isStarted());
|
||||
this.policy = factory.getPolicy();
|
||||
this.websocket = websocket;
|
||||
this.upgradeRequest = new ClientUpgradeRequest();
|
||||
|
@ -210,9 +212,8 @@ public class IWebSocketClient extends FutureCallback<UpgradeResponse> implements
|
|||
return websocketUri;
|
||||
}
|
||||
|
||||
public void setUpgradeResponse(UpgradeResponse response)
|
||||
public void setUpgradeResponse(ClientUpgradeResponse response)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
this.upgradeResponse = response;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ import java.util.regex.Pattern;
|
|||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.Utf8LineParser;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeException;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.client.internal.ClientUpgradeResponse;
|
||||
|
||||
/**
|
||||
|
@ -58,7 +57,7 @@ public class HttpResponseHeaderParser
|
|||
return (state == State.END);
|
||||
}
|
||||
|
||||
public UpgradeResponse parse(ByteBuffer buf) throws UpgradeException
|
||||
public ClientUpgradeResponse parse(ByteBuffer buf) throws UpgradeException
|
||||
{
|
||||
while (!isDone() && (buf.remaining() > 0))
|
||||
{
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.io.IOException;
|
|||
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.Executor;
|
||||
|
@ -36,10 +37,17 @@ import org.eclipse.jetty.util.QuotedStringTokenizer;
|
|||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
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.UpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
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.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.ExtensionConfig;
|
||||
|
||||
|
@ -176,14 +184,14 @@ public class UpgradeConnection extends AbstractConnection
|
|||
{
|
||||
LOG.debug("Filled {} bytes - {}",filled,BufferUtil.toDetailString(buffer));
|
||||
}
|
||||
UpgradeResponse resp = parser.parse(buffer);
|
||||
ClientUpgradeResponse resp = parser.parse(buffer);
|
||||
if (resp != null)
|
||||
{
|
||||
// Got a response!
|
||||
client.setUpgradeResponse(resp);
|
||||
validateResponse(resp);
|
||||
notifyConnect();
|
||||
upgradeConnection();
|
||||
upgradeConnection(resp);
|
||||
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();
|
||||
Executor executor = getExecutor();
|
||||
WebSocketClientConnection conn = new WebSocketClientConnection(endp,executor,client);
|
||||
endp.setConnection(conn);
|
||||
WebSocketClientConnection connection = new WebSocketClientConnection(endp,executor,client);
|
||||
|
||||
// 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)
|
||||
|
|
|
@ -21,17 +21,25 @@ package org.eclipse.jetty.websocket.client.internal.io;
|
|||
import java.util.concurrent.Executor;
|
||||
|
||||
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.io.AbstractWebSocketConnection;
|
||||
|
||||
/**
|
||||
* Client side WebSocket physical connection.
|
||||
*/
|
||||
public class WebSocketClientConnection extends AbstractWebSocketConnection
|
||||
{
|
||||
private final WebSocketClientFactory factory;
|
||||
private final IWebSocketClient client;
|
||||
private boolean connected;
|
||||
|
||||
public WebSocketClientConnection(EndPoint endp, Executor executor, IWebSocketClient client)
|
||||
{
|
||||
super(endp,executor,client.getFactory().getScheduler(),client.getPolicy(),client.getFactory().getBufferPool());
|
||||
this.client = client;
|
||||
this.factory = client.getFactory();
|
||||
this.connected = false;
|
||||
}
|
||||
|
||||
public IWebSocketClient getClient()
|
||||
|
@ -39,9 +47,21 @@ public class WebSocketClientConnection extends AbstractWebSocketConnection
|
|||
return client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose()
|
||||
{
|
||||
super.onClose();
|
||||
factory.sessionClosed(getSession());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen()
|
||||
{
|
||||
if (!connected)
|
||||
{
|
||||
factory.sessionOpened(getSession());
|
||||
connected = true;
|
||||
}
|
||||
super.onOpen();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,33 +22,39 @@ import static org.hamcrest.Matchers.*;
|
|||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
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.WebSocketConnection;
|
||||
import org.junit.Assert;
|
||||
|
||||
/**
|
||||
* Testing Socket used on client side WebSocket testing.
|
||||
*/
|
||||
public class TrackingSocket extends WebSocketAdapter
|
||||
{
|
||||
public AtomicBoolean open = new AtomicBoolean(false);
|
||||
public AtomicInteger close = new AtomicInteger(-1);
|
||||
private static final Logger LOG = Log.getLogger(TrackingSocket.class);
|
||||
|
||||
public int closeCode = -1;
|
||||
public StringBuilder closeMessage = new StringBuilder();
|
||||
public CountDownLatch openLatch = new CountDownLatch(1);
|
||||
public CountDownLatch closeLatch = new CountDownLatch(1);
|
||||
public CountDownLatch dataLatch = new CountDownLatch(1);
|
||||
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);
|
||||
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)
|
||||
|
@ -56,36 +62,37 @@ public class TrackingSocket extends WebSocketAdapter
|
|||
Assert.assertThat("Close Reaosn",closeMessage.toString(),is(expectedReason));
|
||||
}
|
||||
|
||||
public void assertIsOpen()
|
||||
public void assertIsOpen() throws InterruptedException
|
||||
{
|
||||
assertWasOpened();
|
||||
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()
|
||||
{
|
||||
Assert.assertThat("Close Code",close.get(),is(-1));
|
||||
Assert.assertThat("Closed Latch",closeLatch.getCount(),greaterThanOrEqualTo(1L));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketBinary(byte[] payload, int offset, int len)
|
||||
{
|
||||
LOG.debug("onWebSocketBinary()");
|
||||
dataLatch.countDown();
|
||||
}
|
||||
|
||||
|
@ -93,7 +100,7 @@ public class TrackingSocket extends WebSocketAdapter
|
|||
public void onWebSocketClose(int statusCode, String reason)
|
||||
{
|
||||
super.onWebSocketClose(statusCode,reason);
|
||||
close.set(statusCode);
|
||||
closeCode = statusCode;
|
||||
closeMessage.append(reason);
|
||||
closeLatch.countDown();
|
||||
}
|
||||
|
@ -102,20 +109,19 @@ public class TrackingSocket extends WebSocketAdapter
|
|||
public void onWebSocketConnect(WebSocketConnection connection)
|
||||
{
|
||||
super.onWebSocketConnect(connection);
|
||||
open.set(true);
|
||||
openLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketText(String message)
|
||||
{
|
||||
dataLatch.countDown();
|
||||
LOG.debug("onWebSocketText({})",message);
|
||||
messageQueue.add(message);
|
||||
dataLatch.countDown();
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
|
@ -49,7 +49,7 @@ import org.junit.Before;
|
|||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
@Ignore("work in progress")
|
||||
@Ignore("Work in Progress")
|
||||
public class WebSocketClientTest
|
||||
{
|
||||
private BlockheadServer server;
|
||||
|
@ -149,9 +149,9 @@ public class WebSocketClientTest
|
|||
final ServerConnection srvSock = server.accept();
|
||||
srvSock.upgrade();
|
||||
|
||||
UpgradeResponse resp = future.get(250,TimeUnit.MILLISECONDS);
|
||||
UpgradeResponse resp = future.get(500,TimeUnit.MILLISECONDS);
|
||||
Assert.assertThat("Response",resp,notNullValue());
|
||||
Assert.assertEquals("Response.success",resp.isSuccess(),is(true));
|
||||
Assert.assertThat("Response.success",resp.isSuccess(),is(true));
|
||||
|
||||
cliSock.assertWasOpened();
|
||||
cliSock.assertNotClosed();
|
||||
|
@ -159,9 +159,9 @@ public class WebSocketClientTest
|
|||
Assert.assertThat("Factory.sockets.size",factory.getConnectionManager().getClients().size(),is(1));
|
||||
|
||||
cliSock.getConnection().write(null,new FutureCallback<Void>(),"Hello World!");
|
||||
srvSock.echoMessage();
|
||||
srvSock.echoMessage(1,TimeUnit.MILLISECONDS,500);
|
||||
// wait for response from server
|
||||
cliSock.waitForResponseMessage();
|
||||
cliSock.waitForMessage(TimeUnit.MILLISECONDS,500);
|
||||
|
||||
cliSock.assertMessage("Hello World!");
|
||||
}
|
||||
|
@ -177,6 +177,11 @@ public class WebSocketClientTest
|
|||
final ServerConnection srvSock = server.accept();
|
||||
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
|
||||
srvSock.write(WebSocketFrame.text("Hello World"));
|
||||
|
||||
|
|
|
@ -31,11 +31,26 @@ import java.net.ServerSocket;
|
|||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
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.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
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.Generator;
|
||||
import org.eclipse.jetty.websocket.protocol.OpCode;
|
||||
import org.eclipse.jetty.websocket.protocol.Parser;
|
||||
import org.eclipse.jetty.websocket.protocol.WebSocketFrame;
|
||||
import org.junit.Assert;
|
||||
|
||||
|
@ -46,15 +61,33 @@ import org.junit.Assert;
|
|||
*/
|
||||
public class BlockheadServer
|
||||
{
|
||||
public static class ServerConnection
|
||||
public static class ServerConnection implements IncomingFrames, OutgoingFrames
|
||||
{
|
||||
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;
|
||||
|
||||
/** Set to true to disable timeouts (for debugging reasons) */
|
||||
private boolean debug = false;
|
||||
private OutputStream out;
|
||||
private InputStream in;
|
||||
|
||||
private IncomingFrames incoming = this;
|
||||
private OutgoingFrames outgoing = this;
|
||||
|
||||
public ServerConnection(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);
|
||||
}
|
||||
|
||||
public void close() throws IOException
|
||||
|
@ -62,10 +95,33 @@ public class BlockheadServer
|
|||
this.socket.close();
|
||||
}
|
||||
|
||||
public void echoMessage()
|
||||
public void disconnect()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
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
|
||||
|
@ -91,6 +147,95 @@ public class BlockheadServer
|
|||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incoming(WebSocketException e)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incoming(WebSocketFrame frame)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@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
|
||||
{
|
||||
LOG.debug("Reading client request");
|
||||
|
@ -138,14 +283,21 @@ public class BlockheadServer
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: parse extensions
|
||||
|
||||
// TODO: setup extensions
|
||||
|
||||
StringBuilder resp = new StringBuilder();
|
||||
resp.append("HTTP/1.1 101 Upgrade\r\n");
|
||||
resp.append("Sec-WebSocket-Accept: ");
|
||||
resp.append(AcceptHash.hashKey(key));
|
||||
resp.append("\r\n");
|
||||
resp.append(AcceptHash.hashKey(key)).append("\r\n");
|
||||
// TODO: respond to used extensions
|
||||
resp.append("\r\n");
|
||||
|
||||
write(resp.toString().getBytes());
|
||||
|
||||
// Configure Parser
|
||||
parser.setIncomingFramesHandler(incomingFrames);
|
||||
}
|
||||
|
||||
private void write(byte[] bytes) throws IOException
|
||||
|
@ -163,10 +315,10 @@ public class BlockheadServer
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -224,6 +224,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
@Override
|
||||
public void onFillable()
|
||||
{
|
||||
LOG.debug("{} onFillable()",policy.getBehavior());
|
||||
ByteBuffer buffer = bufferPool.acquire(policy.getBufferSize(),false);
|
||||
BufferUtil.clear(buffer);
|
||||
boolean readMore = false;
|
||||
|
@ -251,6 +252,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
public void onOpen()
|
||||
{
|
||||
super.onOpen();
|
||||
LOG.debug("fillInterested");
|
||||
fillInterested();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue