int main(int argc, char *argv[])
{
    globus_url_t  url;
    int           i;
    int           result;
    globus_bool_t ok;
    int	          num_successful = 0;
    int		  rc;
    
    globus_module_activate(GLOBUS_COMMON_MODULE);

    globus_libc_printf("Testing globus_url_parse()\n");

    if(argc > 1)
    {
        globus_libc_printf("Bypassing standard tests, parsing command line arguments\n");
        for(i = 1; i < argc; i++)
        {
	    globus_libc_printf("Parsing \"%s\"\n", argv[i]);
	    result = globus_url_parse(argv[i], &url);
	    globus_libc_printf("Parse returned %d\n", result);
	    if(result == GLOBUS_SUCCESS)
	    {
#define printable_string(x) (x==GLOBUS_NULL ? "NULL" : x)

	        globus_libc_printf("url_scheme        = \"%s\"\n"
		                   "url_scheme_type   = %d\n"
				   "user              = \"%s\"\n"
				   "password          = \"%s\"\n"
				   "host              = \"%s\"\n"
				   "port              = %u\n"
				   "url_path          = \"%s\"\n"
				   "dn                = \"%s\"\n"
				   "attributes        = \"%s\"\n"
				   "scope             = \"%s\"\n"
				   "filter            = \"%s\"\n"
				   "url_specific_part = \"%s\"\n",
				   printable_string(url.scheme),
				   url.scheme_type,
				   printable_string(url.user),
				   printable_string(url.password),
				   printable_string(url.host),
				   url.port,
				   printable_string(url.url_path),
				   printable_string(url.dn),
				   printable_string(url.attributes),
				   printable_string(url.scope),
				   printable_string(url.filter),
				   printable_string(url.url_specific_part));

	        result = globus_url_destroy(&url);
		globus_libc_printf("globus_url_destroy returned %d\n", result);
	    }
        }
        globus_module_deactivate_all();
        return 0;
    }
    for(i = 0; i < NUM_TESTS; i++)
    {
	ok = GLOBUS_TRUE;

	result = globus_url_parse(test_urls[i].url, &url);

	if(result != test_urls[i].result)
	{
	    globus_libc_printf(
		"test %d: FAILED (url=%s, expected %d, parse returned %d)\n",
		i+1,
		test_urls[i].url,
		test_urls[i].result,
		result);
	    ok = GLOBUS_FALSE;
	}
	
	if(test_urls[i].result == GLOBUS_SUCCESS)
	{
            /* Verify that parse did what we wanted it to do */
            if(!compare_strings(url.scheme,
                                test_urls[i].url_result.scheme,
				i+1,
				"scheme"))
            {
                ok = GLOBUS_FALSE;
            } 
            if(!compare_ints(url.scheme_type,
	                     test_urls[i].url_result.scheme_type,
			     i+1,
			     "scheme_type"))
	    {
                ok = GLOBUS_FALSE;
	    }
            if(!compare_strings(url.user,
                                test_urls[i].url_result.user,
				i+1,
				"user"))
            {
                ok = GLOBUS_FALSE;
            } 
            if(!compare_strings(url.password,
                                test_urls[i].url_result.password,
				i+1,
				"password"))
            {
                ok = GLOBUS_FALSE;
            } 
            if(!compare_strings(url.host,
                                test_urls[i].url_result.host,
				i+1,
				"host"))
            {
                ok = GLOBUS_FALSE;
            } 
            if(!compare_ints((int) url.port,
                                (int) test_urls[i].url_result.port,
				i+1,
				"port"))
            {
                ok = GLOBUS_FALSE;
            } 
            if(!compare_strings(url.url_path,
                                test_urls[i].url_result.url_path,
				i+1,
				"url_path"))
            {
                ok = GLOBUS_FALSE;
            } 
            if(!compare_strings(url.dn,
                                test_urls[i].url_result.dn,
				i+1,
				"dn"))
            {
                ok = GLOBUS_FALSE;
            } 
            if(!compare_strings(url.attributes,
                                test_urls[i].url_result.attributes,
				i+1,
				"attributes"))
            {
                ok = GLOBUS_FALSE;
            } 
            if(!compare_strings(url.scope,
                                test_urls[i].url_result.scope,
				i+1,
				"scope"))
            {
                ok = GLOBUS_FALSE;
            } 
            if(!compare_strings(url.filter,
                                test_urls[i].url_result.filter,
				i+1,
				"filter"))
            {
                ok = GLOBUS_FALSE;
            } 
            if(!compare_strings(url.url_specific_part,
                                test_urls[i].url_result.url_specific_part,
				i+1,
				"url_specific_part"))
            {
                ok = GLOBUS_FALSE;
            } 

	    result = globus_url_destroy(&url);
	    if(result != GLOBUS_SUCCESS)
	    {
		globus_libc_printf(
		    "test %d: FAILED (could not destroy parsed url)\n",
		     i+1);
		ok = GLOBUS_FALSE;
	    }
	}
	if(ok)
	{
	    num_successful++;
	}
    }

    globus_libc_printf("------------------------------------\n");
    if(num_successful == i)
    {
	globus_libc_printf("ALL TESTS SUCCESSFUL\n");
    }
    else
    {
	globus_libc_printf("%d OF %d TESTS FAILED\n",
			   i - num_successful,
			   i);
    }
    globus_libc_printf("------------------------------------\n");

    rc = (num_successful == i) ? 0 : 1;

    globus_module_deactivate_all();
    return rc;
}
static void
globus_l_gass_server_ez_register_accept_callback(
					void * listener,
					globus_gass_transfer_request_t request 
					)
{
    int rc;
    char * subjectname;
    char * path=GLOBUS_NULL;
    char * url;
    globus_url_t parsed_url;
    globus_l_gass_server_ez_t * s;
    globus_gass_server_ez_request_t *r;
    struct stat	statstruct;
    globus_byte_t * buf;
    int amt;
    int flags=0;

    
    subjectname=globus_gass_transfer_request_get_subject(request);

    /* lookup our options */
    s=(globus_l_gass_server_ez_t *)globus_hashtable_lookup(
                                &globus_l_gass_server_ez_listeners,
                                listener);

    /* Check for valid URL */
    url=globus_gass_transfer_request_get_url(request);
    rc = globus_url_parse(url, &parsed_url);
    if(rc != GLOBUS_SUCCESS ||
       parsed_url.url_path == GLOBUS_NULL || strlen(parsed_url.url_path) == 0U)
    {
        globus_gass_transfer_deny(request, 404, "File Not Found");
        globus_gass_transfer_request_destroy(request);
        if (rc == GLOBUS_SUCCESS)
            globus_url_destroy(&parsed_url);
	goto reregister_nourl;
    }

    if(globus_gass_transfer_request_get_type(request) ==
       GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND)
    {
        flags = O_CREAT | O_WRONLY | O_APPEND;
    }
    else if(globus_gass_transfer_request_get_type(request) ==
            GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT)
    {
        flags = O_CREAT | O_WRONLY | O_TRUNC;
    }
    switch(globus_gass_transfer_request_get_type(request))
        {
          case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND:
          case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT:

	    /* Check to see if this is a request we are allowed to handle */

            if(((s->options & GLOBUS_GASS_SERVER_EZ_WRITE_ENABLE) == 0UL) &&
              ((s->options & GLOBUS_GASS_SERVER_EZ_STDOUT_ENABLE) == 0UL) &&
              ((s->options & GLOBUS_GASS_SERVER_EZ_STDERR_ENABLE) == 0UL) &&
              ((s->options & GLOBUS_GASS_SERVER_EZ_CLIENT_SHUTDOWN_ENABLE) ==
									 0UL))
    	    {
		goto deny;
            }
	
	    /* Expand ~ and ~user prefix if enaabled in options */
    	    rc = globus_l_gass_server_ez_tilde_expand(s->options,
                                              parsed_url.url_path,
                                              &path);
              
            if(strncmp(path, "/dev/saga", 9) == 0 && 
                    (s->options & GLOBUS_GASS_SERVER_EZ_STDOUT_ENABLE))
            {
                rc = s->fd; // the pipe handle!
            
                goto authorize;
            }
            else if(strncmp(path, "/dev/saga/", 9) == 0)
            {
                goto deny;
            }
                
    	    else if(strcmp(path, "/dev/globus_gass_client_shutdown") == 0)
    	    {
        	if(s->options & GLOBUS_GASS_SERVER_EZ_CLIENT_SHUTDOWN_ENABLE &&
           	   s->callback != GLOBUS_NULL)
        	{
            	    s->callback();
        	}

		goto deny;
    	    }
#ifdef TARGET_ARCH_WIN32
			// The call to open() in Windows defaults to text mode, so
			// we to override it.
			flags |= O_BINARY;
#endif
            rc = globus_libc_open(path, flags, 0600);

            if(rc < 0)
            {
                goto deny;
            }
	
	    authorize:
            globus_gass_transfer_authorize(request, 0);
	    if(s->options & GLOBUS_GASS_SERVER_EZ_LINE_BUFFER)
	    {
	        r=(globus_gass_server_ez_request_t *)globus_malloc(
				sizeof(globus_gass_server_ez_request_t));
		r->fd=rc;
		r->line_buffer=globus_malloc(80);
                r->line_buffer_used= 0UL;
        	r->line_buffer_length = 80UL;
        	r->linebuffer = GLOBUS_TRUE;

		globus_gass_transfer_receive_bytes(request,
						globus_malloc(1024),
						1024,
						1,
						globus_gass_server_ez_put_memory_done,
						r);
	    }
	    else
	    {
                globus_gass_transfer_receive_bytes(request,
                                               globus_malloc(1024),
                                               1024,
                                               1,
                                               globus_l_gass_server_ez_put_callback,
                                               (void *) rc);
	    }
            break;

          case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_GET:
            flags = O_RDONLY;

			/* Expand ~ and ~user prefix if enaabled in options */
            rc = globus_l_gass_server_ez_tilde_expand(s->options,
                                              parsed_url.url_path,
                                              &path);

   	    if((s->options & GLOBUS_GASS_SERVER_EZ_READ_ENABLE) == 0UL)
    	    {
		goto deny;
    	    }
	   
	    if(stat(path, &statstruct)==0)
	    {
#ifdef TARGET_ARCH_WIN32
				// The call to open() in Windows defaults to text mode, 
				// so we to override it.
				flags |= O_BINARY;
#endif
                rc = globus_libc_open(path, flags, 0600);
		fstat(rc, &statstruct);
	    }
	    else
	    {
		globus_gass_transfer_deny(request, 404, "File Not Found");
		globus_gass_transfer_request_destroy(request);
		goto reregister;
	    }

            buf = globus_malloc(1024);
            amt = read(rc, buf, 1024);
            if(amt == -1)
            {
                globus_free(buf);
                goto deny;
            }
            globus_gass_transfer_authorize(request,
                                           statstruct.st_size);

            globus_gass_transfer_send_bytes(request,
                                            buf,
                                            amt,
                                            GLOBUS_FALSE,
                                            globus_l_gass_server_ez_get_callback,
                                            (void *) rc);
	  break;
	default:
	deny:
	  globus_gass_transfer_deny(request, 400, "Bad Request");
	  globus_gass_transfer_request_destroy(request);

	}

  reregister:
    globus_url_destroy(&parsed_url);

  reregister_nourl:
    globus_gass_transfer_register_listen(
				(globus_gass_transfer_listener_t) listener,
				globus_l_gass_server_ez_listen_callback,
				s->reqattr);

    if (path != GLOBUS_NULL) globus_free(path);

} /*globus_l_gass_server_ez_register_accept_callback*/
/**
 * @brief Create a HTTP-framed copy of a GRAM request
 * @ingroup globus_gram_protocol_framing
 *
 * @details
 * The globus_gram_protocol_frame_request() function adds HTTP 1.1
 * framing around the input message. The framed message includes HTTP headers 
 * relating the the destination URL and the length of the message content.
 * The framed message is returned by modifying @a framedmsg to point to a
 * newly allocated string. The integer pointed to by the @a framedsize
 * parameter is set to the length of this message.
 *
 * @param url
 *        The URL of the GRAM resource to contact. This is parsed and used
 *        to generate the HTTP POST operation destination and the Host
 *        HTTP header.
 * @param msg
 *        A string containing the message content to be framed.
 * @param msgsize
 *        The length of the string pointed to by @a msg
 * @param framedmsg
 *        An output parameter which will be set to a copy of the @a msg string
 *        with an HTTP frame around it.
 * @param framedsize
 *        An output parameter which will be set to the length of the 
 *        framed message.
 *
 * @return
 *     Upon success, globus_gram_protocol_frame_request() will return
 *     GLOBUS_SUCCESS and the @a framedmsg and @a framedsize parameters will be
 *     modified to point to the new framed message string and its length
 *     respectively. When this occurs, the caller is responsible for freeing
 *     the string pointed to by @a framedmsg. If an error occurs, its value
 *     will returned and the @a framedmsg and @a framedsize parameters will 
 *     be uninitialized.
 *
 * @retval GLOBUS_SUCCESS
 *     Success
 * @retval GLOBUS_GRAM_PROTOCOL_ERROR_INVALID_JOB_CONTACT
 *     Invalid job contact
 */
int
globus_gram_protocol_frame_request(
    const char *			url,
    const globus_byte_t *		msg,
    globus_size_t			msgsize,
    globus_byte_t **			framedmsg,
    globus_size_t *			framedsize)
{
    char *				buf;
    globus_size_t			digits = 0;
    globus_size_t			tmp;
    globus_size_t			framedlen;
    globus_url_t			parsed;
    int					rc;

    rc = globus_url_parse(url, &parsed);

    if(rc != GLOBUS_SUCCESS)
    {
	rc = GLOBUS_GRAM_PROTOCOL_ERROR_INVALID_JOB_CONTACT;

        goto out;
    }

    if (parsed.url_path == NULL)
    {
	rc = GLOBUS_GRAM_PROTOCOL_ERROR_INVALID_JOB_CONTACT;

        goto destroy_out;
    }

    /*
     * HTTP request message framing:
     *    POST <uri> HTTP/1.1<CR><LF>
     *    Host: <hostname><CR><LF>
     *    Content-Type: application/x-globus-gram<CR><LF>
     *    Content-Length: <msgsize><CR><LF>
     *    <CR><LF>
     *    <msg>
     */
    tmp = msgsize;

    do
    {
	tmp /= 10;
	digits++;
    }
    while(tmp > 0);

    framedlen  = strlen(GLOBUS_GRAM_HTTP_REQUEST_LINE);
    framedlen += strlen((char *) parsed.url_path);
    framedlen += strlen(GLOBUS_GRAM_HTTP_HOST_LINE);
    framedlen += strlen((char *) parsed.host);
    framedlen += strlen(GLOBUS_GRAM_HTTP_CONTENT_TYPE_LINE);
    framedlen += strlen(GLOBUS_GRAM_HTTP_CONTENT_LENGTH_LINE);
    framedlen += digits;
    framedlen += 2;
    framedlen += msgsize;

    buf = (char *) globus_libc_malloc(framedlen + 1 /*null terminator*/);

    tmp  = 0;
    tmp += globus_libc_sprintf(buf + tmp,
			      GLOBUS_GRAM_HTTP_REQUEST_LINE,
			      parsed.url_path);
    tmp += globus_libc_sprintf(buf + tmp,
			      GLOBUS_GRAM_HTTP_HOST_LINE,
			      parsed.host);
    tmp += globus_libc_sprintf(buf + tmp,
			       GLOBUS_GRAM_HTTP_CONTENT_TYPE_LINE);
    tmp += globus_libc_sprintf(buf + tmp,
			       GLOBUS_GRAM_HTTP_CONTENT_LENGTH_LINE,
			       (long) msgsize);
    tmp += globus_libc_sprintf(buf + tmp,
			       CRLF);

    if (msgsize > 0)    /* allow for empty message body (msg==NULL) */
    {
	memcpy(buf + tmp,
	       msg,
	       msgsize);
    }

    *framedmsg = (globus_byte_t *) buf;
    *framedsize = tmp + msgsize;

destroy_out:
    globus_url_destroy(&parsed);
out:
    return rc;
}