1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.handler.codec.http;
17
18 import io.netty5.buffer.api.Buffer;
19 import io.netty5.util.CharsetUtil;
20
21 import java.util.regex.Matcher;
22 import java.util.regex.Pattern;
23
24 import static io.netty5.util.internal.ObjectUtil.checkNonEmptyAfterTrim;
25 import static io.netty5.util.internal.ObjectUtil.checkPositiveOrZero;
26 import static java.util.Objects.requireNonNull;
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 private static final String HTTP_1_0_STRING = "HTTP/1.0";
39 private 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 requireNonNull(text, "text");
61
62 text = text.trim();
63
64 if (text.isEmpty()) {
65 throw new IllegalArgumentException("text is empty (possibly HTTP/0.9)");
66 }
67
68
69
70
71
72
73
74
75
76 HttpVersion version = version0(text);
77 if (version == null) {
78 version = new HttpVersion(text, true);
79 }
80 return version;
81 }
82
83 private static HttpVersion version0(String text) {
84 if (HTTP_1_1_STRING.equals(text)) {
85 return HTTP_1_1;
86 }
87 if (HTTP_1_0_STRING.equals(text)) {
88 return HTTP_1_0;
89 }
90 return null;
91 }
92
93 private final String protocolName;
94 private final int majorVersion;
95 private final int minorVersion;
96 private final String text;
97 private final boolean keepAliveDefault;
98 private final byte[] bytes;
99
100
101
102
103
104
105
106
107
108
109
110
111 public HttpVersion(String text, boolean keepAliveDefault) {
112 text = checkNonEmptyAfterTrim(text, "text").toUpperCase();
113
114 Matcher m = VERSION_PATTERN.matcher(text);
115 if (!m.matches()) {
116 throw new IllegalArgumentException("invalid version format: " + text);
117 }
118
119 protocolName = m.group(1);
120 majorVersion = Integer.parseInt(m.group(2));
121 minorVersion = Integer.parseInt(m.group(3));
122 this.text = protocolName + '/' + majorVersion + '.' + minorVersion;
123 this.keepAliveDefault = keepAliveDefault;
124 bytes = null;
125 }
126
127
128
129
130
131
132
133
134
135
136
137
138 public HttpVersion(
139 String protocolName, int majorVersion, int minorVersion,
140 boolean keepAliveDefault) {
141 this(protocolName, majorVersion, minorVersion, keepAliveDefault, false);
142 }
143
144 private HttpVersion(
145 String protocolName, int majorVersion, int minorVersion,
146 boolean keepAliveDefault, boolean bytes) {
147 protocolName = checkNonEmptyAfterTrim(protocolName, "protocolName").toUpperCase();
148
149 for (int i = 0; i < protocolName.length(); i ++) {
150 if (Character.isISOControl(protocolName.charAt(i)) ||
151 Character.isWhitespace(protocolName.charAt(i))) {
152 throw new IllegalArgumentException("invalid character in protocolName");
153 }
154 }
155
156 checkPositiveOrZero(majorVersion, "majorVersion");
157 checkPositiveOrZero(minorVersion, "minorVersion");
158
159 this.protocolName = protocolName;
160 this.majorVersion = majorVersion;
161 this.minorVersion = minorVersion;
162 text = protocolName + '/' + majorVersion + '.' + minorVersion;
163 this.keepAliveDefault = keepAliveDefault;
164
165 if (bytes) {
166 this.bytes = text.getBytes(CharsetUtil.US_ASCII);
167 } else {
168 this.bytes = null;
169 }
170 }
171
172
173
174
175 public String protocolName() {
176 return protocolName;
177 }
178
179
180
181
182 public int majorVersion() {
183 return majorVersion;
184 }
185
186
187
188
189 public int minorVersion() {
190 return minorVersion;
191 }
192
193
194
195
196 public String text() {
197 return text;
198 }
199
200
201
202
203
204 public boolean isKeepAliveDefault() {
205 return keepAliveDefault;
206 }
207
208
209
210
211 @Override
212 public String toString() {
213 return text();
214 }
215
216 @Override
217 public int hashCode() {
218 return (protocolName().hashCode() * 31 + majorVersion()) * 31 +
219 minorVersion();
220 }
221
222 @Override
223 public boolean equals(Object o) {
224 if (!(o instanceof HttpVersion)) {
225 return false;
226 }
227
228 HttpVersion that = (HttpVersion) o;
229 return minorVersion() == that.minorVersion() &&
230 majorVersion() == that.majorVersion() &&
231 protocolName().equals(that.protocolName());
232 }
233
234 @Override
235 public int compareTo(HttpVersion o) {
236 int v = protocolName().compareTo(o.protocolName());
237 if (v != 0) {
238 return v;
239 }
240
241 v = majorVersion() - o.majorVersion();
242 if (v != 0) {
243 return v;
244 }
245
246 return minorVersion() - o.minorVersion();
247 }
248
249 void encode(Buffer buf) {
250 if (bytes == null) {
251 buf.writeCharSequence(text, CharsetUtil.US_ASCII);
252 } else {
253 buf.writeBytes(bytes);
254 }
255 }
256 }