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 }