convert MetaData to HttpField as a list

This commit is contained in:
Greg Wilkins 2014-06-11 16:53:17 +02:00
parent bbd61f8e19
commit c319c19125
5 changed files with 216 additions and 119 deletions

View File

@ -18,6 +18,8 @@
package org.eclipse.jetty.http; package org.eclipse.jetty.http;
import java.util.ArrayList;
import org.eclipse.jetty.util.QuotedStringTokenizer; import org.eclipse.jetty.util.QuotedStringTokenizer;
@ -69,13 +71,135 @@ public class HttpField
public String[] getValues() public String[] getValues()
{ {
QuotedStringTokenizer tok = new QuotedStringTokenizer(_value, ",", false, false); ArrayList<String> list = new ArrayList<>();
tok.setSingle(false); int state = 0;
String[] v = new String[tok.countTokens()]; int start=0;
int t=0; int end=0;
while(tok.hasMoreTokens()) StringBuilder builder = new StringBuilder();
v[t++]=tok.nextToken();
return v; for (int i=0;i<_value.length();i++)
{
char c = _value.charAt(i);
switch(state)
{
case 0: // initial white space
switch(c)
{
case '"': // open quote
state=2;
break;
case ',': // leading empty field
list.add("");
break;
case ' ': // more white space
case '\t':
break;
default: // character
start=i;
end=i;
state=1;
}
break;
case 1: // In token
switch(c)
{
case ',': // next field
list.add(_value.substring(start,end+1));
state=0;
break;
case ' ': // more white space
case '\t':
break;
default:
end=i;
}
break;
case 2: // In Quoted
switch(c)
{
case '\\': // next field
state=3;
break;
case '"': // end quote
list.add(builder.toString());
builder.setLength(0);
state=4;
break;
default:
builder.append(c);
}
break;
case 3: // In Quoted Quoted
builder.append(c);
state=2;
break;
case 4: // WS after end quote
switch(c)
{
case ' ': // white space
case '\t': // white space
break;
case ',': // white space
state=0;
break;
default:
throw new IllegalArgumentException("c="+(int)c);
}
break;
}
}
switch(state)
{
case 0:
break;
case 1:
list.add(_value.substring(start,end+1));
break;
case 4:
break;
default:
throw new IllegalArgumentException("state="+state);
}
return list.toArray(new String[list.size()]);
}
/* ------------------------------------------------------------ */
/** Look for a value in a possible multi valued field
* @param value
* @return True iff the value is contained in the field value entirely or
* as an element of a quoted comma separated list
*/
public boolean contains(String value)
{
if (_value==null)
return value==null;
if (_value.equalsIgnoreCase(value))
return true;
String[] values = getValues();
for (String v:values)
if (v.equalsIgnoreCase(value))
return true;
return false;
} }
@Override @Override

View File

@ -24,13 +24,11 @@ import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set; import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.regex.Pattern;
import org.eclipse.jetty.util.ArrayTernaryTrie; import org.eclipse.jetty.util.ArrayTernaryTrie;
import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.LazyList;
@ -50,14 +48,12 @@ import org.eclipse.jetty.util.log.Logger;
* <p>The cookie handling provided by this class is guided by the Servlet specification and RFC6265. * <p>The cookie handling provided by this class is guided by the Servlet specification and RFC6265.
* *
*/ */
public class HttpFields implements Iterable<HttpField> public class HttpFields extends ArrayList<HttpField>
{ {
private static final long serialVersionUID = 1L;
private static final Logger LOG = Log.getLogger(HttpFields.class); private static final Logger LOG = Log.getLogger(HttpFields.class);
private final static Pattern __splitter = Pattern.compile("\\s*,\\s*");
public final static String __separators = ", \t"; public final static String __separators = ", \t";
private final ArrayList<HttpField> _fields = new ArrayList<>(20);
/** /**
* Constructor. * Constructor.
*/ */
@ -65,13 +61,21 @@ public class HttpFields implements Iterable<HttpField>
{ {
} }
/**
* Constructor.
*/
public HttpFields(int capacity)
{
super(capacity);
}
/** /**
* Get Collection of header names. * Get Collection of header names.
*/ */
public Collection<String> getFieldNamesCollection() public Collection<String> getFieldNamesCollection()
{ {
final Set<String> list = new HashSet<>(_fields.size()); final Set<String> list = new HashSet<>(size());
for (HttpField f : _fields) for (HttpField f : this)
{ {
if (f!=null) if (f!=null)
list.add(f.getName()); list.add(f.getName());
@ -88,11 +92,6 @@ public class HttpFields implements Iterable<HttpField>
return Collections.enumeration(getFieldNamesCollection()); return Collections.enumeration(getFieldNamesCollection());
} }
public int size()
{
return _fields.size();
}
/** /**
* Get a Field by index. * Get a Field by index.
* @return A Field value or null if the Field value has not been set * @return A Field value or null if the Field value has not been set
@ -100,20 +99,14 @@ public class HttpFields implements Iterable<HttpField>
*/ */
public HttpField getField(int i) public HttpField getField(int i)
{ {
return _fields.get(i); return get(i);
}
@Override
public Iterator<HttpField> iterator()
{
return _fields.iterator();
} }
public HttpField getField(HttpHeader header) public HttpField getField(HttpHeader header)
{ {
for (int i=0;i<_fields.size();i++) for (int i=0;i<size();i++)
{ {
HttpField f=_fields.get(i); HttpField f=get(i);
if (f.getHeader()==header) if (f.getHeader()==header)
return f; return f;
} }
@ -122,9 +115,9 @@ public class HttpFields implements Iterable<HttpField>
public HttpField getField(String name) public HttpField getField(String name)
{ {
for (int i=0;i<_fields.size();i++) for (int i=0;i<size();i++)
{ {
HttpField f=_fields.get(i); HttpField f=get(i);
if (f.getName().equalsIgnoreCase(name)) if (f.getName().equalsIgnoreCase(name))
return f; return f;
} }
@ -133,10 +126,10 @@ public class HttpFields implements Iterable<HttpField>
public boolean contains(HttpHeader header, String value) public boolean contains(HttpHeader header, String value)
{ {
for (int i=0;i<_fields.size();i++) for (int i=0;i<size();i++)
{ {
HttpField f=_fields.get(i); HttpField f=get(i);
if (f.getHeader()==header && contains(f,value)) if (f.getHeader()==header && f.contains(value))
return true; return true;
} }
return false; return false;
@ -144,39 +137,21 @@ public class HttpFields implements Iterable<HttpField>
public boolean contains(String name, String value) public boolean contains(String name, String value)
{ {
for (int i=0;i<_fields.size();i++) for (int i=0;i<size();i++)
{ {
HttpField f=_fields.get(i); HttpField f=get(i);
if (f.getName().equalsIgnoreCase(name) && contains(f,value)) if (f.getName().equalsIgnoreCase(name) && f.contains(value))
return true; return true;
} }
return false; return false;
} }
private boolean contains(HttpField field,String value)
{
String v = field.getValue();
if (v==null)
return false;
if (value.equalsIgnoreCase(v))
return true;
String[] split = __splitter.split(v);
for (int i = 0; split!=null && i < split.length; i++)
{
if (value.equals(split[i]))
return true;
}
return false;
}
public boolean containsKey(String name) public boolean containsKey(String name)
{ {
for (int i=0;i<_fields.size();i++) for (int i=0;i<size();i++)
{ {
HttpField f=_fields.get(i); HttpField f=get(i);
if (f.getName().equalsIgnoreCase(name)) if (f.getName().equalsIgnoreCase(name))
return true; return true;
} }
@ -218,7 +193,7 @@ public class HttpFields implements Iterable<HttpField>
public List<String> getValuesList(String name) public List<String> getValuesList(String name)
{ {
final List<String> list = new ArrayList<>(); final List<String> list = new ArrayList<>();
for (HttpField f : _fields) for (HttpField f : this)
if (f.getName().equalsIgnoreCase(name)) if (f.getName().equalsIgnoreCase(name))
list.add(f.getValue()); list.add(f.getValue());
return list; return list;
@ -232,9 +207,9 @@ public class HttpFields implements Iterable<HttpField>
*/ */
public Enumeration<String> getValues(final String name) public Enumeration<String> getValues(final String name)
{ {
for (int i=0;i<_fields.size();i++) for (int i=0;i<size();i++)
{ {
final HttpField f = _fields.get(i); final HttpField f = get(i);
if (f.getName().equalsIgnoreCase(name) && f.getValue()!=null) if (f.getName().equalsIgnoreCase(name) && f.getValue()!=null)
{ {
@ -249,9 +224,9 @@ public class HttpFields implements Iterable<HttpField>
{ {
if (field==null) if (field==null)
{ {
while (i<_fields.size()) while (i<size())
{ {
field=_fields.get(i++); field=get(i++);
if (field.getName().equalsIgnoreCase(name) && field.getValue()!=null) if (field.getName().equalsIgnoreCase(name) && field.getValue()!=null)
return true; return true;
} }
@ -330,22 +305,22 @@ public class HttpFields implements Iterable<HttpField>
public void put(HttpField field) public void put(HttpField field)
{ {
boolean put=false; boolean put=false;
for (int i=_fields.size();i-->0;) for (int i=size();i-->0;)
{ {
HttpField f=_fields.get(i); HttpField f=get(i);
if (f.isSameName(field)) if (f.isSameName(field))
{ {
if (put) if (put)
_fields.remove(i); remove(i);
else else
{ {
_fields.set(i,field); set(i,field);
put=true; put=true;
} }
} }
} }
if (!put) if (!put)
_fields.add(field); add(field);
} }
/** /**
@ -410,7 +385,7 @@ public class HttpFields implements Iterable<HttpField>
return; return;
HttpField field = new HttpField(name, value); HttpField field = new HttpField(name, value);
_fields.add(field); add(field);
} }
public void add(HttpHeader header, HttpHeaderValue value) throws IllegalArgumentException public void add(HttpHeader header, HttpHeaderValue value) throws IllegalArgumentException
@ -431,7 +406,7 @@ public class HttpFields implements Iterable<HttpField>
if (value == null) throw new IllegalArgumentException("null value"); if (value == null) throw new IllegalArgumentException("null value");
HttpField field = new HttpField(header, value); HttpField field = new HttpField(header, value);
_fields.add(field); add(field);
} }
/** /**
@ -441,11 +416,11 @@ public class HttpFields implements Iterable<HttpField>
*/ */
public HttpField remove(HttpHeader name) public HttpField remove(HttpHeader name)
{ {
for (int i=_fields.size();i-->0;) for (int i=size();i-->0;)
{ {
HttpField f=_fields.get(i); HttpField f=get(i);
if (f.getHeader()==name) if (f.getHeader()==name)
return _fields.remove(i); return remove(i);
} }
return null; return null;
} }
@ -457,11 +432,11 @@ public class HttpFields implements Iterable<HttpField>
*/ */
public HttpField remove(String name) public HttpField remove(String name)
{ {
for (int i=_fields.size();i-->0;) for (int i=size();i-->0;)
{ {
HttpField f=_fields.get(i); HttpField f=get(i);
if (f.getName().equalsIgnoreCase(name)) if (f.getName().equalsIgnoreCase(name))
return _fields.remove(i); return remove(i);
} }
return null; return null;
} }
@ -570,7 +545,7 @@ public class HttpFields implements Iterable<HttpField>
try try
{ {
StringBuilder buffer = new StringBuilder(); StringBuilder buffer = new StringBuilder();
for (HttpField field : _fields) for (HttpField field : this)
{ {
if (field != null) if (field != null)
{ {
@ -592,21 +567,6 @@ public class HttpFields implements Iterable<HttpField>
} }
} }
/**
* Clear the header.
*/
public void clear()
{
_fields.clear();
}
public void add(HttpField field)
{
_fields.add(field);
}
/** /**
* Add fields from another HttpFields instance. Single valued fields are replaced, while all * Add fields from another HttpFields instance. Single valued fields are replaced, while all
* others are added. * others are added.

View File

@ -436,4 +436,32 @@ public class HttpFieldsTest
assertEquals(""+i,i>=4,header.contains(""+i,"def")); assertEquals(""+i,i>=4,header.contains(""+i,"def"));
} }
} }
@Test
public void testValues()
{
String[] values = new HttpField("name","value").getValues();
assertEquals(1,values.length);
assertEquals("value",values[0]);
values = new HttpField("name","a,b,c").getValues();
assertEquals(3,values.length);
assertEquals("a",values[0]);
assertEquals("b",values[1]);
assertEquals("c",values[2]);
values = new HttpField("name","a,\"x,y,z\",c").getValues();
assertEquals(3,values.length);
assertEquals("a",values[0]);
assertEquals("x,y,z",values[1]);
assertEquals("c",values[2]);
values = new HttpField("name","a,\"x,\\\"p,q\\\",z\",c").getValues();
assertEquals(3,values.length);
assertEquals("a",values[0]);
assertEquals("x,\"p,q\",z",values[1]);
assertEquals("c",values[2]);
}
} }

View File

@ -19,14 +19,11 @@
package org.eclipse.jetty.http2.hpack; package org.eclipse.jetty.http2.hpack;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpScheme;
@ -35,9 +32,9 @@ import org.eclipse.jetty.http.HttpScheme;
*/ */
public class MetaData implements Iterable<HttpField> public class MetaData implements Iterable<HttpField>
{ {
private final Iterable<HttpField> _fields; private final HttpFields _fields;
public MetaData(Iterable<HttpField> fields) public MetaData(HttpFields fields)
{ {
_fields=fields; _fields=fields;
} }
@ -58,14 +55,9 @@ public class MetaData implements Iterable<HttpField>
return _fields.iterator(); return _fields.iterator();
} }
public List<HttpField> getFields() public HttpFields getFields()
{ {
if (_fields instanceof List) return _fields;
return (List<HttpField>)_fields;
ArrayList<HttpField> list = new ArrayList<>();
for (HttpField field:_fields)
list.add(field);
return list;
} }
@Override @Override
@ -112,7 +104,7 @@ public class MetaData implements Iterable<HttpField>
private final int _port; private final int _port;
private final String _path; private final String _path;
public Request(HttpScheme scheme, String method, String authority, String host, int port, String path, Iterable<HttpField> fields) public Request(HttpScheme scheme, String method, String authority, String host, int port, String path, HttpFields fields)
{ {
super(fields); super(fields);
_authority=authority; _authority=authority;
@ -200,12 +192,6 @@ public class MetaData implements Iterable<HttpField>
_status=status; _status=status;
} }
public Response(int status, Iterable<HttpField> fields)
{
super(fields);
_status=status;
}
@Override @Override
public boolean isRequest() public boolean isRequest()
{ {

View File

@ -19,12 +19,10 @@
package org.eclipse.jetty.http2.hpack; package org.eclipse.jetty.http2.hpack;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HostPortHttpField;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpScheme;
/* -------------------------------------------------------- */ /* -------------------------------------------------------- */
@ -40,7 +38,7 @@ public class MetaDataBuilder
private int _port; private int _port;
private String _path; private String _path;
List<HttpField> _fields = new ArrayList<>(); HttpFields _fields = new HttpFields(10);
public void emit(HttpField field) public void emit(HttpField field)
{ {
@ -104,11 +102,13 @@ public class MetaDataBuilder
{ {
try try
{ {
HttpFields fields = _fields;
_fields = new HttpFields(Math.max(10,fields.size()+5));
if (_method!=null) if (_method!=null)
return new MetaData.Request(_scheme,_method,_authority,_host,_port,_path,new ArrayList<>(_fields)); return new MetaData.Request(_scheme,_method,_authority,_host,_port,_path,fields);
if (_status!=0) if (_status!=0)
return new MetaData.Response(_status,new ArrayList<>(_fields)); return new MetaData.Response(_status,fields);
return new MetaData(new ArrayList<>(_fields)); return new MetaData(fields);
} }
finally finally
{ {
@ -119,7 +119,6 @@ public class MetaDataBuilder
_path=null; _path=null;
_host=null; _host=null;
_port=0; _port=0;
_fields.clear();
} }
} }
} }