1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.http;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.buffer.ByteBufUtil;
20 import io.netty.util.AsciiString;
21 import io.netty.util.CharsetUtil;
22 import io.netty.util.internal.ObjectUtil;
23
24 import static io.netty.handler.codec.http.HttpConstants.SP;
25 import static io.netty.util.ByteProcessor.FIND_ASCII_SPACE;
26 import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
27 import static java.lang.Integer.parseInt;
28
29
30
31
32
33
34 public class HttpResponseStatus implements Comparable<HttpResponseStatus> {
35
36
37
38
39 public static final HttpResponseStatus CONTINUE = newStatus(100, "Continue");
40
41
42
43
44 public static final HttpResponseStatus SWITCHING_PROTOCOLS = newStatus(101, "Switching Protocols");
45
46
47
48
49 public static final HttpResponseStatus PROCESSING = newStatus(102, "Processing");
50
51
52
53
54 public static final HttpResponseStatus EARLY_HINTS = newStatus(103, "Early Hints");
55
56
57
58
59 public static final HttpResponseStatus OK = newStatus(200, "OK");
60
61
62
63
64 public static final HttpResponseStatus CREATED = newStatus(201, "Created");
65
66
67
68
69 public static final HttpResponseStatus ACCEPTED = newStatus(202, "Accepted");
70
71
72
73
74 public static final HttpResponseStatus NON_AUTHORITATIVE_INFORMATION =
75 newStatus(203, "Non-Authoritative Information");
76
77
78
79
80 public static final HttpResponseStatus NO_CONTENT = newStatus(204, "No Content");
81
82
83
84
85 public static final HttpResponseStatus RESET_CONTENT = newStatus(205, "Reset Content");
86
87
88
89
90 public static final HttpResponseStatus PARTIAL_CONTENT = newStatus(206, "Partial Content");
91
92
93
94
95 public static final HttpResponseStatus MULTI_STATUS = newStatus(207, "Multi-Status");
96
97
98
99
100 public static final HttpResponseStatus MULTIPLE_CHOICES = newStatus(300, "Multiple Choices");
101
102
103
104
105 public static final HttpResponseStatus MOVED_PERMANENTLY = newStatus(301, "Moved Permanently");
106
107
108
109
110 public static final HttpResponseStatus FOUND = newStatus(302, "Found");
111
112
113
114
115 public static final HttpResponseStatus SEE_OTHER = newStatus(303, "See Other");
116
117
118
119
120 public static final HttpResponseStatus NOT_MODIFIED = newStatus(304, "Not Modified");
121
122
123
124
125 public static final HttpResponseStatus USE_PROXY = newStatus(305, "Use Proxy");
126
127
128
129
130 public static final HttpResponseStatus TEMPORARY_REDIRECT = newStatus(307, "Temporary Redirect");
131
132
133
134
135 public static final HttpResponseStatus PERMANENT_REDIRECT = newStatus(308, "Permanent Redirect");
136
137
138
139
140 public static final HttpResponseStatus BAD_REQUEST = newStatus(400, "Bad Request");
141
142
143
144
145 public static final HttpResponseStatus UNAUTHORIZED = newStatus(401, "Unauthorized");
146
147
148
149
150 public static final HttpResponseStatus PAYMENT_REQUIRED = newStatus(402, "Payment Required");
151
152
153
154
155 public static final HttpResponseStatus FORBIDDEN = newStatus(403, "Forbidden");
156
157
158
159
160 public static final HttpResponseStatus NOT_FOUND = newStatus(404, "Not Found");
161
162
163
164
165 public static final HttpResponseStatus METHOD_NOT_ALLOWED = newStatus(405, "Method Not Allowed");
166
167
168
169
170 public static final HttpResponseStatus NOT_ACCEPTABLE = newStatus(406, "Not Acceptable");
171
172
173
174
175 public static final HttpResponseStatus PROXY_AUTHENTICATION_REQUIRED =
176 newStatus(407, "Proxy Authentication Required");
177
178
179
180
181 public static final HttpResponseStatus REQUEST_TIMEOUT = newStatus(408, "Request Timeout");
182
183
184
185
186 public static final HttpResponseStatus CONFLICT = newStatus(409, "Conflict");
187
188
189
190
191 public static final HttpResponseStatus GONE = newStatus(410, "Gone");
192
193
194
195
196 public static final HttpResponseStatus LENGTH_REQUIRED = newStatus(411, "Length Required");
197
198
199
200
201 public static final HttpResponseStatus PRECONDITION_FAILED = newStatus(412, "Precondition Failed");
202
203
204
205
206 public static final HttpResponseStatus REQUEST_ENTITY_TOO_LARGE =
207 newStatus(413, "Request Entity Too Large");
208
209
210
211
212 public static final HttpResponseStatus REQUEST_URI_TOO_LONG = newStatus(414, "Request-URI Too Long");
213
214
215
216
217 public static final HttpResponseStatus UNSUPPORTED_MEDIA_TYPE = newStatus(415, "Unsupported Media Type");
218
219
220
221
222 public static final HttpResponseStatus REQUESTED_RANGE_NOT_SATISFIABLE =
223 newStatus(416, "Requested Range Not Satisfiable");
224
225
226
227
228 public static final HttpResponseStatus EXPECTATION_FAILED = newStatus(417, "Expectation Failed");
229
230
231
232
233
234
235 public static final HttpResponseStatus MISDIRECTED_REQUEST = newStatus(421, "Misdirected Request");
236
237
238
239
240 public static final HttpResponseStatus UNPROCESSABLE_ENTITY = newStatus(422, "Unprocessable Entity");
241
242
243
244
245 public static final HttpResponseStatus LOCKED = newStatus(423, "Locked");
246
247
248
249
250 public static final HttpResponseStatus FAILED_DEPENDENCY = newStatus(424, "Failed Dependency");
251
252
253
254
255 public static final HttpResponseStatus UNORDERED_COLLECTION = newStatus(425, "Unordered Collection");
256
257
258
259
260 public static final HttpResponseStatus UPGRADE_REQUIRED = newStatus(426, "Upgrade Required");
261
262
263
264
265 public static final HttpResponseStatus PRECONDITION_REQUIRED = newStatus(428, "Precondition Required");
266
267
268
269
270 public static final HttpResponseStatus TOO_MANY_REQUESTS = newStatus(429, "Too Many Requests");
271
272
273
274
275 public static final HttpResponseStatus REQUEST_HEADER_FIELDS_TOO_LARGE =
276 newStatus(431, "Request Header Fields Too Large");
277
278
279
280
281 public static final HttpResponseStatus INTERNAL_SERVER_ERROR = newStatus(500, "Internal Server Error");
282
283
284
285
286 public static final HttpResponseStatus NOT_IMPLEMENTED = newStatus(501, "Not Implemented");
287
288
289
290
291 public static final HttpResponseStatus BAD_GATEWAY = newStatus(502, "Bad Gateway");
292
293
294
295
296 public static final HttpResponseStatus SERVICE_UNAVAILABLE = newStatus(503, "Service Unavailable");
297
298
299
300
301 public static final HttpResponseStatus GATEWAY_TIMEOUT = newStatus(504, "Gateway Timeout");
302
303
304
305
306 public static final HttpResponseStatus HTTP_VERSION_NOT_SUPPORTED =
307 newStatus(505, "HTTP Version Not Supported");
308
309
310
311
312 public static final HttpResponseStatus VARIANT_ALSO_NEGOTIATES = newStatus(506, "Variant Also Negotiates");
313
314
315
316
317 public static final HttpResponseStatus INSUFFICIENT_STORAGE = newStatus(507, "Insufficient Storage");
318
319
320
321
322 public static final HttpResponseStatus NOT_EXTENDED = newStatus(510, "Not Extended");
323
324
325
326
327 public static final HttpResponseStatus NETWORK_AUTHENTICATION_REQUIRED =
328 newStatus(511, "Network Authentication Required");
329
330 private static HttpResponseStatus newStatus(int statusCode, String reasonPhrase) {
331 return new HttpResponseStatus(statusCode, reasonPhrase, true);
332 }
333
334
335
336
337
338
339 public static HttpResponseStatus valueOf(int code) {
340 HttpResponseStatus status = valueOf0(code);
341 return status != null ? status : new HttpResponseStatus(code);
342 }
343
344 private static HttpResponseStatus valueOf0(int code) {
345 switch (code) {
346 case 100:
347 return CONTINUE;
348 case 101:
349 return SWITCHING_PROTOCOLS;
350 case 102:
351 return PROCESSING;
352 case 103:
353 return EARLY_HINTS;
354 case 200:
355 return OK;
356 case 201:
357 return CREATED;
358 case 202:
359 return ACCEPTED;
360 case 203:
361 return NON_AUTHORITATIVE_INFORMATION;
362 case 204:
363 return NO_CONTENT;
364 case 205:
365 return RESET_CONTENT;
366 case 206:
367 return PARTIAL_CONTENT;
368 case 207:
369 return MULTI_STATUS;
370 case 300:
371 return MULTIPLE_CHOICES;
372 case 301:
373 return MOVED_PERMANENTLY;
374 case 302:
375 return FOUND;
376 case 303:
377 return SEE_OTHER;
378 case 304:
379 return NOT_MODIFIED;
380 case 305:
381 return USE_PROXY;
382 case 307:
383 return TEMPORARY_REDIRECT;
384 case 308:
385 return PERMANENT_REDIRECT;
386 case 400:
387 return BAD_REQUEST;
388 case 401:
389 return UNAUTHORIZED;
390 case 402:
391 return PAYMENT_REQUIRED;
392 case 403:
393 return FORBIDDEN;
394 case 404:
395 return NOT_FOUND;
396 case 405:
397 return METHOD_NOT_ALLOWED;
398 case 406:
399 return NOT_ACCEPTABLE;
400 case 407:
401 return PROXY_AUTHENTICATION_REQUIRED;
402 case 408:
403 return REQUEST_TIMEOUT;
404 case 409:
405 return CONFLICT;
406 case 410:
407 return GONE;
408 case 411:
409 return LENGTH_REQUIRED;
410 case 412:
411 return PRECONDITION_FAILED;
412 case 413:
413 return REQUEST_ENTITY_TOO_LARGE;
414 case 414:
415 return REQUEST_URI_TOO_LONG;
416 case 415:
417 return UNSUPPORTED_MEDIA_TYPE;
418 case 416:
419 return REQUESTED_RANGE_NOT_SATISFIABLE;
420 case 417:
421 return EXPECTATION_FAILED;
422 case 421:
423 return MISDIRECTED_REQUEST;
424 case 422:
425 return UNPROCESSABLE_ENTITY;
426 case 423:
427 return LOCKED;
428 case 424:
429 return FAILED_DEPENDENCY;
430 case 425:
431 return UNORDERED_COLLECTION;
432 case 426:
433 return UPGRADE_REQUIRED;
434 case 428:
435 return PRECONDITION_REQUIRED;
436 case 429:
437 return TOO_MANY_REQUESTS;
438 case 431:
439 return REQUEST_HEADER_FIELDS_TOO_LARGE;
440 case 500:
441 return INTERNAL_SERVER_ERROR;
442 case 501:
443 return NOT_IMPLEMENTED;
444 case 502:
445 return BAD_GATEWAY;
446 case 503:
447 return SERVICE_UNAVAILABLE;
448 case 504:
449 return GATEWAY_TIMEOUT;
450 case 505:
451 return HTTP_VERSION_NOT_SUPPORTED;
452 case 506:
453 return VARIANT_ALSO_NEGOTIATES;
454 case 507:
455 return INSUFFICIENT_STORAGE;
456 case 510:
457 return NOT_EXTENDED;
458 case 511:
459 return NETWORK_AUTHENTICATION_REQUIRED;
460 }
461 return null;
462 }
463
464
465
466
467
468
469
470
471
472 public static HttpResponseStatus valueOf(int code, String reasonPhrase) {
473 HttpResponseStatus responseStatus = valueOf0(code);
474 return responseStatus != null && responseStatus.reasonPhrase().contentEquals(reasonPhrase) ? responseStatus :
475 new HttpResponseStatus(code, reasonPhrase);
476 }
477
478
479
480
481
482
483
484
485
486
487 public static HttpResponseStatus parseLine(CharSequence line) {
488 return (line instanceof AsciiString) ? parseLine((AsciiString) line) : parseLine(line.toString());
489 }
490
491
492
493
494
495
496
497
498
499
500 public static HttpResponseStatus parseLine(String line) {
501 try {
502 int space = line.indexOf(' ');
503 return space == -1 ? valueOf(parseInt(line)) :
504 valueOf(parseInt(line.substring(0, space)), line.substring(space + 1));
505 } catch (Exception e) {
506 throw new IllegalArgumentException("malformed status line: " + line, e);
507 }
508 }
509
510
511
512
513
514
515
516
517
518
519 public static HttpResponseStatus parseLine(AsciiString line) {
520 try {
521 int space = line.forEachByte(FIND_ASCII_SPACE);
522 return space == -1 ? valueOf(line.parseInt()) : valueOf(line.parseInt(0, space), line.toString(space + 1));
523 } catch (Exception e) {
524 throw new IllegalArgumentException("malformed status line: " + line, e);
525 }
526 }
527
528 private final int code;
529 private final AsciiString codeAsText;
530 private final HttpStatusClass codeClass;
531
532 private final String reasonPhrase;
533 private final byte[] bytes;
534
535
536
537
538 private HttpResponseStatus(int code) {
539 this(code, HttpStatusClass.valueOf(code).defaultReasonPhrase() + " (" + code + ')', false);
540 }
541
542
543
544
545 public HttpResponseStatus(int code, String reasonPhrase) {
546 this(code, reasonPhrase, false);
547 }
548
549 private HttpResponseStatus(int code, String reasonPhrase, boolean bytes) {
550 checkPositiveOrZero(code, "code");
551 ObjectUtil.checkNotNull(reasonPhrase, "reasonPhrase");
552
553 for (int i = 0; i < reasonPhrase.length(); i ++) {
554 char c = reasonPhrase.charAt(i);
555
556 switch (c) {
557 case '\n': case '\r':
558 throw new IllegalArgumentException(
559 "reasonPhrase contains one of the following prohibited characters: " +
560 "\\r\\n: " + reasonPhrase);
561 }
562 }
563
564 this.code = code;
565 this.codeClass = HttpStatusClass.valueOf(code);
566 String codeString = Integer.toString(code);
567 codeAsText = new AsciiString(codeString);
568 this.reasonPhrase = reasonPhrase;
569 if (bytes) {
570 this.bytes = (codeString + ' ' + reasonPhrase).getBytes(CharsetUtil.US_ASCII);
571 } else {
572 this.bytes = null;
573 }
574 }
575
576
577
578
579 public int code() {
580 return code;
581 }
582
583
584
585
586 public AsciiString codeAsText() {
587 return codeAsText;
588 }
589
590
591
592
593 public String reasonPhrase() {
594 return reasonPhrase;
595 }
596
597
598
599
600 public HttpStatusClass codeClass() {
601 return this.codeClass;
602 }
603
604 @Override
605 public int hashCode() {
606 return code();
607 }
608
609
610
611
612
613 @Override
614 public boolean equals(Object o) {
615 if (!(o instanceof HttpResponseStatus)) {
616 return false;
617 }
618
619 return code() == ((HttpResponseStatus) o).code();
620 }
621
622
623
624
625
626 @Override
627 public int compareTo(HttpResponseStatus o) {
628 return code() - o.code();
629 }
630
631 @Override
632 public String toString() {
633 return new StringBuilder(reasonPhrase.length() + 4)
634 .append(codeAsText)
635 .append(' ')
636 .append(reasonPhrase)
637 .toString();
638 }
639
640 void encode(ByteBuf buf) {
641 if (bytes == null) {
642 ByteBufUtil.copy(codeAsText, buf);
643 buf.writeByte(SP);
644 buf.writeCharSequence(reasonPhrase, CharsetUtil.US_ASCII);
645 } else {
646 buf.writeBytes(bytes);
647 }
648 }
649 }