1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.handler.codec.http2;
17
18 import java.util.LinkedList;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22 import java.util.TreeSet;
23
24
25
26
27
28
29
30
31
32
33
34
35
36 public class HttpHeaders {
37
38
39
40
41
42 public static final class Names {
43
44
45
46 public static final String ACCEPT = "Accept";
47
48
49
50 public static final String ACCEPT_CHARSET = "Accept-Charset";
51
52
53
54 public static final String ACCEPT_ENCODING = "Accept-Encoding";
55
56
57
58 public static final String ACCEPT_LANGUAGE = "Accept-Language";
59
60
61
62 public static final String ACCEPT_RANGES = "Accept-Ranges";
63
64
65
66 public static final String ACCEPT_PATCH = "Accept-Patch";
67
68
69
70 public static final String AGE = "Age";
71
72
73
74 public static final String ALLOW = "Allow";
75
76
77
78 public static final String AUTHORIZATION = "Authorization";
79
80
81
82 public static final String CACHE_CONTROL = "Cache-Control";
83
84
85
86 public static final String CONNECTION = "Connection";
87
88
89
90 public static final String CONTENT_BASE = "Content-Base";
91
92
93
94 public static final String CONTENT_ENCODING = "Content-Encoding";
95
96
97
98 public static final String CONTENT_LANGUAGE = "Content-Language";
99
100
101
102 public static final String CONTENT_LENGTH = "Content-Length";
103
104
105
106 public static final String CONTENT_LOCATION = "Content-Location";
107
108
109
110 public static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
111
112
113
114 public static final String CONTENT_MD5 = "Content-MD5";
115
116
117
118 public static final String CONTENT_RANGE = "Content-Range";
119
120
121
122 public static final String CONTENT_TYPE = "Content-Type";
123
124
125
126 public static final String COOKIE = "Cookie";
127
128
129
130 public static final String DATE = "Date";
131
132
133
134 public static final String ETAG = "ETag";
135
136
137
138 public static final String EXPECT = "Expect";
139
140
141
142 public static final String EXPIRES = "Expires";
143
144
145
146 public static final String FROM = "From";
147
148
149
150 public static final String HOST = "Host";
151
152
153
154 public static final String IF_MATCH = "If-Match";
155
156
157
158 public static final String IF_MODIFIED_SINCE = "If-Modified-Since";
159
160
161
162 public static final String IF_NONE_MATCH = "If-None-Match";
163
164
165
166 public static final String IF_RANGE = "If-Range";
167
168
169
170 public static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since";
171
172
173
174 public static final String LAST_MODIFIED = "Last-Modified";
175
176
177
178 public static final String LOCATION = "Location";
179
180
181
182 public static final String MAX_FORWARDS = "Max-Forwards";
183
184
185
186 public static final String ORIGIN = "Origin";
187
188
189
190 public static final String PRAGMA = "Pragma";
191
192
193
194 public static final String PROXY_AUTHENTICATE = "Proxy-Authenticate";
195
196
197
198 public static final String PROXY_AUTHORIZATION = "Proxy-Authorization";
199
200
201
202 public static final String RANGE = "Range";
203
204
205
206 public static final String REFERER = "Referer";
207
208
209
210 public static final String RETRY_AFTER = "Retry-After";
211
212
213
214 public static final String SEC_WEBSOCKET_KEY1 = "Sec-WebSocket-Key1";
215
216
217
218 public static final String SEC_WEBSOCKET_KEY2 = "Sec-WebSocket-Key2";
219
220
221
222 public static final String SEC_WEBSOCKET_LOCATION = "Sec-WebSocket-Location";
223
224
225
226 public static final String SEC_WEBSOCKET_ORIGIN = "Sec-WebSocket-Origin";
227
228
229
230 public static final String SEC_WEBSOCKET_PROTOCOL = "Sec-WebSocket-Protocol";
231
232
233
234 public static final String SEC_WEBSOCKET_VERSION = "Sec-WebSocket-Version";
235
236
237
238 public static final String SEC_WEBSOCKET_KEY = "Sec-WebSocket-Key";
239
240
241
242 public static final String SEC_WEBSOCKET_ACCEPT = "Sec-WebSocket-Accept";
243
244
245
246 public static final String SERVER = "Server";
247
248
249
250 public static final String SET_COOKIE = "Set-Cookie";
251
252
253
254 public static final String SET_COOKIE2 = "Set-Cookie2";
255
256
257
258 public static final String TE = "TE";
259
260
261
262 public static final String TRAILER = "Trailer";
263
264
265
266 public static final String TRANSFER_ENCODING = "Transfer-Encoding";
267
268
269
270 public static final String UPGRADE = "Upgrade";
271
272
273
274 public static final String USER_AGENT = "User-Agent";
275
276
277
278 public static final String VARY = "Vary";
279
280
281
282 public static final String VIA = "Via";
283
284
285
286 public static final String WARNING = "Warning";
287
288
289
290 public static final String WEBSOCKET_LOCATION = "WebSocket-Location";
291
292
293
294 public static final String WEBSOCKET_ORIGIN = "WebSocket-Origin";
295
296
297
298 public static final String WEBSOCKET_PROTOCOL = "WebSocket-Protocol";
299
300
301
302 public static final String WWW_AUTHENTICATE = "WWW-Authenticate";
303
304 private Names() {
305 super();
306 }
307 }
308
309
310
311
312
313
314
315
316
317
318 public static final class Values {
319
320
321
322
323 public static final String APPLICATION_X_WWW_FORM_URLENCODED =
324 "application/x-www-form-urlencoded";
325
326
327
328 static final String BOUNDARY = "boundary";
329
330
331
332 static final String MULTIPART_FORM_DATA = "multipart/form-data";
333
334
335
336
337 public static final String BASE64 = "base64";
338
339
340
341 public static final String BINARY = "binary";
342
343
344
345 public static final String BYTES = "bytes";
346
347
348
349 public static final String CHARSET = "charset";
350
351
352
353 public static final String CHUNKED = "chunked";
354
355
356
357 public static final String CLOSE = "close";
358
359
360
361 public static final String COMPRESS = "compress";
362
363
364
365 public static final String CONTINUE = "100-continue";
366
367
368
369 public static final String DEFLATE = "deflate";
370
371
372
373 public static final String GZIP = "gzip";
374
375
376
377 public static final String IDENTITY = "identity";
378
379
380
381 public static final String KEEP_ALIVE = "keep-alive";
382
383
384
385 public static final String MAX_AGE = "max-age";
386
387
388
389 public static final String MAX_STALE = "max-stale";
390
391
392
393 public static final String MIN_FRESH = "min-fresh";
394
395
396
397 public static final String MUST_REVALIDATE = "must-revalidate";
398
399
400
401 public static final String NO_CACHE = "no-cache";
402
403
404
405 public static final String NO_STORE = "no-store";
406
407
408
409 public static final String NO_TRANSFORM = "no-transform";
410
411
412
413 public static final String NONE = "none";
414
415
416
417 public static final String ONLY_IF_CACHED = "only-if-cached";
418
419
420
421 public static final String PRIVATE = "private";
422
423
424
425 public static final String PROXY_REVALIDATE = "proxy-revalidate";
426
427
428
429 public static final String PUBLIC = "public";
430
431
432
433 public static final String QUOTED_PRINTABLE = "quoted-printable";
434
435
436
437 public static final String S_MAXAGE = "s-maxage";
438
439
440
441 public static final String TRAILERS = "trailers";
442
443
444
445 public static final String UPGRADE = "Upgrade";
446
447
448
449 public static final String WEBSOCKET = "WebSocket";
450
451 private Values() {
452 super();
453 }
454 }
455
456
457
458
459
460
461
462
463 public static boolean isKeepAlive(HttpMessage message) {
464 String connection = message.getHeader(Names.CONNECTION);
465 if (Values.CLOSE.equalsIgnoreCase(connection)) {
466 return false;
467 }
468
469 if (message.getProtocolVersion().isKeepAliveDefault()) {
470 return !Values.CLOSE.equalsIgnoreCase(connection);
471 } else {
472 return Values.KEEP_ALIVE.equalsIgnoreCase(connection);
473 }
474 }
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495 public static void setKeepAlive(HttpMessage message, boolean keepAlive) {
496 if (message.getProtocolVersion().isKeepAliveDefault()) {
497 if (keepAlive) {
498 message.removeHeader(Names.CONNECTION);
499 } else {
500 message.setHeader(Names.CONNECTION, Values.CLOSE);
501 }
502 } else {
503 if (keepAlive) {
504 message.setHeader(Names.CONNECTION, Values.KEEP_ALIVE);
505 } else {
506 message.removeHeader(Names.CONNECTION);
507 }
508 }
509 }
510
511
512
513
514
515
516
517
518 public static String getHeader(HttpMessage message, String name) {
519 return message.getHeader(name);
520 }
521
522
523
524
525
526
527
528
529
530 public static String getHeader(HttpMessage message, String name, String defaultValue) {
531 String value = message.getHeader(name);
532 if (value == null) {
533 return defaultValue;
534 }
535 return value;
536 }
537
538
539
540
541
542 public static void setHeader(HttpMessage message, String name, Object value) {
543 message.setHeader(name, value);
544 }
545
546
547
548
549
550 public static void setHeader(HttpMessage message, String name, Iterable<?> values) {
551 message.setHeader(name, values);
552 }
553
554
555
556
557 public static void addHeader(HttpMessage message, String name, Object value) {
558 message.addHeader(name, value);
559 }
560
561
562
563
564
565
566
567
568
569
570 public static int getIntHeader(HttpMessage message, String name) {
571 String value = getHeader(message, name);
572 if (value == null) {
573 throw new NumberFormatException("null");
574 }
575 return Integer.parseInt(value);
576 }
577
578
579
580
581
582
583
584
585
586 public static int getIntHeader(HttpMessage message, String name, int defaultValue) {
587 String value = getHeader(message, name);
588 if (value == null) {
589 return defaultValue;
590 }
591
592 try {
593 return Integer.parseInt(value);
594 } catch (NumberFormatException e) {
595 return defaultValue;
596 }
597 }
598
599
600
601
602
603 public static void setIntHeader(HttpMessage message, String name, int value) {
604 message.setHeader(name, value);
605 }
606
607
608
609
610
611 public static void setIntHeader(HttpMessage message, String name, Iterable<Integer> values) {
612 message.setHeader(name, values);
613 }
614
615
616
617
618 public static void addIntHeader(HttpMessage message, String name, int value) {
619 message.addHeader(name, value);
620 }
621
622
623
624
625
626
627
628
629
630
631 public static long getContentLength(HttpMessage message) {
632 return getContentLength(message, 0L);
633 }
634
635
636
637
638
639
640
641
642
643
644 public static long getContentLength(HttpMessage message, long defaultValue) {
645 String contentLength = message.getHeader(Names.CONTENT_LENGTH);
646 if (contentLength != null) {
647 return Long.parseLong(contentLength);
648 }
649
650
651 if (message instanceof HttpRequest) {
652 HttpRequest req = (HttpRequest) message;
653 if (HttpMethod.GET.equals(req.getMethod()) &&
654 req.containsHeader(Names.SEC_WEBSOCKET_KEY1) &&
655 req.containsHeader(Names.SEC_WEBSOCKET_KEY2)) {
656 return 8;
657 }
658 } else if (message instanceof HttpResponse) {
659 HttpResponse res = (HttpResponse) message;
660 if (res.getStatus().getCode() == 101 &&
661 res.containsHeader(Names.SEC_WEBSOCKET_ORIGIN) &&
662 res.containsHeader(Names.SEC_WEBSOCKET_LOCATION)) {
663 return 16;
664 }
665 }
666
667 return defaultValue;
668 }
669
670
671
672
673 public static void setContentLength(HttpMessage message, long length) {
674 message.setHeader(Names.CONTENT_LENGTH, length);
675 }
676
677
678
679
680 public static String getHost(HttpMessage message) {
681 return message.getHeader(Names.HOST);
682 }
683
684
685
686
687
688 public static String getHost(HttpMessage message, String defaultValue) {
689 return getHeader(message, Names.HOST, defaultValue);
690 }
691
692
693
694
695 public static void setHost(HttpMessage message, String value) {
696 message.setHeader(Names.HOST, value);
697 }
698
699
700
701
702
703 public static boolean is100ContinueExpected(HttpMessage message) {
704
705 if (!(message instanceof HttpRequest)) {
706 return false;
707 }
708
709
710 if (message.getProtocolVersion().compareTo(HttpVersion.HTTP_1_1) < 0) {
711 return false;
712 }
713
714
715 String value = message.getHeader(Names.EXPECT);
716 if (value == null) {
717 return false;
718 }
719 if (Values.CONTINUE.equalsIgnoreCase(value)) {
720 return true;
721 }
722
723
724 for (String v: message.getHeaders(Names.EXPECT)) {
725 if (Values.CONTINUE.equalsIgnoreCase(v)) {
726 return true;
727 }
728 }
729 return false;
730 }
731
732
733
734
735
736
737 public static void set100ContinueExpected(HttpMessage message) {
738 set100ContinueExpected(message, true);
739 }
740
741
742
743
744
745
746
747
748 public static void set100ContinueExpected(HttpMessage message, boolean set) {
749 if (set) {
750 message.setHeader(Names.EXPECT, Values.CONTINUE);
751 } else {
752 message.removeHeader(Names.EXPECT);
753 }
754 }
755
756 private static final int BUCKET_SIZE = 17;
757
758 private static int hash(String name) {
759 int h = 0;
760 for (int i = name.length() - 1; i >= 0; i --) {
761 char c = name.charAt(i);
762 if (c >= 'A' && c <= 'Z') {
763 c += 32;
764 }
765 h = 31 * h + c;
766 }
767
768 if (h > 0) {
769 return h;
770 } else if (h == Integer.MIN_VALUE) {
771 return Integer.MAX_VALUE;
772 } else {
773 return -h;
774 }
775 }
776
777 private static boolean eq(String name1, String name2) {
778 int nameLen = name1.length();
779 if (nameLen != name2.length()) {
780 return false;
781 }
782
783 for (int i = nameLen - 1; i >= 0; i --) {
784 char c1 = name1.charAt(i);
785 char c2 = name2.charAt(i);
786 if (c1 != c2) {
787 if (c1 >= 'A' && c1 <= 'Z') {
788 c1 += 32;
789 }
790 if (c2 >= 'A' && c2 <= 'Z') {
791 c2 += 32;
792 }
793 if (c1 != c2) {
794 return false;
795 }
796 }
797 }
798 return true;
799 }
800
801 private static int index(int hash) {
802 return hash % BUCKET_SIZE;
803 }
804
805 private final Entry[] entries = new Entry[BUCKET_SIZE];
806 private final Entry head = new Entry(-1, null, null);
807
808 HttpHeaders() {
809 head.before = head.after = head;
810 }
811
812 void validateHeaderName(String name) {
813 HttpCodecUtil.validateHeaderName(name);
814 }
815
816 void addHeader(final String name, final Object value) {
817 validateHeaderName(name);
818 String strVal = toString(value);
819 HttpCodecUtil.validateHeaderValue(strVal);
820 int h = hash(name);
821 int i = index(h);
822 addHeader0(h, i, name, strVal);
823 }
824
825 private void addHeader0(int h, int i, final String name, final String value) {
826
827 Entry e = entries[i];
828 Entry newEntry;
829 entries[i] = newEntry = new Entry(h, name, value);
830 newEntry.next = e;
831
832
833 newEntry.addBefore(head);
834 }
835
836 void removeHeader(final String name) {
837 if (name == null) {
838 throw new NullPointerException("name");
839 }
840 int h = hash(name);
841 int i = index(h);
842 removeHeader0(h, i, name);
843 }
844
845 private void removeHeader0(int h, int i, String name) {
846 Entry e = entries[i];
847 if (e == null) {
848 return;
849 }
850
851 for (;;) {
852 if (e.hash == h && eq(name, e.key)) {
853 e.remove();
854 Entry next = e.next;
855 if (next != null) {
856 entries[i] = next;
857 e = next;
858 } else {
859 entries[i] = null;
860 return;
861 }
862 } else {
863 break;
864 }
865 }
866
867 for (;;) {
868 Entry next = e.next;
869 if (next == null) {
870 break;
871 }
872 if (next.hash == h && eq(name, next.key)) {
873 e.next = next.next;
874 next.remove();
875 } else {
876 e = next;
877 }
878 }
879 }
880
881 void setHeader(final String name, final Object value) {
882 validateHeaderName(name);
883 String strVal = toString(value);
884 HttpCodecUtil.validateHeaderValue(strVal);
885 int h = hash(name);
886 int i = index(h);
887 removeHeader0(h, i, name);
888 addHeader0(h, i, name, strVal);
889 }
890
891 void setHeader(final String name, final Iterable<?> values) {
892 if (values == null) {
893 throw new NullPointerException("values");
894 }
895
896 validateHeaderName(name);
897
898 int h = hash(name);
899 int i = index(h);
900
901 removeHeader0(h, i, name);
902 for (Object v: values) {
903 if (v == null) {
904 break;
905 }
906 String strVal = toString(v);
907 HttpCodecUtil.validateHeaderValue(strVal);
908 addHeader0(h, i, name, strVal);
909 }
910 }
911
912 void clearHeaders() {
913 for (int i = 0; i < entries.length; i ++) {
914 entries[i] = null;
915 }
916 head.before = head.after = head;
917 }
918
919 String getHeader(final String name) {
920 if (name == null) {
921 throw new NullPointerException("name");
922 }
923
924 int h = hash(name);
925 int i = index(h);
926 Entry e = entries[i];
927 while (e != null) {
928 if (e.hash == h && eq(name, e.key)) {
929 return e.value;
930 }
931
932 e = e.next;
933 }
934 return null;
935 }
936
937 List<String> getHeaders(final String name) {
938 if (name == null) {
939 throw new NullPointerException("name");
940 }
941
942 LinkedList<String> values = new LinkedList<String>();
943
944 int h = hash(name);
945 int i = index(h);
946 Entry e = entries[i];
947 while (e != null) {
948 if (e.hash == h && eq(name, e.key)) {
949 values.addFirst(e.value);
950 }
951 e = e.next;
952 }
953 return values;
954 }
955
956 List<Map.Entry<String, String>> getHeaders() {
957 List<Map.Entry<String, String>> all =
958 new LinkedList<Map.Entry<String, String>>();
959
960 Entry e = head.after;
961 while (e != head) {
962 all.add(e);
963 e = e.after;
964 }
965 return all;
966 }
967
968 boolean containsHeader(String name) {
969 return getHeader(name) != null;
970 }
971
972 Set<String> getHeaderNames() {
973 Set<String> names =
974 new TreeSet<String>(CaseIgnoringComparator.INSTANCE);
975
976 Entry e = head.after;
977 while (e != head) {
978 names.add(e.key);
979 e = e.after;
980 }
981 return names;
982 }
983
984 private static String toString(Object value) {
985 if (value == null) {
986 return null;
987 }
988 return value.toString();
989 }
990
991 private static final class Entry implements Map.Entry<String, String> {
992 final int hash;
993 final String key;
994 String value;
995 Entry next;
996 Entry before, after;
997
998 Entry(int hash, String key, String value) {
999 this.hash = hash;
1000 this.key = key;
1001 this.value = value;
1002 }
1003
1004 void remove() {
1005 before.after = after;
1006 after.before = before;
1007 }
1008
1009 void addBefore(Entry e) {
1010 after = e;
1011 before = e.before;
1012 before.after = this;
1013 after.before = this;
1014 }
1015
1016 public String getKey() {
1017 return key;
1018 }
1019
1020 public String getValue() {
1021 return value;
1022 }
1023
1024 public String setValue(String value) {
1025 if (value == null) {
1026 throw new NullPointerException("value");
1027 }
1028 HttpCodecUtil.validateHeaderValue(value);
1029 String oldValue = this.value;
1030 this.value = value;
1031 return oldValue;
1032 }
1033
1034 @Override
1035 public String toString() {
1036 return key + "=" + value;
1037 }
1038 }
1039 }