diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index 2c636bfaefa..9569e38bca7 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -450,7 +450,7 @@ public class HttpFields implements Iterable } return new Enumeration() - { + { Field f = field; @Override @@ -467,7 +467,7 @@ public class HttpFields implements Iterable f = f._next; return n.getValue(); } - }; + }; } /* -------------------------------------------------------------- */ @@ -1262,5 +1262,36 @@ public class HttpFields implements Iterable { return ("[" + getName() + "=" + _value + (_next == null ? "" : "->") + "]"); } + + /* ------------------------------------------------------------ */ + public boolean contains(String value) + { + if (_value==null) + return false; + + if (value.equalsIgnoreCase(_value)) + return true; + + String[] split = _value.split("\\s*,\\s*"); + for (String s : split) + { + if (value.equalsIgnoreCase(s)) + return true; + } + + if (_next!=null) + return _next.contains(value); + + return false; + } + } + + /* ------------------------------------------------------------ */ + public boolean contains(HttpHeader header, String value) + { + Field field = getField(header); + if (field==null) + return false; + return field.contains(value); } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index ccc1b89099f..7f0cbb47f14 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -62,7 +62,6 @@ public class HttpParser private HttpHeaderValue _value; private String _valueString; private int _responseStatus; - private boolean _persistent; /* ------------------------------------------------------------------------------- */ private State _state=State.START; @@ -186,12 +185,6 @@ public class HttpParser return _state == state; } - /* ------------------------------------------------------------------------------- */ - public boolean isPersistent() - { - return _persistent; - } - /* ------------------------------------------------------------------------------- */ /* Quick lookahead for the start state looking for a request method or a HTTP version, * otherwise skip white space until something else to parse. @@ -218,7 +211,6 @@ public class HttpParser if (_version!=null) { buffer.position(buffer.position()+_version.asString().length()+1); - _persistent=_version.getVerion()>=HttpVersion.HTTP_1_1.getVerion(); _state=State.SPACE1; return; } @@ -309,7 +301,6 @@ public class HttpParser badMessage(buffer, "Unknown Version"); return true; } - _persistent=_version.getVerion()>=HttpVersion.HTTP_1_1.getVerion(); _state=State.SPACE1; } else if (ch < HttpTokens.SPACE && ch>=0) @@ -377,10 +368,9 @@ public class HttpParser _uri=_utf8.toString(); _utf8.reset(); return_from_parse|=_requestHandler.startRequest(_method,_methodString,_uri,null); - _persistent=false; _state=State.END; BufferUtil.clear(buffer); - return_from_parse|=_handler.headerComplete(false,_persistent); + return_from_parse|=_handler.headerComplete(); return_from_parse|=_handler.messageComplete(_contentPosition); } else @@ -410,7 +400,6 @@ public class HttpParser _string.setLength(0); buffer.position(buffer.position()+_version.asString().length()-1); _eol=buffer.get(); - _persistent=_version.getVerion()>=HttpVersion.HTTP_1_1.getVerion(); _state=State.HEADER; return_from_parse|=_requestHandler.startRequest(_method,_methodString, _uri, _version); } @@ -429,10 +418,9 @@ public class HttpParser { // HTTP/0.9 return_from_parse|=_requestHandler.startRequest(_method,_methodString, _uri, null); - _persistent=false; _state=State.END; BufferUtil.clear(buffer); - return_from_parse|=_handler.headerComplete(false,_persistent); + return_from_parse|=_handler.headerComplete(); return_from_parse|=_handler.messageComplete(_contentPosition); } } @@ -450,7 +438,6 @@ public class HttpParser } _eol=ch; - _persistent=_version.getVerion()>=HttpVersion.HTTP_1_1.getVerion(); _state=State.HEADER; return_from_parse|=_requestHandler.startRequest(_method,_methodString, _uri, _version); continue; @@ -568,37 +555,6 @@ public class HttpParser } } break; - - case CONNECTION: - switch(_value==null?HttpHeaderValue.UNKNOWN:_value) - { - case CLOSE: - _persistent=false; - break; - - case KEEP_ALIVE: - _persistent=true; - break; - - default: // No match, may be multi valued - { - for (String v : _valueString.toString().split(",")) - { - HttpHeaderValue val=HttpHeaderValue.CACHE.get(v.trim()); - switch(val==null?HttpHeaderValue.UNKNOWN:val) - { - case CLOSE: - _persistent=false; - break; - - case KEEP_ALIVE: - _persistent=true; - break; - } - } - break; - } - } } } @@ -634,24 +590,23 @@ public class HttpParser { case EOF_CONTENT: _state=State.EOF_CONTENT; - _persistent=false; - return_from_parse|=_handler.headerComplete(true,_persistent); + return_from_parse|=_handler.headerComplete(); break; case CHUNKED_CONTENT: _state=State.CHUNKED_CONTENT; - return_from_parse|=_handler.headerComplete(true,_persistent); + return_from_parse|=_handler.headerComplete(); break; case NO_CONTENT: - return_from_parse|=_handler.headerComplete(false,_persistent); + return_from_parse|=_handler.headerComplete(); _state=State.END; return_from_parse|=_handler.messageComplete(_contentPosition); break; default: _state=State.CONTENT; - return_from_parse|=_handler.headerComplete(true,_persistent); + return_from_parse|=_handler.headerComplete(); break; } } @@ -1103,7 +1058,6 @@ public class HttpParser private void badMessage(ByteBuffer buffer, String reason) { BufferUtil.clear(buffer); - _persistent=false; _state=State.END; _handler.badMessage(400, reason); } @@ -1111,8 +1065,6 @@ public class HttpParser /* ------------------------------------------------------------------------------- */ public void inputShutdown() { - _persistent=false; - // was this unexpected? switch(_state) { @@ -1139,15 +1091,18 @@ public class HttpParser { if (_state!=State.END && _state!=State.CLOSED) LOG.warn("Closing {}",this); - _persistent=false; - reset(); + _state=State.CLOSED; + _endOfContent=EndOfContent.UNKNOWN_CONTENT; + _contentPosition=0; + _responseStatus=0; + _contentChunk=null; } /* ------------------------------------------------------------------------------- */ public void reset() { // reset state - _state=_persistent?State.START:State.CLOSED; + _state=State.START; _endOfContent=EndOfContent.UNKNOWN_CONTENT; _contentPosition=0; _responseStatus=0; @@ -1159,19 +1114,16 @@ public class HttpParser { this._state=state; _endOfContent=EndOfContent.UNKNOWN_CONTENT; - if (state==State.CLOSED) - _persistent=false; } /* ------------------------------------------------------------------------------- */ @Override public String toString() { - return String.format("%s{s=%s,c=%d,p=%b}", + return String.format("%s{s=%s,c=%d}", getClass().getSimpleName(), _state, - _contentLength, - _persistent); + _contentLength); } /* ------------------------------------------------------------ */ @@ -1185,7 +1137,7 @@ public class HttpParser { public boolean content(ByteBuffer ref); - public boolean headerComplete(boolean hasBody,boolean persistent); + public boolean headerComplete(); public boolean messageComplete(long contentLength); diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java index c9c38db1ee8..ee7ea6bb657 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java @@ -112,10 +112,9 @@ public class HttpTester } @Override - public boolean headerComplete(boolean hasBody, boolean persistent) + public boolean headerComplete() { - if (hasBody) - _content=new ByteArrayOutputStream(); + _content=new ByteArrayOutputStream(); return false; } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java index 63b56f007a2..267bcef7fdb 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java @@ -436,4 +436,25 @@ public class HttpFieldsTest } + @Test + public void testContains() throws Exception + { + HttpFields header = new HttpFields(); + + header.add("0", ""); + header.add("1", ","); + header.add("2", ",,"); + header.add("3", "abc"); + header.add("4", "def"); + header.add("5", "abc,def,hig"); + header.add("6", "abc"); + header.add("6", "def"); + header.add("6", "hig"); + + for (int i=0;i<7;i++) + { + assertFalse(""+i,header.getField(""+i).contains("xyz")); + assertEquals(""+i,i>=4,header.getField(""+i).contains("def")); + } + } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java index cd074b79831..065de85c42d 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java @@ -60,7 +60,7 @@ public class HttpGeneratorServerTest } @Override - public boolean headerComplete(boolean hasBody,boolean persistent) + public boolean headerComplete() { _content= null; return false; diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java index ddb473d7f73..79dbc75758b 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java @@ -735,7 +735,7 @@ public class HttpParserTest } @Override - public boolean headerComplete(boolean hasBody,boolean persistent) + public boolean headerComplete() { //System.err.println("headerComplete"); _content= null; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index 9172f2e8ef8..f3df83e9b80 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -500,14 +500,17 @@ public abstract class HttpChannel } @Override - public boolean headerComplete(boolean hasBody,boolean persistent) + public boolean headerComplete() { _requests++; + boolean persistent; switch (_version) { case HTTP_0_9: + persistent=false; break; case HTTP_1_0: + persistent=_request.getHttpFields().contains(HttpHeader.CONNECTION,HttpHeaderValue.KEEP_ALIVE.asString()); if (persistent) _response.getHttpFields().add(HttpHeader.CONNECTION,HttpHeaderValue.KEEP_ALIVE); @@ -516,7 +519,8 @@ public abstract class HttpChannel break; case HTTP_1_1: - + persistent=!_request.getHttpFields().contains(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE.asString()); + if (!persistent) _response.getHttpFields().add(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE); @@ -537,7 +541,10 @@ public abstract class HttpChannel break; default: + throw new IllegalStateException(); } + + _request.setPersistent(persistent); // Either handle now or wait for first content/message complete if (_expect100Continue) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index 71dd53ba6e2..db05edfe683 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -252,16 +252,19 @@ public class HttpConnection extends AbstractConnection // Parse the buffer if (_parser.parseNext(_requestBuffer)) { + // reset header count + _headerBytes=0; + // For most requests, there will not be a body, so we can try to recycle the buffer now releaseRequestBuffer(); - _headerBytes=0; + if (!_channel.getRequest().isPersistent()) + _generator.setPersistent(false); + // The parser returned true, which indicates the channel is ready // to handle a request. Call the channel and this will either handle the // request/response to completion OR if the request suspends, the channel // will be left in !idle state so our outer loop will exit. - if (!_parser.isPersistent()) - _generator.setPersistent(false); _channel.handle(); // Return if the channel is still processing the request diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 773122f9e48..ad24f4ceed4 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -159,6 +159,7 @@ public class Request implements HttpServletRequest private SessionManager _sessionManager; private long _timeStamp; private long _dispatchTime; + private boolean _persistent; private HttpURI _uri; @@ -184,7 +185,19 @@ public class Request implements HttpServletRequest { return _in; } - + + /* ------------------------------------------------------------ */ + public boolean isPersistent() + { + return _persistent; + } + + /* ------------------------------------------------------------ */ + public void setPersistent(boolean persistent) + { + _persistent = persistent; + } + /* ------------------------------------------------------------ */ public void addEventListener(final EventListener listener) { diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java index 706b16342d8..7c49efb18ba 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java @@ -47,7 +47,9 @@ import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.session.HashSessionIdManager; import org.eclipse.jetty.server.session.HashSessionManager; import org.eclipse.jetty.server.session.HashedSession; +import org.hamcrest.Matchers; import org.junit.After; +import org.junit.Assert; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; @@ -585,6 +587,7 @@ public class ResponseTest { server.setHandler(new AbstractHandler() { + @Override public void handle(String string, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setStatus(200); @@ -607,14 +610,14 @@ public class ResponseTest LineNumberReader reader = new LineNumberReader(new InputStreamReader(socket.getInputStream())); String line = reader.readLine(); - assertTrue(line!=null && line.startsWith("HTTP/1.1 200 OK")); + Assert.assertThat(line,Matchers.startsWith("HTTP/1.1 200 OK")); // look for blank line while (line!=null && line.length()>0) line = reader.readLine(); // Read the first line of the GET line = reader.readLine(); - assertTrue(line!=null && line.startsWith("HTTP/1.1 200 OK")); + Assert.assertThat(line,Matchers.startsWith("HTTP/1.1 200 OK")); String last=null; while (line!=null) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/AttributesMap.java b/jetty-util/src/main/java/org/eclipse/jetty/util/AttributesMap.java index 1ee017175da..adbf6d575c3 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/AttributesMap.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/AttributesMap.java @@ -16,10 +16,10 @@ package org.eclipse.jetty.util; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; /* ------------------------------------------------------------ */ /** AttributesMap. @@ -33,7 +33,7 @@ public class AttributesMap implements Attributes /* ------------------------------------------------------------ */ public AttributesMap() { - _map=new HashMap(); + _map=new ConcurrentHashMap(); } /* ------------------------------------------------------------ */ @@ -45,13 +45,14 @@ public class AttributesMap implements Attributes /* ------------------------------------------------------------ */ public AttributesMap(AttributesMap map) { - _map=new HashMap(map._map); + _map=new ConcurrentHashMap(map._map); } /* ------------------------------------------------------------ */ /* * @see org.eclipse.jetty.util.Attributes#removeAttribute(java.lang.String) */ + @Override public void removeAttribute(String name) { _map.remove(name); @@ -61,6 +62,7 @@ public class AttributesMap implements Attributes /* * @see org.eclipse.jetty.util.Attributes#setAttribute(java.lang.String, java.lang.Object) */ + @Override public void setAttribute(String name, Object attribute) { if (attribute==null) @@ -73,6 +75,7 @@ public class AttributesMap implements Attributes /* * @see org.eclipse.jetty.util.Attributes#getAttribute(java.lang.String) */ + @Override public Object getAttribute(String name) { return _map.get(name); @@ -82,6 +85,7 @@ public class AttributesMap implements Attributes /* * @see org.eclipse.jetty.util.Attributes#getAttributeNames() */ + @Override public Enumeration getAttributeNames() { return Collections.enumeration(_map.keySet()); @@ -120,6 +124,7 @@ public class AttributesMap implements Attributes /* * @see org.eclipse.jetty.util.Attributes#clear() */ + @Override public void clearAttributes() { _map.clear();