1
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
34 public class HttpResponseStatus implements Comparable<HttpResponseStatus> {
35
36
39 public static final HttpResponseStatus CONTINUE = newStatus(100, "Continue");
40
41
44 public static final HttpResponseStatus SWITCHING_PROTOCOLS = newStatus(101, "Switching Protocols");
45
46
49 public static final HttpResponseStatus PROCESSING = newStatus(102, "Processing");
50
51
54 public static final HttpResponseStatus OK = newStatus(200, "OK");
55
56
59 public static final HttpResponseStatus CREATED = newStatus(201, "Created");
60
61
64 public static final HttpResponseStatus ACCEPTED = newStatus(202, "Accepted");
65
66
69 public static final HttpResponseStatus NON_AUTHORITATIVE_INFORMATION =
70 newStatus(203, "Non-Authoritative Information");
71
72
75 public static final HttpResponseStatus NO_CONTENT = newStatus(204, "No Content");
76
77
80 public static final HttpResponseStatus RESET_CONTENT = newStatus(205, "Reset Content");
81
82
85 public static final HttpResponseStatus PARTIAL_CONTENT = newStatus(206, "Partial Content");
86
87
90 public static final HttpResponseStatus MULTI_STATUS = newStatus(207, "Multi-Status");
91
92
95 public static final HttpResponseStatus MULTIPLE_CHOICES = newStatus(300, "Multiple Choices");
96
97
100 public static final HttpResponseStatus MOVED_PERMANENTLY = newStatus(301, "Moved Permanently");
101
102
105 public static final HttpResponseStatus FOUND = newStatus(302, "Found");
106
107
110 public static final HttpResponseStatus SEE_OTHER = newStatus(303, "See Other");
111
112
115 public static final HttpResponseStatus NOT_MODIFIED = newStatus(304, "Not Modified");
116
117
120 public static final HttpResponseStatus USE_PROXY = newStatus(305, "Use Proxy");
121
122
125 public static final HttpResponseStatus TEMPORARY_REDIRECT = newStatus(307, "Temporary Redirect");
126
127
130 public static final HttpResponseStatus PERMANENT_REDIRECT = newStatus(308, "Permanent Redirect");
131
132
135 public static final HttpResponseStatus BAD_REQUEST = newStatus(400, "Bad Request");
136
137
140 public static final HttpResponseStatus UNAUTHORIZED = newStatus(401, "Unauthorized");
141
142
145 public static final HttpResponseStatus PAYMENT_REQUIRED = newStatus(402, "Payment Required");
146
147
150 public static final HttpResponseStatus FORBIDDEN = newStatus(403, "Forbidden");
151
152
155 public static final HttpResponseStatus NOT_FOUND = newStatus(404, "Not Found");
156
157
160 public static final HttpResponseStatus METHOD_NOT_ALLOWED = newStatus(405, "Method Not Allowed");
161
162
165 public static final HttpResponseStatus NOT_ACCEPTABLE = newStatus(406, "Not Acceptable");
166
167
170 public static final HttpResponseStatus PROXY_AUTHENTICATION_REQUIRED =
171 newStatus(407, "Proxy Authentication Required");
172
173
176 public static final HttpResponseStatus REQUEST_TIMEOUT = newStatus(408, "Request Timeout");
177
178
181 public static final HttpResponseStatus CONFLICT = newStatus(409, "Conflict");
182
183
186 public static final HttpResponseStatus GONE = newStatus(410, "Gone");
187
188
191 public static final HttpResponseStatus LENGTH_REQUIRED = newStatus(411, "Length Required");
192
193
196 public static final HttpResponseStatus PRECONDITION_FAILED = newStatus(412, "Precondition Failed");
197
198
201 public static final HttpResponseStatus REQUEST_ENTITY_TOO_LARGE =
202 newStatus(413, "Request Entity Too Large");
203
204
207 public static final HttpResponseStatus REQUEST_URI_TOO_LONG = newStatus(414, "Request-URI Too Long");
208
209
212 public static final HttpResponseStatus UNSUPPORTED_MEDIA_TYPE = newStatus(415, "Unsupported Media Type");
213
214
217 public static final HttpResponseStatus REQUESTED_RANGE_NOT_SATISFIABLE =
218 newStatus(416, "Requested Range Not Satisfiable");
219
220
223 public static final HttpResponseStatus EXPECTATION_FAILED = newStatus(417, "Expectation Failed");
224
225
230 public static final HttpResponseStatus MISDIRECTED_REQUEST = newStatus(421, "Misdirected Request");
231
232
235 public static final HttpResponseStatus UNPROCESSABLE_ENTITY = newStatus(422, "Unprocessable Entity");
236
237
240 public static final HttpResponseStatus LOCKED = newStatus(423, "Locked");
241
242
245 public static final HttpResponseStatus FAILED_DEPENDENCY = newStatus(424, "Failed Dependency");
246
247
250 public static final HttpResponseStatus UNORDERED_COLLECTION = newStatus(425, "Unordered Collection");
251
252
255 public static final HttpResponseStatus UPGRADE_REQUIRED = newStatus(426, "Upgrade Required");
256
257
260 public static final HttpResponseStatus PRECONDITION_REQUIRED = newStatus(428, "Precondition Required");
261
262
265 public static final HttpResponseStatus TOO_MANY_REQUESTS = newStatus(429, "Too Many Requests");
266
267
270 public static final HttpResponseStatus REQUEST_HEADER_FIELDS_TOO_LARGE =
271 newStatus(431, "Request Header Fields Too Large");
272
273
276 public static final HttpResponseStatus INTERNAL_SERVER_ERROR = newStatus(500, "Internal Server Error");
277
278
281 public static final HttpResponseStatus NOT_IMPLEMENTED = newStatus(501, "Not Implemented");
282
283
286 public static final HttpResponseStatus BAD_GATEWAY = newStatus(502, "Bad Gateway");
287
288
291 public static final HttpResponseStatus SERVICE_UNAVAILABLE = newStatus(503, "Service Unavailable");
292
293
296 public static final HttpResponseStatus GATEWAY_TIMEOUT = newStatus(504, "Gateway Timeout");
297
298
301 public static final HttpResponseStatus HTTP_VERSION_NOT_SUPPORTED =
302 newStatus(505, "HTTP Version Not Supported");
303
304
307 public static final HttpResponseStatus VARIANT_ALSO_NEGOTIATES = newStatus(506, "Variant Also Negotiates");
308
309
312 public static final HttpResponseStatus INSUFFICIENT_STORAGE = newStatus(507, "Insufficient Storage");
313
314
317 public static final HttpResponseStatus NOT_EXTENDED = newStatus(510, "Not Extended");
318
319
322 public static final HttpResponseStatus NETWORK_AUTHENTICATION_REQUIRED =
323 newStatus(511, "Network Authentication Required");
324
325 private static HttpResponseStatus newStatus(int statusCode, String reasonPhrase) {
326 return new HttpResponseStatus(statusCode, reasonPhrase, true);
327 }
328
329
334 public static HttpResponseStatus valueOf(int code) {
335 HttpResponseStatus status = valueOf0(code);
336 return status != null ? status : new HttpResponseStatus(code);
337 }
338
339 private static HttpResponseStatus valueOf0(int code) {
340 switch (code) {
341 case 100:
342 return CONTINUE;
343 case 101:
344 return SWITCHING_PROTOCOLS;
345 case 102:
346 return PROCESSING;
347 case 200:
348 return OK;
349 case 201:
350 return CREATED;
351 case 202:
352 return ACCEPTED;
353 case 203:
354 return NON_AUTHORITATIVE_INFORMATION;
355 case 204:
356 return NO_CONTENT;
357 case 205:
358 return RESET_CONTENT;
359 case 206:
360 return PARTIAL_CONTENT;
361 case 207:
362 return MULTI_STATUS;
363 case 300:
364 return MULTIPLE_CHOICES;
365 case 301:
366 return MOVED_PERMANENTLY;
367 case 302:
368 return FOUND;
369 case 303:
370 return SEE_OTHER;
371 case 304:
372 return NOT_MODIFIED;
373 case 305:
374 return USE_PROXY;
375 case 307:
376 return TEMPORARY_REDIRECT;
377 case 308:
378 return PERMANENT_REDIRECT;
379 case 400:
380 return BAD_REQUEST;
381 case 401:
382 return UNAUTHORIZED;
383 case 402:
384 return PAYMENT_REQUIRED;
385 case 403:
386 return FORBIDDEN;
387 case 404:
388 return NOT_FOUND;
389 case 405:
390 return METHOD_NOT_ALLOWED;
391 case 406:
392 return NOT_ACCEPTABLE;
393 case 407:
394 return PROXY_AUTHENTICATION_REQUIRED;
395 case 408:
396 return REQUEST_TIMEOUT;
397 case 409:
398 return CONFLICT;
399 case 410:
400 return GONE;
401 case 411:
402 return LENGTH_REQUIRED;
403 case 412:
404 return PRECONDITION_FAILED;
405 case 413:
406 return REQUEST_ENTITY_TOO_LARGE;
407 case 414:
408 return REQUEST_URI_TOO_LONG;
409 case 415:
410 return UNSUPPORTED_MEDIA_TYPE;
411 case 416:
412 return REQUESTED_RANGE_NOT_SATISFIABLE;
413 case 417:
414 return EXPECTATION_FAILED;
415 case 421:
416 return MISDIRECTED_REQUEST;
417 case 422:
418 return UNPROCESSABLE_ENTITY;
419 case 423:
420 return LOCKED;
421 case 424:
422 return FAILED_DEPENDENCY;
423 case 425:
424 return UNORDERED_COLLECTION;
425 case 426:
426 return UPGRADE_REQUIRED;
427 case 428:
428 return PRECONDITION_REQUIRED;
429 case 429:
430 return TOO_MANY_REQUESTS;
431 case 431:
432 return REQUEST_HEADER_FIELDS_TOO_LARGE;
433 case 500:
434 return INTERNAL_SERVER_ERROR;
435 case 501:
436 return NOT_IMPLEMENTED;
437 case 502:
438 return BAD_GATEWAY;
439 case 503:
440 return SERVICE_UNAVAILABLE;
441 case 504:
442 return GATEWAY_TIMEOUT;
443 case 505:
444 return HTTP_VERSION_NOT_SUPPORTED;
445 case 506:
446 return VARIANT_ALSO_NEGOTIATES;
447 case 507:
448 return INSUFFICIENT_STORAGE;
449 case 510:
450 return NOT_EXTENDED;
451 case 511:
452 return NETWORK_AUTHENTICATION_REQUIRED;
453 }
454 return null;
455 }
456
457
465 public static HttpResponseStatus valueOf(int code, String reasonPhrase) {
466 HttpResponseStatus responseStatus = valueOf0(code);
467 return responseStatus != null && responseStatus.reasonPhrase().contentEquals(reasonPhrase) ? responseStatus :
468 new HttpResponseStatus(code, reasonPhrase);
469 }
470
471
480 public static HttpResponseStatus parseLine(CharSequence line) {
481 return (line instanceof AsciiString) ? parseLine((AsciiString) line) : parseLine(line.toString());
482 }
483
484
493 public static HttpResponseStatus parseLine(String line) {
494 try {
495 int space = line.indexOf(' ');
496 return space == -1 ? valueOf(parseInt(line)) :
497 valueOf(parseInt(line.substring(0, space)), line.substring(space + 1));
498 } catch (Exception e) {
499 throw new IllegalArgumentException("malformed status line: " + line, e);
500 }
501 }
502
503
512 public static HttpResponseStatus parseLine(AsciiString line) {
513 try {
514 int space = line.forEachByte(FIND_ASCII_SPACE);
515 return space == -1 ? valueOf(line.parseInt()) : valueOf(line.parseInt(0, space), line.toString(space + 1));
516 } catch (Exception e) {
517 throw new IllegalArgumentException("malformed status line: " + line, e);
518 }
519 }
520
521 private final int code;
522 private final AsciiString codeAsText;
523 private HttpStatusClass codeClass;
524
525 private final String reasonPhrase;
526 private final byte[] bytes;
527
528
531 private HttpResponseStatus(int code) {
532 this(code, HttpStatusClass.valueOf(code).defaultReasonPhrase() + " (" + code + ')', false);
533 }
534
535
538 public HttpResponseStatus(int code, String reasonPhrase) {
539 this(code, reasonPhrase, false);
540 }
541
542 private HttpResponseStatus(int code, String reasonPhrase, boolean bytes) {
543 checkPositiveOrZero(code, "code");
544 ObjectUtil.checkNotNull(reasonPhrase, "reasonPhrase");
545
546 for (int i = 0; i < reasonPhrase.length(); i ++) {
547 char c = reasonPhrase.charAt(i);
548
549 switch (c) {
550 case '\n': case '\r':
551 throw new IllegalArgumentException(
552 "reasonPhrase contains one of the following prohibited characters: " +
553 "\\r\\n: " + reasonPhrase);
554 }
555 }
556
557 this.code = code;
558 String codeString = Integer.toString(code);
559 codeAsText = new AsciiString(codeString);
560 this.reasonPhrase = reasonPhrase;
561 if (bytes) {
562 this.bytes = (codeString + ' ' + reasonPhrase).getBytes(CharsetUtil.US_ASCII);
563 } else {
564 this.bytes = null;
565 }
566 }
567
568
571 public int code() {
572 return code;
573 }
574
575
578 public AsciiString codeAsText() {
579 return codeAsText;
580 }
581
582
585 public String reasonPhrase() {
586 return reasonPhrase;
587 }
588
589
592 public HttpStatusClass codeClass() {
593 HttpStatusClass type = this.codeClass;
594 if (type == null) {
595 this.codeClass = type = HttpStatusClass.valueOf(code);
596 }
597 return type;
598 }
599
600 @Override
601 public int hashCode() {
602 return code();
603 }
604
605
609 @Override
610 public boolean equals(Object o) {
611 if (!(o instanceof HttpResponseStatus)) {
612 return false;
613 }
614
615 return code() == ((HttpResponseStatus) o).code();
616 }
617
618
622 @Override
623 public int compareTo(HttpResponseStatus o) {
624 return code() - o.code();
625 }
626
627 @Override
628 public String toString() {
629 return new StringBuilder(reasonPhrase.length() + 4)
630 .append(codeAsText)
631 .append(' ')
632 .append(reasonPhrase)
633 .toString();
634 }
635
636 void encode(ByteBuf buf) {
637 if (bytes == null) {
638 ByteBufUtil.copy(codeAsText, buf);
639 buf.writeByte(SP);
640 buf.writeCharSequence(reasonPhrase, CharsetUtil.US_ASCII);
641 } else {
642 buf.writeBytes(bytes);
643 }
644 }
645 }
646