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 contains(HttpHeader header)
176 {
177 for (int i=0;i<_fields.size();i++)
178 {
179 HttpField f=_fields.get(i);
180 if (f.getHeader()==header)
181 return true;
182 }
183 return false;
184 }
185
186 public boolean containsKey(String name)
187 {
188 for (int i=0;i<_fields.size();i++)
189 {
190 HttpField f=_fields.get(i);
191 if (f.getName().equalsIgnoreCase(name))
192 return true;
193 }
194 return false;
195 }
196
197
198 public String getStringField(HttpHeader header)
199 {
200 return getStringField(header.asString());
201 }
202
203 public String get(HttpHeader header)
204 {
205 return getStringField(header.asString());
206 }
207
208 public String get(String header)
209 {
210 return getStringField(header);
211 }
212
213
214
215
216
217
218 public String getStringField(String name)
219 {
220 HttpField field = getField(name);
221 return field==null?null:field.getValue();
222 }
223
224
225
226
227
228
229
230 public List<String> getValuesList(String name)
231 {
232 final List<String> list = new ArrayList<>();
233 for (HttpField f : _fields)
234 if (f.getName().equalsIgnoreCase(name))
235 list.add(f.getValue());
236 return list;
237 }
238
239
240
241
242
243
244
245 public Enumeration<String> getValues(final String name)
246 {
247 for (int i=0;i<_fields.size();i++)
248 {
249 final HttpField f = _fields.get(i);
250
251 if (f.getName().equalsIgnoreCase(name) && f.getValue()!=null)
252 {
253 final int first=i;
254 return new Enumeration<String>()
255 {
256 HttpField field=f;
257 int i = first+1;
258
259 @Override
260 public boolean hasMoreElements()
261 {
262 if (field==null)
263 {
264 while (i<_fields.size())
265 {
266 field=_fields.get(i++);
267 if (field.getName().equalsIgnoreCase(name) && field.getValue()!=null)
268 return true;
269 }
270 field=null;
271 return false;
272 }
273 return true;
274 }
275
276 @Override
277 public String nextElement() throws NoSuchElementException
278 {
279 if (hasMoreElements())
280 {
281 String value=field.getValue();
282 field=null;
283 return value;
284 }
285 throw new NoSuchElementException();
286 }
287
288 };
289 }
290 }
291
292 List<String> empty=Collections.emptyList();
293 return Collections.enumeration(empty);
294 }
295
296
297
298
299
300
301
302
303
304
305 public Enumeration<String> getValues(String name, final String separators)
306 {
307 final Enumeration<String> e = getValues(name);
308 if (e == null)
309 return null;
310 return new Enumeration<String>()
311 {
312 QuotedStringTokenizer tok = null;
313
314 @Override
315 public boolean hasMoreElements()
316 {
317 if (tok != null && tok.hasMoreElements()) return true;
318 while (e.hasMoreElements())
319 {
320 String value = e.nextElement();
321 if (value!=null)
322 {
323 tok = new QuotedStringTokenizer(value, separators, false, false);
324 if (tok.hasMoreElements()) return true;
325 }
326 }
327 tok = null;
328 return false;
329 }
330
331 @Override
332 public String nextElement() throws NoSuchElementException
333 {
334 if (!hasMoreElements()) throw new NoSuchElementException();
335 String next = (String) tok.nextElement();
336 if (next != null) next = next.trim();
337 return next;
338 }
339 };
340 }
341
342 public void put(HttpField field)
343 {
344 boolean put=false;
345 for (int i=_fields.size();i-->0;)
346 {
347 HttpField f=_fields.get(i);
348 if (f.isSame(field))
349 {
350 if (put)
351 _fields.remove(i);
352 else
353 {
354 _fields.set(i,field);
355 put=true;
356 }
357 }
358 }
359 if (!put)
360 _fields.add(field);
361 }
362
363
364
365
366
367
368
369 public void put(String name, String value)
370 {
371 if (value == null)
372 remove(name);
373 else
374 put(new HttpField(name, value));
375 }
376
377 public void put(HttpHeader header, HttpHeaderValue value)
378 {
379 put(header,value.toString());
380 }
381
382
383
384
385
386
387
388 public void put(HttpHeader header, String value)
389 {
390 if (value == null)
391 remove(header);
392 else
393 put(new HttpField(header, value));
394 }
395
396
397
398
399
400
401
402 public void put(String name, List<String> list)
403 {
404 remove(name);
405 for (String v : list)
406 if (v!=null)
407 add(name,v);
408 }
409
410
411
412
413
414
415
416
417
418
419 public void add(String name, String value) throws IllegalArgumentException
420 {
421 if (value == null)
422 return;
423
424 HttpField field = new HttpField(name, value);
425 _fields.add(field);
426 }
427
428 public void add(HttpHeader header, HttpHeaderValue value) throws IllegalArgumentException
429 {
430 add(header,value.toString());
431 }
432
433
434
435
436
437
438
439
440
441 public void add(HttpHeader header, String value) throws IllegalArgumentException
442 {
443 if (value == null) throw new IllegalArgumentException("null value");
444
445 HttpField field = new HttpField(header, value);
446 _fields.add(field);
447 }
448
449
450
451
452
453
454 public HttpField remove(HttpHeader name)
455 {
456 for (int i=_fields.size();i-->0;)
457 {
458 HttpField f=_fields.get(i);
459 if (f.getHeader()==name)
460 return _fields.remove(i);
461 }
462 return null;
463 }
464
465
466
467
468
469
470 public HttpField remove(String name)
471 {
472 for (int i=_fields.size();i-->0;)
473 {
474 HttpField f=_fields.get(i);
475 if (f.getName().equalsIgnoreCase(name))
476 return _fields.remove(i);
477 }
478 return null;
479 }
480
481
482
483
484
485
486
487
488 public long getLongField(String name) throws NumberFormatException
489 {
490 HttpField field = getField(name);
491 return field==null?-1L:StringUtil.toLong(field.getValue());
492 }
493
494
495
496
497
498
499
500 public long getDateField(String name)
501 {
502 HttpField field = getField(name);
503 if (field == null)
504 return -1;
505
506 String val = valueParameters(field.getValue(), null);
507 if (val == null)
508 return -1;
509
510 final long date = DateParser.parseDate(val);
511 if (date==-1)
512 throw new IllegalArgumentException("Cannot convert date: " + val);
513 return date;
514 }
515
516
517
518
519
520
521
522
523 public void putLongField(HttpHeader name, long value)
524 {
525 String v = Long.toString(value);
526 put(name, v);
527 }
528
529
530
531
532
533
534
535 public void putLongField(String name, long value)
536 {
537 String v = Long.toString(value);
538 put(name, v);
539 }
540
541
542
543
544
545
546
547
548 public void putDateField(HttpHeader 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 putDateField(String name, long date)
561 {
562 String d=DateGenerator.formatDate(date);
563 put(name, d);
564 }
565
566
567
568
569
570
571
572 public void addDateField(String name, long date)
573 {
574 String d=DateGenerator.formatDate(date);
575 add(name,d);
576 }
577
578 @Override
579 public String
580 toString()
581 {
582 try
583 {
584 StringBuilder buffer = new StringBuilder();
585 for (HttpField field : _fields)
586 {
587 if (field != null)
588 {
589 String tmp = field.getName();
590 if (tmp != null) buffer.append(tmp);
591 buffer.append(": ");
592 tmp = field.getValue();
593 if (tmp != null) buffer.append(tmp);
594 buffer.append("\r\n");
595 }
596 }
597 buffer.append("\r\n");
598 return buffer.toString();
599 }
600 catch (Exception e)
601 {
602 LOG.warn(e);
603 return e.toString();
604 }
605 }
606
607
608
609
610 public void clear()
611 {
612 _fields.clear();
613 }
614
615 public void add(HttpField field)
616 {
617 _fields.add(field);
618 }
619
620
621
622
623
624
625
626
627
628 public void add(HttpFields fields)
629 {
630 if (fields == null) return;
631
632 Enumeration<String> e = fields.getFieldNames();
633 while (e.hasMoreElements())
634 {
635 String name = e.nextElement();
636 Enumeration<String> values = fields.getValues(name);
637 while (values.hasMoreElements())
638 add(name, values.nextElement());
639 }
640 }
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656 public static String valueParameters(String value, Map<String,String> parameters)
657 {
658 if (value == null) return null;
659
660 int i = value.indexOf(';');
661 if (i < 0) return value;
662 if (parameters == null) return value.substring(0, i).trim();
663
664 StringTokenizer tok1 = new QuotedStringTokenizer(value.substring(i), ";", false, true);
665 while (tok1.hasMoreTokens())
666 {
667 String token = tok1.nextToken();
668 StringTokenizer tok2 = new QuotedStringTokenizer(token, "= ");
669 if (tok2.hasMoreTokens())
670 {
671 String paramName = tok2.nextToken();
672 String paramVal = null;
673 if (tok2.hasMoreTokens()) paramVal = tok2.nextToken();
674 parameters.put(paramName, paramVal);
675 }
676 }
677
678 return value.substring(0, i).trim();
679 }
680
681 private static final Float __one = new Float("1.0");
682 private static final Float __zero = new Float("0.0");
683 private static final Trie<Float> __qualities = new ArrayTernaryTrie<>();
684 static
685 {
686 __qualities.put("*", __one);
687 __qualities.put("1.0", __one);
688 __qualities.put("1", __one);
689 __qualities.put("0.9", new Float("0.9"));
690 __qualities.put("0.8", new Float("0.8"));
691 __qualities.put("0.7", new Float("0.7"));
692 __qualities.put("0.66", new Float("0.66"));
693 __qualities.put("0.6", new Float("0.6"));
694 __qualities.put("0.5", new Float("0.5"));
695 __qualities.put("0.4", new Float("0.4"));
696 __qualities.put("0.33", new Float("0.33"));
697 __qualities.put("0.3", new Float("0.3"));
698 __qualities.put("0.2", new Float("0.2"));
699 __qualities.put("0.1", new Float("0.1"));
700 __qualities.put("0", __zero);
701 __qualities.put("0.0", __zero);
702 }
703
704 public static Float getQuality(String value)
705 {
706 if (value == null) return __zero;
707
708 int qe = value.indexOf(";");
709 if (qe++ < 0 || qe == value.length()) return __one;
710
711 if (value.charAt(qe++) == 'q')
712 {
713 qe++;
714 Float q = __qualities.get(value, qe, value.length() - qe);
715 if (q != null)
716 return q;
717 }
718
719 Map<String,String> params = new HashMap<>(4);
720 valueParameters(value, params);
721 String qs = params.get("q");
722 if (qs==null)
723 qs="*";
724 Float q = __qualities.get(qs);
725 if (q == null)
726 {
727 try
728 {
729 q = new Float(qs);
730 }
731 catch (Exception e)
732 {
733 q = __one;
734 }
735 }
736 return q;
737 }
738
739
740
741
742
743
744
745 public static List<String> qualityList(Enumeration<String> e)
746 {
747 if (e == null || !e.hasMoreElements())
748 return Collections.emptyList();
749
750 Object list = null;
751 Object qual = null;
752
753
754 while (e.hasMoreElements())
755 {
756 String v = e.nextElement();
757 Float q = getQuality(v);
758
759 if (q >= 0.001)
760 {
761 list = LazyList.add(list, v);
762 qual = LazyList.add(qual, q);
763 }
764 }
765
766 List<String> vl = LazyList.getList(list, false);
767 if (vl.size() < 2)
768 return vl;
769
770 List<Float> ql = LazyList.getList(qual, false);
771
772
773 Float last = __zero;
774 for (int i = vl.size(); i-- > 0;)
775 {
776 Float q = ql.get(i);
777 if (last.compareTo(q) > 0)
778 {
779 String tmp = vl.get(i);
780 vl.set(i, vl.get(i + 1));
781 vl.set(i + 1, tmp);
782 ql.set(i, ql.get(i + 1));
783 ql.set(i + 1, q);
784 last = __zero;
785 i = vl.size();
786 continue;
787 }
788 last = q;
789 }
790 ql.clear();
791 return vl;
792 }
793
794
795
796 }