comparison src/org/eclipse/jetty/http/HttpFields.java @ 1022:3718afd99988

HttpHeaders uses StringCache
author Franklin Schmidt <fschmidt@gmail.com>
date Tue, 01 Nov 2016 01:04:46 -0600
parents e350c11242be
children eca26899c4bc
comparison
equal deleted inserted replaced
1021:e350c11242be 1022:3718afd99988
38 import java.util.TimeZone; 38 import java.util.TimeZone;
39 import java.util.concurrent.ConcurrentHashMap; 39 import java.util.concurrent.ConcurrentHashMap;
40 import java.util.concurrent.ConcurrentMap; 40 import java.util.concurrent.ConcurrentMap;
41 41
42 import org.eclipse.jetty.io.Buffer; 42 import org.eclipse.jetty.io.Buffer;
43 import org.eclipse.jetty.io.BufferCache;
44 import org.eclipse.jetty.io.BufferCache.CachedBuffer;
45 import org.eclipse.jetty.io.BufferUtil; 43 import org.eclipse.jetty.io.BufferUtil;
46 import org.eclipse.jetty.io.ByteArrayBuffer; 44 import org.eclipse.jetty.io.ByteArrayBuffer;
47 import org.eclipse.jetty.util.LazyList; 45 import org.eclipse.jetty.util.LazyList;
48 import org.eclipse.jetty.util.QuotedStringTokenizer; 46 import org.eclipse.jetty.util.QuotedStringTokenizer;
49 import org.eclipse.jetty.util.StringUtil; 47 import org.eclipse.jetty.util.StringUtil;
265 return new DateParser(); 263 return new DateParser();
266 } 264 }
267 }; 265 };
268 266
269 private final static String __01Jan1970 = formatDate(0); 267 private final static String __01Jan1970 = formatDate(0);
270 private final static Buffer __01Jan1970_BUFFER = new ByteArrayBuffer(__01Jan1970);
271 private final static String __01Jan1970_COOKIE = formatCookieDate(0).trim(); 268 private final static String __01Jan1970_COOKIE = formatCookieDate(0).trim();
272 269
273 270
274 271
275 272
276 273
277 274
278 private final ArrayList<Field> _fields = new ArrayList<Field>(20); 275 private final ArrayList<Field> _fields = new ArrayList<Field>();
279 private final HashMap<Buffer,Field> _names = new HashMap<Buffer,Field>(32); 276 private final HashMap<String,Field> _names = new HashMap<String,Field>();
280 /* 277
281 private Buffer convertValue(String value)
282 {
283 try
284 {
285 return new ByteArrayBuffer(value,StringUtil.__ISO_8859_1);
286 }
287 catch (UnsupportedEncodingException e)
288 {
289 throw new RuntimeException(e);
290 }
291 }
292 */
293 278
294 /* -------------------------------------------------------------- */ 279 /* -------------------------------------------------------------- */
295 /** 280 /**
296 * Get Collection of header names. 281 * Get Collection of header names.
297 */ 282 */
344 public Field getField(int i) 329 public Field getField(int i)
345 { 330 {
346 return _fields.get(i); 331 return _fields.get(i);
347 } 332 }
348 333
349 /* ------------------------------------------------------------ */
350 private Field getField(String name) 334 private Field getField(String name)
351 { 335 {
352 return _names.get(HttpHeaders.CACHE.lookup(name)); 336 return _names.get(name.toLowerCase());
353 } 337 }
354 338
355 /* ------------------------------------------------------------ */
356 private Field getField(Buffer name)
357 {
358 return _names.get(HttpHeaders.CACHE.lookup(name));
359 }
360
361 /* ------------------------------------------------------------ */
362 public boolean containsKey(Buffer name)
363 {
364 return _names.containsKey(HttpHeaders.CACHE.lookup(name));
365 }
366
367 /* ------------------------------------------------------------ */
368 public boolean containsKey(String name) 339 public boolean containsKey(String name)
369 { 340 {
370 return _names.containsKey(HttpHeaders.CACHE.lookup(name)); 341 return _names.containsKey(name.toLowerCase());
371 } 342 }
372 343
373 /* -------------------------------------------------------------- */ 344 /* -------------------------------------------------------------- */
374 /** 345 /**
375 * @return the value of a field, or null if not found. For multiple fields of the same name, 346 * @return the value of a field, or null if not found. For multiple fields of the same name,
377 * @param name the case-insensitive field name 348 * @param name the case-insensitive field name
378 */ 349 */
379 public String getStringField(String name) 350 public String getStringField(String name)
380 { 351 {
381 Field field = getField(name); 352 Field field = getField(name);
382 return field==null?null:field.getValue(); 353 return field==null ? null : field.getValue();
383 }
384
385 /* -------------------------------------------------------------- */
386 /**
387 * @return the value of a field, or null if not found. For multiple fields of the same name,
388 * only the first is returned.
389 * @param name the case-insensitive field name
390 */
391 public String getStringField(Buffer name)
392 {
393 Field field = getField(name);
394 return field==null?null:field.getValue();
395 } 354 }
396 355
397 /* -------------------------------------------------------------- */ 356 /* -------------------------------------------------------------- */
398 /** 357 /**
399 * Get multi headers 358 * Get multi headers
423 * 382 *
424 * @return Enumeration of the values 383 * @return Enumeration of the values
425 * @param name the case-insensitive field name 384 * @param name the case-insensitive field name
426 */ 385 */
427 public Enumeration<String> getValues(String name) 386 public Enumeration<String> getValues(String name)
428 {
429 final Field field = getField(name);
430 if (field == null)
431 {
432 List<String> empty=Collections.emptyList();
433 return Collections.enumeration(empty);
434 }
435
436 return new Enumeration<String>()
437 {
438 Field f = field;
439
440 public boolean hasMoreElements()
441 {
442 return f != null;
443 }
444
445 public String nextElement() throws NoSuchElementException
446 {
447 if (f == null) throw new NoSuchElementException();
448 Field n = f;
449 f = f._next;
450 return n.getValue();
451 }
452 };
453 }
454
455 /* -------------------------------------------------------------- */
456 /**
457 * Get multi headers
458 *
459 * @return Enumeration of the value Strings
460 * @param name the case-insensitive field name
461 */
462 public Enumeration<String> getValues(Buffer name)
463 { 387 {
464 final Field field = getField(name); 388 final Field field = getField(name);
465 if (field == null) 389 if (field == null)
466 { 390 {
467 List<String> empty=Collections.emptyList(); 391 List<String> empty=Collections.emptyList();
537 * @param name the name of the field 461 * @param name the name of the field
538 * @param value the value of the field. If null the field is cleared. 462 * @param value the value of the field. If null the field is cleared.
539 */ 463 */
540 public void put(String name, String value) 464 public void put(String name, String value)
541 { 465 {
542 if (value==null) 466 String nameLower = name.toLowerCase();
543 remove(name); 467 removeLower(nameLower);
544 else
545 {
546 Buffer n = HttpHeaders.CACHE.lookup(name);
547 put(n, value);
548 }
549 }
550
551 /* -------------------------------------------------------------- */
552 /**
553 * Set a field.
554 *
555 * @param name the name of the field
556 * @param value the value of the field. If null the field is cleared.
557 */
558 public void put(Buffer name, String value)
559 {
560 /*
561 Buffer n = HttpHeaders.CACHE.lookup(name);
562 Buffer v = convertValue(value);
563 put(n, v);
564 */
565 remove(name);
566 if (value == null) 468 if (value == null)
567 return; 469 return;
568 470
569 if (!(name instanceof BufferCache.CachedBuffer))
570 name = HttpHeaders.CACHE.lookup(name);
571 int valueOrdinal = HttpHeaderValues.CACHE.getOrdinal(value);
572
573 // new value;
574 Field field = new Field(name, value, valueOrdinal);
575 _fields.add(field);
576 _names.put(name, field);
577 }
578
579 /* -------------------------------------------------------------- */
580 /**
581 * Set a field.
582 *
583 * @param name the name of the field
584 * @param value the value of the field. If null the field is cleared.
585 */
586 public void put(Buffer name, Buffer value)
587 {
588 /*
589 remove(name);
590 if (value == null)
591 return;
592
593 if (!(name instanceof BufferCache.CachedBuffer))
594 name = HttpHeaders.CACHE.lookup(name);
595 if (!(value instanceof CachedBuffer))
596 value = HttpHeaderValues.CACHE.lookup(value).asImmutableBuffer();
597
598 // new value; 471 // new value;
599 Field field = new Field(name, value); 472 Field field = new Field(name, value);
600 _fields.add(field); 473 _fields.add(field);
601 _names.put(name, field); 474 _names.put(nameLower, field);
602 */
603 String s = value==null ? null : value.toString();
604 put(name,s);
605 } 475 }
606 476
607 /* -------------------------------------------------------------- */ 477 /* -------------------------------------------------------------- */
608 /** 478 /**
609 * Add to or set a field. If the field is allowed to have multiple values, add will add multiple 479 * Add to or set a field. If the field is allowed to have multiple values, add will add multiple
614 * @exception IllegalArgumentException If the name is a single valued field and already has a 484 * @exception IllegalArgumentException If the name is a single valued field and already has a
615 * value. 485 * value.
616 */ 486 */
617 public void add(String name, String value) throws IllegalArgumentException 487 public void add(String name, String value) throws IllegalArgumentException
618 { 488 {
619 if (value==null)
620 return;
621 Buffer n = HttpHeaders.CACHE.lookup(name);
622 add(n, value);
623 }
624
625 /* -------------------------------------------------------------- */
626 /**
627 * Add to or set a field. If the field is allowed to have multiple values, add will add multiple
628 * headers of the same name.
629 *
630 * @param name the name of the field
631 * @param value the value of the field.
632 * @exception IllegalArgumentException If the name is a single valued field and already has a
633 * value.
634 */
635 public void add(Buffer name, String value) throws IllegalArgumentException
636 {
637 if (value == null) throw new IllegalArgumentException("null value"); 489 if (value == null) throw new IllegalArgumentException("null value");
638 490
639 if (!(name instanceof CachedBuffer)) 491 String nameLower = name.toLowerCase();
640 name = HttpHeaders.CACHE.lookup(name); 492
641 name=name.asImmutableBuffer(); 493 Field field = _names.get(nameLower);
642 /*
643 if (!(value instanceof CachedBuffer) && HttpHeaderValues.hasKnownValues(HttpHeaders.CACHE.getOrdinal(name)))
644 value= HttpHeaderValues.CACHE.lookup(value);
645 value=value.asImmutableBuffer();
646 */
647 Field field = _names.get(name);
648 Field last = null; 494 Field last = null;
649 while (field != null) 495 while (field != null)
650 { 496 {
651 last = field; 497 last = field;
652 field = field._next; 498 field = field._next;
653 } 499 }
654 500
655 // create the field 501 // create the field
656 int valueOrdinal = HttpHeaderValues.CACHE.getOrdinal(value); 502 field = new Field(name, value);
657 field = new Field(name, value, valueOrdinal);
658 _fields.add(field); 503 _fields.add(field);
659 504
660 // look for chain to add too 505 // look for chain to add too
661 if (last != null) 506 if (last != null)
662 last._next = field; 507 last._next = field;
663 else 508 else
664 _names.put(name, field); 509 _names.put(nameLower, field);
665 } 510 }
666 511
667 /* ------------------------------------------------------------ */ 512 /* ------------------------------------------------------------ */
668 /** 513 /**
669 * Remove a field. 514 * Remove a field.
670 * 515 *
671 * @param name 516 * @param name
672 */ 517 */
673 public void remove(String name) 518 public void remove(String name)
674 { 519 {
675 remove(HttpHeaders.CACHE.lookup(name)); 520 removeLower(name.toLowerCase());
676 } 521 }
677 522
678 /* ------------------------------------------------------------ */ 523 private void removeLower(String nameLower) {
679 /** 524 Field field = _names.remove(nameLower);
680 * Remove a field.
681 *
682 * @param name
683 */
684 public void remove(Buffer name)
685 {
686 if (!(name instanceof BufferCache.CachedBuffer))
687 name = HttpHeaders.CACHE.lookup(name);
688 Field field = _names.remove(name);
689 while (field != null) 525 while (field != null)
690 { 526 {
691 _fields.remove(field); 527 _fields.remove(field);
692 field = field._next; 528 field = field._next;
693 } 529 }
700 * 536 *
701 * @param name the case-insensitive field name 537 * @param name the case-insensitive field name
702 * @exception NumberFormatException If bad long found 538 * @exception NumberFormatException If bad long found
703 */ 539 */
704 public long getLongField(String name) throws NumberFormatException 540 public long getLongField(String name) throws NumberFormatException
705 {
706 Field field = getField(name);
707 return field==null?-1L:field.getLongValue();
708 }
709
710 /* -------------------------------------------------------------- */
711 /**
712 * Get a header as an long value. Returns the value of an integer field or -1 if not found. The
713 * case of the field name is ignored.
714 *
715 * @param name the case-insensitive field name
716 * @exception NumberFormatException If bad long found
717 */
718 public long getLongField(Buffer name) throws NumberFormatException
719 { 541 {
720 Field field = getField(name); 542 Field field = getField(name);
721 return field==null?-1L:field.getLongValue(); 543 return field==null?-1L:field.getLongValue();
722 } 544 }
723 545
749 * Sets the value of an long field. 571 * Sets the value of an long field.
750 * 572 *
751 * @param name the field name 573 * @param name the field name
752 * @param value the field long value 574 * @param value the field long value
753 */ 575 */
754 public void putLongField(Buffer name, long value) 576 public void putLongField(String name, long value)
755 { 577 {
756 // Buffer v = BufferUtil.toBuffer(value);
757 String v = Long.toString(value); 578 String v = Long.toString(value);
758 put(name, v); 579 put(name, v);
759 } 580 }
760 581
761 /* -------------------------------------------------------------- */ 582 /* -------------------------------------------------------------- */
763 * Sets the value of an long field. 584 * Sets the value of an long field.
764 * 585 *
765 * @param name the field name 586 * @param name the field name
766 * @param value the field long value 587 * @param value the field long value
767 */ 588 */
768 public void putLongField(String name, long value)
769 {
770 Buffer n = HttpHeaders.CACHE.lookup(name);
771 // Buffer v = BufferUtil.toBuffer(value);
772 String v = Long.toString(value);
773 put(n, v);
774 }
775
776 /* -------------------------------------------------------------- */
777 /**
778 * Sets the value of an long field.
779 *
780 * @param name the field name
781 * @param value the field long value
782 */
783 public void addLongField(String name, long value) 589 public void addLongField(String name, long value)
784 { 590 {
785 Buffer n = HttpHeaders.CACHE.lookup(name);
786 // Buffer v = BufferUtil.toBuffer(value);
787 String v = Long.toString(value);
788 add(n, v);
789 }
790
791 /* -------------------------------------------------------------- */
792 /**
793 * Sets the value of an long field.
794 *
795 * @param name the field name
796 * @param value the field long value
797 */
798 public void addLongField(Buffer name, long value)
799 {
800 // Buffer v = BufferUtil.toBuffer(value);
801 String v = Long.toString(value); 591 String v = Long.toString(value);
802 add(name, v); 592 add(name, v);
803 } 593 }
804 594
805 /* -------------------------------------------------------------- */ 595 /* -------------------------------------------------------------- */
807 * Sets the value of a date field. 597 * Sets the value of a date field.
808 * 598 *
809 * @param name the field name 599 * @param name the field name
810 * @param date the field date value 600 * @param date the field date value
811 */ 601 */
812 public void putDateField(Buffer name, long date) 602 public void putDateField(String name, long date)
813 { 603 {
814 String d=formatDate(date); 604 String d = formatDate(date);
815 Buffer v = new ByteArrayBuffer(d); 605 put(name, d);
816 put(name, v);
817 } 606 }
818 607
819 /* -------------------------------------------------------------- */ 608 /* -------------------------------------------------------------- */
820 /** 609 /**
821 * Sets the value of a date field. 610 * Sets the value of a date field.
822 * 611 *
823 * @param name the field name 612 * @param name the field name
824 * @param date the field date value 613 * @param date the field date value
825 */ 614 */
826 public void putDateField(String name, long date)
827 {
828 Buffer n = HttpHeaders.CACHE.lookup(name);
829 putDateField(n,date);
830 }
831
832 /* -------------------------------------------------------------- */
833 /**
834 * Sets the value of a date field.
835 *
836 * @param name the field name
837 * @param date the field date value
838 */
839 public void addDateField(String name, long date) 615 public void addDateField(String name, long date)
840 { 616 {
841 String d=formatDate(date); 617 String d = formatDate(date);
842 Buffer n = HttpHeaders.CACHE.lookup(name); 618 add(name, d);
843 // Buffer v = new ByteArrayBuffer(d);
844 add(n, d);
845 } 619 }
846 620
847 /* ------------------------------------------------------------ */ 621 /* ------------------------------------------------------------ */
848 /** 622 /**
849 * Format a set cookie value 623 * Format a set cookie value
963 if (((!hasDomain && !val.contains("Domain")) || (hasDomain && val.contains("Domain="+domain))) && 737 if (((!hasDomain && !val.contains("Domain")) || (hasDomain && val.contains("Domain="+domain))) &&
964 ((!hasPath && !val.contains("Path")) || (hasPath && val.contains("Path="+path)))) 738 ((!hasPath && !val.contains("Path")) || (hasPath && val.contains("Path="+path))))
965 { 739 {
966 _fields.remove(field); 740 _fields.remove(field);
967 if (last==null) 741 if (last==null)
968 _names.put(HttpHeaders.SET_COOKIE_BUFFER,field._next); 742 _names.put(HttpHeaders.SET_COOKIE,field._next);
969 else 743 else
970 last._next=field._next; 744 last._next=field._next;
971 break; 745 break;
972 } 746 }
973 } 747 }
974 last=field; 748 last=field;
975 field=field._next; 749 field=field._next;
976 } 750 }
977 751
978 add(HttpHeaders.SET_COOKIE_BUFFER, name_value_params); 752 add(HttpHeaders.SET_COOKIE, name_value_params);
979 753
980 // Expire responses with set-cookie headers so they do not get cached. 754 // Expire responses with set-cookie headers so they do not get cached.
981 put(HttpHeaders.EXPIRES_BUFFER, __01Jan1970_BUFFER); 755 put(HttpHeaders.EXPIRES, __01Jan1970);
982 } 756 }
983 757
984 @Override 758 @Override
985 public String toString() 759 public String toString()
986 { 760 {
1157 } 931 }
1158 932
1159 933
1160 public static final class Field 934 public static final class Field
1161 { 935 {
1162 private final Buffer _name; 936 private final String _name;
1163 private final String _value; 937 private final String _value;
1164 private final int _valueOrdinal;
1165 private Field _next; 938 private Field _next;
1166 939
1167 private Field(Buffer name, String value, int valueOrdinal) 940 private Field(String name, String value)
1168 { 941 {
1169 _name = name; 942 _name = name;
1170 _value = value; 943 _value = value;
1171 _valueOrdinal = valueOrdinal;
1172 _next = null; 944 _next = null;
1173 } 945 }
1174 /* 946
1175 private Field(Buffer name, Buffer value)
1176 {
1177 this(name,value.toString(),HttpHeaderValues.CACHE.getOrdinal(value));
1178 }
1179 */
1180 public void putTo(Buffer buffer) throws IOException 947 public void putTo(Buffer buffer) throws IOException
1181 { 948 {
1182 int o=(_name instanceof CachedBuffer)?((CachedBuffer)_name).getOrdinal():-1; 949 byte[] nameBytes = StringUtil.getBytes(_name);
1183 if (o>=0) 950 if (getNameOrdinal() >=0 )
1184 buffer.put(_name); 951 buffer.put(nameBytes);
1185 else 952 else
1186 { 953 {
1187 int s=_name.getIndex(); 954 for( byte b : nameBytes ) {
1188 int e=_name.putIndex();
1189 while (s<e)
1190 {
1191 byte b=_name.peek(s++);
1192 switch(b) 955 switch(b)
1193 { 956 {
1194 case '\r': 957 case '\r':
1195 case '\n': 958 case '\n':
1196 case ':' : 959 case ':' :
1202 } 965 }
1203 966
1204 buffer.put((byte) ':'); 967 buffer.put((byte) ':');
1205 buffer.put((byte) ' '); 968 buffer.put((byte) ' ');
1206 969
1207 o = _valueOrdinal;
1208 byte[] valueBytes = StringUtil.getBytes(_value); 970 byte[] valueBytes = StringUtil.getBytes(_value);
1209 if (o>=0) 971 if (getValueOrdinal() >= 0)
1210 buffer.put(valueBytes); 972 buffer.put(valueBytes);
1211 else 973 else
1212 { 974 {
1213 for( byte b : valueBytes ) { 975 for( byte b : valueBytes ) {
1214 switch(b) 976 switch(b)
1240 return _value; 1002 return _value;
1241 } 1003 }
1242 1004
1243 public int getValueOrdinal() 1005 public int getValueOrdinal()
1244 { 1006 {
1245 return _valueOrdinal; 1007 return HttpHeaderValues.CACHE.getOrdinal(_value);
1246 } 1008 }
1247 1009
1248 public int getIntValue() 1010 public int getIntValue()
1249 { 1011 {
1250 return (int) getLongValue(); 1012 return (int) getLongValue();