Repository: netty/netty
Issue: Add the method that tells the class of HTTP status code to HttpResponseStatus 
Labels: feature

It should be convenient to have an easy way to classify an HttpResponseStatus based on the first digit of the HTTP status code, as defined in the RFC 2616:
- Information 1xx
- Success 2xx
- Redirection 3xx
- Client Error 4xx
- Server Error 5xx


Issue comments:
@trustin Not trying to be picky or anything, but wouldn't it be better to call the enum `HttpStatus` or `HttpStatusType` or `HttpStatusCategory` or `HttpStatusGroup` instead of `HttpStatusClass`? Ending it with `Class` just feels weird to me.  [Some other synonyms of classification/type](http://www.thesaurus.com/browse/category)

@blucas - I'm guessing this terminology was used because it is used in the RFC http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html?

@Scottmitch - I completely agree that is probably why trustin used `Class`. All I'm trying to say is that I don't believe `class` fits as well as some of my suggestions given the context. This is purely an opinion/preference.

> 10.2 Successful 2xx
> 
> This class of status code indicates that the client's request was successfully received, understood, and accepted.

The above quote is in the context of an RFC document.  The use of the word `class` here is just shorthand for `classification`.  This could easily be replaced by `category` `group(ing)` `type` or other synonyms.  In the context of a document such as the RFC, `class` fits in quite well.  My opinion is that `class` does not fit in as well in the context of a programming language.

Again, this is only my opinion/preference and by all means the name of the enum can remain as it is.  I am merely suggesting some alternative names which may work better in the context of this programming language.

@blucas - All good points.  I agree that `class` in type names can be confusing in programming language constructs.   However I also think it is important to use consistent terminology.  I could go either way @trustin WDYT?

Let me also chime in..... I think the current naming is good as it maps perfect to the rfc.

@normanmaurer +1


Pull request review comments:

Patch that resolved the issue:
diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpResponseStatus.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpResponseStatus.java
index 7e4fba3fc98..b5fffee57ae 100644
--- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpResponseStatus.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpResponseStatus.java
@@ -435,25 +435,7 @@ public static HttpResponseStatus valueOf(int code) {
             return NETWORK_AUTHENTICATION_REQUIRED;
         }
 
-        final String reasonPhrase;
-
-        if (code < 100) {
-            reasonPhrase = "Unknown Status";
-        } else if (code < 200) {
-            reasonPhrase = "Informational";
-        } else if (code < 300) {
-            reasonPhrase = "Successful";
-        } else if (code < 400) {
-            reasonPhrase = "Redirection";
-        } else if (code < 500) {
-            reasonPhrase = "Client Error";
-        } else if (code < 600) {
-            reasonPhrase = "Server Error";
-        } else {
-            reasonPhrase = "Unknown Status";
-        }
-
-        return new HttpResponseStatus(code, reasonPhrase + " (" + code + ')');
+        return new HttpResponseStatus(code);
     }
 
     /**
@@ -488,13 +470,20 @@ public static HttpResponseStatus parseLine(CharSequence line) {
 
     private final int code;
     private final AsciiString codeAsText;
+    private HttpStatusClass codeClass;
 
     private final String reasonPhrase;
     private final byte[] bytes;
 
     /**
-     * Creates a new instance with the specified {@code code} and its
-     * {@code reasonPhrase}.
+     * Creates a new instance with the specified {@code code} and the auto-generated default reason phrase.
+     */
+    private HttpResponseStatus(int code) {
+        this(code, HttpStatusClass.valueOf(code).defaultReasonPhrase() + " (" + code + ')', false);
+    }
+
+    /**
+     * Creates a new instance with the specified {@code code} and its {@code reasonPhrase}.
      */
     public HttpResponseStatus(int code, String reasonPhrase) {
         this(code, reasonPhrase, false);
@@ -552,6 +541,17 @@ public String reasonPhrase() {
         return reasonPhrase;
     }
 
+    /**
+     * Returns the class of this {@link HttpResponseStatus}
+     */
+    public HttpStatusClass codeClass() {
+        HttpStatusClass type = this.codeClass;
+        if (type == null) {
+            this.codeClass = type = HttpStatusClass.valueOf(code);
+        }
+        return type;
+    }
+
     @Override
     public int hashCode() {
         return code();
diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpStatusClass.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpStatusClass.java
new file mode 100644
index 00000000000..62d9092fb4a
--- /dev/null
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpStatusClass.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2014 The Netty Project
+ *
+ * The Netty Project licenses this file to you under the Apache License,
+ * version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at:
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package io.netty.handler.codec.http;
+
+import io.netty.handler.codec.AsciiString;
+
+/**
+ * The class of HTTP status.
+ */
+public enum HttpStatusClass {
+    /**
+     * The informational class (1xx)
+     */
+    INFORMATIONAL(100, 200, "Informational"),
+    /**
+     * The success class (2xx)
+     */
+    SUCCESS(200, 300, "Success"),
+    /**
+     * The redirection class (3xx)
+     */
+    REDIRECTION(300, 400, "Redirection"),
+    /**
+     * The client error class (4xx)
+     */
+    CLIENT_ERROR(400, 500, "Client Error"),
+    /**
+     * The server error class (5xx)
+     */
+    SERVER_ERROR(500, 600, "Server Error"),
+    /**
+     * The unknown class
+     */
+    UNKNOWN(0, 0, "Unknown Status") {
+        @Override
+        public boolean contains(int code) {
+            return code < 100 || code >= 600;
+        }
+    };
+
+    /**
+     * Returns the class of the specified HTTP status code.
+     */
+    public static HttpStatusClass valueOf(int code) {
+        if (INFORMATIONAL.contains(code)) {
+            return INFORMATIONAL;
+        }
+        if (SUCCESS.contains(code)) {
+            return SUCCESS;
+        }
+        if (REDIRECTION.contains(code)) {
+            return REDIRECTION;
+        }
+        if (CLIENT_ERROR.contains(code)) {
+            return CLIENT_ERROR;
+        }
+        if (SERVER_ERROR.contains(code)) {
+            return SERVER_ERROR;
+        }
+        return UNKNOWN;
+    }
+
+    private final int min;
+    private final int max;
+    private final AsciiString defaultReasonPhrase;
+
+    HttpStatusClass(int min, int max, String defaultReasonPhrase) {
+        this.min = min;
+        this.max = max;
+        this.defaultReasonPhrase = new AsciiString(defaultReasonPhrase);
+    }
+
+    /**
+     * Returns {@code true} if and only if the specified HTTP status code falls into this class.
+     */
+    public boolean contains(int code) {
+        return code >= min && code < max;
+    }
+
+    /**
+     * Returns the default reason phrase of this HTTP status class.
+     */
+    AsciiString defaultReasonPhrase() {
+        return defaultReasonPhrase;
+    }
+}


Test patch: