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 }