View Javadoc

1   /*
2    * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpURL.java,v 1.17 2004/05/02 15:19:15 mbecke Exp $
3    * $Revision: 1.17 $
4    * $Date: 2004/05/02 15:19:15 $
5    *
6    * ====================================================================
7    *
8    *  Copyright 2002-2004 The Apache Software Foundation
9    *
10   *  Licensed under the Apache License, Version 2.0 (the "License");
11   *  you may not use this file except in compliance with the License.
12   *  You may obtain a copy of the License at
13   *
14   *      http://www.apache.org/licenses/LICENSE-2.0
15   *
16   *  Unless required by applicable law or agreed to in writing, software
17   *  distributed under the License is distributed on an "AS IS" BASIS,
18   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19   *  See the License for the specific language governing permissions and
20   *  limitations under the License.
21   * ====================================================================
22   *
23   * This software consists of voluntary contributions made by many
24   * individuals on behalf of the Apache Software Foundation.  For more
25   * information on the Apache Software Foundation, please see
26   * <http://www.apache.org/>.
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      // ----------------------------------------------------------- Constructors
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, host, port, path, null, null);
121         checkValid();
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, host, port, path, query, null);
139         checkValid();
140     }
141 
142 
143     /***
144      * Construct a HTTP URL from given components.
145      *
146      * @param user the user name
147      * @param password his or her password
148      * @param host the host string
149      * @throws URIException If {@link #checkValid()} fails
150      * @see #getDefaultProtocolCharset
151      */
152     public HttpURL(String user, String password, String host)
153         throws URIException {
154 
155         this((user == null) ? null : user 
156             + ((password == null) ? "" : ':' +  password),
157                 host, -1, null, null, null);
158         checkValid();
159     }
160 
161 
162     /***
163      * Construct a HTTP URL from given components.
164      *
165      * @param user the user name
166      * @param password his or her password
167      * @param host the host string
168      * @param port the port number
169      * @throws URIException If {@link #checkValid()} fails
170      * @see #getDefaultProtocolCharset
171      */
172     public HttpURL(String user, String password, String host, int port)
173         throws URIException {
174 
175         this((user == null) ? null : user 
176             + ((password == null) ? "" : ':' +  password),
177                 host, port, null, null, null);
178         checkValid();
179     }
180 
181 
182     /***
183      * Construct a HTTP URL from given components.
184      *
185      * @param user the user name
186      * @param password his or her password
187      * @param host the host string
188      * @param port the port number
189      * @param path the path string
190      * @throws URIException If {@link #checkValid()} fails
191      * @see #getDefaultProtocolCharset
192      */
193     public HttpURL(String user, String password, String host, int port,
194             String path) throws URIException {
195 
196         this((user == null) ? null : user 
197             + ((password == null) ? "" : ':' +  password),
198                 host, port, path, null, null);
199         checkValid();
200     }
201 
202 
203     /***
204      * Construct a HTTP URL from given components.
205      *
206      * @param user the user name
207      * @param password his or her password
208      * @param host the host string
209      * @param port the port number
210      * @param path the path string
211      * @param query The query string.
212      * @throws URIException If {@link #checkValid()} fails
213      * @see #getDefaultProtocolCharset
214      */
215     public HttpURL(String user, String password, String host, int port,
216             String path, String query) throws URIException {
217 
218         this((user == null) ? null : user 
219             + ((password == null) ? "" : ':' + password),
220                 host, port, path, query, null);
221         checkValid();
222     }
223 
224 
225     /***
226      * Construct a HTTP URL from given components.
227      *
228      * @param host the host string
229      * @param path the path string
230      * @param query the query string
231      * @param fragment the fragment string
232      * @throws URIException If {@link #checkValid()} fails
233      * @see #getDefaultProtocolCharset
234      */
235     public HttpURL(String host, String path, String query, String fragment)
236         throws URIException {
237 
238         this(null, host, -1, path, query, fragment);
239         checkValid();
240     }
241 
242 
243     /***
244      * Construct a HTTP URL from given components.
245      *
246      * @param userinfo the userinfo string
247      * @param host the host string
248      * @param path the path string
249      * @param query the query string
250      * @param fragment the fragment string
251      * @throws URIException If {@link #checkValid()} fails
252      * @see #getDefaultProtocolCharset
253      */
254     public HttpURL(String userinfo, String host, String path, String query,
255             String fragment) throws URIException {
256 
257         this(userinfo, host, -1, path, query, fragment);
258         checkValid();
259     }
260 
261 
262     /***
263      * Construct a HTTP URL from given components.
264      *
265      * @param userinfo the userinfo string
266      * @param host the host string
267      * @param port the port number
268      * @param path the path string
269      * @throws URIException If {@link #checkValid()} fails
270      * @see #getDefaultProtocolCharset
271      */
272     public HttpURL(String userinfo, String host, int port, String path)
273         throws URIException {
274 
275         this(userinfo, host, port, path, null, null);
276         checkValid();
277     }
278 
279 
280     /***
281      * Construct a HTTP URL from given components.
282      *
283      * @param userinfo the userinfo string
284      * @param host the host string
285      * @param port the port number
286      * @param path the path string
287      * @param query the query string
288      * @throws URIException If {@link #checkValid()} fails
289      * @see #getDefaultProtocolCharset
290      */
291     public HttpURL(String userinfo, String host, int port, String path,
292             String query) throws URIException {
293 
294         this(userinfo, host, port, path, query, null);
295         checkValid();
296     }
297 
298 
299     /***
300      * Construct a HTTP URL from given components.
301      *
302      * @param userinfo the userinfo string
303      * @param host the host string
304      * @param port the port number
305      * @param path the path string
306      * @param query the query string
307      * @param fragment the fragment string
308      * @throws URIException If {@link #checkValid()} fails
309      * @see #getDefaultProtocolCharset
310      */
311     public HttpURL(String userinfo, String host, int port, String path,
312             String query, String fragment) throws URIException {
313 
314         // validate and contruct the URI character sequence
315         StringBuffer buff = new StringBuffer();
316         if (userinfo != null || host != null || port != -1) {
317             _scheme = DEFAULT_SCHEME; // in order to verify the own protocol
318             buff.append(_default_scheme);
319             buff.append("://");
320             if (userinfo != null) {
321                 buff.append(URIUtil.encode(userinfo, URI.allowed_userinfo));
322                 buff.append('@');
323             }
324             if (host != null) {
325                 buff.append(URIUtil.encode(host, URI.allowed_host));
326                 if (port != -1 || port != DEFAULT_PORT) {
327                     buff.append(':');
328                     buff.append(port);
329                 }
330             }
331         }
332         if (path != null) {  // accept empty path
333             if (scheme != null && !path.startsWith("/")) {
334                 throw new URIException(URIException.PARSING,
335                         "abs_path requested");
336             }
337             buff.append(URIUtil.encode(path, URI.allowed_abs_path));
338         }
339         if (query != null) {
340             buff.append('?');
341             buff.append(URIUtil.encode(query, URI.allowed_query));
342         }
343         if (fragment != null) {
344             buff.append('#');
345             buff.append(URIUtil.encode(fragment, URI.allowed_fragment));
346         }
347         parseUriReference(buff.toString(), true);
348         checkValid();
349     }
350 
351 
352     /***
353      * Construct a HTTP URL with a given relative URL string.
354      *
355      * @param base the base HttpURL
356      * @param relative the relative HTTP URL string
357      * @throws URIException If {@link #checkValid()} fails
358      */
359     public HttpURL(HttpURL base, String relative) throws URIException {
360         this(base, new HttpURL(relative));
361     }
362 
363 
364     /***
365      * Construct a HTTP URL with a given relative URL.
366      *
367      * @param base the base HttpURL
368      * @param relative the relative HttpURL
369      * @throws URIException If {@link #checkValid()} fails
370      */
371     public HttpURL(HttpURL base, HttpURL relative) throws URIException {
372         super(base, relative);
373         checkValid();
374     }
375 
376     // -------------------------------------------------------------- Constants
377 
378     /***
379      * Default scheme for HTTP URL.
380      */
381     public static final char[] DEFAULT_SCHEME = { 'h', 't', 't', 'p' };
382 
383     /***
384      * Default scheme for HTTP URL.
385      * @deprecated Use {@link #DEFAULT_SCHEME} instead.  This one doesn't
386      * conform to the project naming conventions.
387      */
388     public static final char[] _default_scheme = DEFAULT_SCHEME;
389 
390     /***
391      * Default port for HTTP URL.
392      */
393     public static final int DEFAULT_PORT = 80;
394 
395     /***
396      * Default port for HTTP URL.
397      * @deprecated Use {@link #DEFAULT_PORT} instead.  This one doesn't conform
398      * to the project naming conventions.
399      */
400     public static final int _default_port = DEFAULT_PORT;
401 
402     /***
403      * The serialVersionUID.
404      */
405     static final long serialVersionUID = -7158031098595039459L;
406 
407     // ------------------------------------------------------------- The scheme
408 
409     /***
410      * Get the scheme.  You can get the scheme explicitly.
411      *
412      * @return the scheme
413      */
414     public char[] getRawScheme() {
415         return (_scheme == null) ? null : HttpURL.DEFAULT_SCHEME;
416     }
417 
418 
419     /***
420      * Get the scheme.  You can get the scheme explicitly.
421      *
422      * @return the scheme null if empty or undefined
423      */
424     public String getScheme() {
425         return (_scheme == null) ? null : new String(HttpURL.DEFAULT_SCHEME);
426     }
427 
428     // --------------------------------------------------------------- The port
429 
430     /***
431      * Get the port number.
432      * @return the port number
433      */
434     public int getPort() {
435         return (_port == -1) ? HttpURL.DEFAULT_PORT : _port;
436     }
437 
438     // ----------------------------------------------------------- The userinfo
439 
440     /***
441      * Set the raw-escaped user and password.
442      *
443      * @param escapedUser the raw-escaped user
444      * @param escapedPassword the raw-escaped password; could be null
445      * @throws URIException escaped user not valid or user required; escaped
446      * password not valid or username missed
447      */
448     public void setRawUserinfo(char[] escapedUser, char[] escapedPassword)
449         throws URIException {
450 
451         if (escapedUser == null || escapedUser.length == 0) {
452             throw new URIException(URIException.PARSING, "user required");
453         }
454         if (!validate(escapedUser, within_userinfo) 
455             || ((escapedPassword != null) 
456             && !validate(escapedPassword, within_userinfo))) {
457             throw new URIException(URIException.ESCAPING,
458                     "escaped userinfo not valid");
459         }
460         String username = new String(escapedUser);
461         String password = (escapedPassword == null) 
462             ? null : new String(escapedPassword);
463         String userinfo = username + ((password == null) ? "" : ":" + password);
464         String hostname = new String(getRawHost());
465         String hostport = (_port == -1) ? hostname : hostname + ":" + _port;
466         String authority = userinfo + "@" + hostport;
467         _userinfo = userinfo.toCharArray();
468         _authority = authority.toCharArray();
469         setURI();
470     }
471 
472 
473     /***
474      * Set the raw-escaped user and password.
475      *
476      * @param escapedUser the escaped user
477      * @param escapedPassword the escaped password; could be null
478      * @throws URIException escaped user not valid or user required; escaped
479      * password not valid or username missed
480      * @throws NullPointerException null user
481      */
482     public void setEscapedUserinfo(String escapedUser, String escapedPassword)
483         throws URIException, NullPointerException {
484 
485         setRawUserinfo(escapedUser.toCharArray(), (escapedPassword == null) 
486             ? null : escapedPassword.toCharArray());
487     }
488 
489 
490     /***
491      * Set the user and password.
492      *
493      * @param user the user
494      * @param password the password; could be null
495      * @throws URIException encoding error or username missed
496      * @throws NullPointerException null user
497      */
498     public void setUserinfo(String user, String password) 
499         throws URIException, NullPointerException {
500         // set the charset to do escape encoding
501         String charset = getProtocolCharset();
502         setRawUserinfo(encode(user, within_userinfo, charset),
503                 (password == null) 
504                 ? null 
505                 : encode(password, within_userinfo, charset));
506     }
507 
508 
509     /***
510      * Set the raw-escaped user.
511      *
512      * @param escapedUser the raw-escaped user
513      * @throws URIException escaped user not valid or user required
514      */
515     public void setRawUser(char[] escapedUser) throws URIException {
516         if (escapedUser == null || escapedUser.length == 0) {
517             throw new URIException(URIException.PARSING, "user required");
518         }
519         if (!validate(escapedUser, within_userinfo)) {
520             throw new URIException(URIException.ESCAPING,
521                     "escaped user not valid");
522         }
523         String username = new String(escapedUser);
524         String password = new String(getRawPassword());
525         String userinfo = username + ((password == null) ? "" : ":" + password);
526         String hostname = new String(getRawHost());
527         String hostport = (_port == -1) ? hostname : hostname + ":" + _port;
528         String authority = userinfo + "@" + hostport;
529         _userinfo = userinfo.toCharArray();
530         _authority = authority.toCharArray();
531         setURI();
532     }
533 
534 
535     /***
536      * Set the escaped user string.
537      *
538      * @param escapedUser the escaped user string
539      * @throws URIException escaped user not valid
540      * @throws NullPointerException null user
541      */
542     public void setEscapedUser(String escapedUser)
543         throws URIException, NullPointerException {
544         setRawUser(escapedUser.toCharArray());
545     }
546 
547 
548     /***
549      * Set the user string.
550      *
551      * @param user the user string
552      * @throws URIException user encoding error
553      * @throws NullPointerException null user
554      */
555     public void setUser(String user) throws URIException, NullPointerException {
556         setRawUser(encode(user, allowed_within_userinfo, getProtocolCharset()));
557     }
558 
559 
560     /***
561      * Get the raw-escaped user.
562      *
563      * @return the raw-escaped user
564      */
565     public char[] getRawUser() {
566         if (_userinfo == null || _userinfo.length == 0) {
567             return null;
568         }
569         int to = indexFirstOf(_userinfo, ':');
570         // String.indexOf(':', 0, _userinfo.length, _userinfo, 0, 1, 0);
571         if (to == -1) {
572             return _userinfo; // only user.
573         }
574         char[] result = new char[to];
575         System.arraycopy(_userinfo, 0, result, 0, to);
576         return result;
577     }
578 
579 
580     /***
581      * Get the escaped user
582      *
583      * @return the escaped user
584      */
585     public String getEscapedUser() {
586         char[] user = getRawUser();
587         return (user == null) ? null : new String(user);
588     }
589 
590 
591     /***
592      * Get the user.
593      *
594      * @return the user name
595      * @throws URIException If {@link #decode} fails
596      */
597     public String getUser() throws URIException {
598         char[] user = getRawUser();
599         return (user == null) ? null : decode(user, getProtocolCharset());
600     }
601 
602 
603     /***
604      * Set the raw-escaped password.
605      *
606      * @param escapedPassword the raw-escaped password; could be null
607      * @throws URIException escaped password not valid or username missed
608      */
609     public void setRawPassword(char[] escapedPassword) throws URIException {
610         if (escapedPassword != null 
611             && !validate(escapedPassword, within_userinfo)) {
612             throw new URIException(URIException.ESCAPING,
613                "escaped password not valid");
614         }
615         if (getRawUser() == null || getRawUser().length == 0) {
616             throw new URIException(URIException.PARSING, "username required");
617         }
618         String username = new String(getRawUser());
619         String password = new String(escapedPassword);
620         // an emtpy string is allowed as a password
621         String userinfo = username + ((password == null) ? "" : ":" + password);
622         String hostname = new String(getRawHost());
623         String hostport = (_port == -1) ? hostname : hostname + ":" + _port;
624         String authority = userinfo + "@" + hostport;
625         _userinfo = userinfo.toCharArray();
626         _authority = authority.toCharArray();
627         setURI();
628     }
629 
630 
631     /***
632      * Set the escaped password string.
633      *
634      * @param escapedPassword the escaped password string; could be null
635      * @throws URIException escaped password not valid or username missed
636      */
637     public void setEscapedPassword(String escapedPassword) throws URIException {
638         setRawPassword((escapedPassword == null) ? null 
639             : escapedPassword.toCharArray());
640     }
641 
642 
643     /***
644      * Set the password string.
645      *
646      * @param password the password string; could be null
647      * @throws URIException encoding error or username missed
648      */
649     public void setPassword(String password) throws URIException {
650         setRawPassword((password == null) ? null : encode(password,
651                     allowed_within_userinfo, getProtocolCharset()));
652     }
653 
654 
655     /***
656      * Get the raw-escaped password.
657      *
658      * @return the raw-escaped password
659      */
660     public char[] getRawPassword() {
661         int from = indexFirstOf(_userinfo, ':');
662         if (from == -1) {
663             return null; // null or only user.
664         }
665         int len = _userinfo.length - from - 1;
666         char[] result = new char[len];
667         System.arraycopy(_userinfo, from + 1, result, 0, len);
668         return result;
669     }
670 
671 
672     /***
673      * Get the escaped password.
674      *
675      * @return the escaped password
676      */
677     public String getEscapedPassword() {
678         char[] password = getRawPassword();
679         return (password == null) ? null : new String(password);
680     }
681 
682 
683     /***
684      * Get the password.
685      *
686      * @return the password
687      * @throws URIException If {@link #decode(char[],String)} fails.
688      */
689     public String getPassword() throws URIException {
690         char[] password = getRawPassword();
691         return (password == null) ? null : decode(password,
692                 getProtocolCharset());
693     }
694 
695     // --------------------------------------------------------------- The path
696 
697     /***
698      * Get the raw-escaped current hierarchy level.
699      *
700      * @return the raw-escaped current hierarchy level
701      * @throws URIException If {@link #getRawCurrentHierPath(char[])} fails.
702      */
703     public char[] getRawCurrentHierPath() throws URIException {
704         return (_path == null || _path.length == 0) ? rootPath 
705             : super.getRawCurrentHierPath(_path);
706     }
707 
708 
709     /***
710      * Get the level above the this hierarchy level.
711      *
712      * @return the raw above hierarchy level
713      * @throws URIException If {@link #getRawCurrentHierPath(char[])} fails.
714      */
715     public char[] getRawAboveHierPath() throws URIException {
716         char[] path = getRawCurrentHierPath();
717         return (path == null || path.length == 0) ? rootPath : getRawCurrentHierPath(path);
718     }
719 
720 
721     /***
722      * Get the raw escaped path.
723      *
724      * @return the path '/' if empty or undefined
725      */
726     public char[] getRawPath() {
727         char[] path =  super.getRawPath();
728         return (path == null || path.length == 0) ? rootPath : path;
729     }
730 
731     // -------------------------------------------------------------- The query
732 
733     /***
734      * Set the query as the name and value pair.
735      *
736      * @param queryName the query string.
737      * @param queryValue the query string.
738      * @throws URIException incomplete trailing escape pattern
739      * Or unsupported character encoding
740      * @throws NullPointerException null query
741      * @see #encode
742      */
743     public void setQuery(String queryName, String queryValue)
744         throws URIException, NullPointerException {
745 
746         StringBuffer buff = new StringBuffer();
747         // set the charset to do escape encoding
748         String charset = getProtocolCharset();
749         buff.append(encode(queryName, allowed_within_query, charset));
750         buff.append('=');
751         buff.append(encode(queryValue, allowed_within_query, charset));
752         _query = buff.toString().toCharArray();
753         setURI();
754     }
755 
756 
757     /***
758      * Set the query as the name and value pairs.
759      *
760      * @param queryName the array of the query string.
761      * @param queryValue the array of the query string.
762      * @throws URIException incomplete trailing escape pattern,
763      * unsupported character encoding or wrong array size
764      * @throws NullPointerException null query
765      * @see #encode
766      */
767     public void setQuery(String[] queryName, String[] queryValue)
768         throws URIException, NullPointerException {
769 
770         int length = queryName.length;
771         if (length != queryValue.length) {
772             throw new URIException("wrong array size of query");
773         }
774 
775         StringBuffer buff = new StringBuffer();
776         // set the charset to do escape encoding
777         String charset = getProtocolCharset();
778         for (int i = 0; i < length; i++) {
779             buff.append(encode(queryName[i], allowed_within_query, charset));
780             buff.append('=');
781             buff.append(encode(queryValue[i], allowed_within_query, charset));
782             if (i + 1 < length) { 
783                 buff.append('&');
784             }
785         }
786         _query = buff.toString().toCharArray();
787         setURI();
788     }
789 
790     // ---------------------------------------------------------------- Utility
791 
792     /***
793      * Verify the valid class use for construction.
794      *
795      * @throws URIException the wrong scheme use
796      */
797     protected void checkValid() throws URIException {
798         // could be explicit protocol or undefined.
799         if (!(equals(_scheme, DEFAULT_SCHEME) || _scheme == null)) {
800             throw new URIException(URIException.PARSING, "wrong class use");
801         }
802     }
803 
804 }
805