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