/*
 * Copyright (c) 2002, The EROS Group, LLC and Johns Hopkins
 * University. All rights reserved.
 * 
 * This software was developed to support the EROS secure operating
 * system project (http://www.eros-os.org). The latest version of
 * the OpenCM software can be found at http://www.opencm.org.
 * 
 * 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. Neither the name of the The EROS Group, LLC nor the name of
 *    Johns Hopkins University, nor the names of its contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS 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 THE COPYRIGHT OWNER OR 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.
 */

#include <opencm.h>

static void
uri_GuessPort(URI *uri)
{
  if (uri->scheme == 0)
    uri->port = DEFAULT_PORT;
  else if (strcmp(uri->scheme, "http") == 0)
    uri->port = HTTP_PORT;
  else if (strcmp(uri->scheme, "https") == 0)
    uri->port = HTTPS_PORT;
  else if (strcmp(uri->scheme, "ftp") == 0)
    uri->port = FTP_PORT;
  else if (strcmp(uri->scheme, "opencm") == 0)
    uri->port = OPENCM_PORT;
}

URI *
uri_create(const char *uri_str)
{
  char *s;
  
  URI *uri = (URI *) GC_MALLOC(sizeof(URI));

  uri->URI = xstrdup(uri_str);
  
  uri->well_formed = 0;		/* until proven otherwise */
  uri->scheme = 0;
  uri->path = 0;
  uri->netloc = 0;
  uri->port = 0;
  uri->relative = 0;
  
  s = strchr(uri->URI, ':');

  /* A colon is valid in a file name, which presents a definite
   * problem, as "file:name/more-path" might be either a file URI or a
   * relative path. We basically don't try to deal with this at all
   * beyond one or two obvious checks.  At this point, we have a
   * colon, and we check to see if the following thing is a '/' (as it
   * should be if this is a non-relative URI).  If not, we assume that
   * it's a relative URI.  I'm sure the URI spec says something
   * relevant about how to handle this, but being on an airplane makes
   * it hard to check at the moment.
   */

  if (s == 0 || s[1] != '/') {
    uri->path = xstrdup(uri->URI);
    uri->relative = 1;
    uri->well_formed = 1;
    return uri;
  }
  
  /* We have a valid scheme id: */
  uri->scheme = xstrndup(uri->URI, s - uri->URI);

  if ( (strcmp(uri->scheme, "file") == 0) ||
       (strcmp(uri->scheme, "rcsfs") == 0) ) {
    uri->path = xstrdup(s+1);
    uri->well_formed = 1;
    return uri;
  }
      
  /* Skip the "//", if any. Do this forgivingly:
  */
  s++;
  while (*s == '/')
    s++;
  
  /* until otherwise proven: */
  uri->netloc = xstrdup("localhost");
  uri_GuessPort(uri);

  /* Check for explicit host + port number: */
  {
     char *port = strchr(s, ':');
     char *slash = strchr(s, '/');

     /* Port could have been buried in residual path, which doesn't
	count. If there is further path info, check that port number
	qualifier comes in the first fragment: */
     if (slash && (slash - s) < (port - s))
       port = 0;

     /* Trim the port part: */
     if (port) {
       if (port != s)
	 uri->netloc = xstrndup(s, port - s);

       port++;
       if (slash)
	 port = xstrndup(port, slash - port);

       uri->port = strtoul(port, 0, 0);
     }
     else if (slash)
       uri->netloc = xstrndup(s, slash - s);
     else
       uri->netloc = s;

     if (slash)
       uri->path = xstrdup(slash);
  }

  uri->well_formed = 1;

#if 0
  debug(DBG_URI, 
	"\nScheme: %s\nPort: %d\nNetloc: %s\nUsername: %s\nPath: %s\n", 
	 uri->scheme, uri->port, uri->netloc, uri->username, uri->path);
#endif 
  
  /* When all done, restore the entire URI for future use:*/
  uri->URI = xstrdup(uri_str);

  return uri;
}
