View Javadoc

1   /*
2    * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/HttpURL.java,v 1.18 2004/09/30 17:26:41 oglueck Exp $
3    * $Revision: 358634 $
4    * $Date: 2005-12-22 16:23:15 -0500 (Thu, 22 Dec 2005) $
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, 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>&lt;username&gt;:&lt;password&gt;</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>&lt;username&gt;:&lt;password&gt;</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>&lt;username&gt;:&lt;password&gt;</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>&lt;username&gt;:&lt;password&gt;</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         // validate and contruct the URI character sequence
313         StringBuffer buff = new StringBuffer();
314         if (userinfo != null || host != null || port != -1) {
315             _scheme = DEFAULT_SCHEME; // in order to verify the own protocol
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) {  // accept empty path
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); //sufficient for real world
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     // -------------------------------------------------------------- Constants
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     // ------------------------------------------------------------- The scheme
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     // --------------------------------------------------------------- The port
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     // ----------------------------------------------------------- The userinfo
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         // set the charset to do escape encoding
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         // String.indexOf(':', 0, _userinfo.length, _userinfo, 0, 1, 0);
598         if (to == -1) {
599             return _userinfo; // only user.
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         // an emtpy string is allowed as a password
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; // null or only user.
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     // --------------------------------------------------------------- The path
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     // -------------------------------------------------------------- The query
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         // set the charset to do escape encoding
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         // set the charset to do escape encoding
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     // ---------------------------------------------------------------- Utility
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         // could be explicit protocol or undefined.
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         // set _uri
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) { // has_authority
847                 if (_userinfo != null) { // by default, remove userinfo part
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             // _is_hier_part or _is_relativeURI
864             if (_path.length != 0) {
865                 buf.append(_path);
866             }
867         }
868         if (_query != null) { // has_query
869             buf.append('?');
870             buf.append(_query);
871         }
872         // ignore the fragment identifier
873         _uri = buf.toString().toCharArray();
874         hash = 0;
875     }
876     
877 }
878