1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.http2;
17
18 import io.netty.handler.codec.Headers;
19 import io.netty.util.AsciiString;
20 import io.netty.util.HashingStrategy;
21
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.Iterator;
25 import java.util.LinkedHashSet;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.NoSuchElementException;
29 import java.util.Set;
30
31 import static io.netty.handler.codec.CharSequenceValueConverter.*;
32 import static io.netty.handler.codec.http2.DefaultHttp2Headers.*;
33 import static io.netty.util.AsciiString.*;
34 import static io.netty.util.internal.EmptyArrays.*;
35 import static io.netty.util.internal.ObjectUtil.checkNotNullArrayParam;
36
37
38
39
40
41
42
43
44
45
46 public final class ReadOnlyHttp2Headers implements Http2Headers {
47 private static final byte PSEUDO_HEADER_TOKEN = (byte) ':';
48 private final AsciiString[] pseudoHeaders;
49 private final AsciiString[] otherHeaders;
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 public static ReadOnlyHttp2Headers trailers(boolean validateHeaders, AsciiString... otherHeaders) {
66 return new ReadOnlyHttp2Headers(validateHeaders, EMPTY_ASCII_STRINGS, otherHeaders);
67 }
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 public static ReadOnlyHttp2Headers clientHeaders(boolean validateHeaders,
85 AsciiString method, AsciiString path,
86 AsciiString scheme, AsciiString authority,
87 AsciiString... otherHeaders) {
88 return new ReadOnlyHttp2Headers(validateHeaders,
89 new AsciiString[] {
90 PseudoHeaderName.METHOD.value(), method, PseudoHeaderName.PATH.value(), path,
91 PseudoHeaderName.SCHEME.value(), scheme, PseudoHeaderName.AUTHORITY.value(), authority
92 },
93 otherHeaders);
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107
108 public static ReadOnlyHttp2Headers serverHeaders(boolean validateHeaders,
109 AsciiString status,
110 AsciiString... otherHeaders) {
111 return new ReadOnlyHttp2Headers(validateHeaders,
112 new AsciiString[] { PseudoHeaderName.STATUS.value(), status },
113 otherHeaders);
114 }
115
116 private ReadOnlyHttp2Headers(boolean validateHeaders, AsciiString[] pseudoHeaders, AsciiString... otherHeaders) {
117 assert (pseudoHeaders.length & 1) == 0;
118 if ((otherHeaders.length & 1) != 0) {
119 throw newInvalidArraySizeException();
120 }
121 if (validateHeaders) {
122 validateHeaders(pseudoHeaders, otherHeaders);
123 }
124 this.pseudoHeaders = pseudoHeaders;
125 this.otherHeaders = otherHeaders;
126 }
127
128 private static IllegalArgumentException newInvalidArraySizeException() {
129 return new IllegalArgumentException("pseudoHeaders and otherHeaders must be arrays of [name, value] pairs");
130 }
131
132 private static void validateHeaders(AsciiString[] pseudoHeaders, AsciiString... otherHeaders) {
133
134 for (int i = 1; i < pseudoHeaders.length; i += 2) {
135
136 AsciiString value = pseudoHeaders[i];
137 checkNotNullArrayParam(value, i, "pseudoHeaders");
138 defaultHttp2ValueValidator().validate(value);
139 }
140
141 boolean seenNonPseudoHeader = false;
142 final int otherHeadersEnd = otherHeaders.length - 1;
143 for (int i = 0; i < otherHeadersEnd; i += 2) {
144 AsciiString name = otherHeaders[i];
145 defaultHtt2NameValidator().validateName(name);
146 if (!seenNonPseudoHeader && !name.isEmpty() && name.byteAt(0) != PSEUDO_HEADER_TOKEN) {
147 seenNonPseudoHeader = true;
148 } else if (seenNonPseudoHeader && !name.isEmpty() && name.byteAt(0) == PSEUDO_HEADER_TOKEN) {
149 throw new IllegalArgumentException(
150 "otherHeaders name at index " + i + " is a pseudo header that appears after non-pseudo headers.");
151 }
152 AsciiString value = otherHeaders[i + 1];
153 checkNotNullArrayParam(value, i + 1, "otherHeaders");
154 defaultHttp2ValueValidator().validate(value);
155 }
156 }
157
158 private AsciiString get0(CharSequence name) {
159 final int nameHash = AsciiString.hashCode(name);
160
161 final int pseudoHeadersEnd = pseudoHeaders.length - 1;
162 for (int i = 0; i < pseudoHeadersEnd; i += 2) {
163 AsciiString roName = pseudoHeaders[i];
164 if (roName.hashCode() == nameHash && roName.contentEqualsIgnoreCase(name)) {
165 return pseudoHeaders[i + 1];
166 }
167 }
168
169 final int otherHeadersEnd = otherHeaders.length - 1;
170 for (int i = 0; i < otherHeadersEnd; i += 2) {
171 AsciiString roName = otherHeaders[i];
172 if (roName.hashCode() == nameHash && roName.contentEqualsIgnoreCase(name)) {
173 return otherHeaders[i + 1];
174 }
175 }
176 return null;
177 }
178
179 @Override
180 public CharSequence get(CharSequence name) {
181 return get0(name);
182 }
183
184 @Override
185 public CharSequence get(CharSequence name, CharSequence defaultValue) {
186 CharSequence value = get(name);
187 return value != null ? value : defaultValue;
188 }
189
190 @Override
191 public CharSequence getAndRemove(CharSequence name) {
192 throw new UnsupportedOperationException("read only");
193 }
194
195 @Override
196 public CharSequence getAndRemove(CharSequence name, CharSequence defaultValue) {
197 throw new UnsupportedOperationException("read only");
198 }
199
200 @Override
201 public List<CharSequence> getAll(CharSequence name) {
202 final int nameHash = AsciiString.hashCode(name);
203 List<CharSequence> values = new ArrayList<CharSequence>();
204
205 final int pseudoHeadersEnd = pseudoHeaders.length - 1;
206 for (int i = 0; i < pseudoHeadersEnd; i += 2) {
207 AsciiString roName = pseudoHeaders[i];
208 if (roName.hashCode() == nameHash && roName.contentEqualsIgnoreCase(name)) {
209 values.add(pseudoHeaders[i + 1]);
210 }
211 }
212
213 final int otherHeadersEnd = otherHeaders.length - 1;
214 for (int i = 0; i < otherHeadersEnd; i += 2) {
215 AsciiString roName = otherHeaders[i];
216 if (roName.hashCode() == nameHash && roName.contentEqualsIgnoreCase(name)) {
217 values.add(otherHeaders[i + 1]);
218 }
219 }
220
221 return values;
222 }
223
224 @Override
225 public List<CharSequence> getAllAndRemove(CharSequence name) {
226 throw new UnsupportedOperationException("read only");
227 }
228
229 @Override
230 public Boolean getBoolean(CharSequence name) {
231 AsciiString value = get0(name);
232 return value != null ? INSTANCE.convertToBoolean(value) : null;
233 }
234
235 @Override
236 public boolean getBoolean(CharSequence name, boolean defaultValue) {
237 Boolean value = getBoolean(name);
238 return value != null ? value : defaultValue;
239 }
240
241 @Override
242 public Byte getByte(CharSequence name) {
243 AsciiString value = get0(name);
244 if (value != null) {
245 try {
246 return INSTANCE.convertToByte(value);
247 } catch (RuntimeException ignore) {
248 return null;
249 }
250 }
251 return null;
252 }
253
254 @Override
255 public byte getByte(CharSequence name, byte defaultValue) {
256 Byte value = getByte(name);
257 return value != null ? value : defaultValue;
258 }
259
260 @Override
261 public Character getChar(CharSequence name) {
262 AsciiString value = get0(name);
263 if (value != null) {
264 try {
265 return INSTANCE.convertToChar(value);
266 } catch (RuntimeException ignore) {
267 return null;
268 }
269 }
270 return null;
271 }
272
273 @Override
274 public char getChar(CharSequence name, char defaultValue) {
275 Character value = getChar(name);
276 return value != null ? value : defaultValue;
277 }
278
279 @Override
280 public Short getShort(CharSequence name) {
281 AsciiString value = get0(name);
282 if (value != null) {
283 try {
284 return INSTANCE.convertToShort(value);
285 } catch (RuntimeException ignore) {
286 return null;
287 }
288 }
289 return null;
290 }
291
292 @Override
293 public short getShort(CharSequence name, short defaultValue) {
294 Short value = getShort(name);
295 return value != null ? value : defaultValue;
296 }
297
298 @Override
299 public Integer getInt(CharSequence name) {
300 AsciiString value = get0(name);
301 if (value != null) {
302 try {
303 return INSTANCE.convertToInt(value);
304 } catch (RuntimeException ignore) {
305 return null;
306 }
307 }
308 return null;
309 }
310
311 @Override
312 public int getInt(CharSequence name, int defaultValue) {
313 Integer value = getInt(name);
314 return value != null ? value : defaultValue;
315 }
316
317 @Override
318 public Long getLong(CharSequence name) {
319 AsciiString value = get0(name);
320 if (value != null) {
321 try {
322 return INSTANCE.convertToLong(value);
323 } catch (RuntimeException ignore) {
324 return null;
325 }
326 }
327 return null;
328 }
329
330 @Override
331 public long getLong(CharSequence name, long defaultValue) {
332 Long value = getLong(name);
333 return value != null ? value : defaultValue;
334 }
335
336 @Override
337 public Float getFloat(CharSequence name) {
338 AsciiString value = get0(name);
339 if (value != null) {
340 try {
341 return INSTANCE.convertToFloat(value);
342 } catch (RuntimeException ignore) {
343 return null;
344 }
345 }
346 return null;
347 }
348
349 @Override
350 public float getFloat(CharSequence name, float defaultValue) {
351 Float value = getFloat(name);
352 return value != null ? value : defaultValue;
353 }
354
355 @Override
356 public Double getDouble(CharSequence name) {
357 AsciiString value = get0(name);
358 if (value != null) {
359 try {
360 return INSTANCE.convertToDouble(value);
361 } catch (RuntimeException ignore) {
362 return null;
363 }
364 }
365 return null;
366 }
367
368 @Override
369 public double getDouble(CharSequence name, double defaultValue) {
370 Double value = getDouble(name);
371 return value != null ? value : defaultValue;
372 }
373
374 @Override
375 public Long getTimeMillis(CharSequence name) {
376 AsciiString value = get0(name);
377 return value != null ? INSTANCE.convertToTimeMillis(value) : null;
378 }
379
380 @Override
381 public long getTimeMillis(CharSequence name, long defaultValue) {
382 Long value = getTimeMillis(name);
383 return value != null ? value : defaultValue;
384 }
385
386 @Override
387 public Boolean getBooleanAndRemove(CharSequence name) {
388 throw new UnsupportedOperationException("read only");
389 }
390
391 @Override
392 public boolean getBooleanAndRemove(CharSequence name, boolean defaultValue) {
393 throw new UnsupportedOperationException("read only");
394 }
395
396 @Override
397 public Byte getByteAndRemove(CharSequence name) {
398 throw new UnsupportedOperationException("read only");
399 }
400
401 @Override
402 public byte getByteAndRemove(CharSequence name, byte defaultValue) {
403 throw new UnsupportedOperationException("read only");
404 }
405
406 @Override
407 public Character getCharAndRemove(CharSequence name) {
408 throw new UnsupportedOperationException("read only");
409 }
410
411 @Override
412 public char getCharAndRemove(CharSequence name, char defaultValue) {
413 throw new UnsupportedOperationException("read only");
414 }
415
416 @Override
417 public Short getShortAndRemove(CharSequence name) {
418 throw new UnsupportedOperationException("read only");
419 }
420
421 @Override
422 public short getShortAndRemove(CharSequence name, short defaultValue) {
423 throw new UnsupportedOperationException("read only");
424 }
425
426 @Override
427 public Integer getIntAndRemove(CharSequence name) {
428 throw new UnsupportedOperationException("read only");
429 }
430
431 @Override
432 public int getIntAndRemove(CharSequence name, int defaultValue) {
433 throw new UnsupportedOperationException("read only");
434 }
435
436 @Override
437 public Long getLongAndRemove(CharSequence name) {
438 throw new UnsupportedOperationException("read only");
439 }
440
441 @Override
442 public long getLongAndRemove(CharSequence name, long defaultValue) {
443 throw new UnsupportedOperationException("read only");
444 }
445
446 @Override
447 public Float getFloatAndRemove(CharSequence name) {
448 throw new UnsupportedOperationException("read only");
449 }
450
451 @Override
452 public float getFloatAndRemove(CharSequence name, float defaultValue) {
453 throw new UnsupportedOperationException("read only");
454 }
455
456 @Override
457 public Double getDoubleAndRemove(CharSequence name) {
458 throw new UnsupportedOperationException("read only");
459 }
460
461 @Override
462 public double getDoubleAndRemove(CharSequence name, double defaultValue) {
463 throw new UnsupportedOperationException("read only");
464 }
465
466 @Override
467 public Long getTimeMillisAndRemove(CharSequence name) {
468 throw new UnsupportedOperationException("read only");
469 }
470
471 @Override
472 public long getTimeMillisAndRemove(CharSequence name, long defaultValue) {
473 throw new UnsupportedOperationException("read only");
474 }
475
476 @Override
477 public boolean contains(CharSequence name) {
478 return get(name) != null;
479 }
480
481 @Override
482 public boolean contains(CharSequence name, CharSequence value) {
483 return contains(name, value, false);
484 }
485
486 @Override
487 public boolean containsObject(CharSequence name, Object value) {
488 if (value instanceof CharSequence) {
489 return contains(name, (CharSequence) value);
490 }
491 return contains(name, value.toString());
492 }
493
494 @Override
495 public boolean containsBoolean(CharSequence name, boolean value) {
496 return contains(name, String.valueOf(value));
497 }
498
499 @Override
500 public boolean containsByte(CharSequence name, byte value) {
501 return contains(name, String.valueOf(value));
502 }
503
504 @Override
505 public boolean containsChar(CharSequence name, char value) {
506 return contains(name, String.valueOf(value));
507 }
508
509 @Override
510 public boolean containsShort(CharSequence name, short value) {
511 return contains(name, String.valueOf(value));
512 }
513
514 @Override
515 public boolean containsInt(CharSequence name, int value) {
516 return contains(name, String.valueOf(value));
517 }
518
519 @Override
520 public boolean containsLong(CharSequence name, long value) {
521 return contains(name, String.valueOf(value));
522 }
523
524 @Override
525 public boolean containsFloat(CharSequence name, float value) {
526 return false;
527 }
528
529 @Override
530 public boolean containsDouble(CharSequence name, double value) {
531 return contains(name, String.valueOf(value));
532 }
533
534 @Override
535 public boolean containsTimeMillis(CharSequence name, long value) {
536 return contains(name, String.valueOf(value));
537 }
538
539 @Override
540 public int size() {
541 return pseudoHeaders.length + otherHeaders.length >>> 1;
542 }
543
544 @Override
545 public boolean isEmpty() {
546 return pseudoHeaders.length == 0 && otherHeaders.length == 0;
547 }
548
549 @Override
550 public Set<CharSequence> names() {
551 if (isEmpty()) {
552 return Collections.emptySet();
553 }
554 Set<CharSequence> names = new LinkedHashSet<CharSequence>(size());
555 final int pseudoHeadersEnd = pseudoHeaders.length - 1;
556 for (int i = 0; i < pseudoHeadersEnd; i += 2) {
557 names.add(pseudoHeaders[i]);
558 }
559
560 final int otherHeadersEnd = otherHeaders.length - 1;
561 for (int i = 0; i < otherHeadersEnd; i += 2) {
562 names.add(otherHeaders[i]);
563 }
564 return names;
565 }
566
567 @Override
568 public Http2Headers add(CharSequence name, CharSequence value) {
569 throw new UnsupportedOperationException("read only");
570 }
571
572 @Override
573 public Http2Headers add(CharSequence name, Iterable<? extends CharSequence> values) {
574 throw new UnsupportedOperationException("read only");
575 }
576
577 @Override
578 public Http2Headers add(CharSequence name, CharSequence... values) {
579 throw new UnsupportedOperationException("read only");
580 }
581
582 @Override
583 public Http2Headers addObject(CharSequence name, Object value) {
584 throw new UnsupportedOperationException("read only");
585 }
586
587 @Override
588 public Http2Headers addObject(CharSequence name, Iterable<?> values) {
589 throw new UnsupportedOperationException("read only");
590 }
591
592 @Override
593 public Http2Headers addObject(CharSequence name, Object... values) {
594 throw new UnsupportedOperationException("read only");
595 }
596
597 @Override
598 public Http2Headers addBoolean(CharSequence name, boolean value) {
599 throw new UnsupportedOperationException("read only");
600 }
601
602 @Override
603 public Http2Headers addByte(CharSequence name, byte value) {
604 throw new UnsupportedOperationException("read only");
605 }
606
607 @Override
608 public Http2Headers addChar(CharSequence name, char value) {
609 throw new UnsupportedOperationException("read only");
610 }
611
612 @Override
613 public Http2Headers addShort(CharSequence name, short value) {
614 throw new UnsupportedOperationException("read only");
615 }
616
617 @Override
618 public Http2Headers addInt(CharSequence name, int value) {
619 throw new UnsupportedOperationException("read only");
620 }
621
622 @Override
623 public Http2Headers addLong(CharSequence name, long value) {
624 throw new UnsupportedOperationException("read only");
625 }
626
627 @Override
628 public Http2Headers addFloat(CharSequence name, float value) {
629 throw new UnsupportedOperationException("read only");
630 }
631
632 @Override
633 public Http2Headers addDouble(CharSequence name, double value) {
634 throw new UnsupportedOperationException("read only");
635 }
636
637 @Override
638 public Http2Headers addTimeMillis(CharSequence name, long value) {
639 throw new UnsupportedOperationException("read only");
640 }
641
642 @Override
643 public Http2Headers add(Headers<? extends CharSequence, ? extends CharSequence, ?> headers) {
644 throw new UnsupportedOperationException("read only");
645 }
646
647 @Override
648 public Http2Headers set(CharSequence name, CharSequence value) {
649 throw new UnsupportedOperationException("read only");
650 }
651
652 @Override
653 public Http2Headers set(CharSequence name, Iterable<? extends CharSequence> values) {
654 throw new UnsupportedOperationException("read only");
655 }
656
657 @Override
658 public Http2Headers set(CharSequence name, CharSequence... values) {
659 throw new UnsupportedOperationException("read only");
660 }
661
662 @Override
663 public Http2Headers setObject(CharSequence name, Object value) {
664 throw new UnsupportedOperationException("read only");
665 }
666
667 @Override
668 public Http2Headers setObject(CharSequence name, Iterable<?> values) {
669 throw new UnsupportedOperationException("read only");
670 }
671
672 @Override
673 public Http2Headers setObject(CharSequence name, Object... values) {
674 throw new UnsupportedOperationException("read only");
675 }
676
677 @Override
678 public Http2Headers setBoolean(CharSequence name, boolean value) {
679 throw new UnsupportedOperationException("read only");
680 }
681
682 @Override
683 public Http2Headers setByte(CharSequence name, byte value) {
684 throw new UnsupportedOperationException("read only");
685 }
686
687 @Override
688 public Http2Headers setChar(CharSequence name, char value) {
689 throw new UnsupportedOperationException("read only");
690 }
691
692 @Override
693 public Http2Headers setShort(CharSequence name, short value) {
694 throw new UnsupportedOperationException("read only");
695 }
696
697 @Override
698 public Http2Headers setInt(CharSequence name, int value) {
699 throw new UnsupportedOperationException("read only");
700 }
701
702 @Override
703 public Http2Headers setLong(CharSequence name, long value) {
704 throw new UnsupportedOperationException("read only");
705 }
706
707 @Override
708 public Http2Headers setFloat(CharSequence name, float value) {
709 throw new UnsupportedOperationException("read only");
710 }
711
712 @Override
713 public Http2Headers setDouble(CharSequence name, double value) {
714 throw new UnsupportedOperationException("read only");
715 }
716
717 @Override
718 public Http2Headers setTimeMillis(CharSequence name, long value) {
719 throw new UnsupportedOperationException("read only");
720 }
721
722 @Override
723 public Http2Headers set(Headers<? extends CharSequence, ? extends CharSequence, ?> headers) {
724 throw new UnsupportedOperationException("read only");
725 }
726
727 @Override
728 public Http2Headers setAll(Headers<? extends CharSequence, ? extends CharSequence, ?> headers) {
729 throw new UnsupportedOperationException("read only");
730 }
731
732 @Override
733 public boolean remove(CharSequence name) {
734 throw new UnsupportedOperationException("read only");
735 }
736
737 @Override
738 public Http2Headers clear() {
739 throw new UnsupportedOperationException("read only");
740 }
741
742 @Override
743 public Iterator<Map.Entry<CharSequence, CharSequence>> iterator() {
744 return new ReadOnlyIterator();
745 }
746
747 @Override
748 public Iterator<CharSequence> valueIterator(CharSequence name) {
749 return new ReadOnlyValueIterator(name);
750 }
751
752 @Override
753 public Http2Headers method(CharSequence value) {
754 throw new UnsupportedOperationException("read only");
755 }
756
757 @Override
758 public Http2Headers scheme(CharSequence value) {
759 throw new UnsupportedOperationException("read only");
760 }
761
762 @Override
763 public Http2Headers authority(CharSequence value) {
764 throw new UnsupportedOperationException("read only");
765 }
766
767 @Override
768 public Http2Headers path(CharSequence value) {
769 throw new UnsupportedOperationException("read only");
770 }
771
772 @Override
773 public Http2Headers status(CharSequence value) {
774 throw new UnsupportedOperationException("read only");
775 }
776
777 @Override
778 public CharSequence method() {
779 return get(PseudoHeaderName.METHOD.value());
780 }
781
782 @Override
783 public CharSequence scheme() {
784 return get(PseudoHeaderName.SCHEME.value());
785 }
786
787 @Override
788 public CharSequence authority() {
789 return get(PseudoHeaderName.AUTHORITY.value());
790 }
791
792 @Override
793 public CharSequence path() {
794 return get(PseudoHeaderName.PATH.value());
795 }
796
797 @Override
798 public CharSequence status() {
799 return get(PseudoHeaderName.STATUS.value());
800 }
801
802 @Override
803 public boolean contains(CharSequence name, CharSequence value, boolean caseInsensitive) {
804 final int nameHash = AsciiString.hashCode(name);
805 final HashingStrategy<CharSequence> strategy =
806 caseInsensitive ? CASE_INSENSITIVE_HASHER : CASE_SENSITIVE_HASHER;
807 final int valueHash = strategy.hashCode(value);
808
809 return contains(name, nameHash, value, valueHash, strategy, otherHeaders)
810 || contains(name, nameHash, value, valueHash, strategy, pseudoHeaders);
811 }
812
813 private static boolean contains(CharSequence name, int nameHash, CharSequence value, int valueHash,
814 HashingStrategy<CharSequence> hashingStrategy, AsciiString[] headers) {
815 final int headersEnd = headers.length - 1;
816 for (int i = 0; i < headersEnd; i += 2) {
817 AsciiString roName = headers[i];
818 AsciiString roValue = headers[i + 1];
819 if (roName.hashCode() == nameHash && roValue.hashCode() == valueHash &&
820 roName.contentEqualsIgnoreCase(name) && hashingStrategy.equals(roValue, value)) {
821 return true;
822 }
823 }
824 return false;
825 }
826
827 @Override
828 public String toString() {
829 StringBuilder builder = new StringBuilder(getClass().getSimpleName()).append('[');
830 String separator = "";
831 for (Map.Entry<CharSequence, CharSequence> entry : this) {
832 builder.append(separator);
833 builder.append(entry.getKey()).append(": ").append(entry.getValue());
834 separator = ", ";
835 }
836 return builder.append(']').toString();
837 }
838
839 private final class ReadOnlyValueIterator implements Iterator<CharSequence> {
840 private int i;
841 private final int nameHash;
842 private final CharSequence name;
843 private AsciiString[] current = pseudoHeaders.length != 0 ? pseudoHeaders : otherHeaders;
844 private AsciiString next;
845
846 ReadOnlyValueIterator(CharSequence name) {
847 nameHash = AsciiString.hashCode(name);
848 this.name = name;
849 calculateNext();
850 }
851
852 @Override
853 public boolean hasNext() {
854 return next != null;
855 }
856
857 @Override
858 public CharSequence next() {
859 if (!hasNext()) {
860 throw new NoSuchElementException();
861 }
862 CharSequence current = next;
863 calculateNext();
864 return current;
865 }
866
867 @Override
868 public void remove() {
869 throw new UnsupportedOperationException("read only");
870 }
871
872 private void calculateNext() {
873 for (; i < current.length; i += 2) {
874 AsciiString roName = current[i];
875 if (roName.hashCode() == nameHash && roName.contentEqualsIgnoreCase(name)) {
876 if (i + 1 < current.length) {
877 next = current[i + 1];
878 i += 2;
879 }
880 return;
881 }
882 }
883 if (current == pseudoHeaders) {
884 i = 0;
885 current = otherHeaders;
886 calculateNext();
887 } else {
888 next = null;
889 }
890 }
891 }
892
893 private final class ReadOnlyIterator implements Map.Entry<CharSequence, CharSequence>,
894 Iterator<Map.Entry<CharSequence, CharSequence>> {
895 private int i;
896 private AsciiString[] current = pseudoHeaders.length != 0 ? pseudoHeaders : otherHeaders;
897 private AsciiString key;
898 private AsciiString value;
899
900 @Override
901 public boolean hasNext() {
902 return i != current.length;
903 }
904
905 @Override
906 public Map.Entry<CharSequence, CharSequence> next() {
907 if (!hasNext()) {
908 throw new NoSuchElementException();
909 }
910 key = current[i];
911 value = current[i + 1];
912 i += 2;
913 if (i == current.length && current == pseudoHeaders) {
914 current = otherHeaders;
915 i = 0;
916 }
917 return this;
918 }
919
920 @Override
921 public CharSequence getKey() {
922 return key;
923 }
924
925 @Override
926 public CharSequence getValue() {
927 return value;
928 }
929
930 @Override
931 public CharSequence setValue(CharSequence value) {
932 throw new UnsupportedOperationException("read only");
933 }
934
935 @Override
936 public void remove() {
937 throw new UnsupportedOperationException("read only");
938 }
939
940 @Override
941 public String toString() {
942 return key.toString() + '=' + value.toString();
943 }
944 }
945 }