View Javadoc

    1   /*
    2    * Copyright 2012 The Netty Project
    3    *
    4    * The Netty Project licenses this file to you under the Apache License,
    5    * version 2.0 (the "License"); you may not use this file except in compliance
    6    * with the License. You may obtain a copy of the License at:
    7    *
    8    *   http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    13   * License for the specific language governing permissions and limitations
    14   * under the License.
    15   */
    16  package org.jboss.netty.handler.codec.http;
    17
    18  import java.util.regex.Matcher;
    19  import java.util.regex.Pattern;
    20
    21  /**
    22   * The version of HTTP or its derived protocols, such as
    23   * <a href="http://en.wikipedia.org/wiki/Real_Time_Streaming_Protocol">RTSP</a> and
    24   * <a href="http://en.wikipedia.org/wiki/Internet_Content_Adaptation_Protocol">ICAP</a>.
    25   * @apiviz.exclude
    26   */
    27  public class HttpVersion implements Comparable<HttpVersion> {
    28
    29      private static final Pattern VERSION_PATTERN =
    30          Pattern.compile("(\\S+)/(\\d+)\\.(\\d+)");
    31
    32      /**
    33       * HTTP/1.0
    34       */
    35      public static final HttpVersion HTTP_1_0 = new HttpVersion("HTTP", 1, 0, false);
    36
    37      /**
    38       * HTTP/1.1
    39       */
    40      public static final HttpVersion HTTP_1_1 = new HttpVersion("HTTP", 1, 1, true);
    41
    42      /**
    43       * Returns an existing or new {@link HttpVersion} instance which matches to
    44       * the specified protocol version string.  If the specified {@code text} is
    45       * equal to {@code "HTTP/1.0"}, {@link #HTTP_1_0} will be returned.  If the
    46       * specified {@code text} is equal to {@code "HTTP/1.1"}, {@link #HTTP_1_1}
    47       * will be returned.  Otherwise, a new {@link HttpVersion} instance will be
    48       * returned.
    49       */
    50      public static HttpVersion valueOf(String text) {
    51          if (text == null) {
    52              throw new NullPointerException("text");
    53          }
    54
    55          text = text.trim().toUpperCase();
    56          if (text.equals("HTTP/1.1")) {
    57              return HTTP_1_1;
    58          }
    59          if (text.equals("HTTP/1.0")) {
    60              return HTTP_1_0;
    61          }
    62          return new HttpVersion(text, true);
    63      }
    64
    65      private final String protocolName;
    66      private final int majorVersion;
    67      private final int minorVersion;
    68      private final String text;
    69      private final boolean keepAliveDefault;
    70
    71      /**
    72       * @deprecated Use {@link #HttpVersion(String, boolean)} instead.
    73       */
    74      @Deprecated
    75      public HttpVersion(String text) {
    76          this(text, true);
    77      }
    78
    79      /**
    80       * Creates a new HTTP version with the specified version string.  You will
    81       * not need to create a new instance unless you are implementing a protocol
    82       * derived from HTTP, such as
    83       * <a href="http://en.wikipedia.org/wiki/Real_Time_Streaming_Protocol">RTSP</a> and
    84       * <a href="http://en.wikipedia.org/wiki/Internet_Content_Adaptation_Protocol">ICAP</a>.
    85       *
    86       * @param keepAliveDefault
    87       *        {@code true} if and only if the connection is kept alive unless
    88       *        the {@code "Connection"} header is set to {@code "close"} explicitly.
    89       */
    90      public HttpVersion(String text, boolean keepAliveDefault) {
    91          if (text == null) {
    92              throw new NullPointerException("text");
    93          }
    94
    95          text = text.trim().toUpperCase();
    96          if (text.length() == 0) {
    97              throw new IllegalArgumentException("empty text");
    98          }
    99
    100         Matcher m = VERSION_PATTERN.matcher(text);
    101         if (!m.matches()) {
    102             throw new IllegalArgumentException("invalid version format: " + text);
    103         }
    104
    105         protocolName = m.group(1);
    106         majorVersion = Integer.parseInt(m.group(2));
    107         minorVersion = Integer.parseInt(m.group(3));
    108         this.text = protocolName + '/' + majorVersion + '.' + minorVersion;
    109         this.keepAliveDefault = keepAliveDefault;
    110     }
    111
    112     /**
    113      * @deprecated Use {@link #HttpVersion(String, int, int, boolean)} instead.
    114      */
    115     @Deprecated
    116     public HttpVersion(
    117             String protocolName, int majorVersion, int minorVersion) {
    118         this(protocolName, majorVersion, minorVersion, true);
    119     }
    120
    121     /**
    122      * Creates a new HTTP version with the specified protocol name and version
    123      * numbers.  You will not need to create a new instance unless you are
    124      * implementing a protocol derived from HTTP, such as
    125      * <a href="http://en.wikipedia.org/wiki/Real_Time_Streaming_Protocol">RTSP</a> and
    126      * <a href="http://en.wikipedia.org/wiki/Internet_Content_Adaptation_Protocol">ICAP</a>
    127      *
    128      * @param keepAliveDefault
    129      *        {@code true} if and only if the connection is kept alive unless
    130      *        the {@code "Connection"} header is set to {@code "close"} explicitly.
    131      */
    132     public HttpVersion(
    133             String protocolName, int majorVersion, int minorVersion,
    134             boolean keepAliveDefault) {
    135         if (protocolName == null) {
    136             throw new NullPointerException("protocolName");
    137         }
    138
    139         protocolName = protocolName.trim().toUpperCase();
    140         if (protocolName.length() == 0) {
    141             throw new IllegalArgumentException("empty protocolName");
    142         }
    143
    144         for (int i = 0; i < protocolName.length(); i ++) {
    145             if (Character.isISOControl(protocolName.charAt(i)) ||
    146                 Character.isWhitespace(protocolName.charAt(i))) {
    147                 throw new IllegalArgumentException("invalid character in protocolName");
    148             }
    149         }
    150
    151         if (majorVersion < 0) {
    152             throw new IllegalArgumentException("negative majorVersion");
    153         }
    154         if (minorVersion < 0) {
    155             throw new IllegalArgumentException("negative minorVersion");
    156         }
    157
    158         this.protocolName = protocolName;
    159         this.majorVersion = majorVersion;
    160         this.minorVersion = minorVersion;
    161         text = protocolName + '/' + majorVersion + '.' + minorVersion;
    162         this.keepAliveDefault = keepAliveDefault;
    163     }
    164
    165     /**
    166      * Returns the name of the protocol such as {@code "HTTP"} in {@code "HTTP/1.0"}.
    167      */
    168     public String getProtocolName() {
    169         return protocolName;
    170     }
    171
    172     /**
    173      * Returns the name of the protocol such as {@code 1} in {@code "HTTP/1.0"}.
    174      */
    175     public int getMajorVersion() {
    176         return majorVersion;
    177     }
    178
    179     /**
    180      * Returns the name of the protocol such as {@code 0} in {@code "HTTP/1.0"}.
    181      */
    182     public int getMinorVersion() {
    183         return minorVersion;
    184     }
    185
    186     /**
    187      * Returns the full protocol version text such as {@code "HTTP/1.0"}.
    188      */
    189     public String getText() {
    190         return text;
    191     }
    192
    193     /**
    194      * Returns {@code true} if and only if the connection is kept alive unless
    195      * the {@code "Connection"} header is set to {@code "close"} explicitly.
    196      */
    197     public boolean isKeepAliveDefault() {
    198         return keepAliveDefault;
    199     }
    200
    201     /**
    202      * Returns the full protocol version text such as {@code "HTTP/1.0"}.
    203      */
    204     @Override
    205     public String toString() {
    206         return getText();
    207     }
    208
    209     @Override
    210     public int hashCode() {
    211         return (getProtocolName().hashCode() * 31 + getMajorVersion()) * 31 +
    212                getMinorVersion();
    213     }
    214
    215     @Override
    216     public boolean equals(Object o) {
    217         if (!(o instanceof HttpVersion)) {
    218             return false;
    219         }
    220
    221         HttpVersion that = (HttpVersion) o;
    222         return getMinorVersion() == that.getMinorVersion() &&
    223                getMajorVersion() == that.getMajorVersion() &&
    224                getProtocolName().equals(that.getProtocolName());
    225     }
    226
    227     public int compareTo(HttpVersion o) {
    228         int v = getProtocolName().compareTo(o.getProtocolName());
    229         if (v != 0) {
    230             return v;
    231         }
    232
    233         v = getMajorVersion() - o.getMajorVersion();
    234         if (v != 0) {
    235             return v;
    236         }
    237
    238         return getMinorVersion() - o.getMinorVersion();
    239     }
    240 }