1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.mortbay.jetty;
16
17 import java.io.UnsupportedEncodingException;
18
19 import org.mortbay.util.MultiMap;
20 import org.mortbay.util.StringUtil;
21 import org.mortbay.util.TypeUtil;
22 import org.mortbay.util.URIUtil;
23 import org.mortbay.util.UrlEncoded;
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 public class HttpURI
43 {
44 private static byte[] __empty={};
45 private final static int
46 START=0,
47 AUTH_OR_PATH=1,
48 SCHEME_OR_PATH=2,
49 AUTH=4,
50 IPV6=5,
51 PORT=6,
52 PATH=7,
53 PARAM=8,
54 QUERY=9,
55 ASTERISK=10;
56
57 boolean _partial=false;
58 byte[] _raw=__empty;
59 String _rawString;
60 int _scheme;
61 int _authority;
62 int _host;
63 int _port;
64 int _path;
65 int _param;
66 int _query;
67 int _fragment;
68 int _end;
69
70 public HttpURI()
71 {
72
73 }
74
75
76
77
78
79 public HttpURI(boolean parsePartialAuth)
80 {
81 _partial=parsePartialAuth;
82 }
83
84 public HttpURI(String raw)
85 {
86 _rawString=raw;
87 byte[] b = raw.getBytes();
88 parse(b,0,b.length);
89 }
90
91 public HttpURI(byte[] raw,int offset, int length)
92 {
93 parse2(raw,offset,length);
94 }
95
96 public void parse(String raw)
97 {
98 byte[] b = raw.getBytes();
99 parse2(b,0,b.length);
100 _rawString=raw;
101 }
102
103 public void parse(byte[] raw,int offset, int length)
104 {
105 _rawString=null;
106 parse2(raw,offset,length);
107 }
108
109 private void parse2(byte[] raw,int offset, int length)
110 {
111 _raw=raw;
112 int i=offset;
113 int e=offset+length;
114 int state=START;
115 int m=offset;
116 _end=offset+length;
117 _scheme=offset;
118 _authority=offset;
119 _host=offset;
120 _port=offset;
121 _path=offset;
122 _param=_end;
123 _query=_end;
124 _fragment=_end;
125 while (i<e)
126 {
127 char c=(char)(0xff&_raw[i]);
128 int s=i++;
129
130 state: switch (state)
131 {
132 case START:
133 {
134 m=s;
135 switch(c)
136 {
137 case '/':
138 state=AUTH_OR_PATH;
139 break;
140 case ';':
141 _param=s;
142 state=PARAM;
143 break;
144 case '?':
145 _param=s;
146 _query=s;
147 state=QUERY;
148 break;
149 case '#':
150 _param=s;
151 _query=s;
152 _fragment=s;
153 break;
154 case '*':
155 _path=s;
156 state=ASTERISK;
157 break;
158
159 default:
160 if (Character.isLetterOrDigit(c))
161 state=SCHEME_OR_PATH;
162 else
163 throw new IllegalArgumentException(StringUtil.toString(_raw,offset,length,URIUtil.__CHARSET));
164 }
165
166 continue;
167 }
168
169 case AUTH_OR_PATH:
170 {
171 if ((_partial||_scheme!=_authority) && c=='/')
172 {
173 _host=i;
174 _port=_end;
175 _path=_end;
176 state=AUTH;
177 }
178 else if (c==';' || c=='?' || c=='#')
179 {
180 i--;
181 state=PATH;
182 }
183 else
184 {
185 _host=m;
186 _port=m;
187 state=PATH;
188 }
189 continue;
190 }
191
192 case SCHEME_OR_PATH:
193 {
194
195 if (length>6 && c=='t')
196 {
197 if (_raw[offset+3]==':')
198 {
199 s=offset+3;
200 i=offset+4;
201 c=':';
202 }
203 else if (_raw[offset+4]==':')
204 {
205 s=offset+4;
206 i=offset+5;
207 c=':';
208 }
209 else if (_raw[offset+5]==':')
210 {
211 s=offset+5;
212 i=offset+6;
213 c=':';
214 }
215 }
216
217 switch (c)
218 {
219 case ':':
220 {
221 m = i++;
222 _authority = m;
223 _path = m;
224 c = (char)(0xff & _raw[i]);
225 if (c == '/')
226 state = AUTH_OR_PATH;
227 else
228 {
229 _host = m;
230 _port = m;
231 state = PATH;
232 }
233 break;
234 }
235
236 case '/':
237 {
238 state = PATH;
239 break;
240 }
241
242 case ';':
243 {
244 _param = s;
245 state = PARAM;
246 break;
247 }
248
249 case '?':
250 {
251 _param = s;
252 _query = s;
253 state = QUERY;
254 break;
255 }
256
257 case '#':
258 {
259 _param = s;
260 _query = s;
261 _fragment = s;
262 break;
263 }
264 }
265 continue;
266 }
267
268 case AUTH:
269 {
270 switch (c)
271 {
272
273 case '/':
274 {
275 m = s;
276 _path = m;
277 _port = _path;
278 state = PATH;
279 break;
280 }
281 case '@':
282 {
283 _host = i;
284 break;
285 }
286 case ':':
287 {
288 _port = s;
289 state = PORT;
290 break;
291 }
292 case '[':
293 {
294 state = IPV6;
295 break;
296 }
297 }
298 continue;
299 }
300
301 case IPV6:
302 {
303 switch (c)
304 {
305 case '/':
306 {
307 throw new IllegalArgumentException("No closing ']' for " + StringUtil.toString(_raw,offset,length,URIUtil.__CHARSET));
308 }
309 case ']':
310 {
311 state = AUTH;
312 break;
313 }
314 }
315
316 continue;
317 }
318
319 case PORT:
320 {
321 if (c=='/')
322 {
323 m=s;
324 _path=m;
325 if (_port<=_authority)
326 _port=_path;
327 state=PATH;
328 }
329 continue;
330 }
331
332 case PATH:
333 {
334 switch (c)
335 {
336 case ';':
337 {
338 _param = s;
339 state = PARAM;
340 break;
341 }
342 case '?':
343 {
344 _param = s;
345 _query = s;
346 state = QUERY;
347 break;
348 }
349 case '#':
350 {
351 _param = s;
352 _query = s;
353 _fragment = s;
354 break state;
355 }
356 }
357 continue;
358 }
359
360 case PARAM:
361 {
362 switch (c)
363 {
364 case '?':
365 {
366 _query = s;
367 state = QUERY;
368 break;
369 }
370 case '#':
371 {
372 _query = s;
373 _fragment = s;
374 break state;
375 }
376 }
377 continue;
378 }
379
380 case QUERY:
381 {
382 if (c=='#')
383 {
384 _fragment=s;
385 break state;
386 }
387 continue;
388 }
389
390 case ASTERISK:
391 {
392 throw new IllegalArgumentException("only '*'");
393 }
394 }
395 }
396 }
397
398
399 public String getScheme()
400 {
401 if (_scheme==_authority)
402 return null;
403 int l=_authority-_scheme;
404 if (l==5 &&
405 _raw[_scheme]=='h' &&
406 _raw[_scheme+1]=='t' &&
407 _raw[_scheme+2]=='t' &&
408 _raw[_scheme+3]=='p' )
409 return HttpSchemes.HTTP;
410 if (l==6 &&
411 _raw[_scheme]=='h' &&
412 _raw[_scheme+1]=='t' &&
413 _raw[_scheme+2]=='t' &&
414 _raw[_scheme+3]=='p' &&
415 _raw[_scheme+4]=='s' )
416 return HttpSchemes.HTTPS;
417 return StringUtil.toString(_raw,_scheme,_authority-_scheme-1,URIUtil.__CHARSET);
418 }
419
420 public String getAuthority()
421 {
422 if (_authority==_path)
423 return null;
424 return StringUtil.toString(_raw,_authority,_path-_authority,URIUtil.__CHARSET);
425 }
426
427 public String getHost()
428 {
429 if (_host==_port)
430 return null;
431 return StringUtil.toString(_raw,_host,_port-_host,URIUtil.__CHARSET);
432 }
433
434 public int getPort()
435 {
436 if (_port==_path)
437 return -1;
438 return TypeUtil.parseInt(_raw, _port+1, _path-_port-1,10);
439 }
440
441 public String getPath()
442 {
443 if (_path==_param)
444 return null;
445 return StringUtil.toString(_raw,_path,_param-_path,URIUtil.__CHARSET);
446 }
447
448 public String getDecodedPath()
449 {
450 if (_path==_param)
451 return null;
452 return URIUtil.decodePath(_raw,_path,_param-_path);
453 }
454
455 public String getPathAndParam()
456 {
457 if (_path==_query)
458 return null;
459 return StringUtil.toString(_raw,_path,_query-_path,URIUtil.__CHARSET);
460 }
461
462 public String getCompletePath()
463 {
464 if (_path==_end)
465 return null;
466 return StringUtil.toString(_raw,_path,_end-_path,URIUtil.__CHARSET);
467 }
468
469 public String getParam()
470 {
471 if (_param==_query)
472 return null;
473 return StringUtil.toString(_raw,_param+1,_query-_param-1,URIUtil.__CHARSET);
474 }
475
476 public String getQuery()
477 {
478 if (_query==_fragment)
479 return null;
480 return StringUtil.toString(_raw,_query+1,_fragment-_query-1,URIUtil.__CHARSET);
481 }
482
483 public String getQuery(String encoding)
484 {
485 if (_query==_fragment)
486 return null;
487 return StringUtil.toString(_raw,_query+1,_fragment-_query-1,encoding==null?URIUtil.__CHARSET:encoding);
488 }
489
490 public String getFragment()
491 {
492 if (_fragment==_end)
493 return null;
494 return StringUtil.toString(_raw,_fragment+1,_end-_fragment-1,URIUtil.__CHARSET);
495 }
496
497 public void decodeQueryTo(MultiMap parameters, String encoding)
498 throws UnsupportedEncodingException
499 {
500 if (_query==_fragment)
501 return;
502
503 if (encoding==null)
504 encoding=URIUtil.__CHARSET;
505
506 if (StringUtil.isUTF8(encoding))
507 UrlEncoded.decodeUtf8To(_raw,_query+1,_fragment-_query-1,parameters);
508 else
509 UrlEncoded.decodeTo(StringUtil.toString(_raw,_query+1,_fragment-_query-1,encoding),parameters,encoding);
510 }
511
512 public void clear()
513 {
514 _scheme=_authority=_host=_port=_path=_param=_query=_fragment=_end=0;
515 _raw=__empty;
516 _rawString="";
517 }
518
519 public String toString()
520 {
521 if (_rawString==null)
522 _rawString= StringUtil.toString(_raw,_scheme,_end-_scheme,URIUtil.__CHARSET);
523 return _rawString;
524 }
525
526 }