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.io.IOException;
22 import java.nio.ByteBuffer;
23 import java.text.SimpleDateFormat;
24 import java.util.ArrayList;
25 import java.util.Calendar;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.Date;
29 import java.util.Enumeration;
30 import java.util.GregorianCalendar;
31 import java.util.HashMap;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.Locale;
35 import java.util.Map;
36 import java.util.NoSuchElementException;
37 import java.util.StringTokenizer;
38 import java.util.TimeZone;
39
40 import org.eclipse.jetty.util.BufferUtil;
41 import org.eclipse.jetty.util.DateCache;
42 import org.eclipse.jetty.util.LazyList;
43 import org.eclipse.jetty.util.QuotedStringTokenizer;
44 import org.eclipse.jetty.util.StringMap;
45 import org.eclipse.jetty.util.StringUtil;
46 import org.eclipse.jetty.util.log.Log;
47 import org.eclipse.jetty.util.log.Logger;
48
49
50
51
52
53
54
55
56
57
58 public class HttpFields implements Iterable<HttpFields.Field>
59 {
60 private static final Logger LOG = Log.getLogger(HttpFields.class);
61 public static final String __COOKIE_DELIM="\"\\\n\r\t\f\b%+ ;=";
62 public static final TimeZone __GMT = TimeZone.getTimeZone("GMT");
63 public static final DateCache __dateCache = new DateCache("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
64
65 static
66 {
67 __GMT.setID("GMT");
68 __dateCache.setTimeZone(__GMT);
69 }
70
71 public final static String __separators = ", \t";
72
73 private static final String[] DAYS =
74 { "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
75 private static final String[] MONTHS =
76 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan"};
77
78
79 private static class DateGenerator
80 {
81 private final StringBuilder buf = new StringBuilder(32);
82 private final GregorianCalendar gc = new GregorianCalendar(__GMT);
83
84
85
86
87 public String formatDate(long date)
88 {
89 buf.setLength(0);
90 gc.setTimeInMillis(date);
91
92 int day_of_week = gc.get(Calendar.DAY_OF_WEEK);
93 int day_of_month = gc.get(Calendar.DAY_OF_MONTH);
94 int month = gc.get(Calendar.MONTH);
95 int year = gc.get(Calendar.YEAR);
96 int century = year / 100;
97 year = year % 100;
98
99 int hours = gc.get(Calendar.HOUR_OF_DAY);
100 int minutes = gc.get(Calendar.MINUTE);
101 int seconds = gc.get(Calendar.SECOND);
102
103 buf.append(DAYS[day_of_week]);
104 buf.append(',');
105 buf.append(' ');
106 StringUtil.append2digits(buf, day_of_month);
107
108 buf.append(' ');
109 buf.append(MONTHS[month]);
110 buf.append(' ');
111 StringUtil.append2digits(buf, century);
112 StringUtil.append2digits(buf, year);
113
114 buf.append(' ');
115 StringUtil.append2digits(buf, hours);
116 buf.append(':');
117 StringUtil.append2digits(buf, minutes);
118 buf.append(':');
119 StringUtil.append2digits(buf, seconds);
120 buf.append(" GMT");
121 return buf.toString();
122 }
123
124
125
126
127 public void formatCookieDate(StringBuilder buf, long date)
128 {
129 gc.setTimeInMillis(date);
130
131 int day_of_week = gc.get(Calendar.DAY_OF_WEEK);
132 int day_of_month = gc.get(Calendar.DAY_OF_MONTH);
133 int month = gc.get(Calendar.MONTH);
134 int year = gc.get(Calendar.YEAR);
135 year = year % 10000;
136
137 int epoch = (int) ((date / 1000) % (60 * 60 * 24));
138 int seconds = epoch % 60;
139 epoch = epoch / 60;
140 int minutes = epoch % 60;
141 int hours = epoch / 60;
142
143 buf.append(DAYS[day_of_week]);
144 buf.append(',');
145 buf.append(' ');
146 StringUtil.append2digits(buf, day_of_month);
147
148 buf.append('-');
149 buf.append(MONTHS[month]);
150 buf.append('-');
151 StringUtil.append2digits(buf, year/100);
152 StringUtil.append2digits(buf, year%100);
153
154 buf.append(' ');
155 StringUtil.append2digits(buf, hours);
156 buf.append(':');
157 StringUtil.append2digits(buf, minutes);
158 buf.append(':');
159 StringUtil.append2digits(buf, seconds);
160 buf.append(" GMT");
161 }
162 }
163
164 private static final ThreadLocal<DateGenerator> __dateGenerator =new ThreadLocal<DateGenerator>()
165 {
166 @Override
167 protected DateGenerator initialValue()
168 {
169 return new DateGenerator();
170 }
171 };
172
173
174
175
176 public static String formatDate(long date)
177 {
178 return __dateGenerator.get().formatDate(date);
179 }
180
181
182
183
184 public static void formatCookieDate(StringBuilder buf, long date)
185 {
186 __dateGenerator.get().formatCookieDate(buf,date);
187 }
188
189
190
191
192 public static String formatCookieDate(long date)
193 {
194 StringBuilder buf = new StringBuilder(28);
195 formatCookieDate(buf, date);
196 return buf.toString();
197 }
198
199 private final static String __dateReceiveFmt[] =
200 {
201 "EEE, dd MMM yyyy HH:mm:ss zzz",
202 "EEE, dd-MMM-yy HH:mm:ss",
203 "EEE MMM dd HH:mm:ss yyyy",
204
205 "EEE, dd MMM yyyy HH:mm:ss", "EEE dd MMM yyyy HH:mm:ss zzz",
206 "EEE dd MMM yyyy HH:mm:ss", "EEE MMM dd yyyy HH:mm:ss zzz", "EEE MMM dd yyyy HH:mm:ss",
207 "EEE MMM-dd-yyyy HH:mm:ss zzz", "EEE MMM-dd-yyyy HH:mm:ss", "dd MMM yyyy HH:mm:ss zzz",
208 "dd MMM yyyy HH:mm:ss", "dd-MMM-yy HH:mm:ss zzz", "dd-MMM-yy HH:mm:ss", "MMM dd HH:mm:ss yyyy zzz",
209 "MMM dd HH:mm:ss yyyy", "EEE MMM dd HH:mm:ss yyyy zzz",
210 "EEE, MMM dd HH:mm:ss yyyy zzz", "EEE, MMM dd HH:mm:ss yyyy", "EEE, dd-MMM-yy HH:mm:ss zzz",
211 "EEE dd-MMM-yy HH:mm:ss zzz", "EEE dd-MMM-yy HH:mm:ss",
212 };
213
214 private static class DateParser
215 {
216 final SimpleDateFormat _dateReceive[]= new SimpleDateFormat[__dateReceiveFmt.length];
217
218 long parse(final String dateVal)
219 {
220 for (int i = 0; i < _dateReceive.length; i++)
221 {
222 if (_dateReceive[i] == null)
223 {
224 _dateReceive[i] = new SimpleDateFormat(__dateReceiveFmt[i], Locale.US);
225 _dateReceive[i].setTimeZone(__GMT);
226 }
227
228 try
229 {
230 Date date = (Date) _dateReceive[i].parseObject(dateVal);
231 return date.getTime();
232 }
233 catch (java.lang.Exception e)
234 {
235
236 }
237 }
238
239 if (dateVal.endsWith(" GMT"))
240 {
241 final String val = dateVal.substring(0, dateVal.length() - 4);
242
243 for (SimpleDateFormat element : _dateReceive)
244 {
245 try
246 {
247 Date date = (Date) element.parseObject(val);
248 return date.getTime();
249 }
250 catch (java.lang.Exception e)
251 {
252
253 }
254 }
255 }
256 return -1;
257 }
258 }
259
260 public static long parseDate(String date)
261 {
262 return __dateParser.get().parse(date);
263 }
264
265 private static final ThreadLocal<DateParser> __dateParser =new ThreadLocal<DateParser>()
266 {
267 @Override
268 protected DateParser initialValue()
269 {
270 return new DateParser();
271 }
272 };
273
274 public final static String __01Jan1970=formatDate(0);
275 public final static ByteBuffer __01Jan1970_BUFFER=BufferUtil.toBuffer(__01Jan1970);
276 public final static String __01Jan1970_COOKIE = formatCookieDate(0).trim();
277 private final static byte[] __colon_space = new byte[] {':',' '};
278 private final ArrayList<Field> _fields = new ArrayList<>(20);
279 private final StringMap<Field> _names = new StringMap<>(true);
280
281
282
283
284 public HttpFields()
285 {
286 }
287
288
289
290
291
292 public Collection<String> getFieldNamesCollection()
293 {
294 final List<String> list = new ArrayList<>(_fields.size());
295 for (Field f : _fields)
296 {
297 if (f!=null)
298 list.add(f._name);
299 }
300 return list;
301 }
302
303
304
305
306
307 public Enumeration<String> getFieldNames()
308 {
309 final Enumeration<?> buffers = Collections.enumeration(_names.keySet());
310 return new Enumeration<String>()
311 {
312 @Override
313 public String nextElement()
314 {
315 return buffers.nextElement().toString();
316 }
317
318 @Override
319 public boolean hasMoreElements()
320 {
321 return buffers.hasMoreElements();
322 }
323 };
324 }
325
326 public int size()
327 {
328 return _fields.size();
329 }
330
331
332
333
334
335
336 public Field getField(int i)
337 {
338 return _fields.get(i);
339 }
340
341 @Override
342 public Iterator<Field> iterator()
343 {
344 return _fields.iterator();
345 }
346
347 public Field getField(HttpHeader header)
348 {
349 return _names.get(header.toString());
350 }
351
352 public Field getField(String name)
353 {
354 return _names.get(name);
355 }
356
357 public boolean containsKey(String name)
358 {
359 return _names.containsKey(name);
360 }
361
362 public String getStringField(HttpHeader header)
363 {
364 return getStringField(header.asString());
365 }
366
367 public String get(HttpHeader header)
368 {
369 return getStringField(header.asString());
370 }
371
372 public String get(String header)
373 {
374 return getStringField(header);
375 }
376
377
378
379
380
381
382 public String getStringField(String name)
383 {
384 Field field = getField(name);
385 return field==null?null:field.getValue();
386 }
387
388
389
390
391
392
393
394
395 public Collection<String> getValuesCollection(String name)
396 {
397 Field field = getField(name);
398 if (field==null)
399 return null;
400
401 final List<String> list = new ArrayList<>();
402
403 while(field!=null)
404 {
405 list.add(field.getValue());
406 field=field._next;
407 }
408 return list;
409 }
410
411
412
413
414
415
416
417 public Enumeration<String> getValues(String name)
418 {
419 final Field field = getField(name);
420 if (field == null)
421 {
422 List<String> empty=Collections.emptyList();
423 return Collections.enumeration(empty);
424 }
425
426 return new Enumeration<String>()
427 {
428 Field f = field;
429
430 @Override
431 public boolean hasMoreElements()
432 {
433 return f != null;
434 }
435
436 @Override
437 public String nextElement() throws NoSuchElementException
438 {
439 if (f == null) throw new NoSuchElementException();
440 Field n = f;
441 f = f._next;
442 return n.getValue();
443 }
444 };
445 }
446
447
448
449
450
451
452
453
454
455
456 public Enumeration<String> getValues(String name, final String separators)
457 {
458 final Enumeration<String> e = getValues(name);
459 if (e == null)
460 return null;
461 return new Enumeration<String>()
462 {
463 QuotedStringTokenizer tok = null;
464
465 @Override
466 public boolean hasMoreElements()
467 {
468 if (tok != null && tok.hasMoreElements()) return true;
469 while (e.hasMoreElements())
470 {
471 String value = e.nextElement();
472 tok = new QuotedStringTokenizer(value, separators, false, false);
473 if (tok.hasMoreElements()) return true;
474 }
475 tok = null;
476 return false;
477 }
478
479 @Override
480 public String nextElement() throws NoSuchElementException
481 {
482 if (!hasMoreElements()) throw new NoSuchElementException();
483 String next = (String) tok.nextElement();
484 if (next != null) next = next.trim();
485 return next;
486 }
487 };
488 }
489
490
491
492
493
494
495
496
497 public void put(String name, String value)
498 {
499 remove(name);
500 if (value == null)
501 return;
502
503
504 Field field = new Field(name, value);
505 _fields.add(field);
506 _names.put(name, field);
507 }
508
509 public void put(HttpHeader header, HttpHeaderValue value)
510 {
511 put(header,value.toString());
512 }
513
514
515
516
517
518
519
520 public void put(HttpHeader header, String value)
521 {
522 remove(header.toString());
523 if (value == null)
524 return;
525
526
527 Field field = new Field(header, value);
528 _fields.add(field);
529 _names.put(header.toString(), field);
530 }
531
532
533
534
535
536
537
538 public void put(String name, List<String> list)
539 {
540 remove(name);
541 for (String v : list)
542 if (v!=null)
543 add(name,v);
544 }
545
546
547
548
549
550
551
552
553
554
555 public void add(String name, String value) throws IllegalArgumentException
556 {
557 if (value == null)
558 return;
559
560 Field field = _names.get(name);
561 Field last = null;
562 while (field != null)
563 {
564 last = field;
565 field = field._next;
566 }
567
568
569 field = new Field(name, value);
570 _fields.add(field);
571
572
573 if (last != null)
574 last._next = field;
575 else
576 _names.put(name, field);
577 }
578
579 public void add(HttpHeader header, HttpHeaderValue value) throws IllegalArgumentException
580 {
581 add(header,value.toString());
582 }
583
584
585
586
587
588
589
590
591
592
593 public void add(HttpHeader header, String value) throws IllegalArgumentException
594 {
595 if (value == null) throw new IllegalArgumentException("null value");
596
597 Field field = _names.get(header.toString());
598 Field last = null;
599 while (field != null)
600 {
601 last = field;
602 field = field._next;
603 }
604
605
606 field = new Field(header, value);
607 _fields.add(field);
608
609
610 if (last != null)
611 last._next = field;
612 else
613 _names.put(header.toString(), field);
614 }
615
616
617
618
619
620
621 public void remove(HttpHeader name)
622 {
623 remove(name.toString());
624 }
625
626
627
628
629
630
631 public void remove(String name)
632 {
633 Field field = _names.remove(name);
634 while (field != null)
635 {
636 _fields.remove(field);
637 field = field._next;
638 }
639 }
640
641
642
643
644
645
646
647
648 public long getLongField(String name) throws NumberFormatException
649 {
650 Field field = getField(name);
651 return field==null?-1L:field.getLongValue();
652 }
653
654
655
656
657
658
659
660 public long getDateField(String name)
661 {
662 Field field = getField(name);
663 if (field == null)
664 return -1;
665
666 String val = valueParameters(field._value, null);
667 if (val == null)
668 return -1;
669
670 final long date = __dateParser.get().parse(val);
671 if (date==-1)
672 throw new IllegalArgumentException("Cannot convert date: " + val);
673 return date;
674 }
675
676
677
678
679
680
681
682
683 public void putLongField(HttpHeader name, long value)
684 {
685 String v = Long.toString(value);
686 put(name, v);
687 }
688
689
690
691
692
693
694
695 public void putLongField(String name, long value)
696 {
697 String v = Long.toString(value);
698 put(name, v);
699 }
700
701
702
703
704
705
706
707
708 public void putDateField(HttpHeader name, long date)
709 {
710 String d=formatDate(date);
711 put(name, d);
712 }
713
714
715
716
717
718
719
720 public void putDateField(String name, long date)
721 {
722 String d=formatDate(date);
723 put(name, d);
724 }
725
726
727
728
729
730
731
732 public void addDateField(String name, long date)
733 {
734 String d=formatDate(date);
735 add(name,d);
736 }
737
738
739
740
741
742
743 public void addSetCookie(HttpCookie cookie)
744 {
745 addSetCookie(
746 cookie.getName(),
747 cookie.getValue(),
748 cookie.getDomain(),
749 cookie.getPath(),
750 cookie.getMaxAge(),
751 cookie.getComment(),
752 cookie.isSecure(),
753 cookie.isHttpOnly(),
754 cookie.getVersion());
755 }
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770 public void addSetCookie(
771 final String name,
772 final String value,
773 final String domain,
774 final String path,
775 final long maxAge,
776 final String comment,
777 final boolean isSecure,
778 final boolean isHttpOnly,
779 int version)
780 {
781 String delim=__COOKIE_DELIM;
782
783
784 if (name == null || name.length() == 0)
785 throw new IllegalArgumentException("Bad cookie name");
786
787
788 StringBuilder buf = new StringBuilder(128);
789 String name_value_params;
790 QuotedStringTokenizer.quoteIfNeeded(buf, name, delim);
791 buf.append('=');
792 String start=buf.toString();
793 boolean hasDomain = false;
794 boolean hasPath = false;
795
796 if (value != null && value.length() > 0)
797 QuotedStringTokenizer.quoteIfNeeded(buf, value, delim);
798
799
800 if (path != null && path.length() > 0)
801 {
802 hasPath = true;
803 buf.append(";Path=");
804 if (path.trim().startsWith("\""))
805 buf.append(path);
806 else
807 QuotedStringTokenizer.quoteIfNeeded(buf,path,delim);
808 }
809 if (domain != null && domain.length() > 0)
810 {
811 hasDomain = true;
812 buf.append(";Domain=");
813 QuotedStringTokenizer.quoteIfNeeded(buf,domain.toLowerCase(Locale.ENGLISH),delim);
814 }
815
816 if (maxAge >= 0)
817 {
818
819 buf.append(";Expires=");
820 if (maxAge == 0)
821 buf.append(__01Jan1970_COOKIE);
822 else
823 formatCookieDate(buf, System.currentTimeMillis() + 1000L * maxAge);
824
825 buf.append(";Max-Age=");
826 buf.append(maxAge);
827 }
828
829 if (isSecure)
830 buf.append(";Secure");
831 if (isHttpOnly)
832 buf.append(";HttpOnly");
833
834 if (comment != null && comment.length() > 0)
835 {
836 buf.append(";Comment=");
837 QuotedStringTokenizer.quoteIfNeeded(buf, comment, delim);
838 }
839
840 name_value_params = buf.toString();
841
842
843 Field field = getField(HttpHeader.SET_COOKIE);
844 Field last=null;
845 while (field!=null)
846 {
847 String val = (field._value == null ? null : field._value.toString());
848 if (val!=null && val.startsWith(start))
849 {
850
851 if (((!hasDomain && !val.contains("Domain")) || (hasDomain && val.contains("Domain="+domain))) &&
852 ((!hasPath && !val.contains("Path")) || (hasPath && val.contains("Path="+path))))
853 {
854 _fields.remove(field);
855 if (last==null)
856 _names.put(HttpHeader.SET_COOKIE.toString(),field._next);
857 else
858 last._next=field._next;
859 break;
860 }
861 }
862 last=field;
863 field=field._next;
864 }
865
866 add(HttpHeader.SET_COOKIE.toString(), name_value_params);
867
868
869 put(HttpHeader.EXPIRES.toString(), __01Jan1970);
870 }
871
872 public void putTo(ByteBuffer bufferInFillMode) throws IOException
873 {
874 for (Field field : _fields)
875 {
876 if (field != null)
877 field.putTo(bufferInFillMode);
878 }
879 BufferUtil.putCRLF(bufferInFillMode);
880 }
881
882 @Override
883 public String
884 toString()
885 {
886 try
887 {
888 StringBuilder buffer = new StringBuilder();
889 for (Field field : _fields)
890 {
891 if (field != null)
892 {
893 String tmp = field.getName();
894 if (tmp != null) buffer.append(tmp);
895 buffer.append(": ");
896 tmp = field.getValue();
897 if (tmp != null) buffer.append(tmp);
898 buffer.append("\r\n");
899 }
900 }
901 buffer.append("\r\n");
902 return buffer.toString();
903 }
904 catch (Exception e)
905 {
906 LOG.warn(e);
907 return e.toString();
908 }
909 }
910
911
912
913
914 public void clear()
915 {
916 _fields.clear();
917 _names.clear();
918 }
919
920
921
922
923
924
925
926 public void add(HttpFields fields)
927 {
928 if (fields == null) return;
929
930 Enumeration<String> e = fields.getFieldNames();
931 while (e.hasMoreElements())
932 {
933 String name = e.nextElement();
934 Enumeration<String> values = fields.getValues(name);
935 while (values.hasMoreElements())
936 add(name, values.nextElement());
937 }
938 }
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954 public static String valueParameters(String value, Map<String,String> parameters)
955 {
956 if (value == null) return null;
957
958 int i = value.indexOf(';');
959 if (i < 0) return value;
960 if (parameters == null) return value.substring(0, i).trim();
961
962 StringTokenizer tok1 = new QuotedStringTokenizer(value.substring(i), ";", false, true);
963 while (tok1.hasMoreTokens())
964 {
965 String token = tok1.nextToken();
966 StringTokenizer tok2 = new QuotedStringTokenizer(token, "= ");
967 if (tok2.hasMoreTokens())
968 {
969 String paramName = tok2.nextToken();
970 String paramVal = null;
971 if (tok2.hasMoreTokens()) paramVal = tok2.nextToken();
972 parameters.put(paramName, paramVal);
973 }
974 }
975
976 return value.substring(0, i).trim();
977 }
978
979 private static final Float __one = new Float("1.0");
980 private static final Float __zero = new Float("0.0");
981 private static final StringMap<Float> __qualities = new StringMap<>();
982 static
983 {
984 __qualities.put("*", __one);
985 __qualities.put("1.0", __one);
986 __qualities.put("1", __one);
987 __qualities.put("0.9", new Float("0.9"));
988 __qualities.put("0.8", new Float("0.8"));
989 __qualities.put("0.7", new Float("0.7"));
990 __qualities.put("0.66", new Float("0.66"));
991 __qualities.put("0.6", new Float("0.6"));
992 __qualities.put("0.5", new Float("0.5"));
993 __qualities.put("0.4", new Float("0.4"));
994 __qualities.put("0.33", new Float("0.33"));
995 __qualities.put("0.3", new Float("0.3"));
996 __qualities.put("0.2", new Float("0.2"));
997 __qualities.put("0.1", new Float("0.1"));
998 __qualities.put("0", __zero);
999 __qualities.put("0.0", __zero);
1000 }
1001
1002 public static Float getQuality(String value)
1003 {
1004 if (value == null) return __zero;
1005
1006 int qe = value.indexOf(";");
1007 if (qe++ < 0 || qe == value.length()) return __one;
1008
1009 if (value.charAt(qe++) == 'q')
1010 {
1011 qe++;
1012 Float q = __qualities.get(value, qe, value.length() - qe);
1013 if (q != null)
1014 return q;
1015 }
1016
1017 Map<String,String> params = new HashMap<>(4);
1018 valueParameters(value, params);
1019 String qs = params.get("q");
1020 if (qs==null)
1021 qs="*";
1022 Float q = __qualities.get(qs);
1023 if (q == null)
1024 {
1025 try
1026 {
1027 q = new Float(qs);
1028 }
1029 catch (Exception e)
1030 {
1031 q = __one;
1032 }
1033 }
1034 return q;
1035 }
1036
1037
1038
1039
1040
1041
1042
1043 public static List<String> qualityList(Enumeration<String> e)
1044 {
1045 if (e == null || !e.hasMoreElements())
1046 return Collections.emptyList();
1047
1048 Object list = null;
1049 Object qual = null;
1050
1051
1052 while (e.hasMoreElements())
1053 {
1054 String v = e.nextElement();
1055 Float q = getQuality(v);
1056
1057 if (q >= 0.001)
1058 {
1059 list = LazyList.add(list, v);
1060 qual = LazyList.add(qual, q);
1061 }
1062 }
1063
1064 List vl = LazyList.getList(list, false);
1065 if (vl.size() < 2) return vl;
1066
1067 List ql = LazyList.getList(qual, false);
1068
1069
1070 Float last = __zero;
1071 for (int i = vl.size(); i-- > 0;)
1072 {
1073 Float q = (Float) ql.get(i);
1074 if (last.compareTo(q) > 0)
1075 {
1076 Object tmp = vl.get(i);
1077 vl.set(i, vl.get(i + 1));
1078 vl.set(i + 1, tmp);
1079 ql.set(i, ql.get(i + 1));
1080 ql.set(i + 1, q);
1081 last = __zero;
1082 i = vl.size();
1083 continue;
1084 }
1085 last = q;
1086 }
1087 ql.clear();
1088 return vl;
1089 }
1090
1091 public static final class Field
1092 {
1093 private final HttpHeader _header;
1094 private final String _name;
1095 private final String _value;
1096 private Field _next;
1097
1098 private Field(HttpHeader header, String value)
1099 {
1100 _header = header;
1101 _name = header.toString();
1102 _value = value;
1103 _next = null;
1104 }
1105
1106 private Field(String name, String value)
1107 {
1108 _header = HttpHeader.CACHE.get(name);
1109 _name = _header==null?name:_header.toString();
1110 _value = value;
1111 _next = null;
1112 }
1113
1114 private byte[] toSanitisedName(String s)
1115 {
1116 byte[] bytes = s.getBytes(StringUtil.__ISO_8859_1_CHARSET);
1117 for (int i=bytes.length;i-->0;)
1118 {
1119 switch(bytes[i])
1120 {
1121 case '\r':
1122 case '\n':
1123 case ':' :
1124 bytes[i]=(byte)'?';
1125 }
1126 }
1127 return bytes;
1128 }
1129
1130 private byte[] toSanitisedValue(String s)
1131 {
1132 byte[] bytes = s.getBytes(StringUtil.__ISO_8859_1_CHARSET);
1133 for (int i=bytes.length;i-->0;)
1134 {
1135 switch(bytes[i])
1136 {
1137 case '\r':
1138 case '\n':
1139 bytes[i]=(byte)'?';
1140 }
1141 }
1142 return bytes;
1143 }
1144
1145 public void putTo(ByteBuffer bufferInFillMode)
1146 {
1147 HttpHeader header = HttpHeader.CACHE.get(_name);
1148 if (header!=null)
1149 {
1150 bufferInFillMode.put(header.getBytesColonSpace());
1151
1152 if (HttpHeaderValue.hasKnownValues(header))
1153 {
1154 HttpHeaderValue value=HttpHeaderValue.CACHE.get(_value);
1155 if (value!=null)
1156 bufferInFillMode.put(value.toBuffer());
1157 else
1158 bufferInFillMode.put(toSanitisedValue(_value));
1159 }
1160 else
1161 bufferInFillMode.put(toSanitisedValue(_value));
1162 }
1163 else
1164 {
1165 bufferInFillMode.put(toSanitisedName(_name));
1166 bufferInFillMode.put(__colon_space);
1167 bufferInFillMode.put(toSanitisedValue(_value));
1168 }
1169
1170 BufferUtil.putCRLF(bufferInFillMode);
1171 }
1172
1173 public void putValueTo(ByteBuffer buffer)
1174 {
1175 buffer.put(toSanitisedValue(_value));
1176 }
1177
1178 public HttpHeader getHeader()
1179 {
1180 return _header;
1181 }
1182
1183 public String getName()
1184 {
1185 return _name;
1186 }
1187
1188 public String getValue()
1189 {
1190 return _value;
1191 }
1192
1193 public int getIntValue()
1194 {
1195 return StringUtil.toInt(_value);
1196 }
1197
1198 public long getLongValue()
1199 {
1200 return StringUtil.toLong(_value);
1201 }
1202
1203 @Override
1204 public String toString()
1205 {
1206 return ("[" + getName() + "=" + _value + (_next == null ? "" : "->") + "]");
1207 }
1208
1209 public boolean contains(String value)
1210 {
1211 if (_value==null)
1212 return false;
1213
1214 if (value.equalsIgnoreCase(_value))
1215 return true;
1216
1217 String[] split = _value.split("\\s*,\\s*");
1218 for (String s : split)
1219 {
1220 if (value.equalsIgnoreCase(s))
1221 return true;
1222 }
1223
1224 if (_next!=null)
1225 return _next.contains(value);
1226
1227 return false;
1228 }
1229 }
1230
1231 public boolean contains(HttpHeader header, String value)
1232 {
1233 Field field = getField(header);
1234 if (field==null)
1235 return false;
1236 return field.contains(value);
1237 }
1238 }