head	1.3;
access;
symbols;
locks; strict;
comment	@# @;


1.3
date	2001.08.11.09.08.10;	author dlr;	state Exp;
branches;
next	1.2;

1.2
date	2001.07.19.19.05.32;	author dlr;	state Exp;
branches;
next	1.1;

1.1
date	2001.07.19.19.04.14;	author dlr;	state Exp;
branches;
next	;


desc
@@


1.3
log
@Upgrading to Turbine 3.0-dev, Fulcrum 1.0, and Torque 1.0.
@
text
@/* ================================================================
 * Copyright (c) 2000 CollabNet.  All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * 3. The end-user documentation included with the redistribution, if
 * any, must include the following acknowlegement: "This product includes
 * software developed by CollabNet (http://www.collab.net/)."
 * Alternately, this acknowlegement may appear in the software itself, if
 * and wherever such third-party acknowlegements normally appear.
 * 
 * 4. The hosted project names must not be used to endorse or promote
 * products derived from this software without prior written
 * permission. For written permission, please contact info@@collab.net.
 * 
 * 5. Products derived from this software may not use the "Tigris" name
 * nor may "Tigris" appear in their names without prior written
 * permission of CollabNet.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL COLLAB.NET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ====================================================================
 * 
 * This software consists of voluntary contributions made by many
 * individuals on behalf of CollabNet.
 */

package org.tigris.helm.util;

import java.io.*;
import java.util.*;
import java.net.URLEncoder;
import javax.servlet.*;
import javax.servlet.http.*;

import org.apache.turbine.util.Log;

import org.tigris.helm.tool.HelmProperties;

/**
 * Parses and builds URLs.  Houses various URL-related constants.
 *
 * @@author <a href="mailto:davidp@@dataweb-systems.com">David C. Pellegrini</a>
 * @@author <a href="mailto:dlr@@collab.net">Daniel Rall</a>
 * @@version $Id: URL.java,v 1.2 2001/07/19 19:05:32 dlr Exp $
 *
 * Copyright (c) 1999 dataweb systems, inc.
 * Copyright (c) 1999-2001 CollabNet, Inc.
 */
public class URL
{
    /**
     * Hypertext transfer protocol's acronym.
     */
    public static final String HTTP_PROTOCOL = "http";

    /**
     * Secure hypertext transfer protocol acronym.
     */
    public static final String HTTPS_PROTOCOL = "https";

    /**
     * The default protocol's acronym.
     */
    public static final String DEFAULT_PROTOCOL = HTTP_PROTOCOL;

    /**
     * The part of the URI which separates the protocol indicator (i.e. the
     * scheme) from the rest of the URI.
     */
    public static final String URI_SCHEME_SEPARATOR = "://";

    /**
     * HTTP port number.
     */
    public static final int HTTP_PORT = 80;

    /**
     * HTTPS port number.
     */
    public static final int HTTPS_PORT = 443;

    /**
     * FTP port number.
     */
    public static final int FTP_PORT = 21;

    /**
     * HTTP port number.
     */
    public static final Integer DEFAULT_HTTP_PORT = new Integer(HTTP_PORT);

    /**
     * HTTPS port number.
     */
    public static final Integer DEFAULT_HTTPS_PORT = new Integer(HTTPS_PORT);

    /**
     * The key for enforcing a servlet scheme.
     */
    public static final String FORCE_SCHEME_KEY = "forceServletScheme";

    // URL % HEX HEX values that need escaping
    public static final String URL_SPACE        = "%20";
    public static final String URL_EXCLAM       = "%21";
    public static final String URL_DBL_QUOTE    = "%22";
    public static final String URL_POUND        = "%23";
    public static final String URL_DOLLAR       = "%24";
    public static final String URL_PERCENT      = "%25";
    public static final String URL_AMPERSAND    = "%26";
    public static final String URL_SINGLE_QUOTE = "%27";
    public static final String URL_LEFT_PAREN   = "%28";
    public static final String URL_RIGHT_PAREN  = "%29";

    /**
     * Key to pull http_port.
     */
    private static final String HTTP_PORT_KEY = "http_port";

    /**
     * Key to pull https_port.
     */
    private static final String HTTPS_PORT_KEY = "https_port";

    /**
     * Turn debug log output on/off
     */
    private static final boolean DEBUG = true;

    private static final String DOMAIN_KEY = "domain";

    /**
     * Tests for inclusion of a protocol in the specified URL.  Useful when 
     * determining whether or not a URL is local.
     *
     * @@param url A string representation of the URL to test.
     * @@return	  Whether the URL is local.
     */
    public static boolean hasProtocol(String url)
    {
        return (url != null ? url.indexOf(URI_SCHEME_SEPARATOR) != -1 : false);
    }

    /**
     * @@see #protoAndServer()
     */
    public static final StringBuffer httpAndServer(HttpServletRequest req)
    {
        return protoAndServer(req, HTTP_PROTOCOL);
    }

    /**
     * @@see #protoAndServer()
     */
    public static final StringBuffer schemeAndServer(HttpServletRequest req)
    {
        return protoAndServer(req, req.getScheme());
    }

    /**
     * Generates the leading part of the URL, up through the server.
     *
     * @@param req      The HTTP request.
     * @@param protocol The protocol to prepend.
     * @@return         A StringBuffer with the protocol and server.
     *
     * @@exception HandlerException
     */
    protected static StringBuffer protoAndServer(HttpServletRequest req,
                                                 String protocol)
    {
        StringBuffer newURL = new StringBuffer(protocol);
        newURL.append(URI_SCHEME_SEPARATOR).append(req.getServerName());
        int p = req.getServerPort();
        if (p != HTTP_PORT && p != HTTPS_PORT)
        {
            newURL.append(':').append(p);
        }
        return newURL;
    }

    /**
     * Returns a URL fragment derived from the provided HTTP request,
     * including the protocol used to address the server (if non-standard
     * for HTTP/HTTPS).  Returns the fragment as a buffer 
     *
     * @@param req The request to extract information from.
     * @@param scheme The protocol indicator to prefix the host name with, or
     * the protocol used to address the server with if <code>null</code>.
     * @@return The desired URL fragment.
     */
    public static StringBuffer makeHostURL(HttpServletRequest req,
                                           String scheme)
    {
        if (scheme == null)
        {
            scheme = req.getScheme();
        }
        StringBuffer url = new StringBuffer()
            .append(scheme)
            .append(URI_SCHEME_SEPARATOR)
            .append(req.getServerName());
        int port = req.getServerPort();
        if (! (("http".equalsIgnoreCase(scheme) && port == HTTP_PORT)  ||
               ("https".equalsIgnoreCase(scheme) && port == HTTPS_PORT) ||
               ("ftp".equalsIgnoreCase(scheme) && port == FTP_PORT)) )
        {
            url.append(':').append(port);
        }
        return url;
    }

    /**
     * Generates the leading part of the URL for a page in the domain.
     * FIXME: This shouldn't be necessary now that currentDomain can
     * be set in BaseHelmServlet.
     */
    public static StringBuffer schemeAndDomain(HttpServletRequest req)
    {
        StringBuffer newURL = new StringBuffer(req.getScheme())
            .append(URI_SCHEME_SEPARATOR).append("www.")
            .append(HelmProperties.getInstance().getProperty(DOMAIN_KEY));
        int p = req.getServerPort();
        if (p != HTTP_PORT) newURL.append(':').append(p);
        return newURL;
    }

    /**
     * @@see #appendCGIParam
     */
    public static String appendCGIParam(String url, String value)
    {
        return appendCGIParam(url, null, value);
    }

    /**
     * @@see #appendCGIParam
     */
    public static String appendCGIParam(StringBuffer url, String value)
    {
        return appendCGIParam(url, null, value);
    }

    /**
     * @@see #appendCGIParam
     */
    public static String appendCGIParam(String url, String name, String value)
    {
        return appendCGIParam(new StringBuffer(url), url, name, value);
    }

    /**
     * @@see #appendCGIParam
     */
    public static String appendCGIParam(StringBuffer url, String name,
                                        String value)
    {
        return appendCGIParam(url, url.toString(), name, value);
    }

    /**
     * Appends the specified name/value pair to the provided URL (handling 
     * addition of query string separator and URL encoding of parameter).
     * Writes to the provided buffer.
     *
     * @@param buf   The buffer to write to.
     * @@param url   The URL to append to.
     * @@param name  The CGI parameter name (or <code>null</code if none).
     * @@param value The CGI parameter value.
     * @@return      The new URL (with param appended).
     */
    private static String appendCGIParam(StringBuffer buf, String url,
                                         String name, String value)
    {
        appendCGISeparator(buf, url);
        if (name != null) buf.append(URLEncoder.encode(name)).append('=');
        buf.append(URLEncoder.encode(value));
        return buf.toString();
    }
    
    /**
     * Appends the CGI parameter separator character appropriate for
     * the supplied URL to the specified buffer.
     *
     * @@param buf The buffer to write to.
     * @@param url The URL to append to.
     */
    public static final void appendCGISeparator(StringBuffer buf, String url)
    {
        buf.append(url.indexOf('?') == -1 ? '?' : '&');
    }

    /**
     * If port is default for the protocol, we return null else we pull port
     * for the passed in protocol from inProperties.
     * 
     * @@param proto Either 'http' or 'https'.    Can be null and we assume
     * the default 'http'.
     *
     * @@return Port to use as string.  Null if port is default for the
     * protocol (80 for 'http' and 443 for 'https').
     *
     * @@exception NullPointerException If i can't get a HelmProperties
     */
     public String getPort(String proto)
        throws NullPointerException
     {
        String port = null;

        String protocol = (proto == null ? getProtocol() : proto);
        boolean isHttp = protocol.equalsIgnoreCase( HTTP_PROTOCOL );
        Integer defaultPort = (isHttp ? DEFAULT_HTTP_PORT: DEFAULT_HTTPS_PORT);
        String portKey = (isHttp ? HTTP_PORT_KEY : HTTPS_PORT_KEY);
        port = HelmProperties.getProperty(portKey);
        if (port == null)
            throw new NullPointerException( portKey + " is null" );
        if ( port.equals(defaultPort.toString()) )
            port = null; // Return null if port is default for the protocol.

        return port;
     }
    
    /**
     * Get protocol (i.e. http or https).
     * 
     * @@see #getProtocol(String)
     */
    public String getProtocol()
        throws NullPointerException, IllegalArgumentException
    {
        return getProtocol( ( String )null );
    }
        
    /**
     * Get protocol (i.e. http or https).
     * 
     * This method is dumb.  All it is doing is looking at the passed in 
     * protocol checking to see if it is http or https.   If null, it will 
     * supply the default.  The default is value of FORCE_SCHEME_KEY property
     * or if not defined, it's 'http'. If passed protocol is not null, 'http' 
     * or 'https',  it throws an exception.   These checks are the value this
     * method provides.  Use it building urls. 
     * 
     * @@param proto Pass 'http' or 'https'.  If null, we assume 'http'.
     *
     * @@return Return 'http' or 'https'
     *
     * @@exception IllegalArgumentException Thrown if you pass anything but 
     * 'http' or 'http' in the proto param.
     */
    public String getProtocol(String proto)
        throws NullPointerException, IllegalArgumentException
    {
        String protocol = DEFAULT_PROTOCOL;

        String forceProtocol = HelmProperties.getProperty(FORCE_SCHEME_KEY);
        if (proto != null)
        {
            protocol = proto;
        }
        else if (forceProtocol != null)
        {
            if (forceProtocol.equalsIgnoreCase(HTTP_PROTOCOL))
            {
                protocol = HTTP_PROTOCOL;
            }
            else if (forceProtocol.equalsIgnoreCase(HTTPS_PROTOCOL))
            {
                protocol = HTTPS_PROTOCOL;
            }
        }
        else if (proto == null)
        {
            protocol = HTTP_PROTOCOL;
        }

        if ( !protocol.equalsIgnoreCase(HTTP_PROTOCOL)
             && !protocol.equalsIgnoreCase(HTTPS_PROTOCOL) )
        {
            throw new IllegalArgumentException("Unsupported protocol: "
                                               + proto);
        }

        return protocol;
    }

    /**
     * Converts characters to their %xx equivalent
     *
     * @@param String to convert
     * @@return String with converted values
     */
    public static String encode(String unclean)
    {
         StringBuffer clean = new StringBuffer(unclean.length());
         char[] uncleanChars = unclean.toCharArray();
         for (int i = 0; i < uncleanChars.length; i++)
         {
             switch(uncleanChars[i])
             {
                 case ' ':
                     clean.append(URL_SPACE);
                     break;
                 case '!':
                     clean.append(URL_EXCLAM);
                     break;
                 case '"':
                     clean.append(URL_DBL_QUOTE);

                 case '#':
                     clean.append(URL_POUND);
                     break;

                 case '$':
                     clean.append(URL_DOLLAR);
                     break;

                 case '%':
                     clean.append(URL_PERCENT);
                     break;

                 case '&':
                     clean.append(URL_AMPERSAND);
                     break;

                 case '\'':
                     clean.append(URL_SINGLE_QUOTE);
                     break;

                 case '(':
                     clean.append(URL_LEFT_PAREN);
                     break;

                 case ')':
                     clean.append(URL_RIGHT_PAREN);
                     break;

                 default:
                     clean.append(uncleanChars[i]);
             }
         }
         return clean.toString();
    }
}
@


1.2
log
@Correct JoistProperties-inflicted complie error (changed references to
HelmProperties).
@
text
@d64 1
a64 1
 * @@version $Id: URL.java,v 1.1 2001/07/19 19:04:14 dlr Exp $
d87 6
d103 5
d160 1
a160 1
        return (url != null ? url.indexOf("://") != -1 : false);
d191 2
a192 2
        StringBuffer newURL = new StringBuffer(protocol).append("://");
        newURL.append(req.getServerName());
d202 31
d234 2
a235 2
     * This wouldn't be necessary if currentDomain was set in UnsecureServlet
     * *sigh*.
d239 3
a241 3
        StringBuffer newURL =
            new StringBuffer(req.getScheme()).append("://www.");
        newURL.append(HelmProperties.getInstance().getProperty(DOMAIN_KEY));
@


1.1
log
@Ported from Joist.
@
text
@d57 2
d64 1
a64 1
 * @@version $Id: URL.java,v 1.41 2001/05/14 20:55:48 dlr Exp $
d199 1
a199 1
        newURL.append(JoistProperties.getInstance().getProperty(DOMAIN_KEY));
d280 1
a280 1
     * @@exception NullPointerException If i can't get a JoistProperties
d291 1
a291 1
        port = JoistProperties.getProperty(portKey);
d333 1
a333 1
        String forceProtocol = JoistProperties.getProperty(FORCE_SCHEME_KEY);
@

