View Javadoc

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