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 }