1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.http;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.util.CharsetUtil;
20
21 import java.util.regex.Matcher;
22 import java.util.regex.Pattern;
23
24
25
26
27
28
29 public class HttpVersion implements Comparable<HttpVersion> {
30
31 private static final Pattern VERSION_PATTERN =
32 Pattern.compile("(\\S+)/(\\d+)\\.(\\d+)");
33
34 private static final String HTTP_1_0_STRING = "HTTP/1.0";
35 private static final String HTTP_1_1_STRING = "HTTP/1.1";
36
37
38
39
40 public static final HttpVersion HTTP_1_0 = new HttpVersion("HTTP", 1, 0, false, true);
41
42
43
44
45 public static final HttpVersion HTTP_1_1 = new HttpVersion("HTTP", 1, 1, true, true);
46
47
48
49
50
51
52
53
54
55 public static HttpVersion valueOf(String text) {
56 if (text == null) {
57 throw new NullPointerException("text");
58 }
59
60 text = text.trim();
61
62 if (text.isEmpty()) {
63 throw new IllegalArgumentException("text is empty (possibly HTTP/0.9)");
64 }
65
66
67
68
69
70
71
72
73
74
75
76
77 HttpVersion version = version0(text);
78 if (version == null) {
79 text = text.toUpperCase();
80
81 version = version0(text);
82 if (version == null) {
83
84 version = new HttpVersion(text, true);
85 }
86 }
87 return version;
88 }
89
90 private static HttpVersion version0(String text) {
91 if (HTTP_1_1_STRING.equals(text)) {
92 return HTTP_1_1;
93 }
94 if (HTTP_1_0_STRING.equals(text)) {
95 return HTTP_1_0;
96 }
97 return null;
98 }
99
100 private final String protocolName;
101 private final int majorVersion;
102 private final int minorVersion;
103 private final String text;
104 private final boolean keepAliveDefault;
105 private final byte[] bytes;
106
107
108
109
110
111
112
113
114
115
116
117
118 public HttpVersion(String text, boolean keepAliveDefault) {
119 if (text == null) {
120 throw new NullPointerException("text");
121 }
122
123 text = text.trim().toUpperCase();
124 if (text.isEmpty()) {
125 throw new IllegalArgumentException("empty text");
126 }
127
128 Matcher m = VERSION_PATTERN.matcher(text);
129 if (!m.matches()) {
130 throw new IllegalArgumentException("invalid version format: " + text);
131 }
132
133 protocolName = m.group(1);
134 majorVersion = Integer.parseInt(m.group(2));
135 minorVersion = Integer.parseInt(m.group(3));
136 this.text = protocolName + '/' + majorVersion + '.' + minorVersion;
137 this.keepAliveDefault = keepAliveDefault;
138 bytes = null;
139 }
140
141
142
143
144
145
146
147
148
149
150
151
152 public HttpVersion(
153 String protocolName, int majorVersion, int minorVersion,
154 boolean keepAliveDefault) {
155 this(protocolName, majorVersion, minorVersion, keepAliveDefault, false);
156 }
157
158 private HttpVersion(
159 String protocolName, int majorVersion, int minorVersion,
160 boolean keepAliveDefault, boolean bytes) {
161 if (protocolName == null) {
162 throw new NullPointerException("protocolName");
163 }
164
165 protocolName = protocolName.trim().toUpperCase();
166 if (protocolName.isEmpty()) {
167 throw new IllegalArgumentException("empty protocolName");
168 }
169
170 for (int i = 0; i < protocolName.length(); i ++) {
171 if (Character.isISOControl(protocolName.charAt(i)) ||
172 Character.isWhitespace(protocolName.charAt(i))) {
173 throw new IllegalArgumentException("invalid character in protocolName");
174 }
175 }
176
177 if (majorVersion < 0) {
178 throw new IllegalArgumentException("negative majorVersion");
179 }
180 if (minorVersion < 0) {
181 throw new IllegalArgumentException("negative minorVersion");
182 }
183
184 this.protocolName = protocolName;
185 this.majorVersion = majorVersion;
186 this.minorVersion = minorVersion;
187 text = protocolName + '/' + majorVersion + '.' + minorVersion;
188 this.keepAliveDefault = keepAliveDefault;
189
190 if (bytes) {
191 this.bytes = text.getBytes(CharsetUtil.US_ASCII);
192 } else {
193 this.bytes = null;
194 }
195 }
196
197
198
199
200 public String protocolName() {
201 return protocolName;
202 }
203
204
205
206
207 public int majorVersion() {
208 return majorVersion;
209 }
210
211
212
213
214 public int minorVersion() {
215 return minorVersion;
216 }
217
218
219
220
221 public String text() {
222 return text;
223 }
224
225
226
227
228
229 public boolean isKeepAliveDefault() {
230 return keepAliveDefault;
231 }
232
233
234
235
236 @Override
237 public String toString() {
238 return text();
239 }
240
241 @Override
242 public int hashCode() {
243 return (protocolName().hashCode() * 31 + majorVersion()) * 31 +
244 minorVersion();
245 }
246
247 @Override
248 public boolean equals(Object o) {
249 if (!(o instanceof HttpVersion)) {
250 return false;
251 }
252
253 HttpVersion that = (HttpVersion) o;
254 return minorVersion() == that.minorVersion() &&
255 majorVersion() == that.majorVersion() &&
256 protocolName().equals(that.protocolName());
257 }
258
259 @Override
260 public int compareTo(HttpVersion o) {
261 int v = protocolName().compareTo(o.protocolName());
262 if (v != 0) {
263 return v;
264 }
265
266 v = majorVersion() - o.majorVersion();
267 if (v != 0) {
268 return v;
269 }
270
271 return minorVersion() - o.minorVersion();
272 }
273
274 void encode(ByteBuf buf) {
275 if (bytes == null) {
276 HttpHeaders.encodeAscii0(text, buf);
277 } else {
278 buf.writeBytes(bytes);
279 }
280 }
281 }