Source for org.apache.commons.httpclient.HttpURL

   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: 507324 $
   4:  * $Date: 2007-02-14 01:12:11 +0100 (Wed, 14 Feb 2007) $
   5:  *
   6:  * ====================================================================
   7:  *
   8:  *  Licensed to the Apache Software Foundation (ASF) under one or more
   9:  *  contributor license agreements.  See the NOTICE file distributed with
  10:  *  this work for additional information regarding copyright ownership.
  11:  *  The ASF licenses this file to You under the Apache License, Version 2.0
  12:  *  (the "License"); you may not use this file except in compliance with
  13:  *  the License.  You may obtain a copy of the License at
  14:  *
  15:  *      http://www.apache.org/licenses/LICENSE-2.0
  16:  *
  17:  *  Unless required by applicable law or agreed to in writing, software
  18:  *  distributed under the License is distributed on an "AS IS" BASIS,
  19:  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  20:  *  See the License for the specific language governing permissions and
  21:  *  limitations under the License.
  22:  * ====================================================================
  23:  *
  24:  * This software consists of voluntary contributions made by many
  25:  * individuals on behalf of the Apache Software Foundation.  For more
  26:  * information on the Apache Software Foundation, please see
  27:  * <http://www.apache.org/>.
  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:    // ----------------------------------------------------------- Constructors
  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>&lt;username&gt;:&lt;password&gt;</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>&lt;username&gt;:&lt;password&gt;</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>&lt;username&gt;:&lt;password&gt;</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>&lt;username&gt;:&lt;password&gt;</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:        // validate and contruct the URI character sequence
 314:        StringBuffer buff = new StringBuffer();
 315:	          if (userinfo != null || host != null || port != -1) {
 316:            _scheme = DEFAULT_SCHEME; // in order to verify the own protocol
 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) {  // accept empty path
 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); //sufficient for real world
 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:    // -------------------------------------------------------------- Constants
 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:    // ------------------------------------------------------------- The scheme
 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:    // --------------------------------------------------------------- The port
 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:    // ----------------------------------------------------------- The userinfo
 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:        // set the charset to do escape encoding
 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:        // String.indexOf(':', 0, _userinfo.length, _userinfo, 0, 1, 0);
 600:	          if (to == -1) {
 601:            return _userinfo; // only user.
 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:        // an emtpy string is allowed as a password
 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; // null or only user.
 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:    // --------------------------------------------------------------- The path
 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:    // -------------------------------------------------------------- The query
 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:        // set the charset to do escape encoding
 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:        // set the charset to do escape encoding
 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:    // ---------------------------------------------------------------- Utility
 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:        // could be explicit protocol or undefined.
 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:        // set _uri
 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) { // has_authority
 849:	                  if (_userinfo != null) { // by default, remove userinfo part
 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:            // _is_hier_part or _is_relativeURI
 866:	              if (_path.length != 0) {
 867:                buf.append(_path);
 868:            }
 869:        }
 870:	          if (_query != null) { // has_query
 871:            buf.append('?');
 872:            buf.append(_query);
 873:        }
 874:        // ignore the fragment identifier
 875:        _uri = buf.toString().toCharArray();
 876:        hash = 0;
 877:    }
 878:    
 879:}