1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package org.apache.commons.httpclient;
31
32 import org.apache.commons.httpclient.util.URIUtil;
33
34 /***
35 * The HTTP URL.
36 *
37 * @author <a href="mailto:jericho at apache.org">Sung-Gu</a>
38 * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
39 */
40 public class HttpURL extends URI {
41
42
43
44 /*** Create an instance as an internal use. */
45 protected HttpURL() {
46 }
47
48
49 /***
50 * Construct a HTTP URL as an escaped form of a character array with the
51 * given charset to do escape encoding.
52 *
53 * @param escaped the HTTP URL character sequence
54 * @param charset the charset string to do escape encoding
55 * @throws URIException If {@link #checkValid()} fails
56 * @throws NullPointerException if <code>escaped</code> is <code>null</code>
57 * @see #getProtocolCharset
58 */
59 public HttpURL(char[] escaped, String charset)
60 throws URIException, NullPointerException {
61 protocolCharset = charset;
62 parseUriReference(new String(escaped), true);
63 checkValid();
64 }
65
66
67 /***
68 * Construct a HTTP URL as an escaped form of a character array.
69 *
70 * @param escaped the HTTP URL character sequence
71 * @throws URIException If {@link #checkValid()} fails
72 * @throws NullPointerException if <code>escaped</code> is <code>null</code>
73 * @see #getDefaultProtocolCharset
74 */
75 public HttpURL(char[] escaped) throws URIException, NullPointerException {
76 parseUriReference(new String(escaped), true);
77 checkValid();
78 }
79
80
81 /***
82 * Construct a HTTP URL from a given string with the given charset to do
83 * escape encoding.
84 *
85 * @param original the HTTP URL string
86 * @param charset the charset string to do escape encoding
87 * @throws URIException If {@link #checkValid()} fails
88 * @see #getProtocolCharset
89 */
90 public HttpURL(String original, String charset) throws URIException {
91 protocolCharset = charset;
92 parseUriReference(original, false);
93 checkValid();
94 }
95
96
97 /***
98 * Construct a HTTP URL from a given string.
99 *
100 * @param original the HTTP URL string
101 * @throws URIException If {@link #checkValid()} fails
102 * @see #getDefaultProtocolCharset
103 */
104 public HttpURL(String original) throws URIException {
105 parseUriReference(original, false);
106 checkValid();
107 }
108
109
110 /***
111 * Construct a HTTP URL from given components.
112 *
113 * @param host the host string
114 * @param port the port number
115 * @param path the path string
116 * @throws URIException If {@link #checkValid()} fails
117 * @see #getDefaultProtocolCharset
118 */
119 public HttpURL(String host, int port, String path) throws URIException {
120 this(null, null, host, port, path, null, null);
121 }
122
123
124 /***
125 * Construct a HTTP URL from given components.
126 *
127 * @param host the host string
128 * @param port the port number
129 * @param path the path string
130 * @param query the query string
131 * @throws URIException If {@link #checkValid()} fails
132 * @see #getDefaultProtocolCharset
133 */
134 public HttpURL(String host, int port, String path, String query)
135 throws URIException {
136
137 this(null, null, host, port, path, query, null);
138 }
139
140
141 /***
142 * Construct a HTTP URL from given components.
143 *
144 * @param user the user name
145 * @param password his or her password
146 * @param host the host string
147 * @throws URIException If {@link #checkValid()} fails
148 * @see #getDefaultProtocolCharset
149 */
150 public HttpURL(String user, String password, String host)
151 throws URIException {
152
153 this(user, password, host, -1, null, null, null);
154 }
155
156
157 /***
158 * Construct a HTTP URL from given components.
159 *
160 * @param user the user name
161 * @param password his or her password
162 * @param host the host string
163 * @param port the port number
164 * @throws URIException If {@link #checkValid()} fails
165 * @see #getDefaultProtocolCharset
166 */
167 public HttpURL(String user, String password, String host, int port)
168 throws URIException {
169
170 this(user, password, host, port, null, null, null);
171 }
172
173
174 /***
175 * Construct a HTTP URL from given components.
176 *
177 * @param user the user name
178 * @param password his or her password
179 * @param host the host string
180 * @param port the port number
181 * @param path the path string
182 * @throws URIException If {@link #checkValid()} fails
183 * @see #getDefaultProtocolCharset
184 */
185 public HttpURL(String user, String password, String host, int port,
186 String path) throws URIException {
187
188 this(user, password, host, port, path, null, null);
189 }
190
191
192 /***
193 * Construct a HTTP URL from given components.
194 *
195 * @param user the user name
196 * @param password his or her password
197 * @param host the host string
198 * @param port the port number
199 * @param path the path string
200 * @param query The query string.
201 * @throws URIException If {@link #checkValid()} fails
202 * @see #getDefaultProtocolCharset
203 */
204 public HttpURL(String user, String password, String host, int port,
205 String path, String query) throws URIException {
206
207 this(user, password, host, port, path, query, null);
208 }
209
210
211 /***
212 * Construct a HTTP URL from given components.
213 *
214 * @param host the host string
215 * @param path the path string
216 * @param query the query string
217 * @param fragment the fragment string
218 * @throws URIException If {@link #checkValid()} fails
219 * @see #getDefaultProtocolCharset
220 */
221 public HttpURL(String host, String path, String query, String fragment)
222 throws URIException {
223
224 this(null, null, host, -1, path, query, fragment);
225 }
226
227
228 /***
229 * Construct a HTTP URL from given components.
230 *
231 * Note: The <code>userinfo</code> format is normally
232 * <code><username>:<password></code> where
233 * username and password must both be URL escaped.
234 *
235 * @param userinfo the userinfo string whose parts are URL escaped
236 * @param host the host string
237 * @param path the path string
238 * @param query the query string
239 * @param fragment the fragment string
240 * @throws URIException If {@link #checkValid()} fails
241 * @see #getDefaultProtocolCharset
242 */
243 public HttpURL(String userinfo, String host, String path, String query,
244 String fragment) throws URIException {
245
246 this(userinfo, host, -1, path, query, fragment);
247 }
248
249
250 /***
251 * Construct a HTTP URL from given components.
252 *
253 * Note: The <code>userinfo</code> format is normally
254 * <code><username>:<password></code> where
255 * username and password must both be URL escaped.
256 *
257 * @param userinfo the userinfo string whose parts are URL escaped
258 * @param host the host string
259 * @param port the port number
260 * @param path the path string
261 * @throws URIException If {@link #checkValid()} fails
262 * @see #getDefaultProtocolCharset
263 */
264 public HttpURL(String userinfo, String host, int port, String path)
265 throws URIException {
266
267 this(userinfo, host, port, path, null, null);
268 }
269
270
271 /***
272 * Construct a HTTP URL from given components.
273 *
274 * Note: The <code>userinfo</code> format is normally
275 * <code><username>:<password></code> where
276 * username and password must both be URL escaped.
277 *
278 * @param userinfo the userinfo string whose parts are URL escaped
279 * @param host the host string
280 * @param port the port number
281 * @param path the path string
282 * @param query the query string
283 * @throws URIException If {@link #checkValid()} fails
284 * @see #getDefaultProtocolCharset
285 */
286 public HttpURL(String userinfo, String host, int port, String path,
287 String query) throws URIException {
288
289 this(userinfo, host, port, path, query, null);
290 }
291
292
293 /***
294 * Construct a HTTP URL from given components.
295 *
296 * Note: The <code>userinfo</code> format is normally
297 * <code><username>:<password></code> where
298 * username and password must both be URL escaped.
299 *
300 * @param userinfo the userinfo string whose parts are URL escaped
301 * @param host the host string
302 * @param port the port number
303 * @param path the path string
304 * @param query the query string
305 * @param fragment the fragment string
306 * @throws URIException If {@link #checkValid()} fails
307 * @see #getDefaultProtocolCharset
308 */
309 public HttpURL(String userinfo, String host, int port, String path,
310 String query, String fragment) throws URIException {
311
312
313 StringBuffer buff = new StringBuffer();
314 if (userinfo != null || host != null || port != -1) {
315 _scheme = DEFAULT_SCHEME;
316 buff.append(_default_scheme);
317 buff.append("://");
318 if (userinfo != null) {
319 buff.append(userinfo);
320 buff.append('@');
321 }
322 if (host != null) {
323 buff.append(URIUtil.encode(host, URI.allowed_host));
324 if (port != -1 || port != DEFAULT_PORT) {
325 buff.append(':');
326 buff.append(port);
327 }
328 }
329 }
330 if (path != null) {
331 if (scheme != null && !path.startsWith("/")) {
332 throw new URIException(URIException.PARSING,
333 "abs_path requested");
334 }
335 buff.append(URIUtil.encode(path, URI.allowed_abs_path));
336 }
337 if (query != null) {
338 buff.append('?');
339 buff.append(URIUtil.encode(query, URI.allowed_query));
340 }
341 if (fragment != null) {
342 buff.append('#');
343 buff.append(URIUtil.encode(fragment, URI.allowed_fragment));
344 }
345 parseUriReference(buff.toString(), true);
346 checkValid();
347 }
348
349
350 /***
351 * Construct a HTTP URL from given components.
352 *
353 * @param user the user name
354 * @param password his or her password
355 * @param host the host string
356 * @param port the port number
357 * @param path the path string
358 * @param query the query string
359 * @param fragment the fragment string
360 * @throws URIException If {@link #checkValid()} fails
361 * @see #getDefaultProtocolCharset
362 */
363 public HttpURL(String user, String password, String host, int port,
364 String path, String query, String fragment) throws URIException {
365 this(toUserinfo(user, password), host, port, path, query, fragment);
366 }
367
368 protected static String toUserinfo(String user, String password) throws URIException {
369 if (user == null) return null;
370 StringBuffer usrinfo = new StringBuffer(20);
371 usrinfo.append(URIUtil.encode(user, URI.allowed_within_userinfo));
372 if (password == null) return usrinfo.toString();
373 usrinfo.append(':');
374 usrinfo.append(URIUtil.encode(password, URI.allowed_within_userinfo));
375 return usrinfo.toString();
376 }
377
378
379 /***
380 * Construct a HTTP URL with a given relative URL string.
381 *
382 * @param base the base HttpURL
383 * @param relative the relative HTTP URL string
384 * @throws URIException If {@link #checkValid()} fails
385 */
386 public HttpURL(HttpURL base, String relative) throws URIException {
387 this(base, new HttpURL(relative));
388 }
389
390
391 /***
392 * Construct a HTTP URL with a given relative URL.
393 *
394 * @param base the base HttpURL
395 * @param relative the relative HttpURL
396 * @throws URIException If {@link #checkValid()} fails
397 */
398 public HttpURL(HttpURL base, HttpURL relative) throws URIException {
399 super(base, relative);
400 checkValid();
401 }
402
403
404
405 /***
406 * Default scheme for HTTP URL.
407 */
408 public static final char[] DEFAULT_SCHEME = { 'h', 't', 't', 'p' };
409
410 /***
411 * Default scheme for HTTP URL.
412 * @deprecated Use {@link #DEFAULT_SCHEME} instead. This one doesn't
413 * conform to the project naming conventions.
414 */
415 public static final char[] _default_scheme = DEFAULT_SCHEME;
416
417 /***
418 * Default port for HTTP URL.
419 */
420 public static final int DEFAULT_PORT = 80;
421
422 /***
423 * Default port for HTTP URL.
424 * @deprecated Use {@link #DEFAULT_PORT} instead. This one doesn't conform
425 * to the project naming conventions.
426 */
427 public static final int _default_port = DEFAULT_PORT;
428
429 /***
430 * The serialVersionUID.
431 */
432 static final long serialVersionUID = -7158031098595039459L;
433
434
435
436 /***
437 * Get the scheme. You can get the scheme explicitly.
438 *
439 * @return the scheme
440 */
441 public char[] getRawScheme() {
442 return (_scheme == null) ? null : HttpURL.DEFAULT_SCHEME;
443 }
444
445
446 /***
447 * Get the scheme. You can get the scheme explicitly.
448 *
449 * @return the scheme null if empty or undefined
450 */
451 public String getScheme() {
452 return (_scheme == null) ? null : new String(HttpURL.DEFAULT_SCHEME);
453 }
454
455
456
457 /***
458 * Get the port number.
459 * @return the port number
460 */
461 public int getPort() {
462 return (_port == -1) ? HttpURL.DEFAULT_PORT : _port;
463 }
464
465
466
467 /***
468 * Set the raw-escaped user and password.
469 *
470 * @param escapedUser the raw-escaped user
471 * @param escapedPassword the raw-escaped password; could be null
472 * @throws URIException escaped user not valid or user required; escaped
473 * password not valid or username missed
474 */
475 public void setRawUserinfo(char[] escapedUser, char[] escapedPassword)
476 throws URIException {
477
478 if (escapedUser == null || escapedUser.length == 0) {
479 throw new URIException(URIException.PARSING, "user required");
480 }
481 if (!validate(escapedUser, within_userinfo)
482 || ((escapedPassword != null)
483 && !validate(escapedPassword, within_userinfo))) {
484 throw new URIException(URIException.ESCAPING,
485 "escaped userinfo not valid");
486 }
487 String username = new String(escapedUser);
488 String password = (escapedPassword == null)
489 ? null : new String(escapedPassword);
490 String userinfo = username + ((password == null) ? "" : ":" + password);
491 String hostname = new String(getRawHost());
492 String hostport = (_port == -1) ? hostname : hostname + ":" + _port;
493 String authority = userinfo + "@" + hostport;
494 _userinfo = userinfo.toCharArray();
495 _authority = authority.toCharArray();
496 setURI();
497 }
498
499
500 /***
501 * Set the raw-escaped user and password.
502 *
503 * @param escapedUser the escaped user
504 * @param escapedPassword the escaped password; could be null
505 * @throws URIException escaped user not valid or user required; escaped
506 * password not valid or username missed
507 * @throws NullPointerException null user
508 */
509 public void setEscapedUserinfo(String escapedUser, String escapedPassword)
510 throws URIException, NullPointerException {
511
512 setRawUserinfo(escapedUser.toCharArray(), (escapedPassword == null)
513 ? null : escapedPassword.toCharArray());
514 }
515
516
517 /***
518 * Set the user and password.
519 *
520 * @param user the user
521 * @param password the password; could be null
522 * @throws URIException encoding error or username missed
523 * @throws NullPointerException null user
524 */
525 public void setUserinfo(String user, String password)
526 throws URIException, NullPointerException {
527
528 String charset = getProtocolCharset();
529 setRawUserinfo(encode(user, within_userinfo, charset),
530 (password == null)
531 ? null
532 : encode(password, within_userinfo, charset));
533 }
534
535
536 /***
537 * Set the raw-escaped user.
538 *
539 * @param escapedUser the raw-escaped user
540 * @throws URIException escaped user not valid or user required
541 */
542 public void setRawUser(char[] escapedUser) throws URIException {
543 if (escapedUser == null || escapedUser.length == 0) {
544 throw new URIException(URIException.PARSING, "user required");
545 }
546 if (!validate(escapedUser, within_userinfo)) {
547 throw new URIException(URIException.ESCAPING,
548 "escaped user not valid");
549 }
550 String username = new String(escapedUser);
551 String password = new String(getRawPassword());
552 String userinfo = username + ((password == null) ? "" : ":" + password);
553 String hostname = new String(getRawHost());
554 String hostport = (_port == -1) ? hostname : hostname + ":" + _port;
555 String authority = userinfo + "@" + hostport;
556 _userinfo = userinfo.toCharArray();
557 _authority = authority.toCharArray();
558 setURI();
559 }
560
561
562 /***
563 * Set the escaped user string.
564 *
565 * @param escapedUser the escaped user string
566 * @throws URIException escaped user not valid
567 * @throws NullPointerException null user
568 */
569 public void setEscapedUser(String escapedUser)
570 throws URIException, NullPointerException {
571 setRawUser(escapedUser.toCharArray());
572 }
573
574
575 /***
576 * Set the user string.
577 *
578 * @param user the user string
579 * @throws URIException user encoding error
580 * @throws NullPointerException null user
581 */
582 public void setUser(String user) throws URIException, NullPointerException {
583 setRawUser(encode(user, allowed_within_userinfo, getProtocolCharset()));
584 }
585
586
587 /***
588 * Get the raw-escaped user.
589 *
590 * @return the raw-escaped user
591 */
592 public char[] getRawUser() {
593 if (_userinfo == null || _userinfo.length == 0) {
594 return null;
595 }
596 int to = indexFirstOf(_userinfo, ':');
597
598 if (to == -1) {
599 return _userinfo;
600 }
601 char[] result = new char[to];
602 System.arraycopy(_userinfo, 0, result, 0, to);
603 return result;
604 }
605
606
607 /***
608 * Get the escaped user
609 *
610 * @return the escaped user
611 */
612 public String getEscapedUser() {
613 char[] user = getRawUser();
614 return (user == null) ? null : new String(user);
615 }
616
617
618 /***
619 * Get the user.
620 *
621 * @return the user name
622 * @throws URIException If {@link #decode} fails
623 */
624 public String getUser() throws URIException {
625 char[] user = getRawUser();
626 return (user == null) ? null : decode(user, getProtocolCharset());
627 }
628
629
630 /***
631 * Set the raw-escaped password.
632 *
633 * @param escapedPassword the raw-escaped password; could be null
634 * @throws URIException escaped password not valid or username missed
635 */
636 public void setRawPassword(char[] escapedPassword) throws URIException {
637 if (escapedPassword != null
638 && !validate(escapedPassword, within_userinfo)) {
639 throw new URIException(URIException.ESCAPING,
640 "escaped password not valid");
641 }
642 if (getRawUser() == null || getRawUser().length == 0) {
643 throw new URIException(URIException.PARSING, "username required");
644 }
645 String username = new String(getRawUser());
646 String password = new String(escapedPassword);
647
648 String userinfo = username + ((password == null) ? "" : ":" + password);
649 String hostname = new String(getRawHost());
650 String hostport = (_port == -1) ? hostname : hostname + ":" + _port;
651 String authority = userinfo + "@" + hostport;
652 _userinfo = userinfo.toCharArray();
653 _authority = authority.toCharArray();
654 setURI();
655 }
656
657
658 /***
659 * Set the escaped password string.
660 *
661 * @param escapedPassword the escaped password string; could be null
662 * @throws URIException escaped password not valid or username missed
663 */
664 public void setEscapedPassword(String escapedPassword) throws URIException {
665 setRawPassword((escapedPassword == null) ? null
666 : escapedPassword.toCharArray());
667 }
668
669
670 /***
671 * Set the password string.
672 *
673 * @param password the password string; could be null
674 * @throws URIException encoding error or username missed
675 */
676 public void setPassword(String password) throws URIException {
677 setRawPassword((password == null) ? null : encode(password,
678 allowed_within_userinfo, getProtocolCharset()));
679 }
680
681
682 /***
683 * Get the raw-escaped password.
684 *
685 * @return the raw-escaped password
686 */
687 public char[] getRawPassword() {
688 int from = indexFirstOf(_userinfo, ':');
689 if (from == -1) {
690 return null;
691 }
692 int len = _userinfo.length - from - 1;
693 char[] result = new char[len];
694 System.arraycopy(_userinfo, from + 1, result, 0, len);
695 return result;
696 }
697
698
699 /***
700 * Get the escaped password.
701 *
702 * @return the escaped password
703 */
704 public String getEscapedPassword() {
705 char[] password = getRawPassword();
706 return (password == null) ? null : new String(password);
707 }
708
709
710 /***
711 * Get the password.
712 *
713 * @return the password
714 * @throws URIException If {@link #decode(char[],String)} fails.
715 */
716 public String getPassword() throws URIException {
717 char[] password = getRawPassword();
718 return (password == null) ? null : decode(password,
719 getProtocolCharset());
720 }
721
722
723
724 /***
725 * Get the raw-escaped current hierarchy level.
726 *
727 * @return the raw-escaped current hierarchy level
728 * @throws URIException If {@link #getRawCurrentHierPath(char[])} fails.
729 */
730 public char[] getRawCurrentHierPath() throws URIException {
731 return (_path == null || _path.length == 0) ? rootPath
732 : super.getRawCurrentHierPath(_path);
733 }
734
735
736 /***
737 * Get the level above the this hierarchy level.
738 *
739 * @return the raw above hierarchy level
740 * @throws URIException If {@link #getRawCurrentHierPath(char[])} fails.
741 */
742 public char[] getRawAboveHierPath() throws URIException {
743 char[] path = getRawCurrentHierPath();
744 return (path == null || path.length == 0) ? rootPath : getRawCurrentHierPath(path);
745 }
746
747
748 /***
749 * Get the raw escaped path.
750 *
751 * @return the path '/' if empty or undefined
752 */
753 public char[] getRawPath() {
754 char[] path = super.getRawPath();
755 return (path == null || path.length == 0) ? rootPath : path;
756 }
757
758
759
760 /***
761 * Set the query as the name and value pair.
762 *
763 * @param queryName the query string.
764 * @param queryValue the query string.
765 * @throws URIException incomplete trailing escape pattern
766 * Or unsupported character encoding
767 * @throws NullPointerException null query
768 * @see #encode
769 */
770 public void setQuery(String queryName, String queryValue)
771 throws URIException, NullPointerException {
772
773 StringBuffer buff = new StringBuffer();
774
775 String charset = getProtocolCharset();
776 buff.append(encode(queryName, allowed_within_query, charset));
777 buff.append('=');
778 buff.append(encode(queryValue, allowed_within_query, charset));
779 _query = buff.toString().toCharArray();
780 setURI();
781 }
782
783
784 /***
785 * Set the query as the name and value pairs.
786 *
787 * @param queryName the array of the query string.
788 * @param queryValue the array of the query string.
789 * @throws URIException incomplete trailing escape pattern,
790 * unsupported character encoding or wrong array size
791 * @throws NullPointerException null query
792 * @see #encode
793 */
794 public void setQuery(String[] queryName, String[] queryValue)
795 throws URIException, NullPointerException {
796
797 int length = queryName.length;
798 if (length != queryValue.length) {
799 throw new URIException("wrong array size of query");
800 }
801
802 StringBuffer buff = new StringBuffer();
803
804 String charset = getProtocolCharset();
805 for (int i = 0; i < length; i++) {
806 buff.append(encode(queryName[i], allowed_within_query, charset));
807 buff.append('=');
808 buff.append(encode(queryValue[i], allowed_within_query, charset));
809 if (i + 1 < length) {
810 buff.append('&');
811 }
812 }
813 _query = buff.toString().toCharArray();
814 setURI();
815 }
816
817
818
819 /***
820 * Verify the valid class use for construction.
821 *
822 * @throws URIException the wrong scheme use
823 */
824 protected void checkValid() throws URIException {
825
826 if (!(equals(_scheme, DEFAULT_SCHEME) || _scheme == null)) {
827 throw new URIException(URIException.PARSING, "wrong class use");
828 }
829 }
830
831 /***
832 * Once it's parsed successfully, set this URI.
833 *
834 * @see #getRawURI
835 */
836 protected void setURI() {
837
838 StringBuffer buf = new StringBuffer();
839
840 if (_scheme != null) {
841 buf.append(_scheme);
842 buf.append(':');
843 }
844 if (_is_net_path) {
845 buf.append("//");
846 if (_authority != null) {
847 if (_userinfo != null) {
848 if (_host != null) {
849 buf.append(_host);
850 if (_port != -1) {
851 buf.append(':');
852 buf.append(_port);
853 }
854 }
855 } else {
856 buf.append(_authority);
857 }
858 }
859 }
860 if (_opaque != null && _is_opaque_part) {
861 buf.append(_opaque);
862 } else if (_path != null) {
863
864 if (_path.length != 0) {
865 buf.append(_path);
866 }
867 }
868 if (_query != null) {
869 buf.append('?');
870 buf.append(_query);
871 }
872
873 _uri = buf.toString().toCharArray();
874 hash = 0;
875 }
876
877 }
878