1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.http;
20
21 import java.nio.ByteBuffer;
22 import java.nio.charset.StandardCharsets;
23 import java.util.HashSet;
24 import java.util.Set;
25
26 import org.eclipse.jetty.util.ArrayTrie;
27 import org.eclipse.jetty.util.BufferUtil;
28 import org.eclipse.jetty.util.StringUtil;
29 import org.eclipse.jetty.util.Trie;
30
31
32
33
34
35 public class HttpField
36 {
37
38
39
40
41
42
43
44
45
46
47
48
49 public final static Trie<HttpField> CACHE = new ArrayTrie<>(2048);
50 public final static Trie<HttpField> CONTENT_TYPE = new ArrayTrie<>(512);
51
52 static
53 {
54 CACHE.put(new CachedHttpField(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE));
55 CACHE.put(new CachedHttpField(HttpHeader.CONNECTION,HttpHeaderValue.KEEP_ALIVE));
56 CACHE.put(new CachedHttpField(HttpHeader.CONNECTION,HttpHeaderValue.UPGRADE));
57 CACHE.put(new CachedHttpField(HttpHeader.ACCEPT_ENCODING,"gzip"));
58 CACHE.put(new CachedHttpField(HttpHeader.ACCEPT_ENCODING,"gzip, deflate"));
59 CACHE.put(new CachedHttpField(HttpHeader.ACCEPT_ENCODING,"gzip,deflate,sdch"));
60 CACHE.put(new CachedHttpField(HttpHeader.ACCEPT_LANGUAGE,"en-US,en;q=0.5"));
61 CACHE.put(new CachedHttpField(HttpHeader.ACCEPT_LANGUAGE,"en-GB,en-US;q=0.8,en;q=0.6"));
62 CACHE.put(new CachedHttpField(HttpHeader.ACCEPT_CHARSET,"ISO-8859-1,utf-8;q=0.7,*;q=0.3"));
63 CACHE.put(new CachedHttpField(HttpHeader.ACCEPT,"*/*"));
64 CACHE.put(new CachedHttpField(HttpHeader.ACCEPT,"image/png,image/*;q=0.8,*/*;q=0.5"));
65 CACHE.put(new CachedHttpField(HttpHeader.ACCEPT,"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"));
66 CACHE.put(new CachedHttpField(HttpHeader.PRAGMA,"no-cache"));
67 CACHE.put(new CachedHttpField(HttpHeader.CACHE_CONTROL,"private, no-cache, no-cache=Set-Cookie, proxy-revalidate"));
68 CACHE.put(new CachedHttpField(HttpHeader.CACHE_CONTROL,"no-cache"));
69 CACHE.put(new CachedHttpField(HttpHeader.CONTENT_LENGTH,"0"));
70 CACHE.put(new CachedHttpField(HttpHeader.CONTENT_ENCODING,"gzip"));
71 CACHE.put(new CachedHttpField(HttpHeader.CONTENT_ENCODING,"deflate"));
72 CACHE.put(new CachedHttpField(HttpHeader.TRANSFER_ENCODING,"chunked"));
73 CACHE.put(new CachedHttpField(HttpHeader.EXPIRES,"Fri, 01 Jan 1990 00:00:00 GMT"));
74
75
76 for (String type : new String[]{"text/plain","text/html","text/xml","text/json","application/x-www-form-urlencoded"})
77 {
78 HttpField field=new CachedHttpField(HttpHeader.CONTENT_TYPE,type);
79 CACHE.put(field);
80 CONTENT_TYPE.put(type,field);
81
82 for (String charset : new String[]{"UTF-8","ISO-8859-1"})
83 {
84 String type_charset=type+"; charset="+charset;
85 field=new CachedHttpField(HttpHeader.CONTENT_TYPE,type_charset);
86 CACHE.put(field);
87 CACHE.put(new CachedHttpField(HttpHeader.CONTENT_TYPE,type+";charset="+charset));
88 CONTENT_TYPE.put(type_charset,field);
89 CONTENT_TYPE.put(type+";charset="+charset,field);
90 }
91 }
92
93
94 for (HttpHeader h:HttpHeader.values())
95 if (!CACHE.put(new HttpField(h,(String)null)))
96 throw new IllegalStateException("CACHE FULL");
97
98 CACHE.put(new HttpField(HttpHeader.REFERER,(String)null));
99 CACHE.put(new HttpField(HttpHeader.IF_MODIFIED_SINCE,(String)null));
100 CACHE.put(new HttpField(HttpHeader.IF_NONE_MATCH,(String)null));
101 CACHE.put(new HttpField(HttpHeader.AUTHORIZATION,(String)null));
102 CACHE.put(new HttpField(HttpHeader.COOKIE,(String)null));
103 }
104
105 private final static byte[] __colon_space = new byte[] {':',' '};
106
107 private final HttpHeader _header;
108 private final String _name;
109 private final String _value;
110
111 public HttpField(HttpHeader header, String name, String value)
112 {
113 _header = header;
114 _name = name;
115 _value = value;
116 }
117
118 public HttpField(HttpHeader header, String value)
119 {
120 this(header,header.asString(),value);
121 }
122
123
124 public HttpField(HttpHeader header, HttpHeaderValue value)
125 {
126 this(header,header.asString(),value.asString());
127 }
128
129 public HttpField(String name, String value)
130 {
131 this(HttpHeader.CACHE.get(name),name,value);
132 }
133
134 public HttpHeader getHeader()
135 {
136 return _header;
137 }
138
139 public String getName()
140 {
141 return _name;
142 }
143
144 public String getValue()
145 {
146 return _value;
147 }
148
149 public boolean contains(String value)
150 {
151 if (_value==null)
152 return false;
153
154 if (value.equalsIgnoreCase(_value))
155 return true;
156
157 String[] split = _value.split("\\s*,\\s*");
158 for (String s : split)
159 {
160 if (value.equalsIgnoreCase(s))
161 return true;
162 }
163
164 return false;
165 }
166
167
168 public int getIntValue()
169 {
170 return StringUtil.toInt(_value);
171 }
172
173 public long getLongValue()
174 {
175 return StringUtil.toLong(_value);
176 }
177
178 private static byte[] toSanitisedName(String s)
179 {
180 byte[] bytes = s.getBytes(StandardCharsets.ISO_8859_1);
181 for (int i=bytes.length;i-->0;)
182 {
183 switch(bytes[i])
184 {
185 case '\r':
186 case '\n':
187 case ':' :
188 bytes[i]=(byte)'?';
189 }
190 }
191 return bytes;
192 }
193
194 private static byte[] toSanitisedValue(String s)
195 {
196 byte[] bytes = s.getBytes(StandardCharsets.ISO_8859_1);
197 for (int i=bytes.length;i-->0;)
198 {
199 switch(bytes[i])
200 {
201 case '\r':
202 case '\n':
203 bytes[i]=(byte)'?';
204 }
205 }
206 return bytes;
207 }
208
209 public void putTo(ByteBuffer bufferInFillMode)
210 {
211 if (_header!=null)
212 {
213 bufferInFillMode.put(_header.getBytesColonSpace());
214 bufferInFillMode.put(toSanitisedValue(_value));
215 }
216 else
217 {
218 bufferInFillMode.put(toSanitisedName(_name));
219 bufferInFillMode.put(__colon_space);
220 bufferInFillMode.put(toSanitisedValue(_value));
221 }
222
223 BufferUtil.putCRLF(bufferInFillMode);
224 }
225
226 public void putValueTo(ByteBuffer buffer)
227 {
228 buffer.put(toSanitisedValue(_value));
229 }
230
231 @Override
232 public String toString()
233 {
234 String v=getValue();
235 return getName() + ": " + (v==null?"":v);
236 }
237
238 public boolean isSame(HttpField field)
239 {
240 if (field==null)
241 return false;
242 if (field==this)
243 return true;
244 if (_header!=null && _header==field.getHeader())
245 return true;
246 if (_name.equalsIgnoreCase(field.getName()))
247 return true;
248 return false;
249 }
250
251
252
253
254
255 public static class CachedHttpField extends HttpField
256 {
257 final byte[] _bytes;
258 public CachedHttpField(HttpHeader header, String value)
259 {
260 super(header,value);
261 _bytes=new byte[header.asString().length()+2+value.length()+2];
262 System.arraycopy(header.getBytesColonSpace(),0,_bytes,0,header.asString().length()+2);
263 System.arraycopy(toSanitisedValue(value),0,_bytes,header.asString().length()+2,value.length());
264 _bytes[_bytes.length-2]='\r';
265 _bytes[_bytes.length-1]='\n';
266 }
267
268 CachedHttpField(HttpHeader header, HttpHeaderValue value)
269 {
270 this(header,value.asString());
271 }
272
273 @Override
274 public void putTo(ByteBuffer bufferInFillMode)
275 {
276 bufferInFillMode.put(_bytes);
277 }
278 }
279 }