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