diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java b/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java index 53df952595a..89c3db10264 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java @@ -15,12 +15,9 @@ package org.eclipse.jetty.http; import java.io.IOException; -import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.Buffers; -import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EofException; -import org.eclipse.jetty.io.View; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/EncodedHttpURI.java b/jetty-http/src/main/java/org/eclipse/jetty/http/EncodedHttpURI.java index 775206c5935..1fa9a5e064b 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/EncodedHttpURI.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/EncodedHttpURI.java @@ -44,14 +44,14 @@ public class EncodedHttpURI extends HttpURI _raw[_scheme+1]=='t' && _raw[_scheme+2]=='t' && _raw[_scheme+3]=='p' ) - return HttpSchemes.HTTP; + return HttpSchemes.HTTP.toString(); if (l==6 && _raw[_scheme]=='h' && _raw[_scheme+1]=='t' && _raw[_scheme+2]=='t' && _raw[_scheme+3]=='p' && _raw[_scheme+4]=='s' ) - return HttpSchemes.HTTPS; + return HttpSchemes.HTTPS.toString(); return StringUtil.toString(_raw,_scheme,_authority-_scheme-1,_encoding); } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpBuffersImpl.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpBuffersImpl.java index 43db337e73c..7b731a58cd1 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpBuffersImpl.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpBuffersImpl.java @@ -30,10 +30,10 @@ public class HttpBuffersImpl extends AbstractLifeCycle implements HttpBuffers private int _responseHeaderSize=6*1024; private int _maxBuffers=1024; - private Buffers.Type _requestBufferType=Buffers.Type.BYTE_ARRAY; - private Buffers.Type _requestHeaderType=Buffers.Type.BYTE_ARRAY; - private Buffers.Type _responseBufferType=Buffers.Type.BYTE_ARRAY; - private Buffers.Type _responseHeaderType=Buffers.Type.BYTE_ARRAY; + private Buffers.Type _requestBufferType=Buffers.Type.INDIRECT; + private Buffers.Type _requestHeaderType=Buffers.Type.INDIRECT; + private Buffers.Type _responseBufferType=Buffers.Type.INDIRECT; + private Buffers.Type _responseHeaderType=Buffers.Type.INDIRECT; private Buffers _requestBuffers; private Buffers _responseBuffers; 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 36d38a7dea9..86a471a00a8 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 @@ -15,6 +15,7 @@ package org.eclipse.jetty.http; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; @@ -34,16 +35,13 @@ import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import org.eclipse.jetty.io.Buffer; -import org.eclipse.jetty.io.BufferCache; -import org.eclipse.jetty.io.BufferCache.CachedBuffer; import org.eclipse.jetty.io.BufferDateCache; -import org.eclipse.jetty.io.BufferUtil; -import org.eclipse.jetty.io.ByteArrayBuffer; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.QuotedStringTokenizer; import org.eclipse.jetty.util.StringMap; import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -289,12 +287,12 @@ public class HttpFields /* -------------------------------------------------------------- */ public final static String __01Jan1970=formatDate(0); - public final static Buffer __01Jan1970_BUFFER=new ByteArrayBuffer(__01Jan1970); + public final static ByteBuffer __01Jan1970_BUFFER=BufferUtil.toBuffer(__01Jan1970); public final static String __01Jan1970_COOKIE = formatCookieDate(0).trim(); - + private final static byte[] __colon_space = new byte[] {':',' '}; /* -------------------------------------------------------------- */ private final ArrayList _fields = new ArrayList(20); - private final HashMap _names = new HashMap(32); + private final StringMap _names = new StringMap(true); private final int _maxCookieVersion; /* ------------------------------------------------------------ */ @@ -316,38 +314,6 @@ public class HttpFields } - // TODO externalize this cache so it can be configurable - private static ConcurrentMap __cache = new ConcurrentHashMap(); - private static int __cacheSize = Integer.getInteger("org.eclipse.jetty.http.HttpFields.CACHE",2000); - - /* -------------------------------------------------------------- */ - private Buffer convertValue(String value) - { - Buffer buffer = __cache.get(value); - if (buffer!=null) - return buffer; - - try - { - buffer = new ByteArrayBuffer(value,StringUtil.__ISO_8859_1); - - if (__cacheSize>0) - { - if (__cache.size()>__cacheSize) - __cache.clear(); - Buffer b=__cache.putIfAbsent(value,buffer); - if (b!=null) - buffer=b; - } - - return buffer; - } - catch (UnsupportedEncodingException e) - { - throw new RuntimeException(e); - } - } - /* -------------------------------------------------------------- */ /** * Get Collection of header names. @@ -355,11 +321,10 @@ public class HttpFields public Collection getFieldNamesCollection() { final List list = new ArrayList(_fields.size()); - for (Field f : _fields) { if (f!=null) - list.add(BufferUtil.to8859_1_String(f._name)); + list.add(f._name); } return list; } @@ -404,29 +369,29 @@ public class HttpFields } /* ------------------------------------------------------------ */ - private Field getField(String name) + public Field getField(HttpHeaders header) { - return _names.get(HttpHeaders.CACHE.lookup(name)); + return _names.get(header.toString()); } - + /* ------------------------------------------------------------ */ - private Field getField(Buffer name) + public Field getField(String name) { - return _names.get(HttpHeaders.CACHE.lookup(name)); - } - - /* ------------------------------------------------------------ */ - public boolean containsKey(Buffer name) - { - return _names.containsKey(HttpHeaders.CACHE.lookup(name)); + return _names.get(name); } /* ------------------------------------------------------------ */ public boolean containsKey(String name) { - return _names.containsKey(HttpHeaders.CACHE.lookup(name)); + return _names.containsKey(name); } + /* -------------------------------------------------------------- */ + public String getStringField(HttpHeaders header) + { + return getStringField(header.toString()); + } + /* -------------------------------------------------------------- */ /** * @return the value of a field, or null if not found. For multiple fields of the same name, @@ -439,30 +404,6 @@ public class HttpFields return field==null?null:field.getValue(); } - /* -------------------------------------------------------------- */ - /** - * @return the value of a field, or null if not found. For multiple fields of the same name, - * only the first is returned. - * @param name the case-insensitive field name - */ - public String getStringField(Buffer name) - { - Field field = getField(name); - return field==null?null:field.getValue(); - } - - /* -------------------------------------------------------------- */ - /** - * @return the value of a field, or null if not found. For multiple fields of the same name, - * only the first is returned. - * @param name the case-insensitive field name - */ - public Buffer get(Buffer name) - { - Field field = getField(name); - return field==null?null:field._value; - } - /* -------------------------------------------------------------- */ /** @@ -522,41 +463,6 @@ public class HttpFields }; } - /* -------------------------------------------------------------- */ - /** - * Get multi headers - * - * @return Enumeration of the value Strings - * @param name the case-insensitive field name - */ - public Enumeration getValues(Buffer name) - { - final Field field = getField(name); - if (field == null) - { - List empty=Collections.emptyList(); - return Collections.enumeration(empty); - } - - return new Enumeration() - { - Field f = field; - - public boolean hasMoreElements() - { - return f != null; - } - - public String nextElement() throws NoSuchElementException - { - if (f == null) throw new NoSuchElementException(); - Field n = f; - f = f._next; - return n.getValue(); - } - }; - } - /* -------------------------------------------------------------- */ /** * Get multi field values with separator. The multiple values can be represented as separate @@ -599,7 +505,7 @@ public class HttpFields }; } - + /* -------------------------------------------------------------- */ /** * Set a field. @@ -608,49 +514,11 @@ public class HttpFields * @param value the value of the field. If null the field is cleared. */ public void put(String name, String value) - { - if (value==null) - remove(name); - else - { - Buffer n = HttpHeaders.CACHE.lookup(name); - Buffer v = convertValue(value); - put(n, v); - } - } - - /* -------------------------------------------------------------- */ - /** - * Set a field. - * - * @param name the name of the field - * @param value the value of the field. If null the field is cleared. - */ - public void put(Buffer name, String value) - { - Buffer n = HttpHeaders.CACHE.lookup(name); - Buffer v = convertValue(value); - put(n, v); - } - - /* -------------------------------------------------------------- */ - /** - * Set a field. - * - * @param name the name of the field - * @param value the value of the field. If null the field is cleared. - */ - public void put(Buffer name, Buffer value) { remove(name); if (value == null) return; - if (!(name instanceof BufferCache.CachedBuffer)) - name = HttpHeaders.CACHE.lookup(name); - if (!(value instanceof CachedBuffer)) - value= HttpHeaderValues.CACHE.lookup(value).asImmutableBuffer(); - // new value; Field field = new Field(name, value); _fields.add(field); @@ -664,31 +532,12 @@ public class HttpFields * @param name the name of the field * @param list the List value of the field. If null the field is cleared. */ - public void put(String name, List list) + public void put(String name, List list) { - if (list == null || list.size() == 0) - { - remove(name); - return; - } - Buffer n = HttpHeaders.CACHE.lookup(name); - - Object v = list.get(0); - if (v != null) - put(n, HttpHeaderValues.CACHE.lookup(v.toString())); - else - remove(n); - - if (list.size() > 1) - { - java.util.Iterator iter = list.iterator(); - iter.next(); - while (iter.hasNext()) - { - v = iter.next(); - if (v != null) put(n, HttpHeaderValues.CACHE.lookup(v.toString())); - } - } + remove(name); + for (String v : list) + if (v!=null) + add(name,v); } /* -------------------------------------------------------------- */ @@ -702,35 +551,8 @@ public class HttpFields * value. */ public void add(String name, String value) throws IllegalArgumentException - { - if (value==null) - return; - Buffer n = HttpHeaders.CACHE.lookup(name); - Buffer v = convertValue(value); - add(n, v); - } - - /* -------------------------------------------------------------- */ - /** - * Add to or set a field. If the field is allowed to have multiple values, add will add multiple - * headers of the same name. - * - * @param name the name of the field - * @param value the value of the field. - * @exception IllegalArgumentException If the name is a single valued field and already has a - * value. - */ - public void add(Buffer name, Buffer value) throws IllegalArgumentException { if (value == null) throw new IllegalArgumentException("null value"); - - if (!(name instanceof CachedBuffer)) - name = HttpHeaders.CACHE.lookup(name); - name=name.asImmutableBuffer(); - - if (!(value instanceof CachedBuffer) && HttpHeaderValues.hasKnownValues(HttpHeaders.CACHE.getOrdinal(name))) - value= HttpHeaderValues.CACHE.lookup(value); - value=value.asImmutableBuffer(); Field field = _names.get(name); Field last = null; @@ -751,6 +573,7 @@ public class HttpFields _names.put(name, field); } + /* ------------------------------------------------------------ */ /** * Remove a field. @@ -759,19 +582,6 @@ public class HttpFields */ public void remove(String name) { - remove(HttpHeaders.CACHE.lookup(name)); - } - - /* ------------------------------------------------------------ */ - /** - * Remove a field. - * - * @param name - */ - public void remove(Buffer name) - { - if (!(name instanceof BufferCache.CachedBuffer)) - name = HttpHeaders.CACHE.lookup(name); Field field = _names.remove(name); while (field != null) { @@ -794,20 +604,6 @@ public class HttpFields return field==null?-1L:field.getLongValue(); } - /* -------------------------------------------------------------- */ - /** - * Get a header as an long value. Returns the value of an integer field or -1 if not found. The - * case of the field name is ignored. - * - * @param name the case-insensitive field name - * @exception NumberFormatException If bad long found - */ - public long getLongField(Buffer name) throws NumberFormatException - { - Field field = getField(name); - return field==null?-1L:field.getLongValue(); - } - /* -------------------------------------------------------------- */ /** * Get a header as a date value. Returns the value of a date field, or -1 if not found. The case @@ -821,7 +617,7 @@ public class HttpFields if (field == null) return -1; - String val = valueParameters(BufferUtil.to8859_1_String(field._value), null); + String val = valueParameters(field._value, null); if (val == null) return -1; @@ -831,18 +627,6 @@ public class HttpFields return date; } - /* -------------------------------------------------------------- */ - /** - * Sets the value of an long field. - * - * @param name the field name - * @param value the field long value - */ - public void putLongField(Buffer name, long value) - { - Buffer v = BufferUtil.toBuffer(value); - put(name, v); - } /* -------------------------------------------------------------- */ /** @@ -853,52 +637,11 @@ public class HttpFields */ public void putLongField(String name, long value) { - Buffer n = HttpHeaders.CACHE.lookup(name); - Buffer v = BufferUtil.toBuffer(value); - put(n, v); - } - - /* -------------------------------------------------------------- */ - /** - * Sets the value of an long field. - * - * @param name the field name - * @param value the field long value - */ - public void addLongField(String name, long value) - { - Buffer n = HttpHeaders.CACHE.lookup(name); - Buffer v = BufferUtil.toBuffer(value); - add(n, v); - } - - /* -------------------------------------------------------------- */ - /** - * Sets the value of an long field. - * - * @param name the field name - * @param value the field long value - */ - public void addLongField(Buffer name, long value) - { - Buffer v = BufferUtil.toBuffer(value); - add(name, v); - } - - /* -------------------------------------------------------------- */ - /** - * Sets the value of a date field. - * - * @param name the field name - * @param date the field date value - */ - public void putDateField(Buffer name, long date) - { - String d=formatDate(date); - Buffer v = new ByteArrayBuffer(d); + String v = Long.toString(value); put(name, v); } + /* -------------------------------------------------------------- */ /** * Sets the value of a date field. @@ -908,8 +651,8 @@ public class HttpFields */ public void putDateField(String name, long date) { - Buffer n = HttpHeaders.CACHE.lookup(name); - putDateField(n,date); + String d=formatDate(date); + put(name, d); } /* -------------------------------------------------------------- */ @@ -922,9 +665,7 @@ public class HttpFields public void addDateField(String name, long date) { String d=formatDate(date); - Buffer n = HttpHeaders.CACHE.lookup(name); - Buffer v = new ByteArrayBuffer(d); - add(n, v); + add(name,d); } /* ------------------------------------------------------------ */ @@ -1053,7 +794,7 @@ public class HttpFields { _fields.remove(field); if (last==null) - _names.put(HttpHeaders.SET_COOKIE_BUFFER,field._next); + _names.put(HttpHeaders.SET_COOKIE.toString(),field._next); else last._next=field._next; break; @@ -1062,14 +803,14 @@ public class HttpFields field=field._next; } - add(HttpHeaders.SET_COOKIE_BUFFER, new ByteArrayBuffer(name_value_params)); + add(HttpHeaders.SET_COOKIE.toString(), name_value_params); // Expire responses with set-cookie headers so they do not get cached. - put(HttpHeaders.EXPIRES_BUFFER, __01Jan1970_BUFFER); + put(HttpHeaders.EXPIRES.toString(), __01Jan1970); } /* -------------------------------------------------------------- */ - public void putTo(Buffer buffer) throws IOException + public void putTo(ByteBuffer buffer) throws IOException { for (int i = 0; i < _fields.size(); i++) { @@ -1130,11 +871,11 @@ public class HttpFields { if (fields == null) return; - Enumeration e = fields.getFieldNames(); + Enumeration e = fields.getFieldNames(); while (e.hasMoreElements()) { String name = (String) e.nextElement(); - Enumeration values = fields.getValues(name); + Enumeration values = fields.getValues(name); while (values.hasMoreElements()) add(name, (String) values.nextElement()); } @@ -1183,7 +924,7 @@ public class HttpFields /* ------------------------------------------------------------ */ private static final Float __one = new Float("1.0"); private static final Float __zero = new Float("0.0"); - private static final StringMap __qualities = new StringMap(); + private static final StringMap __qualities = new StringMap<>(); static { __qualities.put(null, __one); @@ -1215,11 +956,12 @@ public class HttpFields if (value.charAt(qe++) == 'q') { qe++; - Map.Entry entry = __qualities.getEntry(value, qe, value.length() - qe); - if (entry != null) return (Float) entry.getValue(); + Map.Entry entry = __qualities.getEntry(value, qe, value.length() - qe); + if (entry != null) + return (Float) entry.getValue(); } - HashMap params = new HashMap(3); + Map params = new HashMap(4); valueParameters(value, params); String qs = (String) params.get("q"); Float q = (Float) __qualities.get(qs); @@ -1244,9 +986,10 @@ public class HttpFields * @param e Enumeration of values with quality parameters * @return values in quality order. */ - public static List qualityList(Enumeration e) + public static List qualityList(Enumeration e) { - if (e == null || !e.hasMoreElements()) return Collections.EMPTY_LIST; + if (e == null || !e.hasMoreElements()) + return Collections.emptyList(); Object list = null; Object qual = null; @@ -1296,65 +1039,57 @@ public class HttpFields /* ------------------------------------------------------------ */ public static final class Field { - private Buffer _name; - private Buffer _value; + private final String _name; + private final String _value; private Field _next; - + /* ------------------------------------------------------------ */ - private Field(Buffer name, Buffer value) + private Field(String name, String value) { _name = name; _value = value; _next = null; } - /* ------------------------------------------------------------ */ - public void putTo(Buffer buffer) throws IOException + private byte[] toSanitisedBytes(String s) { - int o=(_name instanceof CachedBuffer)?((CachedBuffer)_name).getOrdinal():-1; - if (o>=0) - buffer.put(_name); - else + byte[] bytes = s.getBytes(StringUtil.__ISO_8859_1_CHARSET); + for (int i=bytes.length;i-->0;) { - int s=_name.getIndex(); - int e=_name.putIndex(); - while (s=0) - buffer.put(_value); else { - int s=_value.getIndex(); - int e=_value.putIndex(); - while (s CACHE= new StringMap(true); + static { - switch(httpHeaderOrdinal) - { - case HttpHeaders.CONNECTION_ORDINAL: - case HttpHeaders.TRANSFER_ENCODING_ORDINAL: - case HttpHeaders.CONTENT_ENCODING_ORDINAL: - return true; - } - return false; + for (HttpHeaderValues value : HttpHeaderValues.values()) + CACHE.put(value.toString(),value); + } + + private final String _string; + private final ByteBuffer _buffer; + + /* ------------------------------------------------------------ */ + HttpHeaderValues(String s) + { + _string=s; + _buffer=BufferUtil.toBuffer(s); + } + + /* ------------------------------------------------------------ */ + public ByteBuffer toBuffer() + { + return _buffer.asReadOnlyBuffer(); + } + + /* ------------------------------------------------------------ */ + public String toString() + { + return _string; + } + + /* ------------------------------------------------------------ */ + private static EnumSet __known = + EnumSet.of(HttpHeaders.CONNECTION, + HttpHeaders.TRANSFER_ENCODING, + HttpHeaders.CONTENT_ENCODING); + + /* ------------------------------------------------------------ */ + public static boolean hasKnownValues(HttpHeaders header) + { + if (header==null) + return false; + return __known.contains(header); } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeaders.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeaders.java index fe73e4c3af0..e55752bcbc7 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeaders.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeaders.java @@ -13,224 +13,125 @@ package org.eclipse.jetty.http; -import org.eclipse.jetty.io.Buffer; -import org.eclipse.jetty.io.BufferCache; +import java.nio.ByteBuffer; -/* ------------------------------------------------------------------------------- */ -/** - */ -public class HttpHeaders extends BufferCache +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.StringMap; + + +public enum HttpHeaders { /* ------------------------------------------------------------ */ /** General Fields. */ - public final static String - CONNECTION= "Connection", - CACHE_CONTROL= "Cache-Control", - DATE= "Date", - PRAGMA= "Pragma", - PROXY_CONNECTION = "Proxy-Connection", - TRAILER= "Trailer", - TRANSFER_ENCODING= "Transfer-Encoding", - UPGRADE= "Upgrade", - VIA= "Via", - WARNING= "Warning", - NEGOTIATE= "Negotiate"; + CONNECTION("Connection"), + CACHE_CONTROL("Cache-Control"), + DATE("Date"), + PRAGMA("Pragma"), + PROXY_CONNECTION ("Proxy-Connection"), + TRAILER("Trailer"), + TRANSFER_ENCODING("Transfer-Encoding"), + UPGRADE("Upgrade"), + VIA("Via"), + WARNING("Warning"), + NEGOTIATE("Negotiate"), /* ------------------------------------------------------------ */ /** Entity Fields. */ - public final static String ALLOW= "Allow", - CONTENT_ENCODING= "Content-Encoding", - CONTENT_LANGUAGE= "Content-Language", - CONTENT_LENGTH= "Content-Length", - CONTENT_LOCATION= "Content-Location", - CONTENT_MD5= "Content-MD5", - CONTENT_RANGE= "Content-Range", - CONTENT_TYPE= "Content-Type", - EXPIRES= "Expires", - LAST_MODIFIED= "Last-Modified"; + ALLOW("Allow"), + CONTENT_ENCODING("Content-Encoding"), + CONTENT_LANGUAGE("Content-Language"), + CONTENT_LENGTH("Content-Length"), + CONTENT_LOCATION("Content-Location"), + CONTENT_MD5("Content-MD5"), + CONTENT_RANGE("Content-Range"), + CONTENT_TYPE("Content-Type"), + EXPIRES("Expires"), + LAST_MODIFIED("Last-Modified"), /* ------------------------------------------------------------ */ /** Request Fields. */ - public final static String ACCEPT= "Accept", - ACCEPT_CHARSET= "Accept-Charset", - ACCEPT_ENCODING= "Accept-Encoding", - ACCEPT_LANGUAGE= "Accept-Language", - AUTHORIZATION= "Authorization", - EXPECT= "Expect", - FORWARDED= "Forwarded", - FROM= "From", - HOST= "Host", - IF_MATCH= "If-Match", - IF_MODIFIED_SINCE= "If-Modified-Since", - IF_NONE_MATCH= "If-None-Match", - IF_RANGE= "If-Range", - IF_UNMODIFIED_SINCE= "If-Unmodified-Since", - KEEP_ALIVE= "Keep-Alive", - MAX_FORWARDS= "Max-Forwards", - PROXY_AUTHORIZATION= "Proxy-Authorization", - RANGE= "Range", - REQUEST_RANGE= "Request-Range", - REFERER= "Referer", - TE= "TE", - USER_AGENT= "User-Agent", - X_FORWARDED_FOR= "X-Forwarded-For", - X_FORWARDED_PROTO= "X-Forwarded-Proto", - X_FORWARDED_SERVER= "X-Forwarded-Server", - X_FORWARDED_HOST= "X-Forwarded-Host"; + ACCEPT("Accept"), + ACCEPT_CHARSET("Accept-Charset"), + ACCEPT_ENCODING("Accept-Encoding"), + ACCEPT_LANGUAGE("Accept-Language"), + AUTHORIZATION("Authorization"), + EXPECT("Expect"), + FORWARDED("Forwarded"), + FROM("From"), + HOST("Host"), + IF_MATCH("If-Match"), + IF_MODIFIED_SINCE("If-Modified-Since"), + IF_NONE_MATCH("If-None-Match"), + IF_RANGE("If-Range"), + IF_UNMODIFIED_SINCE("If-Unmodified-Since"), + KEEP_ALIVE("Keep-Alive"), + MAX_FORWARDS("Max-Forwards"), + PROXY_AUTHORIZATION("Proxy-Authorization"), + RANGE("Range"), + REQUEST_RANGE("Request-Range"), + REFERER("Referer"), + TE("TE"), + USER_AGENT("User-Agent"), + X_FORWARDED_FOR("X-Forwarded-For"), + X_FORWARDED_PROTO("X-Forwarded-Proto"), + X_FORWARDED_SERVER("X-Forwarded-Server"), + X_FORWARDED_HOST("X-Forwarded-Host"), /* ------------------------------------------------------------ */ /** Response Fields. */ - public final static String ACCEPT_RANGES= "Accept-Ranges", - AGE= "Age", - ETAG= "ETag", - LOCATION= "Location", - PROXY_AUTHENTICATE= "Proxy-Authenticate", - RETRY_AFTER= "Retry-After", - SERVER= "Server", - SERVLET_ENGINE= "Servlet-Engine", - VARY= "Vary", - WWW_AUTHENTICATE= "WWW-Authenticate"; + ACCEPT_RANGES("Accept-Ranges"), + AGE("Age"), + ETAG("ETag"), + LOCATION("Location"), + PROXY_AUTHENTICATE("Proxy-Authenticate"), + RETRY_AFTER("Retry-After"), + SERVER("Server"), + SERVLET_ENGINE("Servlet-Engine"), + VARY("Vary"), + WWW_AUTHENTICATE("WWW-Authenticate"), /* ------------------------------------------------------------ */ /** Other Fields. */ - public final static String COOKIE= "Cookie", - SET_COOKIE= "Set-Cookie", - SET_COOKIE2= "Set-Cookie2", - MIME_VERSION= "MIME-Version", - IDENTITY= "identity"; + COOKIE("Cookie"), + SET_COOKIE("Set-Cookie"), + SET_COOKIE2("Set-Cookie2"), + MIME_VERSION("MIME-Version"), + IDENTITY("identity"); - public final static int CONNECTION_ORDINAL= 1, - DATE_ORDINAL= 2, - PRAGMA_ORDINAL= 3, - TRAILER_ORDINAL= 4, - TRANSFER_ENCODING_ORDINAL= 5, - UPGRADE_ORDINAL= 6, - VIA_ORDINAL= 7, - WARNING_ORDINAL= 8, - ALLOW_ORDINAL= 9, - CONTENT_ENCODING_ORDINAL= 10, - CONTENT_LANGUAGE_ORDINAL= 11, - CONTENT_LENGTH_ORDINAL= 12, - CONTENT_LOCATION_ORDINAL= 13, - CONTENT_MD5_ORDINAL= 14, - CONTENT_RANGE_ORDINAL= 15, - CONTENT_TYPE_ORDINAL= 16, - EXPIRES_ORDINAL= 17, - LAST_MODIFIED_ORDINAL= 18, - ACCEPT_ORDINAL= 19, - ACCEPT_CHARSET_ORDINAL= 20, - ACCEPT_ENCODING_ORDINAL= 21, - ACCEPT_LANGUAGE_ORDINAL= 22, - AUTHORIZATION_ORDINAL= 23, - EXPECT_ORDINAL= 24, - FORWARDED_ORDINAL= 25, - FROM_ORDINAL= 26, - HOST_ORDINAL= 27, - IF_MATCH_ORDINAL= 28, - IF_MODIFIED_SINCE_ORDINAL= 29, - IF_NONE_MATCH_ORDINAL= 30, - IF_RANGE_ORDINAL= 31, - IF_UNMODIFIED_SINCE_ORDINAL= 32, - KEEP_ALIVE_ORDINAL= 33, - MAX_FORWARDS_ORDINAL= 34, - PROXY_AUTHORIZATION_ORDINAL= 35, - RANGE_ORDINAL= 36, - REQUEST_RANGE_ORDINAL= 37, - REFERER_ORDINAL= 38, - TE_ORDINAL= 39, - USER_AGENT_ORDINAL= 40, - X_FORWARDED_FOR_ORDINAL= 41, - ACCEPT_RANGES_ORDINAL= 42, - AGE_ORDINAL= 43, - ETAG_ORDINAL= 44, - LOCATION_ORDINAL= 45, - PROXY_AUTHENTICATE_ORDINAL= 46, - RETRY_AFTER_ORDINAL= 47, - SERVER_ORDINAL= 48, - SERVLET_ENGINE_ORDINAL= 49, - VARY_ORDINAL= 50, - WWW_AUTHENTICATE_ORDINAL= 51, - COOKIE_ORDINAL= 52, - SET_COOKIE_ORDINAL= 53, - SET_COOKIE2_ORDINAL= 54, - MIME_VERSION_ORDINAL= 55, - IDENTITY_ORDINAL= 56, - CACHE_CONTROL_ORDINAL=57, - PROXY_CONNECTION_ORDINAL=58, - X_FORWARDED_PROTO_ORDINAL=59, - X_FORWARDED_SERVER_ORDINAL=60, - X_FORWARDED_HOST_ORDINAL=61; - public final static HttpHeaders CACHE= new HttpHeaders(); - - public final static Buffer - HOST_BUFFER=CACHE.add(HOST,HOST_ORDINAL), - ACCEPT_BUFFER=CACHE.add(ACCEPT,ACCEPT_ORDINAL), - ACCEPT_CHARSET_BUFFER=CACHE.add(ACCEPT_CHARSET,ACCEPT_CHARSET_ORDINAL), - ACCEPT_ENCODING_BUFFER=CACHE.add(ACCEPT_ENCODING,ACCEPT_ENCODING_ORDINAL), - ACCEPT_LANGUAGE_BUFFER=CACHE.add(ACCEPT_LANGUAGE,ACCEPT_LANGUAGE_ORDINAL), - - CONTENT_LENGTH_BUFFER=CACHE.add(CONTENT_LENGTH,CONTENT_LENGTH_ORDINAL), - CONNECTION_BUFFER=CACHE.add(CONNECTION,CONNECTION_ORDINAL), - CACHE_CONTROL_BUFFER=CACHE.add(CACHE_CONTROL,CACHE_CONTROL_ORDINAL), - DATE_BUFFER=CACHE.add(DATE,DATE_ORDINAL), - PRAGMA_BUFFER=CACHE.add(PRAGMA,PRAGMA_ORDINAL), - TRAILER_BUFFER=CACHE.add(TRAILER,TRAILER_ORDINAL), - TRANSFER_ENCODING_BUFFER=CACHE.add(TRANSFER_ENCODING,TRANSFER_ENCODING_ORDINAL), - UPGRADE_BUFFER=CACHE.add(UPGRADE,UPGRADE_ORDINAL), - VIA_BUFFER=CACHE.add(VIA,VIA_ORDINAL), - WARNING_BUFFER=CACHE.add(WARNING,WARNING_ORDINAL), - ALLOW_BUFFER=CACHE.add(ALLOW,ALLOW_ORDINAL), - CONTENT_ENCODING_BUFFER=CACHE.add(CONTENT_ENCODING,CONTENT_ENCODING_ORDINAL), - CONTENT_LANGUAGE_BUFFER=CACHE.add(CONTENT_LANGUAGE,CONTENT_LANGUAGE_ORDINAL), - CONTENT_LOCATION_BUFFER=CACHE.add(CONTENT_LOCATION,CONTENT_LOCATION_ORDINAL), - CONTENT_MD5_BUFFER=CACHE.add(CONTENT_MD5,CONTENT_MD5_ORDINAL), - CONTENT_RANGE_BUFFER=CACHE.add(CONTENT_RANGE,CONTENT_RANGE_ORDINAL), - CONTENT_TYPE_BUFFER=CACHE.add(CONTENT_TYPE,CONTENT_TYPE_ORDINAL), - EXPIRES_BUFFER=CACHE.add(EXPIRES,EXPIRES_ORDINAL), - LAST_MODIFIED_BUFFER=CACHE.add(LAST_MODIFIED,LAST_MODIFIED_ORDINAL), - AUTHORIZATION_BUFFER=CACHE.add(AUTHORIZATION,AUTHORIZATION_ORDINAL), - EXPECT_BUFFER=CACHE.add(EXPECT,EXPECT_ORDINAL), - FORWARDED_BUFFER=CACHE.add(FORWARDED,FORWARDED_ORDINAL), - FROM_BUFFER=CACHE.add(FROM,FROM_ORDINAL), - IF_MATCH_BUFFER=CACHE.add(IF_MATCH,IF_MATCH_ORDINAL), - IF_MODIFIED_SINCE_BUFFER=CACHE.add(IF_MODIFIED_SINCE,IF_MODIFIED_SINCE_ORDINAL), - IF_NONE_MATCH_BUFFER=CACHE.add(IF_NONE_MATCH,IF_NONE_MATCH_ORDINAL), - IF_RANGE_BUFFER=CACHE.add(IF_RANGE,IF_RANGE_ORDINAL), - IF_UNMODIFIED_SINCE_BUFFER=CACHE.add(IF_UNMODIFIED_SINCE,IF_UNMODIFIED_SINCE_ORDINAL), - KEEP_ALIVE_BUFFER=CACHE.add(KEEP_ALIVE,KEEP_ALIVE_ORDINAL), - MAX_FORWARDS_BUFFER=CACHE.add(MAX_FORWARDS,MAX_FORWARDS_ORDINAL), - PROXY_AUTHORIZATION_BUFFER=CACHE.add(PROXY_AUTHORIZATION,PROXY_AUTHORIZATION_ORDINAL), - RANGE_BUFFER=CACHE.add(RANGE,RANGE_ORDINAL), - REQUEST_RANGE_BUFFER=CACHE.add(REQUEST_RANGE,REQUEST_RANGE_ORDINAL), - REFERER_BUFFER=CACHE.add(REFERER,REFERER_ORDINAL), - TE_BUFFER=CACHE.add(TE,TE_ORDINAL), - USER_AGENT_BUFFER=CACHE.add(USER_AGENT,USER_AGENT_ORDINAL), - X_FORWARDED_FOR_BUFFER=CACHE.add(X_FORWARDED_FOR,X_FORWARDED_FOR_ORDINAL), - X_FORWARDED_PROTO_BUFFER=CACHE.add(X_FORWARDED_PROTO,X_FORWARDED_PROTO_ORDINAL), - X_FORWARDED_SERVER_BUFFER=CACHE.add(X_FORWARDED_SERVER,X_FORWARDED_SERVER_ORDINAL), - X_FORWARDED_HOST_BUFFER=CACHE.add(X_FORWARDED_HOST,X_FORWARDED_HOST_ORDINAL), - ACCEPT_RANGES_BUFFER=CACHE.add(ACCEPT_RANGES,ACCEPT_RANGES_ORDINAL), - AGE_BUFFER=CACHE.add(AGE,AGE_ORDINAL), - ETAG_BUFFER=CACHE.add(ETAG,ETAG_ORDINAL), - LOCATION_BUFFER=CACHE.add(LOCATION,LOCATION_ORDINAL), - PROXY_AUTHENTICATE_BUFFER=CACHE.add(PROXY_AUTHENTICATE,PROXY_AUTHENTICATE_ORDINAL), - RETRY_AFTER_BUFFER=CACHE.add(RETRY_AFTER,RETRY_AFTER_ORDINAL), - SERVER_BUFFER=CACHE.add(SERVER,SERVER_ORDINAL), - SERVLET_ENGINE_BUFFER=CACHE.add(SERVLET_ENGINE,SERVLET_ENGINE_ORDINAL), - VARY_BUFFER=CACHE.add(VARY,VARY_ORDINAL), - WWW_AUTHENTICATE_BUFFER=CACHE.add(WWW_AUTHENTICATE,WWW_AUTHENTICATE_ORDINAL), - COOKIE_BUFFER=CACHE.add(COOKIE,COOKIE_ORDINAL), - SET_COOKIE_BUFFER=CACHE.add(SET_COOKIE,SET_COOKIE_ORDINAL), - SET_COOKIE2_BUFFER=CACHE.add(SET_COOKIE2,SET_COOKIE2_ORDINAL), - MIME_VERSION_BUFFER=CACHE.add(MIME_VERSION,MIME_VERSION_ORDINAL), - IDENTITY_BUFFER=CACHE.add(IDENTITY,IDENTITY_ORDINAL), - PROXY_CONNECTION_BUFFER=CACHE.add(PROXY_CONNECTION,PROXY_CONNECTION_ORDINAL); - + /* ------------------------------------------------------------ */ + public final static StringMap CACHE= new StringMap(true); + static + { + for (HttpHeaders header : HttpHeaders.values()) + CACHE.put(header.toString(),header); + } + private final String _string; + private final ByteBuffer _buffer; + + /* ------------------------------------------------------------ */ + HttpHeaders(String s) + { + _string=s; + _buffer=BufferUtil.toBuffer(s); + } + + /* ------------------------------------------------------------ */ + public ByteBuffer toBuffer() + { + return _buffer.asReadOnlyBuffer(); + } + + /* ------------------------------------------------------------ */ + public String toString() + { + return _string; + } } + diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethods.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethods.java index 82097ca0b69..0e9a9b54a56 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethods.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethods.java @@ -13,47 +13,47 @@ package org.eclipse.jetty.http; -import org.eclipse.jetty.io.Buffer; -import org.eclipse.jetty.io.BufferCache; +import java.nio.ByteBuffer; + +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.StringMap; + /* ------------------------------------------------------------------------------- */ /** - * - * */ -public class HttpMethods +public enum HttpMethods { - public final static String GET= "GET", - POST= "POST", - HEAD= "HEAD", - PUT= "PUT", - OPTIONS= "OPTIONS", - DELETE= "DELETE", - TRACE= "TRACE", - CONNECT= "CONNECT", - MOVE= "MOVE"; + GET, + POST, + HEAD, + PUT, + OPTIONS, + DELETE, + TRACE, + CONNECT, + MOVE; - public final static int GET_ORDINAL= 1, - POST_ORDINAL= 2, - HEAD_ORDINAL= 3, - PUT_ORDINAL= 4, - OPTIONS_ORDINAL= 5, - DELETE_ORDINAL= 6, - TRACE_ORDINAL= 7, - CONNECT_ORDINAL= 8, - MOVE_ORDINAL= 9; + /* ------------------------------------------------------------ */ + public final static StringMap CACHE= new StringMap(true); + static + { + for (HttpMethods method : HttpMethods.values()) + CACHE.put(method.toString(),method); + } - public final static BufferCache CACHE= new BufferCache(); + /* ------------------------------------------------------------ */ + private final ByteBuffer _buffer; - public final static Buffer - GET_BUFFER= CACHE.add(GET, GET_ORDINAL), - POST_BUFFER= CACHE.add(POST, POST_ORDINAL), - HEAD_BUFFER= CACHE.add(HEAD, HEAD_ORDINAL), - PUT_BUFFER= CACHE.add(PUT, PUT_ORDINAL), - OPTIONS_BUFFER= CACHE.add(OPTIONS, OPTIONS_ORDINAL), - DELETE_BUFFER= CACHE.add(DELETE, DELETE_ORDINAL), - TRACE_BUFFER= CACHE.add(TRACE, TRACE_ORDINAL), - CONNECT_BUFFER= CACHE.add(CONNECT, CONNECT_ORDINAL), - MOVE_BUFFER= CACHE.add(MOVE, MOVE_ORDINAL); + /* ------------------------------------------------------------ */ + HttpMethods() + { + _buffer=BufferUtil.toBuffer(toString()); + } + /* ------------------------------------------------------------ */ + public ByteBuffer toBuffer() + { + return _buffer.asReadOnlyBuffer(); + } } 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 c7d7d39f88a..7cb992dc804 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 @@ -14,16 +14,10 @@ package org.eclipse.jetty.http; import java.io.IOException; +import java.nio.ByteBuffer; -import org.eclipse.jetty.io.Buffer; -import org.eclipse.jetty.io.BufferCache.CachedBuffer; -import org.eclipse.jetty.io.BufferUtil; -import org.eclipse.jetty.io.Buffers; -import org.eclipse.jetty.io.ByteArrayBuffer; -import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EofException; -import org.eclipse.jetty.io.View; -import org.eclipse.jetty.io.bio.StreamEndPoint; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -34,14 +28,14 @@ public class HttpParser implements Parser // States public static final int STATE_START=-14; - public static final int STATE_FIELD0=-13; - public static final int STATE_SPACE1=-12; - public static final int STATE_STATUS=-11; - public static final int STATE_URI=-10; - public static final int STATE_SPACE2=-9; - public static final int STATE_END0=-8; - public static final int STATE_END1=-7; - public static final int STATE_FIELD2=-6; + public static final int STATE_METHOD=-13; + public static final int STATE_RESPONSE_VERSION=-12; + public static final int STATE_SPACE1=-11; + public static final int STATE_STATUS=-10; + public static final int STATE_URI=-9; + public static final int STATE_SPACE2=-8; + public static final int STATE_REQUEST_VERSION=-7; + public static final int STATE_REASON=-6; public static final int STATE_HEADER=-5; public static final int STATE_HEADER_NAME=-4; public static final int STATE_HEADER_IN_NAME=-3; @@ -57,60 +51,44 @@ public class HttpParser implements Parser public static final int STATE_SEEKING_EOF=7; private final EventHandler _handler; - private final Buffers _buffers; // source of buffers - private final EndPoint _endp; - private Buffer _header; // Buffer for header data (and small _content) - private Buffer _body; // Buffer for large content - private Buffer _buffer; // The current buffer in use (either _header or _content) - private CachedBuffer _cached; - private final View.CaseInsensitive _tok0; // Saved token: header name, request method or response version - private final View.CaseInsensitive _tok1; // Saved token: header value, request URI or response code - private String _multiLineValue; - private int _responseStatus; // If >0 then we are parsing a response - private boolean _forceContentBuffer; + private final RequestHandler _requestHandler; + private final ResponseHandler _responseHandler; + private HttpHeaders _header; + private HttpHeaderValues _value; + private int _responseStatus; private boolean _persistent; /* ------------------------------------------------------------------------------- */ - protected final View _contentView=new View(); // View of the content in the buffer for {@link Input} - protected int _state=STATE_START; - protected byte _eol; - protected int _length; - protected long _contentLength; - protected long _contentPosition; - protected int _chunkLength; - protected int _chunkPosition; + private int _state=STATE_START; + private String _field0; + private String _field1; + private byte _eol; + private long _contentLength; + private long _contentPosition; + private int _chunkLength; + private int _chunkPosition; private boolean _headResponse; /* ------------------------------------------------------------------------------- */ /** * Constructor. */ - public HttpParser(Buffer buffer, EventHandler handler) + public HttpParser(RequestHandler handler) { - _endp=null; - _buffers=null; - _header=buffer; - _buffer=buffer; _handler=handler; - - _tok0=new View.CaseInsensitive(_header); - _tok1=new View.CaseInsensitive(_header); + _requestHandler=handler; + _responseHandler=null; } /* ------------------------------------------------------------------------------- */ /** * Constructor. - * @param buffers the buffers to use - * @param endp the endpoint - * @param handler the even handler */ - public HttpParser(Buffers buffers, EndPoint endp, EventHandler handler) + public HttpParser(ResponseHandler handler) { - _buffers=buffers; - _endp=endp; _handler=handler; - _tok0=new View.CaseInsensitive(); - _tok1=new View.CaseInsensitive(); + _requestHandler=null; + _responseHandler=handler; } /* ------------------------------------------------------------------------------- */ @@ -170,14 +148,6 @@ public class HttpParser implements Parser return isState(STATE_END); } - /* ------------------------------------------------------------ */ - public boolean isMoreInBuffer() - throws IOException - { - return ( _header!=null && _header.hasContent() || - _body!=null && _body.hasContent()); - } - /* ------------------------------------------------------------------------------- */ public boolean isState(int state) { @@ -204,7 +174,7 @@ public class HttpParser implements Parser * If the parser is already in the END state, then it is {@link #reset reset} and re-parsed. * @throws IllegalStateException If the buffers have already been partially parsed. */ - public void parse() throws IOException + public void parse(ByteBuffer buffer) throws IOException { if (_state==STATE_END) reset(); @@ -212,8 +182,8 @@ public class HttpParser implements Parser throw new IllegalStateException("!START"); // continue parsing - while (_state != STATE_END) - if (parseNext()<0) + while (_state != STATE_END && buffer.hasRemaining()) + if (!parseNext(buffer)) return; } @@ -225,119 +195,47 @@ public class HttpParser implements Parser * @see #parse * @see #parseNext */ - public boolean parseAvailable() throws IOException + public boolean parseAvailable(ByteBuffer buffer) throws IOException { - boolean progress=parseNext()>0; + boolean progress=parseNext(buffer); // continue parsing - while (!isComplete() && _buffer!=null && _buffer.length()>0) + while (!isComplete() && buffer.hasRemaining()) { - progress |= parseNext()>0; + progress |= parseNext(buffer); } return progress; } - - + /* ------------------------------------------------------------------------------- */ /** * Parse until next Event. - * @return an indication of progress <0 EOF, 0 no progress, >0 progress. + * @return an indication of progress */ - public int parseNext() throws IOException + public boolean parseNext(ByteBuffer buffer) throws IOException { try { int progress=0; if (_state == STATE_END) - return 0; - - if (_buffer==null) - _buffer=getHeaderBuffer(); - + return false; if (_state == STATE_CONTENT && _contentPosition == _contentLength) { _state=STATE_END; _handler.messageComplete(_contentPosition); - returnBuffers(); - return 1; - } - - int length=_buffer.length(); - - // Fill buffer if we can - if (length == 0) - { - int filled=-1; - IOException ex=null; - try - { - filled=fill(); - LOG.debug("filled {}/{}",filled,_buffer.length()); - } - catch(IOException e) - { - LOG.debug(this.toString(),e); - ex=e; - } - - if (filled > 0 ) - progress++; - else if (filled < 0 ) - { - _persistent=false; - - // do we have content to deliver? - if (_state>STATE_END) - { - if (_buffer.length()>0 && !_headResponse) - { - Buffer chunk=_buffer.get(_buffer.length()); - _contentPosition += chunk.length(); - _contentView.update(chunk); - _handler.content(chunk); // May recurse here - } - } - - // was this unexpected? - switch(_state) - { - case STATE_END: - case STATE_SEEKING_EOF: - _state=STATE_END; - break; - - case STATE_EOF_CONTENT: - _state=STATE_END; - _handler.messageComplete(_contentPosition); - break; - - default: - _state=STATE_END; - if (!_headResponse) - _handler.earlyEOF(); - _handler.messageComplete(_contentPosition); - } - - if (ex!=null) - throw ex; - - if (!isComplete() && !isIdle()) - throw new EofException(); - - returnBuffers(); - return -1; - } - length=_buffer.length(); + return true; } // Handle header states byte ch; - byte[] array=_buffer.array(); int last=_state; - while (_state0) + int start=-1; + int length=-1; + + while (_state HttpTokens.SPACE || ch<0) { - _buffer.mark(); - _state=STATE_FIELD0; + start=buffer.position()-1; + _state=_requestHandler!=null?STATE_METHOD:STATE_RESPONSE_VERSION; } break; - case STATE_FIELD0: + case STATE_METHOD: if (ch == HttpTokens.SPACE) { - _tok0.update(_buffer.markIndex(), _buffer.getIndex() - 1); - _responseStatus=HttpVersions.CACHE.get(_tok0)==null?-1:0; + HttpMethods method=HttpMethods.CACHE.get(buffer,start,buffer.position()-start-1); + _field0=method==null?BufferUtil.toString(buffer,start,buffer.position()-start-1,StringUtil.__ISO_8859_1_CHARSET):method.toString(); + _state=STATE_SPACE1; + } + else if (ch < HttpTokens.SPACE && ch>=0) + { + throw new HttpException(HttpStatus.BAD_REQUEST_400); + } + break; + + case STATE_RESPONSE_VERSION: + if (ch == HttpTokens.SPACE) + { + int l=buffer.position()-start; + HttpVersions v=HttpVersions.CACHE.get(buffer,start,l); + _field0=v==null?BufferUtil.toString(buffer,start,l,StringUtil.__ISO_8859_1_CHARSET):v.toString(); + start=-1; + _persistent=HttpVersions.HTTP_1_1==v; _state=STATE_SPACE1; - continue; } else if (ch < HttpTokens.SPACE && ch>=0) { @@ -383,14 +296,16 @@ public class HttpParser implements Parser case STATE_SPACE1: if (ch > HttpTokens.SPACE || ch<0) { - _buffer.mark(); - if (_responseStatus>=0) + if (_responseHandler!=null) { _state=STATE_STATUS; _responseStatus=ch-'0'; } else + { _state=STATE_URI; + start=buffer.position()-1; + } } else if (ch < HttpTokens.SPACE) { @@ -401,95 +316,99 @@ public class HttpParser implements Parser case STATE_STATUS: if (ch == HttpTokens.SPACE) { - _tok1.update(_buffer.markIndex(), _buffer.getIndex() - 1); _state=STATE_SPACE2; - continue; } else if (ch>='0' && ch<='9') { _responseStatus=_responseStatus*10+(ch-'0'); - continue; } else if (ch < HttpTokens.SPACE && ch>=0) { - _handler.startResponse(HttpMethods.CACHE.lookup(_tok0), _responseStatus, null); + _responseHandler.startResponse(_field0, _responseStatus, null); + _eol=ch; _state=STATE_HEADER; - _tok0.setPutIndex(_tok0.getIndex()); - _tok1.setPutIndex(_tok1.getIndex()); - _multiLineValue=null; - continue; + _field0=_field1=null; + } + else + { + throw new IllegalStateException(); } - // not a digit, so must be a URI - _state=STATE_URI; - _responseStatus=-1; break; case STATE_URI: if (ch == HttpTokens.SPACE) { - _tok1.update(_buffer.markIndex(), _buffer.getIndex() - 1); + _field1=BufferUtil.toString(buffer,start,buffer.position()-start-1,StringUtil.__ISO_8859_1_CHARSET); + start=-1; _state=STATE_SPACE2; - continue; } else if (ch < HttpTokens.SPACE && ch>=0) { // HTTP/0.9 - _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _buffer.sliceFromMark(), null); + _field1=BufferUtil.toString(buffer,start,buffer.position()-start-1,StringUtil.__ISO_8859_1_CHARSET); + start=-1; + _requestHandler.startRequest(_field0,_field1,null); _persistent=false; _state=STATE_SEEKING_EOF; _handler.headerComplete(); _handler.messageComplete(_contentPosition); - returnBuffers(); - return 1; } break; case STATE_SPACE2: if (ch > HttpTokens.SPACE || ch<0) { - _buffer.mark(); - _state=STATE_FIELD2; + _state=_requestHandler!=null?STATE_REQUEST_VERSION:STATE_REASON; + start=buffer.position()-1; } else if (ch < HttpTokens.SPACE) { - if (_responseStatus>0) + if (_responseHandler!=null) { - _handler.startResponse(HttpMethods.CACHE.lookup(_tok0), _responseStatus, null); + _responseHandler.startResponse(_field0, _responseStatus, null); _eol=ch; _state=STATE_HEADER; - _tok0.setPutIndex(_tok0.getIndex()); - _tok1.setPutIndex(_tok1.getIndex()); - _multiLineValue=null; + _field0=_field1=null; } else { // HTTP/0.9 - _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, null); + _requestHandler.startRequest(_field0, _field1, null); _persistent=false; _state=STATE_SEEKING_EOF; _handler.headerComplete(); _handler.messageComplete(_contentPosition); - returnBuffers(); - return 1; } } break; - case STATE_FIELD2: + case STATE_REQUEST_VERSION: if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) { - Buffer version; - if (_responseStatus>0) - _handler.startResponse(version=HttpVersions.CACHE.lookup(_tok0), _responseStatus,_buffer.sliceFromMark()); - else - _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, version=HttpVersions.CACHE.lookup(_buffer.sliceFromMark())); + HttpVersions v=HttpVersions.CACHE.get(buffer,start,buffer.position()-start-1); + String version=v==null?BufferUtil.toString(buffer,start,buffer.position()-start-1,StringUtil.__ISO_8859_1_CHARSET):v.toString(); + start=-1; + + _requestHandler.startRequest(_field0, _field1, version); _eol=ch; - _persistent=HttpVersions.CACHE.getOrdinal(version)>=HttpVersions.HTTP_1_1_ORDINAL; + _persistent=HttpVersions.HTTP_1_1==v; _state=STATE_HEADER; - _tok0.setPutIndex(_tok0.getIndex()); - _tok1.setPutIndex(_tok1.getIndex()); - _multiLineValue=null; + _field0=_field1=null; + continue; + } + break; + + case STATE_REASON: + if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) + { + String reason=BufferUtil.toString(buffer,start,buffer.position()-start,StringUtil.__ISO_8859_1_CHARSET); + start=-1; + + _responseHandler.startResponse(_field0, _responseStatus, reason); + _eol=ch; + _state=STATE_HEADER; + _field0=_field1=null; continue; } break; @@ -502,7 +421,7 @@ public class HttpParser implements Parser case HttpTokens.TAB: { // header value without name - continuation? - _length=-1; + length=-1; _state=STATE_HEADER_VALUE; break; } @@ -510,25 +429,19 @@ public class HttpParser implements Parser default: { // handler last header if any - if (_cached!=null || _tok0.length() > 0 || _tok1.length() > 0 || _multiLineValue != null) + if (_field0!=null || _field1!=null) { - Buffer header=_cached!=null?_cached:HttpHeaders.CACHE.lookup(_tok0); - _cached=null; - Buffer value=_multiLineValue == null ? _tok1 : new ByteArrayBuffer(_multiLineValue); - - int ho=HttpHeaders.CACHE.getOrdinal(header); - if (ho >= 0) + // Handle known headers + if (_header!=null) { - int vo; - - switch (ho) + switch (_header) { - case HttpHeaders.CONTENT_LENGTH_ORDINAL: + case CONTENT_LENGTH: if (_contentLength != HttpTokens.CHUNKED_CONTENT && _responseStatus!=304 && _responseStatus!=204 && (_responseStatus<100 || _responseStatus>=200)) { try { - _contentLength=BufferUtil.toLong(value); + _contentLength=Long.parseLong(_field1); } catch(NumberFormatException e) { @@ -540,44 +453,40 @@ public class HttpParser implements Parser } break; - case HttpHeaders.TRANSFER_ENCODING_ORDINAL: - value=HttpHeaderValues.CACHE.lookup(value); - vo=HttpHeaderValues.CACHE.getOrdinal(value); - if (HttpHeaderValues.CHUNKED_ORDINAL == vo) + case TRANSFER_ENCODING: + if (_value==HttpHeaderValues.CHUNKED) _contentLength=HttpTokens.CHUNKED_CONTENT; else { - String c=value.toString(StringUtil.__ISO_8859_1); - if (c.endsWith(HttpHeaderValues.CHUNKED)) + if (_field1.endsWith(HttpHeaderValues.CHUNKED.toString())) _contentLength=HttpTokens.CHUNKED_CONTENT; - - else if (c.indexOf(HttpHeaderValues.CHUNKED) >= 0) + else if (_field1.indexOf(HttpHeaderValues.CHUNKED.toString()) >= 0) throw new HttpException(400,null); } break; - case HttpHeaders.CONNECTION_ORDINAL: - switch(HttpHeaderValues.CACHE.getOrdinal(value)) + case CONNECTION: + switch(_value) { - case HttpHeaderValues.CLOSE_ORDINAL: + case CLOSE: _persistent=false; break; - case HttpHeaderValues.KEEP_ALIVE_ORDINAL: + case KEEP_ALIVE: _persistent=true; break; - case -1: // No match, may be multi valued + default: // No match, may be multi valued { - for (String v : value.toString().split(",")) + for (String v : _field1.toString().split(",")) { - switch(HttpHeaderValues.CACHE.getOrdinal(v.trim())) + switch(HttpHeaderValues.CACHE.get(v.trim())) { - case HttpHeaderValues.CLOSE_ORDINAL: + case CLOSE: _persistent=false; break; - case HttpHeaderValues.KEEP_ALIVE_ORDINAL: + case KEEP_ALIVE: _persistent=true; break; } @@ -588,17 +497,20 @@ public class HttpParser implements Parser } } - _handler.parsedHeader(header, value); - _tok0.setPutIndex(_tok0.getIndex()); - _tok1.setPutIndex(_tok1.getIndex()); - _multiLineValue=null; + _handler.parsedHeader(_field0, _field0); } - _buffer.setMarkIndex(-1); + _field0=_field1=null; + _header=null; + _value=null; // now handle ch if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) { + _eol=ch; + _contentPosition=0; + + // End of headers! // work out the _content demarcation if (_contentLength == HttpTokens.UNKNOWN_CONTENT) { @@ -611,11 +523,6 @@ public class HttpParser implements Parser _contentLength=HttpTokens.EOF_CONTENT; } - _contentPosition=0; - _eol=ch; - if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED) - _eol=_buffer.get(); - // We convert _contentLength to an int for this switch statement because // we don't care about the amount of data available just whether there is some. switch (_contentLength > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) _contentLength) @@ -634,35 +541,20 @@ public class HttpParser implements Parser _handler.headerComplete(); _state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF; _handler.messageComplete(_contentPosition); - returnBuffers(); - return 1; + break; default: _state=STATE_CONTENT; _handler.headerComplete(); // May recurse here ! break; } - return 1; } else { // New header - _length=1; - _buffer.mark(); + start=buffer.position()-1; + length=1; _state=STATE_HEADER_NAME; - - // try cached name! - if (array!=null) - { - _cached=HttpHeaders.CACHE.getBest(array, _buffer.markIndex(), length+1); - - if (_cached!=null) - { - _length=_cached.length(); - _buffer.setGetIndex(_buffer.markIndex()+_length); - length=_buffer.length(); - } - } } } } @@ -674,15 +566,17 @@ public class HttpParser implements Parser { case HttpTokens.CARRIAGE_RETURN: case HttpTokens.LINE_FEED: - if (_length > 0) - _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length); _eol=ch; + _header=HttpHeaders.CACHE.get(buffer,start,length); + _field0=_header==null?BufferUtil.toString(buffer,start,length,StringUtil.__ISO_8859_1_CHARSET):_header.toString(); + start=length=-1; _state=STATE_HEADER; break; + case HttpTokens.COLON: - if (_length > 0 && _cached==null) - _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length); - _length=-1; + _header=HttpHeaders.CACHE.get(buffer,start,length); + _field0=_header==null?BufferUtil.toString(buffer,start,length,StringUtil.__ISO_8859_1_CHARSET):_header.toString(); + start=length=-1; _state=STATE_HEADER_VALUE; break; case HttpTokens.SPACE: @@ -690,10 +584,7 @@ public class HttpParser implements Parser break; default: { - _cached=null; - if (_length == -1) - _buffer.mark(); - _length=_buffer.getIndex() - _buffer.markIndex(); + length=buffer.position()-start; _state=STATE_HEADER_IN_NAME; } } @@ -705,15 +596,17 @@ public class HttpParser implements Parser { case HttpTokens.CARRIAGE_RETURN: case HttpTokens.LINE_FEED: - if (_length > 0) - _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length); _eol=ch; + _header=HttpHeaders.CACHE.get(buffer,start,length); + _field0=_header==null?BufferUtil.toString(buffer,start,length,StringUtil.__ISO_8859_1_CHARSET):_header.toString(); + start=length=-1; _state=STATE_HEADER; break; + case HttpTokens.COLON: - if (_length > 0 && _cached==null) - _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length); - _length=-1; + _header=HttpHeaders.CACHE.get(buffer,start,length); + _field0=_header==null?BufferUtil.toString(buffer,start,length,StringUtil.__ISO_8859_1_CHARSET):_header.toString(); + start=length=-1; _state=STATE_HEADER_VALUE; break; case HttpTokens.SPACE: @@ -721,10 +614,7 @@ public class HttpParser implements Parser _state=STATE_HEADER_NAME; break; default: - { - _cached=null; - _length++; - } + length++; } break; @@ -733,19 +623,26 @@ public class HttpParser implements Parser { case HttpTokens.CARRIAGE_RETURN: case HttpTokens.LINE_FEED: - if (_length > 0) + _eol=ch; + if (length > 0) { - if (_tok1.length() == 0) - _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length); + if (_field1!=null) + { + // multi line value! + _value=null; + _field1+=" "+BufferUtil.toString(buffer,start,length,StringUtil.__ISO_8859_1_CHARSET); + } + else if (HttpHeaderValues.hasKnownValues(_header)) + { + _value=HttpHeaderValues.CACHE.get(buffer,start,length); + _field1=_value.toString(); + } else { - // Continuation line! - if (_multiLineValue == null) _multiLineValue=_tok1.toString(StringUtil.__ISO_8859_1); - _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length); - _multiLineValue += " " + _tok1.toString(StringUtil.__ISO_8859_1); + _field1=BufferUtil.toString(buffer,start,length,StringUtil.__ISO_8859_1_CHARSET); } + start=length=-1; } - _eol=ch; _state=STATE_HEADER; break; case HttpTokens.SPACE: @@ -753,9 +650,9 @@ public class HttpParser implements Parser break; default: { - if (_length == -1) - _buffer.mark(); - _length=_buffer.getIndex() - _buffer.markIndex(); + if (start==-1) + start=buffer.position()-1; + length=buffer.position()-start; _state=STATE_HEADER_IN_VALUE; } } @@ -766,19 +663,26 @@ public class HttpParser implements Parser { case HttpTokens.CARRIAGE_RETURN: case HttpTokens.LINE_FEED: - if (_length > 0) + _eol=ch; + if (length > 0) { - if (_tok1.length() == 0) - _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length); + if (_field1!=null) + { + // multi line value! + _value=null; + _field1+=" "+BufferUtil.toString(buffer,start,length,StringUtil.__ISO_8859_1_CHARSET); + } + else if (HttpHeaderValues.hasKnownValues(_header)) + { + _value=HttpHeaderValues.CACHE.get(buffer,start,length); + _field1=_value.toString(); + } else { - // Continuation line! - if (_multiLineValue == null) _multiLineValue=_tok1.toString(StringUtil.__ISO_8859_1); - _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length); - _multiLineValue += " " + _tok1.toString(StringUtil.__ISO_8859_1); + _field1=BufferUtil.toString(buffer,start,length,StringUtil.__ISO_8859_1_CHARSET); } + start=length=-1; } - _eol=ch; _state=STATE_HEADER; break; case HttpTokens.SPACE: @@ -786,7 +690,7 @@ public class HttpParser implements Parser _state=STATE_HEADER_VALUE; break; default: - _length++; + length++; } break; } @@ -805,10 +709,9 @@ public class HttpParser implements Parser // ========================== // Handle _content - length=_buffer.length(); - Buffer chunk; last=_state; - while (_state > STATE_END && length > 0) + ByteBuffer chunk; + while (_state > STATE_END && buffer.hasRemaining()) { if (last!=_state) { @@ -816,22 +719,21 @@ public class HttpParser implements Parser last=_state; } - if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer.peek() == HttpTokens.LINE_FEED) + if (_eol == HttpTokens.CARRIAGE_RETURN && buffer.get(buffer.position()) == HttpTokens.LINE_FEED) { - _eol=_buffer.get(); - length=_buffer.length(); + _eol=buffer.get(); continue; } _eol=0; + switch (_state) { case STATE_EOF_CONTENT: - chunk=_buffer.get(_buffer.length()); - _contentPosition += chunk.length(); - _contentView.update(chunk); + chunk=buffer.asReadOnlyBuffer(); + _contentPosition += chunk.remaining(); + buffer.position(buffer.position()+chunk.remaining()); _handler.content(chunk); // May recurse here - // TODO adjust the _buffer to keep unconsumed content - return 1; + break; case STATE_CONTENT: { @@ -840,39 +742,39 @@ public class HttpParser implements Parser { _state=_persistent?STATE_END:STATE_SEEKING_EOF; _handler.messageComplete(_contentPosition); - returnBuffers(); - return 1; } - - if (length > remaining) + else { - // We can cast reamining to an int as we know that it is smaller than - // or equal to length which is already an int. - length=(int)remaining; - } + chunk=buffer.asReadOnlyBuffer(); - chunk=_buffer.get(length); - _contentPosition += chunk.length(); - _contentView.update(chunk); - _handler.content(chunk); // May recurse here + // limit content by expected size + if (chunk.remaining() > remaining) + { + // We can cast remaining to an int as we know that it is smaller than + // or equal to length which is already an int. + chunk.limit(chunk.position()+(int)remaining); + } - if(_contentPosition == _contentLength) - { - _state=_persistent?STATE_END:STATE_SEEKING_EOF; - _handler.messageComplete(_contentPosition); - returnBuffers(); + _contentPosition += chunk.remaining(); + buffer.position(buffer.position()+chunk.remaining()); + _handler.content(chunk); // May recurse here + + if(_contentPosition == _contentLength) + { + _state=_persistent?STATE_END:STATE_SEEKING_EOF; + _handler.messageComplete(_contentPosition); + } } - // TODO adjust the _buffer to keep unconsumed content - return 1; + break; } case STATE_CHUNKED_CONTENT: { - ch=_buffer.peek(); + ch=buffer.get(buffer.position()); if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) - _eol=_buffer.get(); + _eol=buffer.get(); else if (ch <= HttpTokens.SPACE) - _buffer.get(); + buffer.get(); else { _chunkLength=0; @@ -884,19 +786,17 @@ public class HttpParser implements Parser case STATE_CHUNK_SIZE: { - ch=_buffer.get(); + ch=buffer.get(); if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) { _eol=ch; if (_chunkLength == 0) { - if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED) - _eol=_buffer.get(); + if (_eol==HttpTokens.CARRIAGE_RETURN && buffer.hasRemaining() && buffer.get(buffer.position())==HttpTokens.LINE_FEED) + _eol=buffer.get(); _state=_persistent?STATE_END:STATE_SEEKING_EOF; _handler.messageComplete(_contentPosition); - returnBuffers(); - return 1; } else _state=STATE_CHUNK; @@ -916,18 +816,16 @@ public class HttpParser implements Parser case STATE_CHUNK_PARAMS: { - ch=_buffer.get(); + ch=buffer.get(); if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) { _eol=ch; if (_chunkLength == 0) { - if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED) - _eol=_buffer.get(); + if (_eol==HttpTokens.CARRIAGE_RETURN && buffer.hasRemaining() && buffer.get(buffer.position())==HttpTokens.LINE_FEED) + _eol=buffer.get(); _state=_persistent?STATE_END:STATE_SEEKING_EOF; _handler.messageComplete(_contentPosition); - returnBuffers(); - return 1; } else _state=STATE_CHUNK; @@ -941,48 +839,34 @@ public class HttpParser implements Parser if (remaining == 0) { _state=STATE_CHUNKED_CONTENT; - break; } - else if (length > remaining) - length=remaining; - chunk=_buffer.get(length); - _contentPosition += chunk.length(); - _chunkPosition += chunk.length(); - _contentView.update(chunk); - _handler.content(chunk); // May recurse here - // TODO adjust the _buffer to keep unconsumed content - return 1; + else + { + chunk=buffer.asReadOnlyBuffer(); + + if (chunk.remaining() > remaining) + chunk.limit(chunk.position()+remaining); + remaining=chunk.remaining(); + + _contentPosition += remaining; + _chunkPosition += remaining; + buffer.position(buffer.position()+remaining); + _handler.content(chunk); // May recurse here + + _handler.content(chunk); + } } case STATE_SEEKING_EOF: - { - // Close if there is more data than CRLF - if (_buffer.length()>2) - { - _state=STATE_END; - _endp.close(); - } - else - { - // or if the data is not white space - while (_buffer.length()>0) - if (!Character.isWhitespace(_buffer.get())) - { - _state=STATE_END; - _endp.close(); - _buffer.clear(); - } - } - - _buffer.clear(); + { + buffer.clear().limit(0); break; } } - length=_buffer.length(); } - return progress; + return progress>0; } catch(HttpException e) { @@ -991,130 +875,54 @@ public class HttpParser implements Parser throw e; } } + /* ------------------------------------------------------------------------------- */ - /** fill the buffers from the endpoint - * - */ - protected int fill() throws IOException + public boolean onEOF() throws IOException { - // Do we have a buffer? - if (_buffer==null) - _buffer=getHeaderBuffer(); + _persistent=false; - // Is there unconsumed content in body buffer - if (_state>STATE_END && _buffer==_header && _header!=null && !_header.hasContent() && _body!=null && _body.hasContent()) + // was this unexpected? + switch(_state) { - _buffer=_body; - return _buffer.length(); + case STATE_END: + case STATE_SEEKING_EOF: + _state=STATE_END; + break; + + case STATE_EOF_CONTENT: + _state=STATE_END; + _handler.messageComplete(_contentPosition); + break; + + default: + _state=STATE_END; + if (!_headResponse) + _handler.earlyEOF(); + _handler.messageComplete(_contentPosition); } - // Shall we switch to a body buffer? - if (_buffer==_header && _state>STATE_END && _header.length()==0 && (_forceContentBuffer || (_contentLength-_contentPosition)>_header.capacity()) && (_body!=null||_buffers!=null)) - { - if (_body==null) - _body=_buffers.getBuffer(); - _buffer=_body; - } + if (!isComplete() && !isIdle()) + throw new EofException(); - // Do we have somewhere to fill from? - if (_endp != null ) - { - // Shall we compact the body? - if (_buffer==_body || _state>STATE_END) - { - _buffer.compact(); - } - - // Are we full? - if (_buffer.space() == 0) - { - LOG.warn("Full {}",_buffer.toDetailString()); - throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "FULL "+(_buffer==_body?"body":"head")); - } - - try - { - int filled = _endp.fill(_buffer); - return filled; - } - catch(IOException e) - { - LOG.debug(e); - throw (e instanceof EofException) ? e:new EofException(e); - } - } - - return -1; + return true; } + + /* ------------------------------------------------------------------------------- */ public void reset() { // reset state - _contentView.setGetIndex(_contentView.putIndex()); - _state=_persistent?STATE_START:(_endp.isInputShutdown()?STATE_END:STATE_SEEKING_EOF); + _state=_persistent?STATE_START:_state==STATE_END?STATE_END:STATE_SEEKING_EOF; _contentLength=HttpTokens.UNKNOWN_CONTENT; _contentPosition=0; - _length=0; _responseStatus=0; - // Consume LF if CRLF - if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer!=null && _buffer.hasContent() && _buffer.peek() == HttpTokens.LINE_FEED) - _eol=_buffer.get(); - if (_body!=null && _body.hasContent()) - { - // There is content in the body after the end of the request. - // This is probably a pipelined header of the next request, so we need to - // copy it to the header buffer. - if (_header==null) - getHeaderBuffer(); - else - { - _header.setMarkIndex(-1); - _header.compact(); - } - int take=_header.space(); - if (take>_body.length()) - take=_body.length(); - _body.peek(_body.getIndex(),take); - _body.skip(_header.put(_body.peek(_body.getIndex(),take))); - } - - if (_header!=null) - { - _header.setMarkIndex(-1); - _header.compact(); - } - if (_body!=null) - _body.setMarkIndex(-1); - - _buffer=_header; - returnBuffers(); } - /* ------------------------------------------------------------------------------- */ - public void returnBuffers() - { - if (_body!=null && !_body.hasContent() && _body.markIndex()==-1 && _buffers!=null) - { - if (_buffer==_body) - _buffer=_header; - if (_buffers!=null) - _buffers.returnBuffer(_body); - _body=null; - } - - if (_header!=null && !_header.hasContent() && _header.markIndex()==-1 && _buffers!=null) - { - if (_buffer==_header) - _buffer=null; - _buffers.returnBuffer(_header); - _header=null; - } - } /* ------------------------------------------------------------------------------- */ public void setState(int state) @@ -1123,151 +931,55 @@ public class HttpParser implements Parser _contentLength=HttpTokens.UNKNOWN_CONTENT; } - /* ------------------------------------------------------------------------------- */ - public String toString(Buffer buf) - { - return "state=" + _state + " length=" + _length + " buf=" + buf.hashCode(); - } /* ------------------------------------------------------------------------------- */ @Override public String toString() { - return String.format("%s{s=%d,l=%d,c=%d}", + return String.format("%s{s=%d,c=%d}", getClass().getSimpleName(), _state, - _length, _contentLength); } + /* ------------------------------------------------------------ */ - public Buffer getHeaderBuffer() + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + public interface EventHandler { - if (_header == null) - { - _header=_buffers.getHeader(); - _tok0.update(_header); - _tok1.update(_header); - } - return _header; - } + public void content(ByteBuffer ref) throws IOException; - /* ------------------------------------------------------------ */ - public Buffer getBodyBuffer() - { - return _body; - } + public void headerComplete() throws IOException; - /* ------------------------------------------------------------ */ - /** - * @param force True if a new buffer will be forced to be used for content and the header buffer will not be used. - */ - public void setForceContentBuffer(boolean force) - { - _forceContentBuffer=force; - } - - /* ------------------------------------------------------------ */ - public Buffer blockForContent(long maxIdleTime) throws IOException - { - if (_contentView.length()>0) - return _contentView; - - if (getState() <= STATE_END || isState(STATE_SEEKING_EOF)) - return null; - - try - { - parseNext(); - - // parse until some progress is made (or IOException thrown for timeout) - while(_contentView.length() == 0 && !(isState(HttpParser.STATE_END)||isState(HttpParser.STATE_SEEKING_EOF)) && _endp!=null && _endp.isOpen()) - { - if (!_endp.isBlocking()) - { - if (parseNext()>0) - continue; - - if (!_endp.blockReadable(maxIdleTime)) - { - _endp.close(); - throw new EofException("timeout"); - } - } - - parseNext(); - } - } - catch(IOException e) - { - // TODO is this needed? - _endp.close(); - throw e; - } - - return _contentView.length()>0?_contentView:null; - } - - /* ------------------------------------------------------------ */ - /* (non-Javadoc) - * @see java.io.InputStream#available() - */ - public int available() throws IOException - { - if (_contentView!=null && _contentView.length()>0) - return _contentView.length(); - - if (_endp.isBlocking()) - { - if (_state>0 && _endp instanceof StreamEndPoint) - return ((StreamEndPoint)_endp).getInputStream().available()>0?1:0; - - return 0; - } - - parseNext(); - return _contentView==null?0:_contentView.length(); - } - - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - public static abstract class EventHandler - { - public abstract void content(Buffer ref) throws IOException; - - public void headerComplete() throws IOException - { - } - - public void messageComplete(long contentLength) throws IOException - { - } + public void messageComplete(long contentLength) throws IOException; /** * This is the method called by parser when a HTTP Header name and value is found */ - public void parsedHeader(Buffer name, Buffer value) throws IOException - { - } + public void parsedHeader(String name, String value) throws IOException; + public void earlyEOF(); + } + + public interface RequestHandler extends EventHandler + { /** * This is the method called by parser when the HTTP request line is parsed */ - public abstract void startRequest(Buffer method, Buffer url, Buffer version) + public abstract void startRequest(String method, String uri, String version) throws IOException; - + } + + public interface ResponseHandler extends EventHandler + { /** * This is the method called by parser when the HTTP request line is parsed */ - public abstract void startResponse(Buffer version, int status, Buffer reason) + public abstract void startResponse(String version, int status, String reason) throws IOException; - - public void earlyEOF() - {} } - } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpSchemes.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpSchemes.java index 1046c78271f..bc3597a6090 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpSchemes.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpSchemes.java @@ -13,21 +13,48 @@ package org.eclipse.jetty.http; -import org.eclipse.jetty.io.Buffer; -import org.eclipse.jetty.io.ByteArrayBuffer; +import java.nio.ByteBuffer; + +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.StringMap; /* ------------------------------------------------------------------------------- */ /** - * - * */ -public class HttpSchemes -{ - public final static String - HTTP ="http", - HTTPS="https"; - - public final static Buffer - HTTP_BUFFER = new ByteArrayBuffer(HTTP), - HTTPS_BUFFER = new ByteArrayBuffer(HTTPS); +public enum HttpSchemes +{ + HTTP("http"), + HTTPS("https"), + WS("ws"), + WSS("wss"); + + /* ------------------------------------------------------------ */ + public final static StringMap CACHE= new StringMap(true); + static + { + for (HttpSchemes version : HttpSchemes.values()) + CACHE.put(version.toString(),version); + } + + private final String _string; + private final ByteBuffer _buffer; + + /* ------------------------------------------------------------ */ + HttpSchemes(String s) + { + _string=s; + _buffer=BufferUtil.toBuffer(s); + } + + /* ------------------------------------------------------------ */ + public ByteBuffer toBuffer() + { + return _buffer.asReadOnlyBuffer(); + } + + /* ------------------------------------------------------------ */ + public String toString() + { + return _string; + } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java index a38c48d35be..fae3fcaeddf 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java @@ -502,14 +502,14 @@ public class HttpURI _raw[_scheme+1]=='t' && _raw[_scheme+2]=='t' && _raw[_scheme+3]=='p' ) - return HttpSchemes.HTTP; + return HttpSchemes.HTTP.toString(); if (l==6 && _raw[_scheme]=='h' && _raw[_scheme+1]=='t' && _raw[_scheme+2]=='t' && _raw[_scheme+3]=='p' && _raw[_scheme+4]=='s' ) - return HttpSchemes.HTTPS; + return HttpSchemes.HTTPS.toString(); return toUtf8String(_scheme,_authority-_scheme-1); } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersions.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersions.java index 07746b6d081..5941f697e3f 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersions.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersions.java @@ -13,30 +13,54 @@ package org.eclipse.jetty.http; -import org.eclipse.jetty.io.Buffer; -import org.eclipse.jetty.io.BufferCache; +import java.nio.ByteBuffer; + +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.StringMap; + /* ------------------------------------------------------------------------------- */ -/** - * - * - */ -public class HttpVersions +public enum HttpVersions { - public final static String - HTTP_0_9 = "", - HTTP_1_0 = "HTTP/1.0", - HTTP_1_1 = "HTTP/1.1"; - - public final static int - HTTP_0_9_ORDINAL=9, - HTTP_1_0_ORDINAL=10, - HTTP_1_1_ORDINAL=11; - - public final static BufferCache CACHE = new BufferCache(); - - public final static Buffer - HTTP_0_9_BUFFER=CACHE.add(HTTP_0_9,HTTP_0_9_ORDINAL), - HTTP_1_0_BUFFER=CACHE.add(HTTP_1_0,HTTP_1_0_ORDINAL), - HTTP_1_1_BUFFER=CACHE.add(HTTP_1_1,HTTP_1_1_ORDINAL); + HTTP_0_9("HTTP/0.9",9), + HTTP_1_0("HTTP/1.0",10), + HTTP_1_1("HTTP/1.1",11); + + /* ------------------------------------------------------------ */ + public final static StringMap CACHE= new StringMap(true); + static + { + for (HttpVersions version : HttpVersions.values()) + CACHE.put(version.toString(),version); + } + + private final String _string; + private final ByteBuffer _buffer; + private final int _version; + + /* ------------------------------------------------------------ */ + HttpVersions(String s,int version) + { + _string=s; + _buffer=BufferUtil.toBuffer(s); + _version=version; + } + + /* ------------------------------------------------------------ */ + public ByteBuffer toBuffer() + { + return _buffer.asReadOnlyBuffer(); + } + + /* ------------------------------------------------------------ */ + public int getVerion() + { + return _version; + } + + /* ------------------------------------------------------------ */ + public String toString() + { + return _string; + } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java index ffb8bf5c6e2..30eba080a5f 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java @@ -13,16 +13,15 @@ package org.eclipse.jetty.http; +import java.nio.ByteBuffer; import java.util.Enumeration; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; -import org.eclipse.jetty.io.Buffer; -import org.eclipse.jetty.io.BufferCache; -import org.eclipse.jetty.io.BufferCache.CachedBuffer; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.StringMap; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -34,94 +33,73 @@ import org.eclipse.jetty.util.log.Logger; */ public class MimeTypes { + public enum Type + { + FORM_ENCODED("application/x-www-form-urlencoded"), + MESSAGE_HTTP("message/http"), + MULTIPART_BYTERANGES("multipart/byteranges"), + + TEXT_HTML("text/html"), + TEXT_PLAIN("text/plain"), + TEXT_XML("text/xml"), + TEXT_JSON("text/json"), + + TEXT_HTML_8859_1("text/html;charset=ISO-8859-1"), + TEXT_PLAIN_8859_1("text/plain;charset=ISO-8859-1"), + TEXT_XML_8859_1("text/xml;charset=ISO-8859-1"), + TEXT_HTML_UTF_8("text/html;charset=UTF-8"), + TEXT_PLAIN_UTF_8("text/plain;charset=UTF-8"), + TEXT_XML_UTF_8("text/xml;charset=UTF-8"), + TEXT_JSON_UTF_8("text/json;charset=UTF-8"); + + + /* ------------------------------------------------------------ */ + private final String _string; + private final ByteBuffer _buffer; + + /* ------------------------------------------------------------ */ + Type(String s) + { + _string=s; + _buffer=BufferUtil.toBuffer(s); + } + + /* ------------------------------------------------------------ */ + public ByteBuffer toBuffer() + { + return _buffer.asReadOnlyBuffer(); + } + + /* ------------------------------------------------------------ */ + public String toString() + { + return _string; + } + } + + /* ------------------------------------------------------------ */ private static final Logger LOG = Log.getLogger(MimeTypes.class); - - public final static String - FORM_ENCODED="application/x-www-form-urlencoded", - MESSAGE_HTTP="message/http", - MULTIPART_BYTERANGES="multipart/byteranges", - - TEXT_HTML="text/html", - TEXT_PLAIN="text/plain", - TEXT_XML="text/xml", - TEXT_JSON="text/json", - - TEXT_HTML_8859_1="text/html;charset=ISO-8859-1", - TEXT_PLAIN_8859_1="text/plain;charset=ISO-8859-1", - TEXT_XML_8859_1="text/xml;charset=ISO-8859-1", - - TEXT_HTML_UTF_8="text/html;charset=UTF-8", - TEXT_PLAIN_UTF_8="text/plain;charset=UTF-8", - TEXT_XML_UTF_8="text/xml;charset=UTF-8", - TEXT_JSON_UTF_8="text/json;charset=UTF-8"; - - private final static String - TEXT_HTML__8859_1="text/html; charset=ISO-8859-1", - TEXT_PLAIN__8859_1="text/plain; charset=ISO-8859-1", - TEXT_XML__8859_1="text/xml; charset=ISO-8859-1", - TEXT_HTML__UTF_8="text/html; charset=UTF-8", - TEXT_PLAIN__UTF_8="text/plain; charset=UTF-8", - TEXT_XML__UTF_8="text/xml; charset=UTF-8", - TEXT_JSON__UTF_8="text/json; charset=UTF-8"; - - private final static int - FORM_ENCODED_ORDINAL=1, - MESSAGE_HTTP_ORDINAL=2, - MULTIPART_BYTERANGES_ORDINAL=3, - - TEXT_HTML_ORDINAL=4, - TEXT_PLAIN_ORDINAL=5, - TEXT_XML_ORDINAL=6, - TEXT_JSON_ORDINAL=7, - - TEXT_HTML_8859_1_ORDINAL=8, - TEXT_PLAIN_8859_1_ORDINAL=9, - TEXT_XML_8859_1_ORDINAL=10, - - TEXT_HTML_UTF_8_ORDINAL=11, - TEXT_PLAIN_UTF_8_ORDINAL=12, - TEXT_XML_UTF_8_ORDINAL=13, - TEXT_JSON_UTF_8_ORDINAL=14; + private final static StringMap CACHE= new StringMap(true); + private final static StringMap TYPES= new StringMap(true); + private final static Map __dftMimeMap = new HashMap(); + private final static Map __encodings = new HashMap(); - private static int __index=15; - - public final static BufferCache CACHE = new BufferCache(); - - public final static CachedBuffer - FORM_ENCODED_BUFFER=CACHE.add(FORM_ENCODED,FORM_ENCODED_ORDINAL), - MESSAGE_HTTP_BUFFER=CACHE.add(MESSAGE_HTTP, MESSAGE_HTTP_ORDINAL), - MULTIPART_BYTERANGES_BUFFER=CACHE.add(MULTIPART_BYTERANGES,MULTIPART_BYTERANGES_ORDINAL), - - TEXT_HTML_BUFFER=CACHE.add(TEXT_HTML,TEXT_HTML_ORDINAL), - TEXT_PLAIN_BUFFER=CACHE.add(TEXT_PLAIN,TEXT_PLAIN_ORDINAL), - TEXT_XML_BUFFER=CACHE.add(TEXT_XML,TEXT_XML_ORDINAL), - TEXT_JSON_BUFFER=CACHE.add(TEXT_JSON,TEXT_JSON_ORDINAL), - - TEXT_HTML_8859_1_BUFFER=CACHE.add(TEXT_HTML_8859_1,TEXT_HTML_8859_1_ORDINAL), - TEXT_PLAIN_8859_1_BUFFER=CACHE.add(TEXT_PLAIN_8859_1,TEXT_PLAIN_8859_1_ORDINAL), - TEXT_XML_8859_1_BUFFER=CACHE.add(TEXT_XML_8859_1,TEXT_XML_8859_1_ORDINAL), - - TEXT_HTML_UTF_8_BUFFER=CACHE.add(TEXT_HTML_UTF_8,TEXT_HTML_UTF_8_ORDINAL), - TEXT_PLAIN_UTF_8_BUFFER=CACHE.add(TEXT_PLAIN_UTF_8,TEXT_PLAIN_UTF_8_ORDINAL), - TEXT_XML_UTF_8_BUFFER=CACHE.add(TEXT_XML_UTF_8,TEXT_XML_UTF_8_ORDINAL), - TEXT_JSON_UTF_8_BUFFER=CACHE.add(TEXT_JSON_UTF_8,TEXT_JSON_UTF_8_ORDINAL), - - TEXT_HTML__8859_1_BUFFER=CACHE.add(TEXT_HTML__8859_1,TEXT_HTML_8859_1_ORDINAL), - TEXT_PLAIN__8859_1_BUFFER=CACHE.add(TEXT_PLAIN__8859_1,TEXT_PLAIN_8859_1_ORDINAL), - TEXT_XML__8859_1_BUFFER=CACHE.add(TEXT_XML__8859_1,TEXT_XML_8859_1_ORDINAL), - - TEXT_HTML__UTF_8_BUFFER=CACHE.add(TEXT_HTML__UTF_8,TEXT_HTML_UTF_8_ORDINAL), - TEXT_PLAIN__UTF_8_BUFFER=CACHE.add(TEXT_PLAIN__UTF_8,TEXT_PLAIN_UTF_8_ORDINAL), - TEXT_XML__UTF_8_BUFFER=CACHE.add(TEXT_XML__UTF_8,TEXT_XML_UTF_8_ORDINAL), - TEXT_JSON__UTF_8_BUFFER=CACHE.add(TEXT_JSON__UTF_8,TEXT_JSON_UTF_8_ORDINAL); - - - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - private final static Map __dftMimeMap = new HashMap(); - private final static Map __encodings = new HashMap(); static { + + for (MimeTypes.Type type : MimeTypes.Type.values()) + { + CACHE.put(type.toString(),type); + TYPES.put(type.toString(),type.toBuffer()); + + int charset=type.toString().indexOf(";charset="); + if (charset>0) + { + CACHE.put(type.toString().replace(";charset=","; charset="),type); + TYPES.put(type.toString().replace(";charset=","; charset="),type.toBuffer()); + } + } + try { ResourceBundle mime = ResourceBundle.getBundle("org/eclipse/jetty/http/mime"); @@ -142,11 +120,11 @@ public class MimeTypes try { ResourceBundle encoding = ResourceBundle.getBundle("org/eclipse/jetty/http/encoding"); - Enumeration i = encoding.getKeys(); + Enumeration i = encoding.getKeys(); while(i.hasMoreElements()) { - Buffer type = normalizeMimeType((String)i.nextElement()); - __encodings.put(type,encoding.getString(type.toString())); + String type = i.nextElement(); + __encodings.put(type,encoding.getString(type)); } } catch(MissingResourceException e) @@ -156,37 +134,11 @@ public class MimeTypes } - TEXT_HTML_BUFFER.setAssociate("ISO-8859-1",TEXT_HTML_8859_1_BUFFER); - TEXT_HTML_BUFFER.setAssociate("ISO_8859_1",TEXT_HTML_8859_1_BUFFER); - TEXT_HTML_BUFFER.setAssociate("iso-8859-1",TEXT_HTML_8859_1_BUFFER); - TEXT_PLAIN_BUFFER.setAssociate("ISO-8859-1",TEXT_PLAIN_8859_1_BUFFER); - TEXT_PLAIN_BUFFER.setAssociate("ISO_8859_1",TEXT_PLAIN_8859_1_BUFFER); - TEXT_PLAIN_BUFFER.setAssociate("iso-8859-1",TEXT_PLAIN_8859_1_BUFFER); - TEXT_XML_BUFFER.setAssociate("ISO-8859-1",TEXT_XML_8859_1_BUFFER); - TEXT_XML_BUFFER.setAssociate("ISO_8859_1",TEXT_XML_8859_1_BUFFER); - TEXT_XML_BUFFER.setAssociate("iso-8859-1",TEXT_XML_8859_1_BUFFER); - - TEXT_HTML_BUFFER.setAssociate("UTF-8",TEXT_HTML_UTF_8_BUFFER); - TEXT_HTML_BUFFER.setAssociate("UTF8",TEXT_HTML_UTF_8_BUFFER); - TEXT_HTML_BUFFER.setAssociate("utf8",TEXT_HTML_UTF_8_BUFFER); - TEXT_HTML_BUFFER.setAssociate("utf-8",TEXT_HTML_UTF_8_BUFFER); - TEXT_PLAIN_BUFFER.setAssociate("UTF-8",TEXT_PLAIN_UTF_8_BUFFER); - TEXT_PLAIN_BUFFER.setAssociate("UTF8",TEXT_PLAIN_UTF_8_BUFFER); - TEXT_PLAIN_BUFFER.setAssociate("utf8",TEXT_PLAIN_UTF_8_BUFFER); - TEXT_PLAIN_BUFFER.setAssociate("utf-8",TEXT_PLAIN_UTF_8_BUFFER); - TEXT_XML_BUFFER.setAssociate("UTF-8",TEXT_XML_UTF_8_BUFFER); - TEXT_XML_BUFFER.setAssociate("UTF8",TEXT_XML_UTF_8_BUFFER); - TEXT_XML_BUFFER.setAssociate("utf8",TEXT_XML_UTF_8_BUFFER); - TEXT_XML_BUFFER.setAssociate("utf-8",TEXT_XML_UTF_8_BUFFER); - TEXT_JSON_BUFFER.setAssociate("UTF-8",TEXT_JSON_UTF_8_BUFFER); - TEXT_JSON_BUFFER.setAssociate("UTF8",TEXT_JSON_UTF_8_BUFFER); - TEXT_JSON_BUFFER.setAssociate("utf8",TEXT_JSON_UTF_8_BUFFER); - TEXT_JSON_BUFFER.setAssociate("utf-8",TEXT_JSON_UTF_8_BUFFER); } /* ------------------------------------------------------------ */ - private Map _mimeMap; + private final Map _mimeMap=new HashMap(); /* ------------------------------------------------------------ */ /** Constructor. @@ -196,7 +148,7 @@ public class MimeTypes } /* ------------------------------------------------------------ */ - public synchronized Map getMimeMap() + public synchronized Map getMimeMap() { return _mimeMap; } @@ -205,22 +157,14 @@ public class MimeTypes /** * @param mimeMap A Map of file extension to mime-type. */ - public void setMimeMap(Map mimeMap) + public void setMimeMap(Map mimeMap) { - if (mimeMap==null) + _mimeMap.clear(); + if (mimeMap!=null) { - _mimeMap=null; - return; + for (String ext : mimeMap.keySet()) + _mimeMap.put(StringUtil.asciiToLowerCase(ext),normalizeMimeType(mimeMap.get(ext))); } - - Map m=new HashMap(); - Iterator i=mimeMap.entrySet().iterator(); - while (i.hasNext()) - { - Map.Entry entry = (Map.Entry)i.next(); - m.put(entry.getKey(),normalizeMimeType(entry.getValue().toString())); - } - _mimeMap=m; } /* ------------------------------------------------------------ */ @@ -229,9 +173,9 @@ public class MimeTypes * @return MIME type matching the longest dot extension of the * file name. */ - public Buffer getMimeByExtension(String filename) + public ByteBuffer getMimeByExtension(String filename) { - Buffer type=null; + ByteBuffer type=null; if (filename!=null) { @@ -245,18 +189,18 @@ public class MimeTypes String ext=StringUtil.asciiToLowerCase(filename.substring(i+1)); if (_mimeMap!=null) - type = (Buffer)_mimeMap.get(ext); + type=_mimeMap.get(ext); if (type==null) - type=(Buffer)__dftMimeMap.get(ext); + type=__dftMimeMap.get(ext); } } if (type==null) { if (_mimeMap!=null) - type=(Buffer)_mimeMap.get("*"); + type=_mimeMap.get("*"); if (type==null) - type=(Buffer)__dftMimeMap.get("*"); + type=__dftMimeMap.get("*"); } return type; @@ -269,49 +213,30 @@ public class MimeTypes */ public void addMimeMapping(String extension,String type) { - if (_mimeMap==null) - _mimeMap=new HashMap(); - _mimeMap.put(StringUtil.asciiToLowerCase(extension),normalizeMimeType(type)); } /* ------------------------------------------------------------ */ - private static synchronized Buffer normalizeMimeType(String type) + private static ByteBuffer normalizeMimeType(String type) { - Buffer b =CACHE.get(type); - if (b==null) - b=CACHE.add(type,__index++); - return b; + MimeTypes.Type t =CACHE.get(type); + if (t!=null) + return t.toBuffer(); + + return BufferUtil.toBuffer(StringUtil.asciiToLowerCase(type)); } /* ------------------------------------------------------------ */ - public static String getCharsetFromContentType(Buffer value) - { - if (value instanceof CachedBuffer) - { - switch(((CachedBuffer)value).getOrdinal()) - { - case TEXT_HTML_8859_1_ORDINAL: - case TEXT_PLAIN_8859_1_ORDINAL: - case TEXT_XML_8859_1_ORDINAL: - return StringUtil.__ISO_8859_1; - - case TEXT_HTML_UTF_8_ORDINAL: - case TEXT_PLAIN_UTF_8_ORDINAL: - case TEXT_XML_UTF_8_ORDINAL: - case TEXT_JSON_UTF_8_ORDINAL: - return StringUtil.__UTF8; - } - } - - int i=value.getIndex(); - int end=value.putIndex(); + public static String getCharsetFromContentType(ByteBuffer value) + { + int i=value.position(); + int end=value.limit(); int state=0; int start=0; boolean quote=false; for (;i e = header.getFieldNames(); while (e.hasMoreElements()) { Object o=e.nextElement(); @@ -69,7 +70,7 @@ public class HttpFieldsTest HttpFields header = new HttpFields(); header.put("name0", "value0"); - header.put(new ByteArrayBuffer("name1"), new ByteArrayBuffer("value1")); + header.put("name1", "value1"); assertEquals("value0",header.getStringField("name0")); assertEquals("value0",header.getStringField("Name0")); @@ -86,11 +87,14 @@ public class HttpFieldsTest header.put("name\r\n1", "value1"); header.put("name:2", "value:\r\n2"); - ByteArrayBuffer buffer = new ByteArrayBuffer(1024); + ByteBuffer buffer = BufferUtil.allocate(1024); + buffer.clear(); header.putTo(buffer); - assertTrue(buffer.toString().contains("name0: value0")); - assertTrue(buffer.toString().contains("name1: value1")); - assertTrue(buffer.toString().contains("name2: value:2")); + buffer.flip(); + String out = BufferUtil.toString(buffer); + assertTrue(out.contains("name0: value??0")); + assertTrue(out.contains("name??1: value1")); + assertTrue(out.contains("name?2: value???2")); } @Test @@ -98,20 +102,22 @@ public class HttpFieldsTest { HttpFields header = new HttpFields(); - header.put("Connection", "keep-alive"); - assertEquals(HttpHeaderValues.KEEP_ALIVE, header.getStringField(HttpHeaders.CONNECTION)); + header.put("Connection", "Keep-Alive"); + header.put("tRansfer-EncOding", "CHUNKED"); + header.put("CONTENT-ENCODING", "gZIP"); - int matches=0; - Enumeration e = header.getFieldNames(); - while (e.hasMoreElements()) - { - Object o=e.nextElement(); - if (o==HttpHeaders.CONTENT_TYPE) - matches++; - if (o==HttpHeaders.CONNECTION) - matches++; - } - assertEquals(1, matches); + ByteBuffer buffer = BufferUtil.allocate(1024); + buffer.clear(); + header.putTo(buffer); + buffer.flip(); + String out = BufferUtil.toString(buffer); + + Assert.assertThat(out,JUnitMatchers.containsString(HttpHeaders.CONNECTION+": "+HttpHeaderValues.KEEP_ALIVE)); + Assert.assertThat(out,JUnitMatchers.containsString(HttpHeaders.TRANSFER_ENCODING+": "+HttpHeaderValues.CHUNKED)); + Assert.assertThat(out,JUnitMatchers.containsString(HttpHeaders.CONTENT_ENCODING+": "+HttpHeaderValues.GZIP)); + + + } @Test @@ -175,7 +181,7 @@ public class HttpFieldsTest assertNull(header.getStringField("name3")); int matches=0; - Enumeration e = header.getFieldNames(); + Enumeration e = header.getFieldNames(); while (e.hasMoreElements()) { Object o=e.nextElement(); @@ -213,7 +219,7 @@ public class HttpFieldsTest assertNull(fields.getStringField("name3")); int matches=0; - Enumeration e = fields.getFieldNames(); + Enumeration e = fields.getFieldNames(); while (e.hasMoreElements()) { Object o=e.nextElement(); @@ -234,122 +240,7 @@ public class HttpFieldsTest assertEquals(false, e.hasMoreElements()); } - @Test - public void testReuse() throws Exception - { - HttpFields header = new HttpFields(); - Buffer n1=new ByteArrayBuffer("name1"); - Buffer va=new ByteArrayBuffer("value1"); - Buffer vb=new ByteArrayBuffer(10); - vb.put((byte)'v'); - vb.put((byte)'a'); - vb.put((byte)'l'); - vb.put((byte)'u'); - vb.put((byte)'e'); - vb.put((byte)'1'); - header.put("name0", "value0"); - header.put(n1,va); - header.put("name2", "value2"); - - assertEquals("value0",header.getStringField("name0")); - assertEquals("value1",header.getStringField("name1")); - assertEquals("value2",header.getStringField("name2")); - assertNull(header.getStringField("name3")); - - header.remove(n1); - assertNull(header.getStringField("name1")); - header.put(n1,vb); - assertEquals("value1",header.getStringField("name1")); - - int matches=0; - Enumeration e = header.getFieldNames(); - while (e.hasMoreElements()) - { - Object o=e.nextElement(); - if ("name0".equals(o)) - matches++; - if ("name1".equals(o)) - matches++; - if ("name2".equals(o)) - matches++; - } - assertEquals(3, matches); - - e = header.getValues("name1"); - assertEquals(true, e.hasMoreElements()); - assertEquals(e.nextElement(), "value1"); - assertEquals(false, e.hasMoreElements()); - } - - @Test - public void testCase() throws Exception - { - HttpFields fields= new HttpFields(); - Set s; - // 0123456789012345678901234567890 - byte[] b ="Message-IDmessage-idvalueVALUE".getBytes(); - ByteArrayBuffer buf= new ByteArrayBuffer(512); - buf.put(b); - - View headUC= new View.CaseInsensitive(buf); - View headLC= new View.CaseInsensitive(buf); - View valUC = new View(buf); - View valLC = new View(buf); - headUC.update(0,10); - headLC.update(10,20); - valUC.update(20,25); - valLC.update(25,30); - - fields.add("header","value"); - fields.add(headUC,valLC); - fields.add("other","data"); - s=enum2set(fields.getFieldNames()); - assertEquals(3,s.size()); - assertTrue(s.contains("message-id")); - assertEquals("value",fields.getStringField("message-id").toLowerCase()); - assertEquals("value",fields.getStringField("Message-ID").toLowerCase()); - - fields.clear(); - - fields.add("header","value"); - fields.add(headLC,valLC); - fields.add("other","data"); - s=enum2set(fields.getFieldNames()); - assertEquals(3,s.size()); - assertTrue(s.contains("message-id")); - assertEquals("value",fields.getStringField("Message-ID").toLowerCase()); - assertEquals("value",fields.getStringField("message-id").toLowerCase()); - - fields.clear(); - - fields.add("header","value"); - fields.add(headUC,valUC); - fields.add("other","data"); - s=enum2set(fields.getFieldNames()); - assertEquals(3,s.size()); - assertTrue(s.contains("message-id")); - assertEquals("value",fields.getStringField("message-id").toLowerCase()); - assertEquals("value",fields.getStringField("Message-ID").toLowerCase()); - - fields.clear(); - - fields.add("header","value"); - fields.add(headLC,valUC); - fields.add("other","data"); - s=enum2set(fields.getFieldNames()); - assertEquals(3,s.size()); - assertTrue(s.contains("message-id")); - assertEquals("value",fields.getStringField("Message-ID").toLowerCase()); - assertEquals("value",fields.getStringField("message-id").toLowerCase()); - } - - @Test - public void testHttpHeaderValues() throws Exception - { - assertTrue(((CachedBuffer)HttpHeaderValues.CACHE.lookup("unknown value")).getOrdinal()<0); - assertTrue(((CachedBuffer)HttpHeaderValues.CACHE.lookup("close")).getOrdinal()>=0); - } @Test public void testSetCookie() throws Exception @@ -524,17 +415,4 @@ public class HttpFieldsTest } - @Test - public void testToString() throws Exception - { - HttpFields header = new HttpFields(); - - header.put(new ByteArrayBuffer("name0"), new View(new ByteArrayBuffer("value0"))); - header.put(new ByteArrayBuffer("name1"), new View(new ByteArrayBuffer("value1".getBytes()))); - String s1=header.toString(); - String s2=header.toString(); - //System.err.println(s1); - //System.err.println(s2); - assertEquals(s1,s2); - } } 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 e861721de0b..dad3204487d 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 @@ -17,11 +17,11 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; -import org.eclipse.jetty.io.Buffer; -import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.SimpleBuffers; import org.eclipse.jetty.io.bio.StringEndPoint; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.StringUtil; import org.junit.Test; @@ -33,14 +33,11 @@ public class HttpParserTest @Test public void testLineParse0() throws Exception { - StringEndPoint io=new StringEndPoint(); - io.setInput("POST /foo HTTP/1.0\015\012" + "\015\012"); - ByteArrayBuffer buffer= new ByteArrayBuffer(4096); - SimpleBuffers buffers=new SimpleBuffers(buffer,null); + ByteBuffer buffer= BufferUtil.toBuffer("POST /foo HTTP/1.0\015\012" + "\015\012"); Handler handler = new Handler(); - HttpParser parser= new HttpParser(buffers,io, handler); - parser.parse(); + HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler); + parser.parse(buffer); assertEquals("POST", f0); assertEquals("/foo", f1); assertEquals("HTTP/1.0", f2); @@ -52,7 +49,7 @@ public class HttpParserTest { StringEndPoint io=new StringEndPoint(); io.setInput("GET /999\015\012"); - ByteArrayBuffer buffer= new ByteArrayBuffer(4096); + ByteBuffer buffer= BufferUtil.allocate(4096); SimpleBuffers buffers=new SimpleBuffers(buffer,null); f2= null; @@ -70,7 +67,7 @@ public class HttpParserTest { StringEndPoint io=new StringEndPoint(); io.setInput("POST /222 \015\012"); - ByteArrayBuffer buffer= new ByteArrayBuffer(4096); + ByteBuffer buffer= BufferUtil.allocate(4096); SimpleBuffers buffers=new SimpleBuffers(buffer,null); f2= null; @@ -88,7 +85,7 @@ public class HttpParserTest { StringEndPoint io=new StringEndPoint(); io.setInput("POST /fo\u0690 HTTP/1.0\015\012" + "\015\012"); - ByteArrayBuffer buffer= new ByteArrayBuffer(4096); + ByteBuffer buffer= BufferUtil.allocate(4096); SimpleBuffers buffers=new SimpleBuffers(buffer,null); Handler handler = new Handler(); @@ -105,7 +102,7 @@ public class HttpParserTest { StringEndPoint io=new StringEndPoint(); io.setInput("POST /foo?param=\u0690 HTTP/1.0\015\012" + "\015\012"); - ByteArrayBuffer buffer= new ByteArrayBuffer(4096); + ByteBuffer buffer= BufferUtil.allocate(4096); SimpleBuffers buffers=new SimpleBuffers(buffer,null); Handler handler = new Handler(); @@ -122,7 +119,7 @@ public class HttpParserTest { StringEndPoint io=new StringEndPoint(); io.setInput("CONNECT 192.168.1.2:80 HTTP/1.1\015\012" + "\015\012"); - ByteArrayBuffer buffer= new ByteArrayBuffer(4096); + ByteBuffer buffer= BufferUtil.allocate(4096); SimpleBuffers buffers=new SimpleBuffers(buffer,null); Handler handler = new Handler(); @@ -150,7 +147,7 @@ public class HttpParserTest + " value4\015\012" + "Server5: notServer\015\012" + "\015\012"); - ByteArrayBuffer buffer= new ByteArrayBuffer(4096); + ByteBuffer buffer= BufferUtil.allocate(4096); SimpleBuffers buffers=new SimpleBuffers(buffer,null); Handler handler = new Handler(); @@ -188,8 +185,8 @@ public class HttpParserTest + "1a\015\012" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ\015\012" + "0\015\012"); - ByteArrayBuffer buffer= new ByteArrayBuffer(4096); - ByteArrayBuffer content=new ByteArrayBuffer(8192); + ByteBuffer buffer= BufferUtil.allocate(4096); + ByteBuffer content=BufferUtil.allocate(8192); SimpleBuffers buffers=new SimpleBuffers(buffer,content); Handler handler = new Handler(); @@ -231,8 +228,8 @@ public class HttpParserTest + "\015\012" + "0123456789\015\012"); - ByteArrayBuffer buffer= new ByteArrayBuffer(4096); - ByteArrayBuffer content=new ByteArrayBuffer(8192); + ByteBuffer buffer= BufferUtil.allocate(4096); + ByteBuffer content=BufferUtil.allocate(8192); SimpleBuffers buffers=new SimpleBuffers(buffer,content); Handler handler = new Handler(); @@ -314,8 +311,8 @@ public class HttpParserTest { f0=f1=f2=null; h=0; - ByteArrayBuffer buffer= new ByteArrayBuffer(tests[t]); - ByteArrayBuffer content=new ByteArrayBuffer(8192); + ByteBuffer buffer= BufferUtil.allocate(tests[t]); + ByteBuffer content=BufferUtil.allocate(8192); SimpleBuffers buffers=new SimpleBuffers(buffer,content); Handler handler = new Handler(); @@ -370,7 +367,7 @@ public class HttpParserTest + "Content-Type: text/plain\015\012" + "\015\012" + "0123456789\015\012"); - ByteArrayBuffer buffer= new ByteArrayBuffer(4096); + ByteBuffer buffer= BufferUtil.allocate(4096); SimpleBuffers buffers=new SimpleBuffers(buffer,null); Handler handler = new Handler(); @@ -392,7 +389,7 @@ public class HttpParserTest "HTTP/1.1 304 Not-Modified\015\012" + "Connection: close\015\012" + "\015\012"); - ByteArrayBuffer buffer= new ByteArrayBuffer(4096); + ByteBuffer buffer= BufferUtil.allocate(4096); SimpleBuffers buffers=new SimpleBuffers(buffer,null); Handler handler = new Handler(); @@ -418,7 +415,7 @@ public class HttpParserTest + "Content-Type: text/plain\015\012" + "\015\012" + "0123456789\015\012"); - ByteArrayBuffer buffer= new ByteArrayBuffer(4096); + ByteBuffer buffer= BufferUtil.allocate(4096); SimpleBuffers buffers=new SimpleBuffers(buffer,null); Handler handler = new Handler(); @@ -450,7 +447,7 @@ public class HttpParserTest + "Content-Type: text/plain\015\012" + "\015\012" + "0123456789\015\012"); - ByteArrayBuffer buffer= new ByteArrayBuffer(4096); + ByteBuffer buffer= BufferUtil.allocate(4096); SimpleBuffers buffers=new SimpleBuffers(buffer,null); Handler handler = new Handler(); @@ -474,7 +471,7 @@ public class HttpParserTest + "Content-Type: text/plain\015\012" + "\015\012" + "0123456789\015\012"); - ByteArrayBuffer buffer= new ByteArrayBuffer(4096); + ByteBuffer buffer= BufferUtil.allocate(4096); SimpleBuffers buffers=new SimpleBuffers(buffer,null); Handler handler = new Handler(); @@ -496,7 +493,7 @@ public class HttpParserTest "HTTP/1.1 304 found\015\012" + "Content-Length: 10\015\012" + "\015\012"); - ByteArrayBuffer buffer= new ByteArrayBuffer(4096); + ByteBuffer buffer= BufferUtil.allocate(4096); SimpleBuffers buffers=new SimpleBuffers(buffer,null); Handler handler = new Handler(); @@ -523,7 +520,7 @@ public class HttpParserTest + "HTTP/1.1 400 OK\015\012"); // extra data causes close - ByteArrayBuffer buffer= new ByteArrayBuffer(4096); + ByteBuffer buffer= BufferUtil.allocate(4096); SimpleBuffers buffers=new SimpleBuffers(buffer,null); Handler handler = new Handler(); @@ -551,48 +548,37 @@ public class HttpParserTest private boolean headerCompleted; private boolean messageCompleted; - private class Handler extends HttpParser.EventHandler + private class Handler implements HttpParser.RequestHandler, HttpParser.ResponseHandler { private HttpFields fields; private boolean request; - public void content(Buffer ref) + public void content(ByteBuffer ref) { if (_content==null) _content=""; _content= _content + ref; } - public void startRequest(Buffer tok0, Buffer tok1, Buffer tok2) + public void startRequest(String tok0, String tok1, String tok2) { - try - { - request=true; - h= -1; - hdr= new String[9]; - val= new String[9]; - f0= tok0.toString(); - f1=new String(tok1.array(),tok1.getIndex(),tok1.length(),StringUtil.__UTF8); - if (tok2!=null) - f2= tok2.toString(); - else - f2=null; - - fields=new HttpFields(); - } - catch (UnsupportedEncodingException e) - { - throw new RuntimeException(e); - } + request=true; + h= -1; + hdr= new String[9]; + val= new String[9]; + f0= tok0; + f1= tok1; + f2= tok2; + fields=new HttpFields(); messageCompleted = false; headerCompleted = false; } - public void parsedHeader(Buffer name, Buffer value) + public void parsedHeader(String name, String value) { - hdr[++h]= name.toString(StringUtil.__ISO_8859_1); - val[h]= value.toString(StringUtil.__ISO_8859_1); + hdr[++h]= name; + val[h]= value; } public void headerComplete() @@ -615,7 +601,7 @@ public class HttpParserTest messageCompleted = true; } - public void startResponse(Buffer version, int status, Buffer reason) + public void startResponse(String version, int status, String reason) { request=false; f0 = version.toString(); @@ -629,5 +615,10 @@ public class HttpParserTest messageCompleted = false; headerCompleted = false; } + + @Override + public void earlyEOF() + { + } } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpStatusCodeTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpStatusCodeTest.java index cb0259e4ead..1a9d6785810 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpStatusCodeTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpStatusCodeTest.java @@ -28,6 +28,6 @@ public class HttpStatusCodeTest public void testHttpMethod() { - assertEquals("GET",HttpMethods.GET_BUFFER.toString()); + assertEquals("GET",HttpMethods.GET.toString()); } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java index e3ea2973793..23a6e977ca2 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java @@ -1,6 +1,8 @@ package org.eclipse.jetty.http; -import org.eclipse.jetty.io.Buffer; +import java.nio.ByteBuffer; + +import org.eclipse.jetty.util.BufferUtil; import org.junit.Assert; import org.junit.Test; @@ -42,9 +44,9 @@ public class MimeTypesTest private void assertMimeTypeByExtension(String expectedMimeType, String filename) { MimeTypes mimetypes = new MimeTypes(); - Buffer contentType = mimetypes.getMimeByExtension(filename); + ByteBuffer contentType = mimetypes.getMimeByExtension(filename); String prefix = "MimeTypes.getMimeByExtension(" + filename + ")"; Assert.assertNotNull(prefix,contentType); - Assert.assertEquals(prefix,expectedMimeType,contentType.toString()); + Assert.assertEquals(prefix,expectedMimeType,BufferUtil.toString(contentType)); } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractBuffers.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractBuffers.java index b5e9dd0f9a0..6b3e1c3c8ee 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractBuffers.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractBuffers.java @@ -2,6 +2,8 @@ package org.eclipse.jetty.io; import java.nio.ByteBuffer; +import org.eclipse.jetty.util.BufferUtil; + public abstract class AbstractBuffers implements Buffers { diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/BufferCache.java b/jetty-io/src/main/java/org/eclipse/jetty/io/BufferCache.java deleted file mode 100644 index 33a23e1cd6d..00000000000 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/BufferCache.java +++ /dev/null @@ -1,201 +0,0 @@ -// ======================================================================== -// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== - -package org.eclipse.jetty.io; - -import java.io.UnsupportedEncodingException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -import org.eclipse.jetty.util.StringMap; -import org.eclipse.jetty.util.StringUtil; - -/* ------------------------------------------------------------------------------- */ -/** - * Stores a collection of {@link ByteBuffer} objects. - * Buffers are stored in an ordered collection and can retreived by index or value - * - */ -public class BufferCache -{ - private final StringMap _stringMap=new StringMap(StringMap.CASE_INSENSTIVE); - private final ArrayList _index= new ArrayList(); - - /* ------------------------------------------------------------------------------- */ - /** Add a buffer to the cache at the specified index. - * @param value The content of the buffer. - */ - public CachedBuffer add(String value, int ordinal) - { - CachedBuffer buffer= new CachedBuffer(value, ordinal); - _stringMap.put(value, buffer); - if (ordinal>=0) - { - while ((ordinal - _index.size()) >= 0) - _index.add(null); - _index.set(ordinal,buffer); - } - return buffer; - } - - public CachedBuffer get(int ordinal) - { - if (ordinal < 0 || ordinal >= _index.size()) - return null; - return (CachedBuffer)_index.get(ordinal); - } - - public ByteBuffer getBuffer(ByteBuffer buffer) - { - CachedBuffer cached=get(buffer); - if (cached!=null) - return cached.getBuffer(); - return buffer; - } - - public String getString(ByteBuffer buffer) - { - CachedBuffer cached=get(buffer); - if (cached!=null) - return cached.toString(); - return BufferUtil.toString(buffer); - } - - public CachedBuffer get(ByteBuffer buffer) - { - byte[] array=buffer.isReadOnly()?null:buffer.array(); - Map.Entry entry=_stringMap.getBestEntry(buffer); - if (entry!=null) - return (CachedBuffer)entry.getValue(); - return null; - } - - public CachedBuffer get(String value) - { - return (CachedBuffer)_stringMap.get(value); - } - - @Deprecated - public ByteBuffer lookup(ByteBuffer buffer) - { - CachedBuffer cached=get(buffer); - if (cached!=null) - return cached.getBuffer(); - - return buffer; - } - - public CachedBuffer getBest(byte[] value, int offset, int maxLength) - { - Entry entry = _stringMap.getBestEntry(value, offset, maxLength); - if (entry!=null) - return (CachedBuffer)entry.getValue(); - return null; - } - - public ByteBuffer lookup(String value) - { - CachedBuffer b= get(value); - if (b == null) - return ByteBuffer.wrap(value.getBytes(StringUtil.__ISO_8859_1_CHARSET)); - return b.getBuffer(); - } - - public String toString(ByteBuffer buffer) - { - CachedBuffer cached = get(buffer); - if (cached!=null) - return cached.toString(); - - - byte[] array=buffer.array(); - if (array!=null) - return new String(array,buffer.position(),buffer.remaining(),StringUtil.__ISO_8859_1_CHARSET); - - array=new byte[buffer.remaining()]; - buffer.asReadOnlyBuffer().get(array); - return new String(array,0,buffer.remaining(),StringUtil.__ISO_8859_1_CHARSET); - } - - public int getOrdinal(String value) - { - CachedBuffer buffer = (CachedBuffer)_stringMap.get(value); - return buffer==null?-1:buffer.getOrdinal(); - } - - public int getOrdinal(ByteBuffer buffer) - { - CachedBuffer cached = get(buffer); - if (cached!=null) - return cached.getOrdinal(); - return -1; - } - - public static class CachedBuffer - { - private final int _ordinal; - private final String _string; - private final ByteBuffer _buffer; - private HashMap _associateMap=null; - - public CachedBuffer(String value, int ordinal) - { - _string=value; - _buffer=ByteBuffer.wrap(value.getBytes(StringUtil.__ISO_8859_1_CHARSET)).asReadOnlyBuffer(); - _ordinal= ordinal; - } - - public int getOrdinal() - { - return _ordinal; - } - - public ByteBuffer getBuffer() - { - return _buffer; - } - - public String toString() - { - return _string; - } - - public CachedBuffer getAssociate(Object key) - { - if (_associateMap==null) - return null; - return (CachedBuffer)_associateMap.get(key); - } - - // TODO Replace Associate with a mime encoding specific solution - public void setAssociate(Object key, CachedBuffer associate) - { - if (_associateMap==null) - _associateMap=new HashMap(); - _associateMap.put(key,associate); - } - } - - - @Override - public String toString() - { - return "CACHE["+ - ",stringMap="+_stringMap+ - ",index="+_index+ - "]"; - } -} diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/BufferDateCache.java b/jetty-io/src/main/java/org/eclipse/jetty/io/BufferDateCache.java index bb2265f070d..302d82e7911 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/BufferDateCache.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/BufferDateCache.java @@ -17,6 +17,7 @@ import java.nio.ByteBuffer; import java.text.DateFormatSymbols; import java.util.Locale; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.DateCache; public class BufferDateCache extends DateCache diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java index 67234c84baf..e650432a4e6 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java @@ -16,6 +16,8 @@ package org.eclipse.jetty.io; import java.io.IOException; import java.nio.ByteBuffer; +import org.eclipse.jetty.util.BufferUtil; + /* ------------------------------------------------------------ */ diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StringEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StringEndPoint.java index f0022160d9c..d33129f0583 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StringEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StringEndPoint.java @@ -18,9 +18,9 @@ import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; import java.nio.charset.Charset; -import org.eclipse.jetty.io.BufferUtil; import org.eclipse.jetty.io.ByteArrayEndPoint; import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.StringUtil; /** diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java index d52fc9678bb..d43d0c94f87 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java @@ -23,8 +23,8 @@ import java.nio.channels.GatheringByteChannel; import java.nio.channels.SelectableChannel; import java.nio.channels.SocketChannel; -import org.eclipse.jetty.io.BufferUtil; import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SslConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SslConnection.java index b10fb8027e1..42c253bf2ce 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SslConnection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SslConnection.java @@ -24,9 +24,9 @@ import javax.net.ssl.SSLSession; import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.AsyncEndPoint; -import org.eclipse.jetty.io.BufferUtil; import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.Timeout.Task; diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/BufferCacheTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/BufferCacheTest.java index 4084c79ccf5..07cc172562e 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/BufferCacheTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/BufferCacheTest.java @@ -19,6 +19,7 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import org.eclipse.jetty.io.BufferCache.CachedBuffer; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.StringUtil; import org.junit.Before; import org.junit.Test; diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/EndPointTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/EndPointTest.java index c9da13cf860..4b62edce1c8 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/EndPointTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/EndPointTest.java @@ -6,6 +6,7 @@ import static org.junit.Assert.assertTrue; import java.nio.ByteBuffer; +import org.eclipse.jetty.util.BufferUtil; import org.junit.Test; public abstract class EndPointTest diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/nio/SelectChannelEndPointTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/nio/SelectChannelEndPointTest.java index 15d5f688209..aafd6d24665 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/nio/SelectChannelEndPointTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/nio/SelectChannelEndPointTest.java @@ -23,9 +23,9 @@ import java.util.concurrent.TimeUnit; import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.AsyncEndPoint; -import org.eclipse.jetty.io.BufferUtil; import org.eclipse.jetty.io.ConnectedEndPoint; import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.thread.QueuedThreadPool; diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/BufferUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java similarity index 91% rename from jetty-io/src/main/java/org/eclipse/jetty/io/BufferUtil.java rename to jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java index c1013ffe309..eb94e4152d4 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/BufferUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java @@ -11,12 +11,11 @@ // You may elect to redistribute this code under either of these licenses. // ======================================================================== -package org.eclipse.jetty.io; +package org.eclipse.jetty.util; import java.nio.ByteBuffer; import java.nio.charset.Charset; -import org.eclipse.jetty.util.StringUtil; /* ------------------------------------------------------------------------------- */ /** @@ -72,13 +71,13 @@ public class BufferUtil public static byte[] toArray(ByteBuffer buffer) { byte[] to = new byte[buffer.remaining()]; - if (buffer.isDirect()) - buffer.slice().get(to); - else + if (buffer.hasArray()) { byte[] array = buffer.array(); - System.arraycopy(array,buffer.position(),to,0,to.length); + System.arraycopy(array,buffer.arrayOffset()+buffer.position(),to,0,to.length); } + else + buffer.slice().get(to); return to; } @@ -117,18 +116,18 @@ public class BufferUtil to.put(from); put=remaining; } - else if (to.isDirect()) + else if (from.hasArray()) { put=to.remaining(); - ByteBuffer slice=from.slice(); - slice.limit(put); - to.put(slice); + to.put(from.array(),from.arrayOffset()+from.position(),put); from.position(from.position()+put); } else { put=to.remaining(); - to.put(from.array(),from.arrayOffset()+from.position(),put); + ByteBuffer slice=from.slice(); + slice.limit(put); + to.put(slice); from.position(from.position()+put); } } @@ -151,25 +150,46 @@ public class BufferUtil return toString(buffer,StringUtil.__ISO_8859_1_CHARSET); } + /* ------------------------------------------------------------ */ public static String toUTF8String(ByteBuffer buffer) { return toString(buffer,StringUtil.__UTF8_CHARSET); } - + + /* ------------------------------------------------------------ */ public static String toString(ByteBuffer buffer, Charset charset) { if (buffer == null) return null; - byte[] array = buffer.isReadOnly()?null:buffer.array(); + byte[] array = buffer.hasArray()?buffer.array():null; if (array == null) { byte[] to = new byte[buffer.remaining()]; buffer.slice().get(to); return new String(to,0,to.length,charset); } - return new String(array,buffer.position(),buffer.remaining(),charset); + return new String(array,buffer.arrayOffset()+buffer.position(),buffer.remaining(),charset); } + /* ------------------------------------------------------------ */ + public static String toString(ByteBuffer buffer, int position, int length, Charset charset) + { + if (buffer == null) + return null; + byte[] array = buffer.hasArray()?buffer.array():null; + if (array == null) + { + ByteBuffer slice=buffer.slice(); + slice.position(position); + slice.limit(position+length); + byte[] to = new byte[length]; + slice.get(to); + return new String(to,0,to.length,charset); + } + return new String(array,buffer.arrayOffset()+position,length,charset); + } + + /* ------------------------------------------------------------ */ /** * Convert buffer to an integer. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown * diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/StringMap.java b/jetty-util/src/main/java/org/eclipse/jetty/util/StringMap.java index a6224f6e744..d227e7546f2 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/StringMap.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/StringMap.java @@ -243,6 +243,15 @@ public class StringMap extends AbstractMap implements Externalizabl return entry.getValue(); } + /* ------------------------------------------------------------ */ + public O get(ByteBuffer buffer, int position, int length) + { + Map.Entry entry = getEntry(buffer,position,length); + if (entry==null) + return null; + return entry.getValue(); + } + /* ------------------------------------------------------------ */ /** Get a map entry by substring key. * @param key String containing the key @@ -360,11 +369,11 @@ public class StringMap extends AbstractMap implements Externalizabl * A simple 8859-1 byte to char mapping is assumed. * @param key byte array containing the key * @param offset Offset of the key within the array. - * @param maxLength The length of the key + * @param length The length of the key * @return The Map.Entry for the key or null if the key is not in * the map. */ - public Map.Entry getBestEntry(byte[] key,int offset, int maxLength) + public Map.Entry getEntry(byte[] key,int offset, int length) { if (key==null) return _nullEntry; @@ -374,7 +383,7 @@ public class StringMap extends AbstractMap implements Externalizabl // look for best match charLoop: - for (int i=0;i extends AbstractMap implements Externalizabl if (ni==-1) { ni=0; - - Node child = (node._children==null)?null:node._children[c%_width]; - - if (child==null && i>0) - return node; // This is the best match - node=child; + node=(node._children==null)?null:node._children[c%_width]; } // While we have a node to try @@ -424,24 +428,31 @@ public class StringMap extends AbstractMap implements Externalizabl * @return The Map.Entry for the key or null if the key is not in * the map. */ - public Map.Entry getBestEntry(ByteBuffer key) + public Map.Entry getEntry(ByteBuffer key) + { + return getEntry(key,key.position(),key.remaining()); + } + + /* ------------------------------------------------------------ */ + /** Get a map entry by ByteBuffer key, using as much of the passed key as needed for a match. + * A simple 8859-1 byte to char mapping is assumed. + * @param key ByteBuffer containing the key + * @return The Map.Entry for the key or null if the key is not in + * the map. + */ + public Map.Entry getEntry(ByteBuffer key,int position,int length) { if (key==null) return _nullEntry; if (!key.isReadOnly() && !key.isDirect()) - return getBestEntry(key.array(),key.position(),key.remaining()); - + return getEntry(key.array(),key.position(),key.remaining()); Node node = _root; int ni=-1; - - // look for best match - int position=key.position(); - int remaining=key.remaining(); charLoop: - for (int i=0;i extends AbstractMap implements Externalizabl if (ni==-1) { ni=0; - - Node child = (node._children==null)?null:node._children[c%_width]; - - if (child==null && i>0) - return node; // This is the best match - node=child; + node=(node._children==null)?null:node._children[c%_width]; } // While we have a node to try diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java index 91e4a03196d..3b41ca2e74e 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java @@ -14,7 +14,10 @@ package org.eclipse.jetty.util; import java.io.UnsupportedEncodingException; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; import java.nio.charset.Charset; +import java.util.Map; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -33,6 +36,9 @@ public class StringUtil { private static final Logger LOG = Log.getLogger(StringUtil.class); + + private final static StringMap CHARSETS= new StringMap(true); + public static final String ALL_INTERFACES="0.0.0.0"; public static final String CRLF="\015\012"; public static final String __LINE_SEPARATOR= @@ -40,7 +46,6 @@ public class StringUtil public static final String __ISO_8859_1="ISO-8859-1"; public final static String __UTF8="UTF-8"; - public final static String __UTF8Alt="UTF8"; public final static String __UTF16="UTF-16"; public final static Charset __UTF8_CHARSET; @@ -50,8 +55,52 @@ public class StringUtil { __UTF8_CHARSET=Charset.forName(__UTF8); __ISO_8859_1_CHARSET=Charset.forName(__ISO_8859_1); + + CHARSETS.put("UTF-8",__UTF8); + CHARSETS.put("UTF8",__UTF8); + CHARSETS.put("UTF-16",__UTF16); + CHARSETS.put("UTF16",__UTF16); + CHARSETS.put("ISO-8859-1",__ISO_8859_1); + CHARSETS.put("ISO_8859_1",__ISO_8859_1); } + /* ------------------------------------------------------------ */ + /** Convert alternate charset names (eg utf8) to normalized + * name (eg UTF-8). + */ + public static String normalizeCharset(String s) + { + String n=CHARSETS.get(s); + return (n==null)?s:n; + } + + /* ------------------------------------------------------------ */ + /** Convert alternate charset names (eg utf8) to normalized + * name (eg UTF-8). + */ + public static String normalizeCharset(String s,int offset,int length) + { + Map.Entry n=CHARSETS.getEntry(s,offset,length); + return (n==null)?s.substring(offset,offset+length):n.getValue(); + } + + /* ------------------------------------------------------------ */ + /** Convert alternate charset names (eg utf8) to normalized + * name (eg UTF-8). + */ + public static String normalizeCharset(ByteBuffer b,int position,int length) + { + Map.Entry n=CHARSETS.getEntry(b,position,length); + if (n!=null) + return n.getValue(); + ByteBuffer slice = b.slice(); + slice.position(position); + slice.limit(position+length); + return BufferUtil.toString(slice); + } + + + private static char[] lowercases = { '\000','\001','\002','\003','\004','\005','\006','\007', '\010','\011','\012','\013','\014','\015','\016','\017', @@ -330,7 +379,7 @@ public class StringUtil /* ------------------------------------------------------------ */ public static boolean isUTF8(String charset) { - return __UTF8.equalsIgnoreCase(charset)||__UTF8Alt.equalsIgnoreCase(charset); + return __UTF8.equalsIgnoreCase(charset)||__UTF8.equalsIgnoreCase(normalizeCharset(charset)); } @@ -497,4 +546,83 @@ public class StringUtil return sidBytes; } + + + /** + * Convert String to an integer. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown + * + * @param string + * A String containing an integer. + * @return an int + */ + public static int toInt(String string) + { + int val = 0; + boolean started = false; + boolean minus = false; + + for (int i = 0; i < string.length(); i++) + { + char b = string.charAt(i); + if (b <= ' ') + { + if (started) + break; + } + else if (b >= '0' && b <= '9') + { + val = val * 10 + (b - '0'); + started = true; + } + else if (b == '-' && !started) + { + minus = true; + } + else + break; + } + + if (started) + return minus?(-val):val; + throw new NumberFormatException(string); + } + + /** + * Convert String to an long. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown + * + * @param string + * A String containing an integer. + * @return an int + */ + public static long toLong(String string) + { + long val = 0; + boolean started = false; + boolean minus = false; + + for (int i = 0; i < string.length(); i++) + { + char b = string.charAt(i); + if (b <= ' ') + { + if (started) + break; + } + else if (b >= '0' && b <= '9') + { + val = val * 10L + (b - '0'); + started = true; + } + else if (b == '-' && !started) + { + minus = true; + } + else + break; + } + + if (started) + return minus?(-val):val; + throw new NumberFormatException(string); + } } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/BufferUtilTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/BufferUtilTest.java similarity index 97% rename from jetty-io/src/test/java/org/eclipse/jetty/io/BufferUtilTest.java rename to jetty-util/src/test/java/org/eclipse/jetty/util/BufferUtilTest.java index e6621d40335..c4e9b56f6c3 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/BufferUtilTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/BufferUtilTest.java @@ -11,13 +11,14 @@ // You may elect to redistribute this code under either of these licenses. // ======================================================================== -package org.eclipse.jetty.io; +package org.eclipse.jetty.util; import static org.junit.Assert.assertEquals; import java.nio.ByteBuffer; +import org.eclipse.jetty.util.BufferUtil; import org.junit.Test; /** diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/StringMapTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/StringMapTest.java index 76e2fd7108c..126167e046b 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/StringMapTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/StringMapTest.java @@ -149,11 +149,6 @@ public class StringMapTest assertEquals("abc",entry.getKey()); assertEquals("2",entry.getValue()); - entry=m5.getBestEntry("xabcyz".getBytes(),1,5); - assertTrue(entry!=null); - assertEquals("abc",entry.getKey()); - assertEquals("2",entry.getValue()); - entry=m5.getEntry("xaBcyz",1,3); assertTrue(entry==null);