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.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.Enumeration;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.NoSuchElementException;
31 import java.util.Set;
32 import java.util.StringTokenizer;
33 import java.util.regex.Pattern;
34
35 import org.eclipse.jetty.util.ArrayTernaryTrie;
36 import org.eclipse.jetty.util.LazyList;
37 import org.eclipse.jetty.util.QuotedStringTokenizer;
38 import org.eclipse.jetty.util.StringUtil;
39 import org.eclipse.jetty.util.Trie;
40 import org.eclipse.jetty.util.log.Log;
41 import org.eclipse.jetty.util.log.Logger;
42
43
44
45
46
47
48
49
50
51
52
53 public class HttpFields implements Iterable<HttpField>
54 {
55 private static final Logger LOG = Log.getLogger(HttpFields.class);
56 private final static Pattern __splitter = Pattern.compile("\\s*,\\s*");
57 public final static String __separators = ", \t";
58
59 private final ArrayList<HttpField> _fields = new ArrayList<>(20);
60
61
62
63
64 public HttpFields()
65 {
66 }
67
68
69
70
71 public Collection<String> getFieldNamesCollection()
72 {
73 final Set<String> list = new HashSet<>(_fields.size());
74 for (HttpField f : _fields)
75 {
76 if (f!=null)
77 list.add(f.getName());
78 }
79 return list;
80 }
81
82
83
84
85
86 public Enumeration<String> getFieldNames()
87 {
88 return Collections.enumeration(getFieldNamesCollection());
89 }
90
91 public int size()
92 {
93 return _fields.size();
94 }
95
96
97
98
99
100
101 public HttpField getField(int i)
102 {
103 return _fields.get(i);
104 }
105
106 @Override
107 public Iterator<HttpField> iterator()
108 {
109 return _fields.iterator();
110 }
111
112 public HttpField getField(HttpHeader header)
113 {
114 for (int i=0;i<_fields.size();i++)
115 {
116 HttpField f=_fields.get(i);
117 if (f.getHeader()==header)
118 return f;
119 }
120 return null;
121 }
122
123 public HttpField getField(String name)
124 {
125 for (int i=0;i<_fields.size();i++)
126 {
127 HttpField f=_fields.get(i);
128 if (f.getName().equalsIgnoreCase(name))
129 return f;
130 }
131 return null;
132 }
133
134 public boolean contains(HttpHeader header, String value)
135 {
136 for (int i=0;i<_fields.size();i++)
137 {
138 HttpField f=_fields.get(i);
139 if (f.getHeader()==header && contains(f,value))
140 return true;
141 }
142 return false;
143 }
144
145 public boolean contains(String name, String value)
146 {
147 for (int i=0;i<_fields.size();i++)
148 {
149 HttpField f=_fields.get(i);
150 if (f.getName().equalsIgnoreCase(name) && contains(f,value))
151 return true;
152 }
153 return false;
154 }
155
156 private boolean contains(HttpField field,String value)
157 {
158 String v = field.getValue();
159 if (v==null)
160 return false;
161
162 if (value.equalsIgnoreCase(v))
163 return true;
164
165 String[] split = __splitter.split(v);
166 for (int i = 0; split!=null && i < split.length; i++)
167 {
168 if (value.equals(split[i]))
169 return true;
170 }
171
172 return false;
173 }
174
175 public boolean containsKey(String name)
176 {
177 for (int i=0;i<_fields.size();i++)
178 {
179 HttpField f=_fields.get(i);
180 if (f.getName().equalsIgnoreCase(name))
181 return true;
182 }
183 return false;
184 }
185
186 public String getStringField(HttpHeader header)
187 {
188 return getStringField(header.asString());
189 }
190
191 public String get(HttpHeader header)
192 {
193 return getStringField(header.asString());
194 }
195
196 public String get(String header)
197 {
198 return getStringField(header);
199 }
200
201
202
203
204
205
206 public String getStringField(String name)
207 {
208 HttpField field = getField(name);
209 return field==null?null:field.getValue();
210 }
211
212
213
214
215
216
217
218 public List<String> getValuesList(String name)
219 {
220 final List<String> list = new ArrayList<>();
221 for (HttpField f : _fields)
222 if (f.getName().equalsIgnoreCase(name))
223 list.add(f.getValue());
224 return list;
225 }
226
227
228
229
230
231
232
233 public Enumeration<String> getValues(final String name)
234 {
235 for (int i=0;i<_fields.size();i++)
236 {
237 final HttpField f = _fields.get(i);
238
239 if (f.getName().equalsIgnoreCase(name) && f.getValue()!=null)
240 {
241 final int first=i;
242 return new Enumeration<String>()
243 {
244 HttpField field=f;
245 int i = first+1;
246
247 @Override
248 public boolean hasMoreElements()
249 {
250 if (field==null)
251 {
252 while (i<_fields.size())
253 {
254 field=_fields.get(i++);
255 if (field.getName().equalsIgnoreCase(name) && field.getValue()!=null)
256 return true;
257 }
258 field=null;
259 return false;
260 }
261 return true;
262 }
263
264 @Override
265 public String nextElement() throws NoSuchElementException
266 {
267 if (hasMoreElements())
268 {
269 String value=field.getValue();
270 field=null;
271 return value;
272 }
273 throw new NoSuchElementException();
274 }
275
276 };
277 }
278 }
279
280 List<String> empty=Collections.emptyList();
281 return Collections.enumeration(empty);
282 }
283
284
285
286
287
288
289
290
291
292
293 public Enumeration<String> getValues(String name, final String separators)
294 {
295 final Enumeration<String> e = getValues(name);
296 if (e == null)
297 return null;
298 return new Enumeration<String>()
299 {
300 QuotedStringTokenizer tok = null;
301
302 @Override
303 public boolean hasMoreElements()
304 {
305 if (tok != null && tok.hasMoreElements()) return true;
306 while (e.hasMoreElements())
307 {
308 String value = e.nextElement();
309 if (value!=null)
310 {
311 tok = new QuotedStringTokenizer(value, separators, false, false);
312 if (tok.hasMoreElements()) return true;
313 }
314 }
315 tok = null;
316 return false;
317 }
318
319 @Override
320 public String nextElement() throws NoSuchElementException
321 {
322 if (!hasMoreElements()) throw new NoSuchElementException();
323 String next = (String) tok.nextElement();
324 if (next != null) next = next.trim();
325 return next;
326 }
327 };
328 }
329
330 public void put(HttpField field)
331 {
332 boolean put=false;
333 for (int i=_fields.size();i-->0;)
334 {
335 HttpField f=_fields.get(i);
336 if (f.isSame(field))
337 {
338 if (put)
339 _fields.remove(i);
340 else
341 {
342 _fields.set(i,field);
343 put=true;
344 }
345 }
346 }
347 if (!put)
348 _fields.add(field);
349 }
350
351
352
353
354
355
356
357 public void put(String name, String value)
358 {
359 if (value == null)
360 remove(name);
361 else
362 put(new HttpField(name, value));
363 }
364
365 public void put(HttpHeader header, HttpHeaderValue value)
366 {
367 put(header,value.toString());
368 }
369
370
371
372
373
374
375
376 public void put(HttpHeader header, String value)
377 {
378 if (value == null)
379 remove(header);
380 else
381 put(new HttpField(header, value));
382 }
383
384
385
386
387
388
389
390 public void put(String name, List<String> list)
391 {
392 remove(name);
393 for (String v : list)
394 if (v!=null)
395 add(name,v);
396 }
397
398
399
400
401
402
403
404
405
406
407 public void add(String name, String value) throws IllegalArgumentException
408 {
409 if (value == null)
410 return;
411
412 HttpField field = new HttpField(name, value);
413 _fields.add(field);
414 }
415
416 public void add(HttpHeader header, HttpHeaderValue value) throws IllegalArgumentException
417 {
418 add(header,value.toString());
419 }
420
421
422
423
424
425
426
427
428
429 public void add(HttpHeader header, String value) throws IllegalArgumentException
430 {
431 if (value == null) throw new IllegalArgumentException("null value");
432
433 HttpField field = new HttpField(header, value);
434 _fields.add(field);
435 }
436
437
438
439
440
441
442 public HttpField remove(HttpHeader name)
443 {
444 for (int i=_fields.size();i-->0;)
445 {
446 HttpField f=_fields.get(i);
447 if (f.getHeader()==name)
448 return _fields.remove(i);
449 }
450 return null;
451 }
452
453
454
455
456
457
458 public HttpField remove(String name)
459 {
460 for (int i=_fields.size();i-->0;)
461 {
462 HttpField f=_fields.get(i);
463 if (f.getName().equalsIgnoreCase(name))
464 return _fields.remove(i);
465 }
466 return null;
467 }
468
469
470
471
472
473
474
475
476 public long getLongField(String name) throws NumberFormatException
477 {
478 HttpField field = getField(name);
479 return field==null?-1L:StringUtil.toLong(field.getValue());
480 }
481
482
483
484
485
486
487
488 public long getDateField(String name)
489 {
490 HttpField field = getField(name);
491 if (field == null)
492 return -1;
493
494 String val = valueParameters(field.getValue(), null);
495 if (val == null)
496 return -1;
497
498 final long date = DateParser.parseDate(val);
499 if (date==-1)
500 throw new IllegalArgumentException("Cannot convert date: " + val);
501 return date;
502 }
503
504
505
506
507
508
509
510
511 public void putLongField(HttpHeader name, long value)
512 {
513 String v = Long.toString(value);
514 put(name, v);
515 }
516
517
518
519
520
521
522
523 public void putLongField(String name, long value)
524 {
525 String v = Long.toString(value);
526 put(name, v);
527 }
528
529
530
531
532
533
534
535
536 public void putDateField(HttpHeader name, long date)
537 {
538 String d=DateGenerator.formatDate(date);
539 put(name, d);
540 }
541
542
543
544
545
546
547
548 public void putDateField(String name, long date)
549 {
550 String d=DateGenerator.formatDate(date);
551 put(name, d);
552 }
553
554
555
556
557
558
559
560 public void addDateField(String name, long date)
561 {
562 String d=DateGenerator.formatDate(date);
563 add(name,d);
564 }
565
566 @Override
567 public String
568 toString()
569 {
570 try
571 {
572 StringBuilder buffer = new StringBuilder();
573 for (HttpField field : _fields)
574 {
575 if (field != null)
576 {
577 String tmp = field.getName();
578 if (tmp != null) buffer.append(tmp);
579 buffer.append(": ");
580 tmp = field.getValue();
581 if (tmp != null) buffer.append(tmp);
582 buffer.append("\r\n");
583 }
584 }
585 buffer.append("\r\n");
586 return buffer.toString();
587 }
588 catch (Exception e)
589 {
590 LOG.warn(e);
591 return e.toString();
592 }
593 }
594
595
596
597
598 public void clear()
599 {
600 _fields.clear();
601 }
602
603 public void add(HttpField field)
604 {
605 _fields.add(field);
606 }
607
608
609
610
611
612
613
614
615
616 public void add(HttpFields fields)
617 {
618 if (fields == null) return;
619
620 Enumeration<String> e = fields.getFieldNames();
621 while (e.hasMoreElements())
622 {
623 String name = e.nextElement();
624 Enumeration<String> values = fields.getValues(name);
625 while (values.hasMoreElements())
626 add(name, values.nextElement());
627 }
628 }
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644 public static String valueParameters(String value, Map<String,String> parameters)
645 {
646 if (value == null) return null;
647
648 int i = value.indexOf(';');
649 if (i < 0) return value;
650 if (parameters == null) return value.substring(0, i).trim();
651
652 StringTokenizer tok1 = new QuotedStringTokenizer(value.substring(i), ";", false, true);
653 while (tok1.hasMoreTokens())
654 {
655 String token = tok1.nextToken();
656 StringTokenizer tok2 = new QuotedStringTokenizer(token, "= ");
657 if (tok2.hasMoreTokens())
658 {
659 String paramName = tok2.nextToken();
660 String paramVal = null;
661 if (tok2.hasMoreTokens()) paramVal = tok2.nextToken();
662 parameters.put(paramName, paramVal);
663 }
664 }
665
666 return value.substring(0, i).trim();
667 }
668
669 private static final Float __one = new Float("1.0");
670 private static final Float __zero = new Float("0.0");
671 private static final Trie<Float> __qualities = new ArrayTernaryTrie<>();
672 static
673 {
674 __qualities.put("*", __one);
675 __qualities.put("1.0", __one);
676 __qualities.put("1", __one);
677 __qualities.put("0.9", new Float("0.9"));
678 __qualities.put("0.8", new Float("0.8"));
679 __qualities.put("0.7", new Float("0.7"));
680 __qualities.put("0.66", new Float("0.66"));
681 __qualities.put("0.6", new Float("0.6"));
682 __qualities.put("0.5", new Float("0.5"));
683 __qualities.put("0.4", new Float("0.4"));
684 __qualities.put("0.33", new Float("0.33"));
685 __qualities.put("0.3", new Float("0.3"));
686 __qualities.put("0.2", new Float("0.2"));
687 __qualities.put("0.1", new Float("0.1"));
688 __qualities.put("0", __zero);
689 __qualities.put("0.0", __zero);
690 }
691
692 public static Float getQuality(String value)
693 {
694 if (value == null) return __zero;
695
696 int qe = value.indexOf(";");
697 if (qe++ < 0 || qe == value.length()) return __one;
698
699 if (value.charAt(qe++) == 'q')
700 {
701 qe++;
702 Float q = __qualities.get(value, qe, value.length() - qe);
703 if (q != null)
704 return q;
705 }
706
707 Map<String,String> params = new HashMap<>(4);
708 valueParameters(value, params);
709 String qs = params.get("q");
710 if (qs==null)
711 qs="*";
712 Float q = __qualities.get(qs);
713 if (q == null)
714 {
715 try
716 {
717 q = new Float(qs);
718 }
719 catch (Exception e)
720 {
721 q = __one;
722 }
723 }
724 return q;
725 }
726
727
728
729
730
731
732
733 public static List<String> qualityList(Enumeration<String> e)
734 {
735 if (e == null || !e.hasMoreElements())
736 return Collections.emptyList();
737
738 Object list = null;
739 Object qual = null;
740
741
742 while (e.hasMoreElements())
743 {
744 String v = e.nextElement();
745 Float q = getQuality(v);
746
747 if (q >= 0.001)
748 {
749 list = LazyList.add(list, v);
750 qual = LazyList.add(qual, q);
751 }
752 }
753
754 List<String> vl = LazyList.getList(list, false);
755 if (vl.size() < 2)
756 return vl;
757
758 List<Float> ql = LazyList.getList(qual, false);
759
760
761 Float last = __zero;
762 for (int i = vl.size(); i-- > 0;)
763 {
764 Float q = ql.get(i);
765 if (last.compareTo(q) > 0)
766 {
767 String tmp = vl.get(i);
768 vl.set(i, vl.get(i + 1));
769 vl.set(i + 1, tmp);
770 ql.set(i, ql.get(i + 1));
771 ql.set(i + 1, q);
772 last = __zero;
773 i = vl.size();
774 continue;
775 }
776 last = q;
777 }
778 ql.clear();
779 return vl;
780 }
781
782
783
784 }