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 static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
19 import static io.netty.util.internal.ObjectUtil.checkNonEmptyAfterTrim;
20
21 import io.netty.buffer.ByteBuf;
22 import io.netty.util.CharsetUtil;
23 import io.netty.util.internal.ObjectUtil;
24
25 import java.util.regex.Matcher;
26 import java.util.regex.Pattern;
27
28
29
30
31
32
33 public class HttpVersion implements Comparable<HttpVersion> {
34
35 private static final Pattern VERSION_PATTERN =
36 Pattern.compile("(\\S+)/(\\d+)\\.(\\d+)");
37
38 static final String HTTP_1_0_STRING = "HTTP/1.0";
39 static final String HTTP_1_1_STRING = "HTTP/1.1";
40
41
42
43
44 public static final HttpVersion HTTP_1_0 = new HttpVersion("HTTP", 1, 0, false, true);
45
46
47
48
49 public static final HttpVersion HTTP_1_1 = new HttpVersion("HTTP", 1, 1, true, true);
50
51
52
53
54
55
56
57
58
59 public static HttpVersion valueOf(String text) {
60 ObjectUtil.checkNotNull(text, "text");
61
62
63 if (text == HTTP_1_1_STRING) {
64 return HTTP_1_1;
65 } else if (text == HTTP_1_0_STRING) {
66 return HTTP_1_0;
67 }
68
69 text = text.trim();
70
71 if (text.isEmpty()) {
72 throw new IllegalArgumentException("text is empty (possibly HTTP/0.9)");
73 }
74
75
76
77
78
79
80
81
82
83 HttpVersion version = version0(text);
84 if (version == null) {
85 version = new HttpVersion(text, true);
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 text = checkNonEmptyAfterTrim(text, "text").toUpperCase();
120
121 Matcher m = VERSION_PATTERN.matcher(text);
122 if (!m.matches()) {
123 throw new IllegalArgumentException("invalid version format: " + text);
124 }
125
126 protocolName = m.group(1);
127 majorVersion = Integer.parseInt(m.group(2));
128 minorVersion = Integer.parseInt(m.group(3));
129 this.text = protocolName + '/' + majorVersion + '.' + minorVersion;
130 this.keepAliveDefault = keepAliveDefault;
131 bytes = null;
132 }
133
134
135
136
137
138
139
140
141
142
143
144
145 public HttpVersion(
146 String protocolName, int majorVersion, int minorVersion,
147 boolean keepAliveDefault) {
148 this(protocolName, majorVersion, minorVersion, keepAliveDefault, false);
149 }
150
151 private HttpVersion(
152 String protocolName, int majorVersion, int minorVersion,
153 boolean keepAliveDefault, boolean bytes) {
154 protocolName = checkNonEmptyAfterTrim(protocolName, "protocolName").toUpperCase();
155
156 for (int i = 0; i < protocolName.length(); i ++) {
157 if (Character.isISOControl(protocolName.charAt(i)) ||
158 Character.isWhitespace(protocolName.charAt(i))) {
159 throw new IllegalArgumentException("invalid character in protocolName");
160 }
161 }
162
163 checkPositiveOrZero(majorVersion, "majorVersion");
164 checkPositiveOrZero(minorVersion, "minorVersion");
165
166 this.protocolName = protocolName;
167 this.majorVersion = majorVersion;
168 this.minorVersion = minorVersion;
169 text = protocolName + '/' + majorVersion + '.' + minorVersion;
170 this.keepAliveDefault = keepAliveDefault;
171
172 if (bytes) {
173 this.bytes = text.getBytes(CharsetUtil.US_ASCII);
174 } else {
175 this.bytes = null;
176 }
177 }
178
179
180
181
182 public String protocolName() {
183 return protocolName;
184 }
185
186
187
188
189 public int majorVersion() {
190 return majorVersion;
191 }
192
193
194
195
196 public int minorVersion() {
197 return minorVersion;
198 }
199
200
201
202
203 public String text() {
204 return text;
205 }
206
207
208
209
210
211 public boolean isKeepAliveDefault() {
212 return keepAliveDefault;
213 }
214
215
216
217
218 @Override
219 public String toString() {
220 return text();
221 }
222
223 @Override
224 public int hashCode() {
225 return (protocolName().hashCode() * 31 + majorVersion()) * 31 +
226 minorVersion();
227 }
228
229 @Override
230 public boolean equals(Object o) {
231 if (!(o instanceof HttpVersion)) {
232 return false;
233 }
234
235 HttpVersion that = (HttpVersion) o;
236 return minorVersion() == that.minorVersion() &&
237 majorVersion() == that.majorVersion() &&
238 protocolName().equals(that.protocolName());
239 }
240
241 @Override
242 public int compareTo(HttpVersion o) {
243 int v = protocolName().compareTo(o.protocolName());
244 if (v != 0) {
245 return v;
246 }
247
248 v = majorVersion() - o.majorVersion();
249 if (v != 0) {
250 return v;
251 }
252
253 return minorVersion() - o.minorVersion();
254 }
255
256 void encode(ByteBuf buf) {
257 if (bytes == null) {
258 buf.writeCharSequence(text, CharsetUtil.US_ASCII);
259 } else {
260 buf.writeBytes(bytes);
261 }
262 }
263 }