/globus_gass_transfer-7.2/library/globus_gass_transfer_http.c
C | 6483 lines | 5093 code | 648 blank | 742 comment | 687 complexity | de1586f4ef60c82a9264f1084549746c MD5 | raw file
Possible License(s): Apache-2.0
- /*
- * Copyright 1999-2006 University of Chicago
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
- /**
- * @file globus_gass_transfer_http.c http/https Protocol Module Implementation
- *
- * This module implements the http and https URL schemes for the GASS transfer
- * library
- *
- * CVS Information:
- * $Source: /home/globdev/CVS/globus-packages/gass/transfer/source/library/globus_gass_transfer_http.c,v $
- * $Date: 2009/11/11 19:48:37 $
- * $Revision: 1.48 $
- * $Author: bester $
- */
- #endif
- #include "globus_i_gass_transfer.h"
- #include "globus_io.h"
- #include "globus_l_gass_transfer_http.h"
- #include <stdlib.h>
- #include <ctype.h>
- #include <string.h>
- #ifndef TARGET_ARCH_WIN32
- #include <strings.h>
- #endif
- #include "version.h"
- #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
- /*
- #define DEBUG_GASS_TRANSFER
- */
- typedef struct
- {
- globus_gass_transfer_http_listener_proto_t * l_proto;
- globus_gass_transfer_request_t request;
- }
- globus_l_gass_transfer_failed_kickout_closure_t;
- #if defined(DEBUG_GASS_TRANSFER)
- static char * globus_l_gass_transfer_http_debug_level="";
- /* Debug Levels */
- /* 1: Major entry points to the library are displayed */
- /* 2: Calls into the gass transfer proto API are displayed */
- /* 3: Callbacks are displayed */
- /* 4: Callback Registration is displayed */
- /* 5: Error returns from lower-level calls */
- /* 6: Protocol dumps */
- /* 9: Thread safety */
- #define debug_printf(level,fmt) \
- if(strchr(globus_l_gass_transfer_http_debug_level, (#level)[0])) \
- {\
- printf fmt;\
- }
- #undef globus_l_gass_transfer_http_lock
- #undef globus_l_gass_transfer_http_unlock
- static int globus_l_gass_lock_line=0;
- static int globus_l_gass_lock_tmp=0;
- #define MYNAME(x) static char * myname=#x
- #define globus_l_gass_transfer_http_lock() \
- printf(strchr(globus_l_gass_transfer_http_debug_level,'9') ? "Thread [%d] acquiring mutex at %s:%d\n" : "", \
- (int) globus_thread_self(), \
- __FILE__, \
- __LINE__), \
- fflush(stdout), \
- globus_l_gass_lock_tmp = \
- globus_mutex_lock(&globus_l_gass_transfer_http_mutex), \
- globus_l_gass_lock_line=__LINE__, \
- globus_l_gass_lock_tmp
- #define globus_l_gass_transfer_http_unlock() \
- printf(strchr(globus_l_gass_transfer_http_debug_level, '9') ? "Thread [%d] releasing mutex at %s:%d\n" : "", \
- (int) globus_thread_self(), \
- __FILE__, \
- __LINE__), \
- fflush(stdout), \
- globus_l_gass_lock_line = 0, \
- globus_mutex_unlock(&globus_l_gass_transfer_http_mutex)
- #else
- #define debug_printf(level, fmt)
- #define MYNAME(x)
- #endif
- static
- void
- globus_l_gass_transfer_http_accept_failed_kickout(
- void * arg);
- static volatile int globus_l_gass_transfer_http_closing;
- #if !defined(GLOBUS_GASS_TRANSFER_HTTP_PARSER_TEST)
- int
- globus_l_gass_transfer_http_activate(void)
- {
- OM_uint32 maj_stat;
- OM_uint32 min_stat;
- gss_name_t name;
- gss_cred_id_t globus_l_gass_transfer_http_credential =
- GSS_C_NO_CREDENTIAL;
- gss_buffer_desc name_buffer;
- MYNAME(globus_l_gass_transfer_http_activate);
-
- globus_l_gass_transfer_http_closing = 0;
- name_buffer.value = GLOBUS_NULL;
- name_buffer.length = 0;
- # if defined(DEBUG_GASS_TRANSFER)
- {
- globus_l_gass_transfer_http_debug_level =
- globus_module_getenv("GLOBUS_GASS_TRANSFER_HTTP_DEBUG_LEVEL");
- if(globus_l_gass_transfer_http_debug_level == GLOBUS_NULL)
- {
- globus_l_gass_transfer_http_debug_level = "";
- }
- }
- # endif
-
- debug_printf(1, (_GTSL("Entering %s()\n"),myname));
- globus_module_activate(GLOBUS_COMMON_MODULE);
- globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE);
- globus_module_activate(GLOBUS_IO_MODULE);
- globus_mutex_init(&globus_l_gass_transfer_http_mutex,
- GLOBUS_NULL);
- globus_cond_init(&globus_l_gass_transfer_http_cond,
- GLOBUS_NULL);
- maj_stat = globus_gss_assist_acquire_cred(
- &min_stat,
- GSS_C_BOTH,
- &globus_l_gass_transfer_http_credential);
- if (maj_stat != GSS_S_COMPLETE)
- {
- goto error_exit;
- }
- maj_stat = gss_inquire_cred(
- &min_stat,
- globus_l_gass_transfer_http_credential,
- &name,
- GLOBUS_NULL,
- GLOBUS_NULL,
- GLOBUS_NULL);
- if (maj_stat != GSS_S_COMPLETE)
- {
- goto error_exit;
- }
- maj_stat = gss_display_name(
- &min_stat,
- name,
- &name_buffer,
- GLOBUS_NULL);
- if (maj_stat != GSS_S_COMPLETE)
- {
- goto error_exit;
- }
- maj_stat = gss_release_name(
- &min_stat,
- &name);
- if (maj_stat != GSS_S_COMPLETE)
- {
- goto error_exit;
- }
-
- globus_l_gass_transfer_http_subject_name = name_buffer.value;
- if (globus_l_gass_transfer_http_credential != GSS_C_NO_CREDENTIAL)
- {
- gss_release_cred(&min_stat, &globus_l_gass_transfer_http_credential);
- }
- debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
-
- return GLOBUS_SUCCESS;
- error_exit:
- if (globus_l_gass_transfer_http_credential != GSS_C_NO_CREDENTIAL)
- {
- gss_release_cred(&min_stat, &globus_l_gass_transfer_http_credential);
- }
- debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
- return GLOBUS_FAILURE;
- }
- int
- globus_l_gass_transfer_http_deactivate(void)
- {
- MYNAME(globus_l_gass_transfer_http_deactivate);
- debug_printf(1, (_GTSL("Entering %s()\n"),myname));
- globus_l_gass_transfer_http_lock();
- while(globus_l_gass_transfer_http_closing > 0)
- {
- globus_l_gass_transfer_http_wait();
- }
- globus_l_gass_transfer_http_unlock();
- globus_module_deactivate(GLOBUS_IO_MODULE);
- globus_module_deactivate(GLOBUS_GSI_GSS_ASSIST_MODULE);
- globus_mutex_destroy(&globus_l_gass_transfer_http_mutex);
- globus_cond_destroy(&globus_l_gass_transfer_http_cond);
- globus_free(globus_l_gass_transfer_http_subject_name);
- globus_module_deactivate(GLOBUS_COMMON_MODULE);
- debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
- return GLOBUS_SUCCESS;
- }
- globus_module_descriptor_t globus_i_gass_transfer_http_module =
- {
- "globus_i_gass_transfer_http",
- globus_l_gass_transfer_http_activate,
- globus_l_gass_transfer_http_deactivate,
- GLOBUS_NULL,
- GLOBUS_NULL,
- &local_version
- };
- /* Protocol Descriptor, which is registered with the GASS system */
- globus_gass_transfer_proto_descriptor_t
- globus_i_gass_transfer_http_descriptor =
- {
- "http",
- /* client-side support */
- globus_l_gass_transfer_http_new_requestattr,
- globus_l_gass_transfer_http_new_request,
- /* server-side support */
- globus_l_gass_transfer_http_new_listenerattr /* new_listenerattr */,
- globus_l_gass_transfer_http_new_listener /* new_listener */
- };
- globus_gass_transfer_proto_descriptor_t
- globus_i_gass_transfer_https_descriptor =
- {
- "https",
- /* client-side support */
- globus_l_gass_transfer_http_new_requestattr,
- globus_l_gass_transfer_http_new_request,
- /* server-side support */
- globus_l_gass_transfer_http_new_listenerattr /* new_listenerattr */,
- globus_l_gass_transfer_http_new_listener /* new_listener */
- };
- /*
- * Function: globus_l_gass_transfer_http_send()
- *
- * Description: Send a byte array to an HTTP server
- *
- * Parameters:
- *
- * Returns:
- */
- static
- void
- globus_l_gass_transfer_http_send(
- globus_gass_transfer_request_proto_t * proto,
- globus_gass_transfer_request_t request,
- globus_byte_t * buffer,
- globus_size_t buffer_length,
- globus_bool_t last_data)
- {
- globus_result_t result;
- globus_gass_transfer_http_request_proto_t * new_proto;
- globus_reltime_t delay_time;
- MYNAME(globus_l_gass_transfer_http_send);
-
- debug_printf(1, (_GTSL("Entering %s()\n"),myname));
- globus_l_gass_transfer_http_lock();
- new_proto = (globus_gass_transfer_http_request_proto_t *) proto;
- new_proto->last_data = last_data;
- /* We can only process a send if the proto is in the "idle" state */
- globus_assert(new_proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE);
- /* state change to "pending" */
- new_proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_PENDING;
- /* Update the buffers to point to those supplied by the user */
- new_proto->user_buffer = buffer;
- new_proto->user_buflen = buffer_length;
- /* If a a failure occurred, callback with the failure bit set,
- * and close the handle
- */
- if(new_proto->failure_occurred)
- {
- goto fail_exit;
- }
- /* Register the send of the data */
- if(new_proto->chunked)
- {
- globus_size_t num_iovecs;
- /* send chunk header and footer as an iovec array */
- sprintf((char *) new_proto->iov[0].iov_base,
- "%lx%s",
- (long) new_proto->user_buflen,
- CRLF);
- new_proto->iov[0].iov_len = strlen((char *) new_proto->iov[0].iov_base);
- new_proto->iov[1].iov_base = (void *) new_proto->user_buffer;
- new_proto->iov[1].iov_len = new_proto->user_buflen;
- new_proto->iov[2].iov_base = CRLF;
- new_proto->iov[2].iov_len = 2;
- if(last_data && new_proto->user_buflen != 0)
- {
- /* last data, need to append a zero-length chunk to
- * indicate this
- */
- num_iovecs = 4;
- }
- else if(last_data && new_proto->user_buflen == 0)
- {
- /* last data, with a zero-length chunk from the user */
- new_proto->iov[1].iov_base = CRLF;
- new_proto->iov[1].iov_len = 2;
- num_iovecs = 2;
- }
- else
- {
- /* normal chunk */
- num_iovecs = 3;
- }
- debug_printf(4, (_GTSL("%s(): Registering writev\n"), myname));
- result = globus_io_register_writev(
- &new_proto->handle,
- new_proto->iov,
- num_iovecs /* 3 iovecs header, body, final CRLF */,
- globus_l_gass_transfer_http_writev_callback,
- new_proto);
- }
- else
- {
- /* send data raw */
- debug_printf(4, (_GTSL("%s(): Registering writev\n"), myname));
- result = globus_io_register_write(
- &new_proto->handle,
- new_proto->user_buffer,
- new_proto->user_buflen,
- globus_l_gass_transfer_http_write_callback,
- new_proto);
- }
- if(result == GLOBUS_SUCCESS)
- {
- /*
- * Registration succeeded. Callback to GASS occurs when I/O
- * completes.
- */
- globus_l_gass_transfer_http_unlock();
- debug_printf(1, (_GTSL("exiting %s()\n"),myname));
- return;
- }
- fail_exit:
- /* Registration failed, close up handle and signal failure to GASS */
- result = globus_l_gass_transfer_http_register_close(new_proto);
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(new_proto);
- }
- GlobusTimeReltimeSet(delay_time, 0, 0);
- debug_printf(4, (_GTSL("%s(): Registering oneshot\n"), myname));
- globus_callback_register_oneshot(
- GLOBUS_NULL,
- &delay_time,
- globus_l_gass_transfer_http_callback_send_callback,
- (void *) new_proto);
- globus_l_gass_transfer_http_unlock();
- debug_printf(1, (_GTSL("exiting %s()\n"),myname));
- }
- /* globus_l_gass_transfer_http_send() */
- /*
- * Function: globus_l_gass_transfer_http_receive()
- *
- * Description: Schedule the next block of data from the http server
- * to end up in the provided byte array
- *
- * Parameters:
- *
- * Returns:
- */
- static
- void
- globus_l_gass_transfer_http_receive(
- globus_gass_transfer_request_proto_t * proto,
- globus_gass_transfer_request_t request,
- globus_byte_t * buffer,
- globus_size_t buffer_length,
- globus_size_t wait_for_length)
- {
- globus_gass_transfer_http_request_proto_t * new_proto;
- globus_reltime_t delay_time;
- MYNAME(globus_l_gass_transfer_http_receive);
-
- debug_printf(1, (_GTSL("Entering %s()\n"),myname));
-
- globus_l_gass_transfer_http_lock();
- new_proto = (globus_gass_transfer_http_request_proto_t *) proto;
- /* We can only process a receive if the proto is in the "idle" state */
- globus_assert(new_proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE);
- /* state change to "pending" */
- new_proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_PENDING;
- /* Update the buffers to point to those supplied by the user */
- new_proto->user_buffer = buffer;
- new_proto->user_buflen = buffer_length;
- new_proto->user_offset = 0;
- new_proto->user_waitlen = wait_for_length;
- new_proto->oneshot_registered = GLOBUS_TRUE;
- GlobusTimeReltimeSet(delay_time, 0, 0);
- debug_printf(4, (_GTSL("%s(): Registering oneshot\n"), myname));
- globus_callback_register_oneshot(
- GLOBUS_NULL,
- &delay_time,
- globus_l_gass_transfer_http_callback_read_buffered_callback,
- (void *) new_proto);
- globus_l_gass_transfer_http_unlock();
- debug_printf(1, (_GTSL("exiting %s()\n"),myname));
- }
- /* globus_l_gass_transfer_http_receive() */
- /*
- * Function: globus_l_gass_transfer_http_fail()
- *
- * Description: Cause the given request to fail for client-caused reasons
- *
- * Parameters:
- *
- * Returns:
- */
- static
- void
- globus_l_gass_transfer_http_fail(
- globus_gass_transfer_request_proto_t * proto,
- globus_gass_transfer_request_t request)
- {
- globus_gass_transfer_http_request_proto_t * new_proto;
- globus_bool_t signalled;
- globus_result_t result;
- MYNAME(globus_l_gass_transfer_http_fail);
- debug_printf(1, (_GTSL("entering %s()\n"),myname));
- new_proto = (globus_gass_transfer_http_request_proto_t *) proto;
- globus_l_gass_transfer_http_lock();
- signalled = GLOBUS_FALSE;
- while(!signalled)
- {
- switch(new_proto->state)
- {
- case GLOBUS_GASS_TRANSFER_HTTP_STATE_PENDING:
- if(new_proto->oneshot_registered == GLOBUS_TRUE)
- {
- new_proto->failure_occurred = GLOBUS_TRUE;
- signalled = GLOBUS_TRUE;
- break;
- }
- else if(new_proto->oneshot_active)
- {
- new_proto->failure_occurred = GLOBUS_TRUE;
- while(new_proto->state ==
- GLOBUS_GASS_TRANSFER_HTTP_STATE_PENDING)
- {
- globus_l_gass_transfer_http_wait();
- }
- break;
- }
- case GLOBUS_GASS_TRANSFER_HTTP_STATE_CONNECTING:
- case GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE:
- /* We will transition to the closing state, signalling the failure,
- * and registering the close (which will transition us to the
- * done state).
- */
- signalled = GLOBUS_TRUE;
- new_proto->failure_occurred = GLOBUS_TRUE;
- result = globus_l_gass_transfer_http_register_close(new_proto);
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(new_proto);
- }
- break;
- case GLOBUS_GASS_TRANSFER_HTTP_STATE_CLOSING:
- case GLOBUS_GASS_TRANSFER_HTTP_STATE_DONE:
- case GLOBUS_GASS_TRANSFER_HTTP_STATE_REQUESTING:
- case GLOBUS_GASS_TRANSFER_HTTP_STATE_RESPONDING:
- case GLOBUS_GASS_TRANSFER_HTTP_STATE_REFERRED:
- case GLOBUS_GASS_TRANSFER_HTTP_STATE_DENIED:
- signalled = GLOBUS_TRUE;
- new_proto->failure_occurred = GLOBUS_TRUE;
- break;
- }
- }
- globus_l_gass_transfer_http_unlock();
- debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
- }
- /* globus_l_gass_transfer_http_fail() */
- static
- void
- globus_l_gass_transfer_http_write_callback(
- void * callback_arg,
- globus_io_handle_t * handle,
- globus_result_t result,
- globus_byte_t * buf,
- globus_size_t nbytes)
- {
- globus_gass_transfer_http_request_proto_t * proto;
- MYNAME(globus_l_gass_transfer_http_write_callback);
- debug_printf(3, (_GTSL("Entering %s()\n"),myname));
- proto = (globus_gass_transfer_http_request_proto_t *) callback_arg;
- globus_l_gass_transfer_http_lock();
- if(result != GLOBUS_SUCCESS ||
- proto->failure_occurred ||
- proto->parse_error)
- {
- proto->last_data = GLOBUS_TRUE;
- }
- if(proto->last_data)
- {
- proto->user_offset = nbytes;
- if((proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT ||
- proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND) &&
- (!proto->failure_occurred && !proto->parse_error))
- {
- if(proto->got_response)
- {
- globus_byte_t * buffer;
- globus_size_t offset;
- globus_gass_transfer_request_t request = proto->request;
- int failed = proto->failure_occurred;
- proto->failure_occurred = GLOBUS_TRUE;
- buffer = proto->user_buffer;
- offset = proto->user_offset;
- result = globus_l_gass_transfer_http_register_close(proto);
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(proto);
- }
- globus_l_gass_transfer_http_unlock();
- globus_gass_transfer_proto_send_complete(request,
- buffer,
- offset,
- failed,
- GLOBUS_TRUE);
- debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
- return;
- }
- else
- {
- /* the callback to read the response is registered at
- * the beginning of the send, so we do nothing here,
- * and wait for the response
- */
- proto->waiting_for_response = GLOBUS_TRUE;
- globus_l_gass_transfer_http_unlock();
- debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
- return;
- }
- }
- else
- {
- globus_gass_transfer_request_t request;
- globus_byte_t * buf;
- globus_size_t nbytes_sent;
- globus_bool_t fail;
- request = proto->request;
- buf = proto->user_buffer;
- nbytes_sent = proto->user_offset;
- fail = proto->failure_occurred;
-
-
- /* need to register the close, and callback to the user */
- result = globus_l_gass_transfer_http_register_close(proto);
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(proto);
- }
-
- globus_l_gass_transfer_http_unlock();
- globus_gass_transfer_proto_send_complete(
- request,
- buf,
- nbytes_sent,
- fail,
- GLOBUS_TRUE);
- debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
- return;
- }
- }
- else
- {
- globus_gass_transfer_request_t request;
- globus_byte_t * buf;
- globus_bool_t fail;
- globus_bool_t last_data;
-
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE;
- request = proto->request;
- buf = proto->user_buffer;
- fail = proto->failure_occurred;
- last_data = proto->last_data;
-
- globus_l_gass_transfer_http_unlock();
- globus_gass_transfer_proto_send_complete(request,
- buf,
- nbytes,
- fail,
- last_data);
- }
- debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
- return;
- }
- /* globus_l_gass_transfer_http_write_callback() */
- static
- void
- globus_l_gass_transfer_http_writev_callback(
- void * callback_arg,
- globus_io_handle_t * handle,
- globus_result_t result,
- struct iovec * iov,
- globus_size_t iovcnt,
- globus_size_t nbytes)
- {
- globus_gass_transfer_http_request_proto_t * proto;
- MYNAME(globus_l_gass_transfer_http_writev_callback);
- debug_printf(3, (_GTSL("Entering %s()\n"),myname));
- proto = (globus_gass_transfer_http_request_proto_t *) callback_arg;
- globus_l_gass_transfer_http_lock();
- if(result != GLOBUS_SUCCESS ||
- proto->failure_occurred ||
- proto->parse_error)
- {
- proto->last_data = GLOBUS_TRUE;
- }
- if(proto->last_data)
- {
- proto->user_offset = nbytes - iov[0].iov_len - iov[2].iov_len;
- if((proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT ||
- proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND) &&
- (!proto->failure_occurred && !proto->parse_error))
- {
- if(proto->got_response)
- {
- globus_byte_t * buffer;
- globus_size_t offset;
- int failed = proto->failure_occurred;
- globus_gass_transfer_request_t request = proto->request;
- buffer = proto->user_buffer;
- offset = proto->user_offset;
- result = globus_l_gass_transfer_http_register_close(proto);
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(proto);
- }
- globus_l_gass_transfer_http_unlock();
- globus_gass_transfer_proto_send_complete(request,
- buffer,
- offset,
- failed,
- GLOBUS_TRUE);
- debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
- return;
- }
- else
- {
- /* the callback to read the response is registered at
- * the beginning of the send, so we do nothing here,
- * and wait for the response
- */
- proto->waiting_for_response = GLOBUS_TRUE;
- globus_l_gass_transfer_http_unlock();
- debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
- return;
- }
- }
- else
- {
- globus_gass_transfer_request_t request;
- globus_byte_t *buf;
- globus_size_t nbytes_sent;
- globus_bool_t fail;
- request = proto->request;
- buf = proto->user_buffer;
- nbytes_sent = proto->user_offset;
- fail = proto->failure_occurred;
- /* need to register the close, and callback to the user */
- result = globus_l_gass_transfer_http_register_close(proto);
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(proto);
- }
- globus_l_gass_transfer_http_unlock();
- globus_gass_transfer_proto_send_complete(
- request,
- buf,
- nbytes_sent,
- fail,
- GLOBUS_TRUE);
- debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
- return;
- }
- }
- else
- {
- globus_gass_transfer_request_t request;
- globus_byte_t *buf;
- globus_size_t nbytes_sent;
- globus_bool_t fail;
-
- request = proto->request;
- buf = proto->user_buffer;
- nbytes_sent = nbytes - iov[0].iov_len - iov[2].iov_len,
- fail = proto->failure_occurred;
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE;
- globus_l_gass_transfer_http_unlock();
- globus_gass_transfer_proto_send_complete(request,
- buf,
- nbytes_sent,
- fail,
- GLOBUS_FALSE);
- debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
- return;
- }
- }
- /* globus_l_gass_transfer_http_writev_callback() */
- /*
- * Function: globus_l_gass_transfer_http_read_callack()
- *
- * Description: Callback when the read of from the connection to the active
- * buffer has completed or failed.
- *
- * Parameters:
- *
- * Returns:
- */
- static
- void
- globus_l_gass_transfer_http_read_callback(
- void * callback_arg,
- globus_io_handle_t * handle,
- globus_result_t result,
- globus_byte_t * buf,
- globus_size_t nbytes)
- {
- globus_object_t * err = GLOBUS_NULL;
- globus_gass_transfer_http_request_proto_t * proto;
- globus_gass_transfer_request_t request;
- globus_bool_t last_data = GLOBUS_FALSE;
- globus_bool_t failure = GLOBUS_FALSE;
- globus_size_t offset = 0;
-
- MYNAME(globus_l_gass_transfer_http_read_callback);
-
- debug_printf(3, (_GTSL("Entering %s()\n"),myname));
-
- proto = (globus_gass_transfer_http_request_proto_t *) callback_arg;
- if(result != GLOBUS_SUCCESS)
- {
- char * tmpstr;
- err = globus_error_get(result);
- tmpstr = globus_object_printable_to_string(err);
- debug_printf(5, (_GTSL("%s(): Error: %s\n"), myname, tmpstr));
- globus_libc_free(tmpstr);
- }
- globus_l_gass_transfer_http_lock();
- proto->user_offset += nbytes;
- proto->handled += nbytes;
- if(nbytes > proto->user_waitlen)
- {
- proto->user_waitlen = 0;
- }
- else
- {
- proto->user_waitlen -= nbytes;
- }
- if(proto->chunked)
- {
- proto->chunk_left -= nbytes;
- }
- if(result != GLOBUS_SUCCESS &&
- globus_io_eof(err))
- {
- proto->eof_read = GLOBUS_TRUE;
- }
- else if(result != GLOBUS_SUCCESS ||
- proto->failure_occurred ||
- proto->parse_error)
- {
- proto->recv_state = GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
- }
- if(proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_EOF &&
- proto->eof_read == GLOBUS_TRUE)
- {
- proto->recv_state = GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF;
- }
- else if(proto->recv_state ==
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_LENGTH &&
- proto->handled == proto->length)
- {
- proto->recv_state = GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF;
- }
- else if(proto->recv_state ==
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_LENGTH &&
- proto->eof_read == GLOBUS_TRUE &&
- proto->handled < proto->length)
- {
- proto->recv_state = GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
- }
- else if(nbytes==0 && proto->eof_read)
- {
- proto->failure_occurred = GLOBUS_TRUE;
- proto->recv_state = GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
- }
- if((proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT ||
- proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND) &&
- proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF)
- {
- char * response;
- globus_size_t response_len=0;
- globus_size_t offset;
- response_len += 1;
- response_len += strlen(GLOBUS_L_GENERIC_RESPONSE);
- response_len += 3;
- response_len += strlen(GLOBUS_L_OK);
- response_len += 2;
- response = globus_malloc(response_len);
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_RESPONDING;
- offset = sprintf(response,
- GLOBUS_L_GENERIC_RESPONSE,
- 0,
- 200,
- GLOBUS_L_OK);
- offset += sprintf(response + offset,
- CRLF);
- debug_printf(4,(_GTSL("%s(): Registering write\n"),myname));
- globus_io_register_write(&proto->handle,
- (globus_byte_t *) response,
- strlen(response),
- globus_l_gass_transfer_http_write_response,
- proto);
- }
- /* Register the socket for closing if we're done reading from it */
- else if(proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF ||
- proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR)
- {
- failure = proto->failure_occurred;
- buf = proto->user_buffer;
- offset = proto->user_offset;
- request = proto->request;
- last_data = GLOBUS_TRUE;
- if(proto->state != GLOBUS_GASS_TRANSFER_HTTP_STATE_CLOSING)
- {
- result = globus_l_gass_transfer_http_register_close(proto);
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(proto);
- }
- }
- globus_l_gass_transfer_http_unlock();
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_receive_complete()")));
- globus_gass_transfer_proto_receive_complete(request,
- buf,
- offset,
- failure,
- last_data);
- goto out;
- }
- if(proto->user_waitlen == 0 ||
- proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF ||
- proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR)
- {
- /*
- * Received the required minimum of data from connection, an
- * error, or the end-of file, signal this to GASS
- */
- if(proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_PENDING)
- {
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE;
- }
- if(proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF ||
- proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR)
- {
- last_data = GLOBUS_TRUE;
- }
- failure = proto->failure_occurred;
- buf = proto->user_buffer;
- offset = proto->user_offset;
- request = proto->request;
- globus_l_gass_transfer_http_unlock();
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_receive_complete()")));
- globus_gass_transfer_proto_receive_complete(request,
- buf,
- offset,
- failure,
- last_data);
- }
- else
- {
- result = globus_l_gass_transfer_http_register_read(proto);
- globus_l_gass_transfer_http_unlock();
- }
- out:
- if(err)
- {
- globus_object_free(err);
- }
- debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
- return;
- }
- /* globus_l_gass_transfer_http_read_callback() */
- /*
- * Function: globus_l_gass_transfer_http_read_buffered_callack()
- *
- * Description: Callback when the read of from the http to the
- * response buffer has completed or failed.
- *
- * Parameters:
- *
- * Returns:
- */
- static
- void
- globus_l_gass_transfer_http_read_buffered_callback(
- void * callback_arg,
- globus_io_handle_t * handle,
- globus_result_t result,
- globus_byte_t * buf,
- globus_size_t nbytes)
- {
- globus_object_t * err = GLOBUS_NULL;
- globus_gass_transfer_http_request_proto_t * proto;
- MYNAME(globus_l_gass_transfer_http_read_buffered_callback);
- debug_printf(3, (_GTSL("Entering %s()\n"),myname));
- proto = (globus_gass_transfer_http_request_proto_t *) callback_arg;
- if(result != GLOBUS_SUCCESS)
- {
- char * tmpstr;
- err = globus_error_get(result);
- tmpstr = globus_object_printable_to_string(err);
- debug_printf(5, (_GTSL("%s(): %s\n"), myname, tmpstr));
- globus_libc_free(tmpstr);
- }
- globus_l_gass_transfer_http_lock();
- proto->response_offset += nbytes;
- if(result != GLOBUS_SUCCESS &&
- globus_io_eof(err))
- {
- proto->eof_read = GLOBUS_TRUE;
- }
- else if(result != GLOBUS_SUCCESS)
- {
- proto->recv_state = GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
- }
- /*
- * Copy the document from the response buffer to the user-supplied
- * buffer, translating end-of-line if necessary, and handling any
- * chunk header/footer information
- */
- globus_l_gass_transfer_http_handle_chunk(proto);
- if(proto->failure_occurred)
- {
- proto->recv_state = GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
- }
- /* successful read for server, send response */
- if((proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT ||
- proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND) &&
- proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF &&
- proto->recv_state != GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR)
- {
- char * response;
- globus_size_t response_len=0;
- globus_size_t offset;
- response_len += 1;
- response_len += strlen(GLOBUS_L_GENERIC_RESPONSE);
- response_len += 3;
- response_len += strlen(GLOBUS_L_OK);
- response_len += 2;
- response = globus_malloc(response_len);
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_RESPONDING;
- offset = sprintf(response,
- GLOBUS_L_GENERIC_RESPONSE,
- 0,
- 200,
- GLOBUS_L_OK);
- offset += sprintf(response + offset,
- CRLF);
- debug_printf(4,(_GTSL("%s(): Registering write\n"),myname));
- globus_io_register_write(&proto->handle,
- (globus_byte_t *) response,
- strlen(response),
- globus_l_gass_transfer_http_write_response,
- proto);
- }
- /* Register the socket for closing if we're done reading from it */
- else if(proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF ||
- proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR)
- {
- if(proto->state != GLOBUS_GASS_TRANSFER_HTTP_STATE_CLOSING)
- {
- result = globus_l_gass_transfer_http_register_close(proto);
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(proto);
- }
- }
- }
- if(proto->user_waitlen == 0 ||
- proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF ||
- proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR)
- {
- globus_gass_transfer_request_t request;
- globus_bool_t last_data = GLOBUS_FALSE;
- globus_bool_t failure ;
- globus_byte_t * buf;
- globus_size_t offset;
- /*
- * Received the required minimum of data from connection, an
- * error, or the end-of file, signal this to GASS
- */
- if(proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_PENDING)
- {
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE;
- }
- if(proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF ||
- proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR)
- {
- last_data = GLOBUS_TRUE;
- }
- if(err)
- {
- globus_object_free(err);
- err = GLOBUS_NULL;
- }
- proto->oneshot_active = GLOBUS_FALSE;
- failure = proto->failure_occurred;
- buf = proto->user_buffer;
- offset = proto->user_offset;
- request = proto->request;
- globus_l_gass_transfer_http_signal();
- globus_l_gass_transfer_http_unlock();
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_receive_complete()\n")));
- globus_gass_transfer_proto_receive_complete(request,
- buf,
- offset,
- failure,
- last_data);
- debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
- return;
- }
- else
- {
- result = globus_l_gass_transfer_http_register_read(proto);
- }
- if(result != GLOBUS_SUCCESS)
- {
- goto error_exit;
- }
- proto->oneshot_active = GLOBUS_FALSE;
- globus_l_gass_transfer_http_unlock();
- if(err)
- {
- globus_object_free(err);
- }
- debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
- return;
- error_exit:
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_CLOSING;
- proto->failure_occurred = GLOBUS_TRUE;
- proto->oneshot_active = GLOBUS_FALSE;
- proto->oneshot_active = GLOBUS_FALSE;
-
- result = globus_l_gass_transfer_http_register_close(proto);
- if(err)
- {
- globus_object_free(err);
- }
- {
- globus_gass_transfer_request_t request;
- globus_byte_t *buf;
- globus_size_t offset;
- request = proto->request;
- buf = proto->user_buffer;
- offset = proto->user_offset;
- /* register close failed, act as though it was closed */
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(proto);
- }
- globus_l_gass_transfer_http_unlock();
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_receive_complete()")));
- globus_gass_transfer_proto_receive_complete(request,
- buf,
- offset,
- GLOBUS_TRUE,
- GLOBUS_TRUE);
- }
- debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
- return;
- }
- /* globus_l_gass_transfer_http_read_buffered_callback() */
- /*
- * Function: globus_l_gass_transfer_http_close_callback()
- *
- * Description: Called upon completion of close()ing the file handle,
- * Will free the proto instance if the client has called
- * the "done" function
- *
- *
- * Parameters:
- *
- * Returns:
- */
- static
- void
- globus_l_gass_transfer_http_close_callback(
- void * callback_arg,
- globus_io_handle_t * handle,
- globus_result_t result)
- {
- globus_gass_transfer_http_request_proto_t * proto;
- MYNAME(globus_l_gass_transfer_http_close_callback);
- debug_printf(3, (_GTSL("Entering %s()\n"),myname));
- proto = (globus_gass_transfer_http_request_proto_t *) callback_arg;
- globus_l_gass_transfer_http_lock();
- globus_l_gass_transfer_http_close(proto);
- globus_l_gass_transfer_http_unlock();
- }
- /* globus_l_gass_transfer_http_close_callback() */
- /*
- * Function: globus_l_gass_transfer_http_close()
- *
- * Description: must be called with the mutex locked
- *
- *
- * Parameters:
- *
- * Returns:
- */
- static
- void
- globus_l_gass_transfer_http_close(
- globus_gass_transfer_http_request_proto_t * proto)
- {
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_DONE;
- if(proto->destroy_called)
- {
- globus_l_gass_transfer_http_proto_destroy(proto);
- }
- globus_l_gass_transfer_http_closing--;
- globus_l_gass_transfer_http_signal();
- }
- /* globus_l_gass_transfer_http_close() */
- /*
- * Function: globus_l_gass_transfer_http_register_close()
- *
- * Description: must be called with the mutex locked
- *
- *
- * Parameters:
- *
- * Returns:
- */
- static
- globus_result_t
- globus_l_gass_transfer_http_register_close(
- globus_gass_transfer_http_request_proto_t * proto)
- {
- globus_result_t result;
- MYNAME(globus_l_gass_transfer_http_register_close);
-
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_CLOSING;
- globus_l_gass_transfer_http_closing++;
-
- debug_printf(4,(_GTSL("%s(): registering close on %p\n"), myname, &proto->handle));
- result = globus_io_register_close(
- &proto->handle,
- globus_l_gass_transfer_http_close_callback,
- proto);
- return result;
- }
- /* globus_l_gass_transfer_http_register_close() */
- /*
- * Function: globus_l_gass_transfer_http_listener_close_callback()
- *
- * Description:
- *
- * Parameters:
- *
- * Returns:
- */
- static
- void
- globus_l_gass_transfer_http_listener_close_callback(
- void * callback_arg,
- globus_io_handle_t * handle,
- globus_result_t result)
- {
- globus_gass_transfer_http_listener_proto_t *
- proto;
- MYNAME(globus_l_gass_transfer_http_listener_close_callback);
- debug_printf(3, (_GTSL("Entering %s()\n"),myname));
- proto = (globus_gass_transfer_http_listener_proto_t *) callback_arg;
- globus_l_gass_transfer_http_lock();
- globus_l_gass_transfer_http_listener_close(proto);
- globus_l_gass_transfer_http_unlock();
- debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
- }
- /* globus_l_gass_transfer_http_listener_close_callback() */
- /*
- * Function: globus_l_gass_transfer_http_listener_close()
- *
- * Description: must be called with the mutex locked
- *
- * Parameters:
- *
- * Returns:
- */
- static
- void
- globus_l_gass_transfer_http_listener_close(
- globus_gass_transfer_http_listener_proto_t * proto)
- {
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSED;
- if(proto->destroy_called)
- {
- globus_l_gass_transfer_http_listener_proto_destroy(proto);
- }
- globus_l_gass_transfer_http_closing--;
- globus_l_gass_transfer_http_signal();
- }
- /* globus_l_gass_transfer_http_listener_close() */
- static
- void
- globus_l_gass_transfer_http_register_listener_close(
- globus_gass_transfer_http_listener_proto_t * proto)
- {
- globus_result_t result;
- MYNAME(globus_l_gass_transfer_http_register_listener_close);
- globus_l_gass_transfer_http_closing++;
- debug_printf(4,(_GTSL("%s(): registering close on %p\n"), myname, &proto->handle));
- result = globus_io_register_close(
- &proto->handle,
- globus_l_gass_transfer_http_listener_close_callback,
- proto);
- globus_assert(result == GLOBUS_SUCCESS);
- if(result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_listener_close(proto);
- }
- }
- /* globus_l_gass_transfer_http_register_listener_close() */
-
- /*
- * Function: globus_l_gass_transfer_http_listener_proto_destroy()
- *
- * Description:
- *
- * Parameters:
- *
- * Returns:
- */
- static
- void
- globus_l_gass_transfer_http_listener_proto_destroy(
- globus_gass_transfer_http_listener_proto_t *
- proto)
- {
- globus_free(proto);
- }
- /* globus_l_gass_transfer_http_listener_proto_destroy() */
- /*
- * Function: globus_l_gass_transfer_http_destroy()
- *
- * Description:
- *
- * Parameters:
- *
- * Returns:
- */
- static
- void
- globus_l_gass_transfer_http_destroy(
- globus_gass_transfer_request_proto_t * proto,
- globus_gass_transfer_request_t request)
- {
- globus_gass_transfer_http_request_proto_t * new_proto;
- MYNAME(globus_l_gass_transfer_http_destroy);
- debug_printf(1, (_GTSL("entering %s()\n"),myname));
- new_proto = (globus_gass_transfer_http_request_proto_t *) proto;
- globus_l_gass_transfer_http_lock();
- if(new_proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_CLOSING ||
- new_proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_REFERRED ||
- new_proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_RESPONDING ||
- new_proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_DENIED)
- {
- new_proto->destroy_called=GLOBUS_TRUE;
- }
- else if(new_proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_DONE)
- {
- globus_l_gass_transfer_http_proto_destroy(new_proto);
- }
- globus_l_gass_transfer_http_unlock();
- debug_printf(1, (_GTSL("exiting %s()\n"),myname));
- }
- /* globus_l_gass_transfer_http_destroy() */
- /*
- * Function: globus_l_gass_transfer_http_listener_destroy()
- *
- * Description:
- *
- * Parameters:
- *
- * Returns:
- */
- static
- void
- globus_l_gass_transfer_http_listener_destroy(
- globus_gass_transfer_listener_proto_t * proto,
- globus_gass_transfer_listener_t listener)
- {
- globus_gass_transfer_http_listener_proto_t *new_proto;
- MYNAME(globus_l_gass_transfer_http_listener_destroy);
- debug_printf(1, (_GTSL("entering %s()\n"),myname));
- new_proto = (globus_gass_transfer_http_listener_proto_t *) proto;
- globus_l_gass_transfer_http_lock();
- if(new_proto->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSED)
- {
- new_proto->destroy_called=GLOBUS_TRUE;
- }
- else
- {
- globus_l_gass_transfer_http_listener_proto_destroy(new_proto);
- }
- globus_l_gass_transfer_http_unlock();
- debug_printf(1, (_GTSL("exiting %s()\n"),myname));
- }
- /* globus_l_gass_transfer_http_listener_destroy() */
- /*
- * Function: globus_l_gass_transfer_http_listen()
- *
- * Description:
- *
- * Parameters:
- *
- * Returns:
- */
- static
- void
- globus_l_gass_transfer_http_listen(
- globus_gass_transfer_listener_proto_t * proto,
- globus_gass_transfer_listener_t listener)
- {
- globus_gass_transfer_http_listener_proto_t *new_proto;
- globus_result_t result;
- globus_reltime_t delay_time;
- MYNAME(globus_l_gass_transfer_http_listen);
- debug_printf(1, (_GTSL("entering %s()\n"),myname));
- new_proto = (globus_gass_transfer_http_listener_proto_t *) proto;
- globus_l_gass_transfer_http_lock();
- debug_printf(4,(_GTSL("%s(): registering listen on %p\n"),
- myname,
- &new_proto->handle));
- result = globus_io_tcp_register_listen(
- &new_proto->handle,
- globus_l_gass_transfer_http_listen_callback,
- (void *) new_proto);
- if(result != GLOBUS_SUCCESS)
- {
- GlobusTimeReltimeSet(delay_time, 0, 0);
- debug_printf(4,(_GTSL("%s(): registering oneshot because listen failed\n"),
- myname));
- globus_callback_register_oneshot(
- GLOBUS_NULL,
- &delay_time,
- globus_l_gass_transfer_http_callback_listen_callback,
- (void *) new_proto);
-
- }
- else
- {
- new_proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_LISTENING;
- }
- globus_l_gass_transfer_http_unlock();
- debug_printf(1, (_GTSL("exiting %s()\n"),myname));
- }
- /* globus_l_gass_transfer_http_listen() */
- static
- void
- globus_l_gass_transfer_http_listen_callback(
- void * callback_arg,
- globus_io_handle_t * handle,
- globus_result_t result)
- {
- globus_gass_transfer_http_listener_proto_t *proto;
- globus_gass_transfer_listener_t listener;
- MYNAME(globus_l_gass_transfer_http_listen_callback);
-
- debug_printf(3, (_GTSL("Entering %s()\n"),myname));
- proto = (globus_gass_transfer_http_listener_proto_t *) callback_arg;
- globus_l_gass_transfer_http_lock();
- switch(proto->state)
- {
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_LISTENING:
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_READY;
- break;
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING1:
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSED:
- break;
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_STARTING:
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_ACCEPTING:
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_READY:
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING2:
- globus_assert(proto->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_STARTING);
- globus_assert(proto->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_ACCEPTING);
- globus_assert(proto->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_READY);
- globus_assert(proto->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING2);
- }
- listener = proto->listener;
- globus_l_gass_transfer_http_unlock();
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_listener_ready()")));
- globus_gass_transfer_proto_listener_ready(listener);
- debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
- }
- /* globus_l_gass_transfer_http_listen_callback() */
- static
- void
- globus_l_gass_transfer_http_accept_callback(
- void * callback_arg,
- globus_io_handle_t * handle,
- globus_result_t result)
- {
- globus_gass_transfer_http_listener_proto_t *l;
- MYNAME(globus_l_gass_transfer_http_accept_callback);
-
- debug_printf(3, (_GTSL("Entering %s()\n"),myname));
- globus_l_gass_transfer_http_lock();
- fflush(stdout);
- l = (globus_gass_transfer_http_listener_proto_t *) callback_arg;
- switch(l->state)
- {
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_ACCEPTING:
- l->request->response_buffer = globus_malloc(GLOBUS_L_GASS_RESPONSE_LEN *
- sizeof(globus_byte_t));
- l->request->response_buflen = GLOBUS_L_GASS_RESPONSE_LEN;
- l->request->response_offset = 0;
- l->request->parsed_offset = 0;
- if(result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_unlock();
- globus_l_gass_transfer_http_request_callback(
- l,
- &l->request->handle,
- result,
- l->request->response_buffer,
- 0);
- debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_accept_callback()\n")));
- return;
- }
- else
- {
- debug_printf(4, (_GTSL("%s(): Registering read on %p\n"),
- myname,
- &l->request->handle));
- globus_io_register_read(&l->request->handle,
- l->request->response_buffer,
- l->request->response_buflen,
- 1,
- globus_l_gass_transfer_http_request_callback,
- l);
- }
- break;
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING2:
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSED:
- globus_l_gass_transfer_http_unlock();
- globus_gass_transfer_proto_new_listener_request(l->listener,
- l->request->request,
- GLOBUS_NULL);
- globus_l_gass_transfer_http_lock();
- /* should destroy the proto->request here? */
- break;
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_STARTING:
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_LISTENING:
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_READY:
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING1:
- globus_assert(l->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_STARTING);
- globus_assert(l->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_LISTENING);
- globus_assert(l->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_READY);
- globus_assert(l->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING1);
- }
- globus_l_gass_transfer_http_unlock();
- debug_printf(3, (_GTSL("Exiting %s()\n"), myname));
- }
- /* globus_l_gass_transfer_http_accept_callback() */
- static
- void
- globus_l_gass_transfer_http_request_refer(
- globus_gass_transfer_request_proto_t * rproto,
- globus_gass_transfer_request_t request)
- {
- globus_gass_transfer_http_request_proto_t * proto;
- globus_gass_transfer_referral_t referral;
- int rc;
- char * referral_string;
- globus_size_t referral_count;
- globus_size_t body_count=0; /* :) */
- globus_size_t offset;
- globus_size_t x;
- globus_size_t i;
- globus_size_t digits = 0;
- MYNAME(globus_l_gass_transfer_http_request_refer);
-
- globus_l_gass_transfer_http_lock();
- proto = (globus_gass_transfer_http_request_proto_t *) rproto;
- rc = globus_gass_transfer_request_get_referral(request,
- &referral);
- /* HTTP/1.1 302 Document Moved CRLF
- * Location: referral.url[0] CRLF
- * Content-Length: $body_count CRLF
- * Content-Type: text/html CRLF
- * CRLF
- * <html><head><title>300 Multiple Choices</title></head><body>
- * <a href="<referral.url[1]>">referral.url[1]</a><br>
- * ..
- * <a href="<referral.url[i]>">referral.url[i]</a><br>
- * </body></html>
- */
- referral_count = 1;
- referral_count += strlen(GLOBUS_L_REFER_RESPONSE);
- referral_count += strlen(GLOBUS_L_LOCATION_HEADER);
- referral_count += 2;
- referral_count += strlen(GLOBUS_L_CONTENT_LENGTH_HEADER);
- referral_count += strlen(GLOBUS_L_HTML_HEADER);
- referral_count += strlen(referral.url[0]);
- body_count += strlen(GLOBUS_L_HTML_REFERRAL_BODY_HEAD);
- body_count += strlen(GLOBUS_L_HTML_REFERRAL_BODY_TAIL);
- for(i = 0 ; i < referral.count; i++)
- {
- body_count += strlen(GLOBUS_L_HTML_HREF);
- body_count += strlen(referral.url[i]);
- body_count += strlen(referral.url[i]);
- }
- /* count the number of decimal digits in the body */
- x=body_count;
- do
- {
- digits++;
- x /= 10;
- } while(x > 0);
- referral_count += digits;
- referral_string = globus_malloc(referral_count + body_count);
- offset = sprintf(referral_string,
- GLOBUS_L_REFER_RESPONSE);
- offset += sprintf(referral_string + offset,
- GLOBUS_L_LOCATION_HEADER,
- referral.url[0]);
- offset += sprintf(referral_string + offset,
- GLOBUS_L_HTML_HEADER);
- offset += sprintf(referral_string + offset,
- GLOBUS_L_CONTENT_LENGTH_HEADER,
- (long) body_count);
- offset += sprintf(referral_string + offset,
- CRLF);
- offset += sprintf(referral_string + offset,
- GLOBUS_L_HTML_REFERRAL_BODY_HEAD);
- for(i = 0 ; i < referral.count; i++)
- {
- offset += sprintf(referral_string + offset,
- GLOBUS_L_HTML_HREF,
- referral.url[i],
- referral.url[i]);
- }
- offset += sprintf(referral_string + offset,
- GLOBUS_L_HTML_REFERRAL_BODY_TAIL);
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_REFERRED;
- globus_gass_transfer_referral_destroy(&referral);
- debug_printf(4, (_GTSL("%s(): Registering write on %p\n"),
- myname,
- &proto->handle));
- globus_io_register_write(&proto->handle,
- (globus_byte_t *) referral_string,
- strlen(referral_string),
- globus_l_gass_transfer_http_write_response,
- proto);
- globus_l_gass_transfer_http_unlock();
- }
- /* globus_l_gass_transfer_http_request_refer() */
- static
- void
- globus_l_gass_transfer_http_request_deny(
- globus_gass_transfer_request_proto_t * rproto,
- globus_gass_transfer_request_t request)
- {
- globus_gass_transfer_http_request_proto_t * proto;
- char * deny_string;
- globus_size_t deny_count;
- globus_size_t body_count=0; /* :) */
- globus_size_t offset;
- globus_size_t x;
- globus_size_t digits = 0;
- int reason;
- char * message;
- MYNAME(globus_l_gass_transfer_http_request_deny);
-
- globus_l_gass_transfer_http_lock();
- proto = (globus_gass_transfer_http_request_proto_t *) rproto;
- reason = globus_gass_transfer_request_get_denial_reason(request);
- if(reason < 400 ||
- reason >= 600)
- {
- reason = 500;
- message = globus_libc_strdup(GLOBUS_L_DEFAULT_DENIAL_MESSAGE);
- }
- else
- {
- message = globus_gass_transfer_request_get_denial_message(request);
- if(message == GLOBUS_NULL)
- {
- message = globus_libc_strdup(GLOBUS_L_DEFAULT_DENIAL_MESSAGE);
- }
- }
- /* HTTP/1.1 %d %s CRLF
- * Content-Length: $body_count CRLF
- * Content-Type: text/html CRLF
- * CRLF
- * <html><head><title>%d %s</title></head><body> CRLF
- * %d %s</title></body></html> CRLF
- */
- deny_count = 1;
- deny_count += strlen(GLOBUS_L_DENIAL_RESPONSE);
- deny_count += 3 ; /* code */
- deny_count += strlen(message);
- deny_count += strlen(GLOBUS_L_CONTENT_LENGTH_HEADER);
- deny_count += strlen(GLOBUS_L_HTML_HEADER);
- deny_count += 2;
- body_count += strlen(GLOBUS_L_HTML_DENIAL_BODY);
- body_count += (strlen(message) * 3);
- body_count += (3 * 3); /* code */
- /* count the number of decimal digits in the body */
- x=body_count;
- do
- {
- digits++;
- x /= 10;
- } while(x > 0);
- deny_count += digits;
- deny_string = globus_malloc(deny_count + body_count);
- offset = sprintf(deny_string,
- GLOBUS_L_DENIAL_RESPONSE,
- reason,
- message);
- offset += sprintf(deny_string + offset,
- GLOBUS_L_HTML_HEADER);
- offset += sprintf(deny_string + offset,
- GLOBUS_L_CONTENT_LENGTH_HEADER,
- (long) body_count);
- offset += sprintf(deny_string + offset,
- CRLF);
- offset += sprintf(deny_string + offset,
- GLOBUS_L_HTML_DENIAL_BODY,
- reason,
- message,
- reason,
- message);
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_DENIED;
- globus_free(message);
- debug_printf(4, (_GTSL("%s(): Registering write on %p\n"),
- myname,
- &proto->handle));
- globus_io_register_write(&proto->handle,
- (globus_byte_t *) deny_string,
- strlen(deny_string),
- globus_l_gass_transfer_http_write_response,
- proto);
- globus_l_gass_transfer_http_unlock();
- }
- /* globus_l_gass_transfer_http_request_deny() */
- static
- void
- globus_l_gass_transfer_http_request_authorize(
- globus_gass_transfer_request_proto_t * rproto,
- globus_gass_transfer_request_t request)
- {
- globus_gass_transfer_http_request_proto_t * proto;
- char * authorize_string;
- globus_size_t authorize_count=0;
- globus_size_t offset;
- globus_size_t length;
- globus_reltime_t delay_time;
- MYNAME(globus_l_gass_transfer_http_request_authorize);
-
- globus_l_gass_transfer_http_lock();
- proto = (globus_gass_transfer_http_request_proto_t *) rproto;
- switch(proto->type)
- {
- case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_GET:
- /* Let's always send an HTTP/1.0 response, to make things easier */
- length = globus_gass_transfer_request_get_length(proto->request);
- if(length != 0)
- {
- globus_size_t x = length;
- globus_size_t digits = 0;
- /* count the number of decimal digits in length */
- do
- {
- digits++;
- x /= 10;
- } while(x > 0);
-
- /* Send a content-length field */
- authorize_count += strlen(GLOBUS_L_CONTENT_LENGTH_HEADER);
- authorize_count += digits;
- }
-
- authorize_count += 1;
- authorize_count += strlen(GLOBUS_L_GENERIC_RESPONSE);
- authorize_count += 3;
- authorize_count += strlen(GLOBUS_L_OK);
- authorize_count += 2;
- if(proto->text_mode)
- {
- authorize_count += strlen(GLOBUS_L_TEXT_HEADER);
- authorize_string = globus_malloc(authorize_count);
- offset = sprintf(authorize_string,
- GLOBUS_L_GENERIC_RESPONSE,
- 0,
- 200,
- GLOBUS_L_OK);
- offset += sprintf(authorize_string + offset,
- GLOBUS_L_TEXT_HEADER);
- }
- else
- {
- authorize_count += strlen(GLOBUS_L_BINARY_HEADER);
- authorize_string = globus_malloc(authorize_count);
- offset = sprintf(authorize_string,
- GLOBUS_L_GENERIC_RESPONSE,
- 0,
- 200,
- GLOBUS_L_OK);
- offset += sprintf(authorize_string + offset,
- GLOBUS_L_BINARY_HEADER);
- }
- if(length != 0)
- {
- offset += sprintf(authorize_string + offset,
- GLOBUS_L_CONTENT_LENGTH_HEADER,
- (long) length);
- }
- offset += sprintf(authorize_string + offset,
- CRLF);
- break;
- case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT:
- case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND:
- /* send nothing back yet */
- break;
- default:
- globus_assert(GLOBUS_FALSE);
- }
- if(authorize_count != 0)
- {
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_RESPONDING;
- debug_printf(4, (_GTSL("%s(): registering write on %p\n"),
- myname,
- &proto->handle));
- globus_io_register_write(&proto->handle,
- (globus_byte_t *) authorize_string,
- strlen(authorize_string),
- globus_l_gass_transfer_http_write_response,
- proto);
- }
- else
- {
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE;
-
- GlobusTimeReltimeSet(delay_time, 0, 0);
- debug_printf(4, (_GTSL("%s(): registering oneshot\n"),
- myname));
- globus_callback_register_oneshot(
- GLOBUS_NULL,
- &delay_time,
- globus_l_gass_transfer_http_callback_ready_callback,
- (void *) proto);
- }
- globus_l_gass_transfer_http_unlock();
- }
- /* globus_l_gass_transfer_http_request_authorize() */
- static
- void
- globus_l_gass_transfer_http_write_response(
- void * arg,
- globus_io_handle_t * handle,
- globus_result_t result,
- globus_byte_t * buf,
- globus_size_t nbytes)
- {
- globus_gass_transfer_http_request_proto_t * proto;
- globus_gass_transfer_request_t request;
- globus_free(buf);
- globus_l_gass_transfer_http_lock();
- proto = (globus_gass_transfer_http_request_proto_t *) arg;
- switch(proto->state)
- {
- case GLOBUS_GASS_TRANSFER_HTTP_STATE_RESPONDING:
- if(proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_GET)
- {
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE;
- globus_l_gass_transfer_http_unlock();
-
- request = proto->request;
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_ready")));
- globus_gass_transfer_proto_request_ready(request,
- (globus_gass_transfer_request_proto_t *) proto);
- return;
- }
- /* other types fall through */
- default:
- result = globus_l_gass_transfer_http_register_close(proto);
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(proto);
- }
- globus_l_gass_transfer_http_unlock();
- return;
- }
- }
- /* globus_l_gass_transfer_http_write_response() */
- static
- globus_bool_t
- globus_l_gass_transfer_http_authorization_callback(
- void * arg,
- globus_io_handle_t * handle,
- globus_result_t result,
- char * identity,
- gss_ctx_id_t context_handle)
- {
- globus_gass_transfer_http_listener_proto_t *proto;
- int rc;
- MYNAME(globus_l_gass_transfer_http_authorization_callback);
- debug_printf(3, (_GTSL("Entering %s()\n"),myname));
- globus_l_gass_transfer_http_lock();
- proto = (globus_gass_transfer_http_listener_proto_t *) arg;
- proto->request->connected_subject = globus_libc_strdup(identity);
- switch(proto->request->authorization_mode)
- {
- case GLOBUS_GASS_TRANSFER_AUTHORIZE_SELF:
- if(strcmp(identity, globus_l_gass_transfer_http_subject_name) == 0)
- {
- rc = GLOBUS_TRUE;
- goto finish;
- }
- else
- {
- rc = GLOBUS_FALSE;
- goto finish;
- }
- case GLOBUS_GASS_TRANSFER_AUTHORIZE_HOST:
- rc = GLOBUS_FALSE;
- goto finish;
- case GLOBUS_GASS_TRANSFER_AUTHORIZE_SUBJECT:
- if(strcmp(identity, proto->request->authorized_subject) == 0)
- {
- rc = GLOBUS_TRUE;
- goto finish;
- }
- else
- {
- rc = GLOBUS_FALSE;
- goto finish;
- }
- case GLOBUS_GASS_TRANSFER_AUTHORIZE_CALLBACK:
- rc = GLOBUS_TRUE;
- goto finish;
- }
- finish:
- globus_l_gass_transfer_http_unlock();
- debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_authorization_callback()\n")));
- return rc;
- }
- /* globus_l_gass_transfer_http_authorization_callback() */
- static
- void
- globus_l_gass_transfer_http_proto_destroy(
- globus_gass_transfer_http_request_proto_t * proto)
- {
- if(proto->response_buffer != GLOBUS_NULL)
- {
- globus_free(proto->response_buffer);
- }
- if(proto->reason != GLOBUS_NULL)
- {
- globus_free(proto->reason);
- }
- if(proto->connected_subject != GLOBUS_NULL)
- {
- globus_free(proto->connected_subject);
- }
- if(proto->client_side)
- {
- globus_url_destroy(&proto->url);
- }
- else
- {
- if(proto->method)
- {
- globus_free(proto->method);
- }
- if(proto->uri)
- {
- globus_free(proto->uri);
- }
- }
- globus_i_gass_transfer_keyvalue_destroy(
- &proto->headers);
- globus_free(proto);
- }
- /* globus_l_gass_transfer_http_proto_destroy() */
- /*
- * Function: globus_l_gass_transfer_http_new_request(()
- *
- * Description: Create a new request's "proto" structure
- *
- * Parameters:
- *
- * Returns:
- */
- static
- void
- globus_l_gass_transfer_http_new_request(
- globus_gass_transfer_request_t request,
- globus_gass_transfer_requestattr_t * attr)
- {
- int rc=GLOBUS_SUCCESS;
- char * proxy=GLOBUS_NULL;
- globus_gass_transfer_file_mode_t file_mode=GLOBUS_GASS_TRANSFER_FILE_MODE_BINARY;
- globus_io_attr_t tcp_attr;
- globus_result_t result;
- globus_gass_transfer_http_request_proto_t * proto;
- int sndbuf;
- int rcvbuf;
- int nodelay;
- globus_reltime_t delay_time;
- MYNAME(globus_l_gass_transfer_http_new_request);
-
- debug_printf(1, (_GTSL("Entering %s()\n"),myname));
- switch(globus_gass_transfer_request_get_type(request))
- {
- case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_GET:
- case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT:
- case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND:
- break;
- default:
- goto error_exit;
- }
- /* Allocate proto instance */
- proto = (globus_gass_transfer_http_request_proto_t *)
- globus_malloc(sizeof(globus_gass_transfer_http_request_proto_t));
- if(proto == GLOBUS_NULL)
- {
- goto error_exit;
- }
- result = globus_io_tcpattr_init(&tcp_attr);
- if(result != GLOBUS_SUCCESS)
- {
- goto proto_error;
- }
- globus_io_attr_set_socket_keepalive(&tcp_attr, GLOBUS_TRUE);
- if(*attr != GLOBUS_NULL)
- {
- /* Check attributes we care about */
- globus_gass_transfer_requestattr_get_proxy_url(attr,
- &proxy);
- rc = globus_gass_transfer_requestattr_get_socket_sndbuf(
- attr,
- &sndbuf);
- if(rc != GLOBUS_SUCCESS)
- {
- goto tcpattr_error;
- }
- else
- {
- if(sndbuf != 0)
- {
- globus_io_attr_set_socket_sndbuf(&tcp_attr,
- sndbuf);
- }
- }
- rc = globus_gass_transfer_requestattr_get_socket_rcvbuf(
- attr,
- &rcvbuf);
- if(rc != GLOBUS_SUCCESS)
- {
- goto tcpattr_error;
- }
- else
- {
- if(rcvbuf != 0)
- {
- globus_io_attr_set_socket_rcvbuf(&tcp_attr,
- rcvbuf);
- }
- }
- rc = globus_gass_transfer_requestattr_get_socket_nodelay(
- attr,
- &nodelay);
- if(rc != GLOBUS_SUCCESS)
- {
- goto tcpattr_error;
- }
- else
- {
- globus_io_attr_set_tcp_nodelay(&tcp_attr,
- nodelay);
- }
- /* File mode is important on Windows */
- rc = globus_gass_transfer_requestattr_get_file_mode(attr,
- &file_mode);
- if(rc != GLOBUS_SUCCESS)
- {
- goto tcpattr_error;
- }
- rc = globus_gass_transfer_requestattr_get_block_size(attr,
- &proto->block_size);
- if(rc != GLOBUS_SUCCESS)
- {
- goto tcpattr_error;
- }
- }
- /* Verify URL */
- if(proxy)
- {
- rc = globus_url_parse(proxy,
- &proto->proxy_url);
- if(rc != GLOBUS_SUCCESS)
- {
- goto tcpattr_error;
- }
- if(strcmp(proto->proxy_url.scheme, "http") != 0 &&
- strcmp(proto->proxy_url.scheme, "https") != 0)
- {
- goto proxy_error;
- }
- }
- proto->url_string = globus_gass_transfer_request_get_url(request);
- rc = globus_url_parse(proto->url_string,
- &proto->url);
- if(rc != GLOBUS_SUCCESS)
- {
- goto proxy_error;
- }
- if(proto->url.url_path == GLOBUS_NULL)
- {
- proto->url.url_path = globus_libc_strdup("/");
- }
- if(strcmp(proto->url.scheme, "http") != 0 &&
- strcmp(proto->url.scheme, "https") != 0)
- {
- goto url_error;
- }
- /* If https, set security attributes of TCP handle */
- if(strcmp(proto->url.scheme, "https")== 0)
- {
- globus_io_secure_authorization_data_t data;
- globus_gass_transfer_authorization_t mode;
- char * subject;
- globus_result_t result;
-
- globus_io_secure_authorization_data_initialize(&data);
- result = globus_io_attr_set_secure_authentication_mode(
- &tcp_attr,
- GLOBUS_IO_SECURE_AUTHENTICATION_MODE_MUTUAL,
- GLOBUS_NULL);
- if(result != GLOBUS_SUCCESS)
- {
- goto url_error;
- }
- result = globus_io_attr_set_secure_channel_mode(
- &tcp_attr,
- GLOBUS_IO_SECURE_CHANNEL_MODE_SSL_WRAP);
- if(result != GLOBUS_SUCCESS)
- {
- goto url_error;
- }
- if(*attr != GLOBUS_NULL)
- {
- rc = globus_gass_transfer_secure_requestattr_get_authorization(
- attr,
- &mode,
- &subject);
- if(rc != GLOBUS_SUCCESS)
- {
- goto url_error;
- }
- }
- else
- {
- mode = GLOBUS_GASS_TRANSFER_AUTHORIZE_SELF;
- }
- switch(mode)
- {
- case GLOBUS_GASS_TRANSFER_AUTHORIZE_SELF:
- globus_io_attr_set_secure_authorization_mode(
- &tcp_attr,
- GLOBUS_IO_SECURE_AUTHORIZATION_MODE_SELF,
- GLOBUS_NULL);
- break;
- case GLOBUS_GASS_TRANSFER_AUTHORIZE_HOST:
- subject = globus_malloc(strlen(proto->url.host) +
- strlen("/CN=")
- +1);
- sprintf(subject,
- "/CN=%s",
- proto->url.host);
- globus_io_secure_authorization_data_set_identity(
- &data,
- subject);
- globus_io_attr_set_secure_authorization_mode(
- &tcp_attr,
- GLOBUS_IO_SECURE_AUTHORIZATION_MODE_IDENTITY,
- &data);
- globus_io_secure_authorization_data_destroy(&data);
- globus_free(subject);
- break;
- case GLOBUS_GASS_TRANSFER_AUTHORIZE_SUBJECT:
- globus_io_secure_authorization_data_set_identity(
- &data,
- subject);
- globus_io_attr_set_secure_authorization_mode(
- &tcp_attr,
- GLOBUS_IO_SECURE_AUTHORIZATION_MODE_IDENTITY,
- &data);
- globus_io_secure_authorization_data_destroy(&data);
- break;
- case GLOBUS_GASS_TRANSFER_AUTHORIZE_CALLBACK:
- globus_assert(mode != GLOBUS_GASS_TRANSFER_AUTHORIZE_CALLBACK);
- goto url_error;
- }
- }
- if(proto == GLOBUS_NULL)
- {
- goto url_error;
- }
- /* Initialize the proto instance */
- proto->send_buffer = globus_l_gass_transfer_http_send;
- proto->recv_buffer = globus_l_gass_transfer_http_receive;
- proto->fail = globus_l_gass_transfer_http_fail;
- proto->deny = GLOBUS_NULL;
- proto->refer = GLOBUS_NULL;
- proto->authorize = GLOBUS_NULL;
- proto->destroy = globus_l_gass_transfer_http_destroy;
- proto->text_mode = (file_mode == GLOBUS_GASS_TRANSFER_FILE_MODE_TEXT);
- proto->line_mode = GLOBUS_L_LINE_MODE_UNKNOWN;
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_CONNECTING;
- proto->request = request;
- proto->type = globus_gass_transfer_request_get_type(request);
- proto->code = 0;
- proto->reason = 0;
- proto->parse_error = GLOBUS_FALSE;
- proto->destroy_called = GLOBUS_FALSE;
- proto->headers = GLOBUS_NULL;
- proto->response_buffer = GLOBUS_NULL;
- proto->length = 0;
- proto->handled = 0;
- proto->chunked = GLOBUS_FALSE;
- proto->chunk_left = 0;
- proto->failure_occurred = GLOBUS_FALSE;
- proto->oneshot_registered = GLOBUS_FALSE;
- proto->oneshot_active = GLOBUS_FALSE;
- proto->eof_read = GLOBUS_FALSE;
- proto->client_side = GLOBUS_TRUE;
- proto->connected_subject = GLOBUS_NULL;
- proto->proxy_connect = proxy ? GLOBUS_TRUE : GLOBUS_FALSE;
- proto->got_response = GLOBUS_FALSE;
- proto->waiting_for_response = GLOBUS_FALSE;
- /* Open the handle */
- if(proxy)
- {
- if(proto->proxy_url.scheme_type == GLOBUS_URL_SCHEME_HTTP &&
- proto->proxy_url.port == 0)
- {
- proto->proxy_url.port = GLOBUS_L_DEFAULT_HTTP_PORT;
- }
- else if(proto->proxy_url.scheme_type == GLOBUS_URL_SCHEME_HTTPS &&
- proto->proxy_url.port == 0)
- {
- proto->proxy_url.port = GLOBUS_L_DEFAULT_HTTPS_PORT;
- }
- debug_printf(4,(_GTSL("%s(): Registering connect to %s\n"),
- myname,
- proto->proxy_url.host));
- result = globus_io_tcp_register_connect(
- proto->proxy_url.host,
- proto->proxy_url.port,
- &tcp_attr,
- globus_l_gass_transfer_http_connect_callback,
- proto,
- &proto->handle);
- }
- else
- {
- if(proto->url.scheme_type == GLOBUS_URL_SCHEME_HTTP &&
- proto->url.port == 0)
- {
- proto->url.port = GLOBUS_L_DEFAULT_HTTP_PORT;
- }
- else if(proto->url.scheme_type == GLOBUS_URL_SCHEME_HTTPS &&
- proto->url.port == 0)
- {
- proto->url.port = GLOBUS_L_DEFAULT_HTTPS_PORT;
- }
- debug_printf(4,(_GTSL("%s(): Registering connect to %s\n"),
- myname,
- proto->url.host));
- result = globus_io_tcp_register_connect(
- proto->url.host,
- proto->url.port,
- &tcp_attr,
- globus_l_gass_transfer_http_connect_callback,
- proto,
- &proto->handle);
- }
- if(proxy)
- {
- globus_url_destroy(&proto->proxy_url);
- }
- if(result != GLOBUS_SUCCESS)
- {
- goto url_error;
- }
- /* Success! */
- globus_io_tcpattr_destroy(&tcp_attr);
- debug_printf(1, (_GTSL("Exiting globus_l_gass_transfer_new_request()\n")));
- return ;
- url_error:
- globus_url_destroy(&proto->url);
- proxy_error:
- if(proxy)
- {
- globus_url_destroy(&proto->proxy_url);
- }
- tcpattr_error:
- globus_io_tcpattr_destroy(&tcp_attr);
- proto_error:
- globus_free(proto);
- error_exit:
-
- GlobusTimeReltimeSet(delay_time, 0, 0);
- debug_printf(4,(_GTSL("%s(): Registering oneshot\n"),
- myname));
- globus_callback_register_oneshot(
- GLOBUS_NULL,
- &delay_time,
- globus_l_gass_transfer_http_callback_denied,
- (void *) request);
- debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
- }
- /* globus_l_gass_transfer_http_new_request() */
- /*
- * Function: globus_l_gass_transfer_http_new_requestattr()
- *
- * Description: Create a new request attribute structure,
- * appropriate for the "http" url scheme
- *
- * Parameters:
- *
- * Returns:
- */
- static
- globus_object_t *
- globus_l_gass_transfer_http_new_requestattr(
- char * url_scheme)
- {
- globus_object_t * obj;
- MYNAME(globus_l_gass_transfer_http_new_requestattr);
- debug_printf(1, (_GTSL("Entering %s()\n"),myname));
- if(strcmp(url_scheme, "https") == 0)
- {
- obj = globus_object_construct(GLOBUS_GASS_OBJECT_TYPE_SECURE_REQUESTATTR);
- debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
- return
- globus_gass_transfer_secure_requestattr_initialize(
- obj,
- GLOBUS_NULL,
- 0,
- GLOBUS_GASS_TRANSFER_FILE_MODE_BINARY,
- GLOBUS_FALSE,
- 0,
- 0,
- GLOBUS_FALSE,
- GLOBUS_GASS_TRANSFER_AUTHORIZE_HOST,
- GLOBUS_NULL);
- }
- else if(strcmp(url_scheme, "http") == 0)
- {
- obj = globus_object_construct(GLOBUS_GASS_OBJECT_TYPE_SOCKET_REQUESTATTR);
- debug_printf(1, (_GTSL("Exiting %s()\n"), myname));
- return
- globus_gass_transfer_socket_requestattr_initialize(
- obj,
- GLOBUS_NULL,
- 0,
- GLOBUS_GASS_TRANSFER_FILE_MODE_BINARY,
- GLOBUS_FALSE,
- 0,
- 0,
- GLOBUS_FALSE);
- }
- else
- {
- debug_printf(1, (_GTSL("Exiting %s()\n"), myname));
- return GLOBUS_NULL;
- }
- }
- /* globus_l_gass_transfer_http_new_requestattr() */
- /*
- * Function: globus_l_gass_transfer_http_new_listenerattr()
- *
- * Description: Create a new listener attribute structure,
- * appropriate for the "http" url scheme
- *
- * Parameters:
- *
- * Returns:
- */
- static
- globus_object_t *
- globus_l_gass_transfer_http_new_listenerattr(
- char * url_scheme)
- {
- globus_object_t * obj;
- MYNAME(globus_l_gass_transfer_http_new_listenerattr);
-
- debug_printf(1, (_GTSL("Entering %s()\n"), myname));
- if(strcmp(url_scheme, "https") == 0 ||
- strcmp(url_scheme, "http") == 0)
- {
- obj = globus_object_construct(GLOBUS_GASS_OBJECT_TYPE_LISTENERATTR);
- debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
- return
- globus_gass_transfer_listenerattr_initialize(
- obj,
- -1,
- 0);
- }
- else
- {
- debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
- return GLOBUS_NULL;
- }
- }
- /* globus_l_gass_transfer_http_new_listenerattr() */
- /*
- * Function: globus_l_gass_transfer_http_new_listener()
- *
- * Description: Create a new listener structure,
- * appropriate for the "http" and "https" url schemes
- *
- * Parameters:
- *
- * Returns:
- */
- static
- int
- globus_l_gass_transfer_http_new_listener(
- globus_gass_transfer_listener_t listener,
- globus_gass_transfer_listenerattr_t * attr,
- char * scheme,
- char ** base_url,
- globus_gass_transfer_listener_proto_t ** ret_proto)
- {
- globus_gass_transfer_http_listener_proto_t *
- proto;
- globus_io_attr_t tcpattr;
- globus_io_secure_authorization_data_t data;
- globus_result_t result;
- int rc;
- unsigned short port=0;
- int backlog=-1;
- char hostname[MAXHOSTNAMELEN];
- globus_size_t url_size;
- MYNAME(globus_l_gass_transfer_http_new_listener);
-
- debug_printf(1, (_GTSL("Entering %s()\n"),myname));
- globus_io_tcpattr_init(&tcpattr);
- globus_io_attr_set_socket_keepalive(&tcpattr, GLOBUS_TRUE);
- /* Allocate proto instance */
- proto = (globus_gass_transfer_http_listener_proto_t *)
- globus_malloc(sizeof(globus_gass_transfer_http_listener_proto_t));
- if(proto == GLOBUS_NULL)
- {
- goto free_tcpattr;
- }
- proto->close_listener = globus_l_gass_transfer_http_close_listener;
- proto->listen = globus_l_gass_transfer_http_listen;
- proto->accept = globus_l_gass_transfer_http_accept;
- proto->destroy = globus_l_gass_transfer_http_listener_destroy;
- proto->listener = listener;
- proto->destroy_called = GLOBUS_FALSE;
- if(strcmp(scheme, "http") == 0)
- {
- proto->url_scheme = GLOBUS_URL_SCHEME_HTTP;
- }
- else if(strcmp(scheme, "https") == 0)
- {
- result = globus_io_attr_set_secure_authentication_mode(
- &tcpattr,
- GLOBUS_IO_SECURE_AUTHENTICATION_MODE_MUTUAL,
- GLOBUS_NULL);
- if(result != GLOBUS_SUCCESS)
- {
- goto free_proto;
- }
-
- result = globus_io_attr_set_secure_channel_mode(
- &tcpattr,
- GLOBUS_IO_SECURE_CHANNEL_MODE_SSL_WRAP);
- if(result != GLOBUS_SUCCESS)
- {
- goto free_proto;
- }
- result = globus_io_secure_authorization_data_initialize(&data);
- if(result != GLOBUS_SUCCESS)
- {
- goto free_auth_data;
- }
- result = globus_io_secure_authorization_data_set_callback(
- &data,
- globus_l_gass_transfer_http_authorization_callback,
- proto);
-
- if(result != GLOBUS_SUCCESS)
- {
- goto free_auth_data;
- }
- result = globus_io_attr_set_secure_authorization_mode(
- &tcpattr,
- GLOBUS_IO_SECURE_AUTHORIZATION_MODE_CALLBACK,
- &data);
- if(result != GLOBUS_SUCCESS)
- {
- goto free_auth_data;
- }
- globus_io_secure_authorization_data_destroy(&data);
- proto->url_scheme = GLOBUS_URL_SCHEME_HTTPS;
- }
- else
- {
- goto free_proto;
- }
- if(attr)
- {
- rc = globus_gass_transfer_listenerattr_get_port(attr,
- &port);
- if(rc != GLOBUS_SUCCESS)
- {
- goto free_proto;
- }
- rc = globus_gass_transfer_listenerattr_get_backlog(attr,
- &backlog);
- if(rc != GLOBUS_SUCCESS)
- {
- goto free_proto;
- }
- }
- result = globus_io_tcp_create_listener(&port,
- backlog,
- &tcpattr,
- &proto->handle);
- globus_io_tcpattr_destroy(&tcpattr);
- if(result != GLOBUS_SUCCESS)
- {
- goto free_proto;
- }
- url_size = 15; /* https://:65536\0 */
- globus_libc_gethostname(hostname,
- MAXHOSTNAMELEN);
- url_size += strlen(hostname);
- *base_url = globus_malloc(url_size);
- sprintf(*base_url,
- "%s://%s:%d",
- proto->url_scheme == GLOBUS_URL_SCHEME_HTTPS ?
- "https" : "http",
- hostname,
- (int) port);
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_STARTING;
- *ret_proto = (globus_gass_transfer_listener_proto_t *) proto;
- debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
- return GLOBUS_SUCCESS;
- free_auth_data:
- globus_io_secure_authorization_data_destroy(&data);
- free_proto:
- globus_free(proto);
- free_tcpattr:
- globus_io_tcpattr_destroy(&tcpattr);
- debug_printf(1, (_GTSL("Exiting %s()\n"),myname));
- return GLOBUS_FAILURE;
- }
- /* globus_l_gass_transfer_http_new_listener() */
- /*
- * Function: globus_l_gass_transfer_http_close_listener(()
- *
- * Description: Called by the GASS system when the user has
- * requested that a listener be closed. This
- * may be called at any time, but only once
- * per listener.
- *
- * Parameters:
- *
- * Returns:
- */
- static
- void
- globus_l_gass_transfer_http_close_listener(
- globus_gass_transfer_listener_proto_t * proto,
- globus_gass_transfer_listener_t listener)
- {
- globus_gass_transfer_http_listener_proto_t *
- new_proto;
- MYNAME(globus_l_gass_transfer_http_close_listener);
- debug_printf(1, (_GTSL("entering %s()\n"),myname));
- new_proto = (globus_gass_transfer_http_listener_proto_t *) proto;
- globus_l_gass_transfer_http_lock();
- {
- switch(new_proto->state)
- {
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_STARTING:
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_READY:
- /* If the listener is in the "idle" or "ready" state, then
- * we can simply register the close, which will free the
- * proto. (GASS is not waiting for a callback now.
- */
- globus_l_gass_transfer_http_register_listener_close(new_proto);
- break;
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_LISTENING:
- /*
- * If we are in the "listening" state, registering the
- * close will cause the listen callback to finish, and
- * after that calls the user, the close callback will delete
- * things
- */
- new_proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING1;
- globus_l_gass_transfer_http_register_listener_close(new_proto);
- break;
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_ACCEPTING:
- /*
- * If we are in the "accepting" state, registering the
- * close will cause any outstanding listen callbacks to finish,
- * from where we can call back to GASS.
- */
- new_proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING2;
- globus_l_gass_transfer_http_register_listener_close(new_proto);
- break;
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING1:
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING2:
- case GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSED:
- /* should not happen */
- globus_assert(new_proto->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING1);
- globus_assert(new_proto->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSING2);
- globus_assert(new_proto->state != GLOBUS_GASS_TRANSFER_HTTP_LISTENER_CLOSED);
- break;
- }
- }
- globus_l_gass_transfer_http_unlock();
- debug_printf(1, (_GTSL("exiting %s()\n"),myname));
- return;
- }
- /* globus_l_gass_transfer_http_close_listener() */
- /*
- * Function: globus_l_gass_transfer_http_connect_callback(()
- *
- * Description: Called upon completion of the TCP connect
- * protocol (and the SSL authentication, if
- * applicable).
- *
- * The request string is sent to the server
- * for processing.
- *
- * Parameters:
- *
- * Returns:
- */
- static
- void
- globus_l_gass_transfer_http_connect_callback(
- void * arg,
- globus_io_handle_t * handle,
- globus_result_t result)
- {
- char * cmd;
- globus_gass_transfer_http_request_proto_t * proto;
- globus_gass_transfer_request_t request;
- int code;
- char * msg;
- MYNAME(globus_l_gass_transfer_http_connect_callback);
-
- debug_printf(3, (_GTSL("Entering %s()\n"), myname));
- /*
- * In this function, we have completed the TCP (and SSL)
- * connection protocol, and will send our request to the
- * server for processing.
- */
- proto = (globus_gass_transfer_http_request_proto_t *)
- arg;
- globus_l_gass_transfer_http_lock();
- globus_assert(proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_CONNECTING);
- if(result != GLOBUS_SUCCESS)
- {
- /*
- * TODO: Evaluate error object here, put into
- * proto->code and proto->reason
- */
- goto deny_exit;
- }
- cmd = globus_l_gass_transfer_http_construct_request(proto);
- if(cmd == GLOBUS_NULL)
- {
- goto deny_exit;
- }
- /* Send our command to the server */
- debug_printf(4,(_GTSL("%s(): Registering write on %p\n"),
- myname,
- &proto->handle));
-
- result = globus_io_register_write(
- &proto->handle,
- (globus_byte_t *) cmd,
- strlen(cmd) * sizeof(char),
- globus_l_gass_transfer_http_command_callback,
- proto);
- if(result == GLOBUS_SUCCESS)
- {
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_REQUESTING;
- globus_l_gass_transfer_http_unlock();
- debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
- return;
- }
- /* Write registration failed, fall through to deny_exit */
- deny_exit:
- /* Give a default error message, if none is generated above */
- if(proto->code == 0)
- {
- proto->code = GLOBUS_L_DEFAULT_FAILURE_CODE;
- proto->reason = globus_libc_strdup(GLOBUS_L_DEFAULT_FAILURE_REASON);
- }
- /*
- * Because the proto is not being returned in a request ready,
- * we must not wait for the GASS system to call the destroyed
- * method of the proto
- */
- proto->destroy_called=GLOBUS_TRUE;
- request = proto->request;
- code = proto->code;
- msg = globus_libc_strdup(proto->reason);
- result = globus_l_gass_transfer_http_register_close(proto);
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(proto);
- }
- globus_l_gass_transfer_http_unlock();
- /* Signal Denial to the GASS system */
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_denied")));
- globus_gass_transfer_proto_request_denied(
- request,
- code,
- msg);
- debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
- }
- /* globus_l_gass_transfer_http_connect_callback() */
- /*
- * Function: globus_l_gass_transfer_http_command_callback(()
- *
- * Description: Called when the HTTP request has been sent
- * to the server for processing.
- *
- * The request string is sent to the server
- * for processing.
- *
- * Parameters:
- *
- * Returns:
- */
- static
- void
- globus_l_gass_transfer_http_command_callback(
- void * arg,
- globus_io_handle_t * handle,
- globus_result_t result,
- globus_byte_t * buf,
- globus_size_t nbytes)
- {
- globus_gass_transfer_http_request_proto_t * proto;
- globus_gass_transfer_request_t request;
- int code;
- char * reason;
- MYNAME(globus_l_gass_transfer_http_command_callback);
-
- debug_printf(3, (_GTSL("Entering %s()\n"),myname));
-
- /*
- * In this function, we have completed sending our request
- * to the server. If there was some sort of error, we
- * will signal a "deny" to the server.
- */
- proto = (globus_gass_transfer_http_request_proto_t *) arg;
- globus_l_gass_transfer_http_lock();
- globus_assert(proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_REQUESTING);
- if(result != GLOBUS_SUCCESS)
- {
- goto deny_exit;
- }
- /*
- * Free the request command buffer.
- */
- globus_free(buf);
- buf = GLOBUS_NULL;
- /*
- * We will now register a response handling buffer & callback
- * The buffer may have to grow if there are a lot of headers.
- */
- proto->response_buffer = globus_malloc(GLOBUS_L_GASS_RESPONSE_LEN *
- sizeof(globus_byte_t));
- proto->response_buflen = GLOBUS_L_GASS_RESPONSE_LEN;
- proto->response_offset = 0;
- proto->parsed_offset = 0;
- switch(proto->type)
- {
- case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT:
- case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND:
- /*
- * If we are a "put" or "append" request, then we can start
- * sending data sort of immediately. So we send an "ready"
- * message to the server. A little optimistic, perhaps...
- * We will not register for the response message until
- * we've sent the last data.
- */
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE;
- debug_printf(4,(_GTSL("%s(): Registering read on %p\n"),
- myname,
- &proto->handle));
-
- result = globus_io_register_read(
- &proto->handle,
- proto->response_buffer,
- proto->response_buflen,
- 1,
- globus_l_gass_transfer_http_response_callback,
- proto);
- if(result != GLOBUS_SUCCESS)
- {
- proto->failure_occurred = GLOBUS_TRUE;
- }
- globus_l_gass_transfer_http_unlock();
-
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_ready")));
- globus_gass_transfer_proto_request_ready(
- proto->request,
- (globus_gass_transfer_request_proto_t *) proto);
- debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
- return;
- case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_GET:
- /*
- * If we are a "GET" request we can't do anything
- * until the server sends us some info, anyway
- */
- debug_printf(4,(_GTSL("%s(): Registering read on %p\n"),
- myname,
- &proto->handle));
- result = globus_io_register_read(
- &proto->handle,
- proto->response_buffer,
- proto->response_buflen,
- 1,
- globus_l_gass_transfer_http_response_callback,
- proto);
- if(result != GLOBUS_SUCCESS)
- {
- /* should interpret the error object */
- goto deny_exit;
- }
- globus_l_gass_transfer_http_unlock();
- debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
- return;
- default:
- globus_assert(proto->type !=
- GLOBUS_GASS_TRANSFER_REQUEST_TYPE_INVALID);
- goto deny_exit;
- }
- deny_exit:
- if(buf != GLOBUS_NULL)
- {
- globus_libc_free(buf);
- buf = GLOBUS_NULL;
- }
- /* Give a default error message, if none is generated above */
- if(proto->code == 0)
- {
- proto->code = GLOBUS_L_DEFAULT_FAILURE_CODE;
- proto->reason = globus_libc_strdup(GLOBUS_L_DEFAULT_FAILURE_REASON);
- }
- request = proto->request;
- code = proto->code;
- reason = globus_libc_strdup(proto->reason);
- result = globus_l_gass_transfer_http_register_close(proto);
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(proto);
- }
-
- globus_l_gass_transfer_http_unlock();
- /* Signal Denial to the GASS system */
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_denied")));
- globus_gass_transfer_proto_request_denied(
- request,
- code,
- reason);
- debug_printf(3, (_GTSL("Exiting %s()\n"),myname));
- }
- /* globus_l_gass_transfer_http_command_callback() */
- static
- void
- globus_l_gass_transfer_http_response_callback(
- void * arg,
- globus_io_handle_t * handle,
- globus_result_t result,
- globus_byte_t * buf,
- globus_size_t nbytes)
- {
- globus_gass_transfer_http_request_proto_t * proto;
- globus_object_t * err=GLOBUS_NULL;
- globus_gass_transfer_request_t request;
- int code;
- char * reason;
- MYNAME(globus_l_gass_transfer_http_response_callback);
- debug_printf(3, (_GTSL("Entering %s()\n"),myname));
- proto = (globus_gass_transfer_http_request_proto_t *) arg;
- if(result != GLOBUS_SUCCESS)
- {
- char * tmpstr;
- err = globus_error_get(result);
- tmpstr = globus_object_printable_to_string(err);
- debug_printf(5, (_GTSL("globus_l_gass_transfer_http_read_callback(): %s"), tmpstr));
- globus_libc_free(tmpstr);
- }
- globus_l_gass_transfer_http_lock();
- request = proto->request;
- /* Did the read succeed? */
- if(result != GLOBUS_SUCCESS &&
- !globus_io_eof(err))
- {
- if(proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT ||
- proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND)
- {
- goto put_fail_exit;
- }
- result = globus_l_gass_transfer_http_register_close(proto);
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(proto);
- }
- globus_l_gass_transfer_http_unlock();
- /* TODO: Evaluate error object, or response from the server here */
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_denied")));
- globus_gass_transfer_proto_request_denied(
- request,
- GLOBUS_L_DEFAULT_FAILURE_CODE,
- globus_libc_strdup(GLOBUS_L_DEFAULT_FAILURE_REASON));
- if(err)
- {
- globus_object_free(err);
- }
- debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
- return;
- }
- /* Update our counters */
- proto->response_offset += nbytes;
- do
- {
- /* Parse the buffer that we have */
- if(globus_l_gass_transfer_http_parse_response(proto))
- {
- /* returns true, if we need to read some more */
- goto repost_read;
- }
- switch(proto->type)
- {
- case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_GET:
- /* If it is a GET request, we need an affirmative
- * response, or a continue, or a referral
- */
- if(proto->code < 100 ||
- proto->code >= 400)
- {
- /* Denied */
- goto deny_exit;
- }
- else if(proto->code >= 100 &&
- proto->code < 200)
- {
- /*
- * Continue... Reset our response buffers,
- * and get another set of headers
- */
- memmove(proto->response_buffer,
- proto->response_buffer + proto->parsed_offset,
- proto->response_offset - proto->parsed_offset);
- proto->response_offset -= proto->parsed_offset;
- proto->parsed_offset = 0;
- if(proto->reason)
- {
- globus_free(proto->reason);
- }
- proto->code = 0;
- proto->reason = GLOBUS_NULL;
- globus_i_gass_transfer_keyvalue_destroy(
- &proto->headers);
- /*
- * There may be more headers in our buffer, so
- * we should go through the parse loop again,
- * maybe
- */
- if(proto->response_offset != 0)
- {
- continue;
- }
- else
- {
- goto repost_read;
- }
- }
- else if(proto->code >= 300 &&
- proto->code < 400)
- {
- char ** referral;
- globus_size_t referral_count;
- /* We've got a referral from the server */
- globus_l_gass_transfer_http_extract_referral(proto,
- &referral,
- &referral_count);
- if(referral == GLOBUS_NULL)
- {
- goto deny_exit;
- }
- else
- {
- /* If this is a get request, then the proto layer
- * doesn't have a pointer to this proto yet,
- * so we need to act like they've destroyed their
- * reference to it
- */
- proto->destroy_called = GLOBUS_TRUE;
- result = globus_l_gass_transfer_http_register_close(proto);
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(proto);
- }
-
- globus_l_gass_transfer_http_unlock();
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_referred")));
- globus_gass_transfer_proto_request_referred(
- request,
- referral,
- referral_count);
- return;
- }
- }
- else
- {
- /*
- * Successful response for the "get", check for
- * interesting headers, and indicate "ready" to
- * the GASS system. (note that first read will
- * have to deal with the data in
- * proto->response_buffer)
- */
- char * value;
- /*
- * Look to see if there are any headers we
- * care about
- */
- value = globus_i_gass_transfer_keyvalue_lookup(
- &proto->headers,
- "transfer-encoding");
- if(value)
- {
- char * tmp;
- for(tmp = value; *tmp != '\0'; tmp++)
- {
- if(! isspace(*tmp))
- {
- break;
- }
- }
- #ifndef TARGET_ARCH_WIN32
- if(strncasecmp(tmp, "chunked", strlen("chunked")) == 0)
- #else
- if(strnicmp(tmp, "chunked", strlen("chunked")) == 0)
- #endif
- {
- proto->recv_buffer =
- globus_l_gass_transfer_http_receive;
- proto->chunked = GLOBUS_TRUE;
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_SIZE;
- proto->length = 0;
- }
- }
- if(!proto->chunked)
- {
- /* If both
- * Transfer-Encoding: chunked and
- * Content-Length: <something>
- * are passed, the Content-length should be ignored,
- * according to RFC 2068
- */
- value = globus_i_gass_transfer_keyvalue_lookup(
- &proto->headers,
- "content-length");
- if(value)
- {
- int save_errno;
- char * tmp;
- for(tmp = value; *tmp != '\0'; tmp++)
- {
- if(! isspace(*tmp))
- {
- break;
- }
- }
- globus_libc_lock();
- errno=0;
- proto->length = strtoul(tmp,
- GLOBUS_NULL,
- 10);
- save_errno=errno;
- globus_libc_unlock();
- if(save_errno != 0)
- {
- proto->code = GLOBUS_L_PROTOCOL_FAILURE_CODE;
- proto->reason = globus_libc_strdup(
- GLOBUS_L_PROTOCOL_FAILURE_REASON);
- goto deny_exit;
- }
- if(proto->length == 0)
- {
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
- }
- else
- {
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_LENGTH;
- }
- }
- else
- {
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_EOF;
- }
-
- if(!proto->text_mode)
- {
- globus_gass_transfer_request_set_length(proto->request,
- proto->length);
-
- }
- }
- /*
- * The response buffer's residue may contain some
- * entity information, so let's keep it around.
- * Also, if we are in text mode, we'll have to copy
- * the data anyway (but should use the block_size)
- */
-
- if(proto->text_mode &&
- proto->block_size > proto->response_buflen)
- {
- globus_byte_t * tmp;
- tmp = globus_libc_realloc(proto->response_buffer,
- proto->block_size *
- sizeof(globus_byte_t));
- if(tmp != GLOBUS_NULL)
- {
- proto->response_buffer = tmp;
- proto->response_buflen = proto->block_size;
- }
- }
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE;
- globus_l_gass_transfer_http_unlock();
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_ready"))); globus_gass_transfer_proto_request_ready(
- proto->request,
- (globus_gass_transfer_request_proto_t *) proto);
- }
- break;
- case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT:
- case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND:
- /* If it is a PUT or APPEND request, we don't expect any
- * response from the server until we're done sending,
- * or the server kills our request
- */
- if(proto->code < 100 ||
- proto->code >= 400)
- {
- /* Request failed. */
- goto put_fail_exit;
- }
- else if(proto->code >= 300 &&
- proto->code < 400)
- {
- char ** referral;
- globus_size_t referral_count;
- /* Request referred. */
- globus_l_gass_transfer_http_extract_referral(proto,
- &referral,
- &referral_count);
- if(referral == GLOBUS_NULL)
- {
- goto put_fail_exit;
- }
- else if(proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE)
- {
- result = globus_l_gass_transfer_http_register_close(proto);
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(proto);
- }
-
- globus_l_gass_transfer_http_unlock();
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_referred")));
- globus_gass_transfer_proto_request_referred(request,
- referral,
- referral_count);
- debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
- return;
- }
- else
- {
- proto->failure_occurred = GLOBUS_TRUE;
- result = globus_l_gass_transfer_http_register_close(proto);
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(proto);
- }
-
- globus_l_gass_transfer_http_unlock();
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_referred")));
- globus_gass_transfer_proto_request_referred(request,
- referral,
- referral_count);
-
- debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
- return;
- }
- }
- else if(proto->code >= 100 &&
- proto->code < 200)
- {
- /*
- * Continue... Reset our response buffers,
- * and get another set of headers
- */
- memmove(proto->response_buffer,
- proto->response_buffer + proto->parsed_offset,
- proto->response_offset - proto->parsed_offset);
- proto->response_offset -= proto->parsed_offset;
- proto->parsed_offset = 0;
- if(proto->reason)
- {
- globus_free(proto->reason);
- }
- proto->code = 0;
- proto->reason = GLOBUS_NULL;
- globus_i_gass_transfer_keyvalue_destroy(
- &proto->headers);
- /*
- * There may be more headers in our buffer, so
- * we should go through the parse loop again,
- * maybe
- */
- if(proto->response_offset != 0)
- {
- continue;
- }
- else
- {
- goto repost_read;
- }
- }
- else
- {
- goto put_success_exit;
- }
- case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_INVALID:
- default:
- globus_assert(proto->type !=
- GLOBUS_GASS_TRANSFER_REQUEST_TYPE_INVALID);
- globus_assert(GLOBUS_FALSE);
- debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
- return;
- }
- }
- while(proto->code == 0 ||
- proto->code == 100);
- debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
- return;
- repost_read:
- if(result != GLOBUS_NULL)
- {
- proto->code = GLOBUS_L_DEFAULT_FAILURE_CODE;
- proto->reason = globus_libc_strdup(GLOBUS_L_DEFAULT_FAILURE_REASON);
- if(proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT ||
- proto->type == GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND)
- {
- goto put_fail_exit;
- }
- else
- {
- goto deny_exit;
- }
- }
- /* Reallocate a larger buffer, if we need to */
- if(proto->response_buflen == proto->response_offset)
- {
- globus_byte_t * tmp;
- tmp = globus_libc_realloc(proto->response_buffer,
- proto->response_buflen *
- 2 *
- sizeof(globus_byte_t));
- if(tmp == GLOBUS_NULL)
- {
- proto->code = GLOBUS_L_MALLOC_FAILURE_CODE;
- proto->reason = globus_libc_strdup(GLOBUS_L_MALLOC_FAILURE_REASON);
- goto deny_exit;
- }
- else
- {
- proto->response_buffer = tmp;
- proto->response_buflen *= 2;
- }
- }
- /* Register another read */
- debug_printf(4,(_GTSL("%s(): Registering read on %p\n"),
- myname,
- &proto->handle));
- result = globus_io_register_read(&proto->handle,
- proto->response_buffer +
- proto->response_offset,
- proto->response_buflen -
- proto->response_offset,
- 1,
- globus_l_gass_transfer_http_response_callback,
- proto);
- if(result != GLOBUS_SUCCESS)
- {
- /* TODO interpret the error object */
- goto deny_exit;
- }
- globus_l_gass_transfer_http_unlock();
- debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
- return;
- deny_exit:
- if(err)
- {
- globus_object_free(err);
- }
- /*
- * Because the proto is not being returned in a request ready,
- * we must not wait for the GASS system to call the destroyed
- * method of the proto
- */
- proto->destroy_called=GLOBUS_TRUE;
- code = proto->code;
- reason = globus_libc_strdup(proto->reason);
- result = globus_l_gass_transfer_http_register_close(proto);
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(proto);
- }
-
- globus_l_gass_transfer_http_unlock();
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_denied")));
- globus_gass_transfer_proto_request_denied(request,
- code,
- reason);
- debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
- return;
- put_success_exit:
- {
- globus_byte_t * buffer;
- globus_size_t offset;
- globus_bool_t failure;
- buffer = proto->user_buffer;
- offset = proto->user_offset;
- failure = proto->failure_occurred;
-
- /*
- * success response from a server, signal this to the GASS system
- */
- globus_assert(proto->state == GLOBUS_GASS_TRANSFER_HTTP_STATE_PENDING);
- result = globus_l_gass_transfer_http_register_close(proto);
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(proto);
- }
-
- globus_l_gass_transfer_http_unlock();
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_send_complete()")));
- globus_gass_transfer_proto_send_complete(request,
- buffer,
- offset,
- failure,
- GLOBUS_TRUE);
- debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
- return;
- }
- put_fail_exit:
- /*
- * request failed after a put or append operation. We
- * need to signal the failure to the GASS system
- */
- proto->got_response = GLOBUS_TRUE;
- proto->failure_occurred = GLOBUS_TRUE;
- if(proto->waiting_for_response)
- {
- globus_byte_t * buffer;
- globus_size_t offset;
- int failed = proto->failure_occurred;
-
- buffer = proto->user_buffer;
- offset = proto->user_offset;
- result = globus_l_gass_transfer_http_register_close(proto);
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(proto);
- }
-
- globus_l_gass_transfer_http_unlock();
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_send_complete()")));
- globus_gass_transfer_proto_send_complete(request,
- buffer,
- offset,
- failed,
- GLOBUS_TRUE);
- debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
- return;
- }
- else
- {
- proto->failure_occurred = GLOBUS_TRUE;
- globus_l_gass_transfer_http_unlock();
- }
- debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_response_callback()\n")));
- }
- /* globus_l_gass_transfer_http_response_callback() */
- static
- void
- globus_l_gass_transfer_http_request_callback(
- void * arg,
- globus_io_handle_t * handle,
- globus_result_t result,
- globus_byte_t * buf,
- globus_size_t nbytes)
- {
- globus_gass_transfer_http_request_proto_t * proto;
- globus_gass_transfer_http_listener_proto_t * l_proto;
- globus_object_t * err=GLOBUS_NULL;
- char * value;
- globus_gass_transfer_request_t request;
- MYNAME(globus_l_gass_transfer_http_request_callback);
- debug_printf(3, (_GTSL("Entering %s()\n"),myname));
- l_proto = (globus_gass_transfer_http_listener_proto_t *) arg;
- proto = l_proto->request;
- if(result != GLOBUS_SUCCESS)
- {
- char * tmpstr;
- err = globus_error_get(result);
- tmpstr = globus_object_printable_to_string(err);
- debug_printf(5, (_GTSL("globus_l_gass_transfer_http_read_callback(): %s"), tmpstr));
- globus_libc_free(tmpstr);
- }
- globus_l_gass_transfer_http_lock();
- request = proto->request;
-
- /* Did the read succeed? */
- if(result != GLOBUS_SUCCESS &&
- !globus_io_eof(err))
- {
- goto deny_exit;
- }
- /* Update our counters */
- proto->response_offset += nbytes;
- /* Parse the buffer that we have */
- if(globus_l_gass_transfer_http_parse_request(proto))
- {
- /* returns true, if we need to read some more */
- if(proto->parsed_offset == 0 &&
- proto->response_offset > 0 &&
- !isupper(proto->response_buffer[0]))
- {
- goto deny_exit;
- }
- goto repost_read;
- }
- else if(proto->parse_error)
- {
- goto deny_exit;
- }
- else if(strcmp(proto->uri, "*") == 0)
- {
- /* Request we don't handle */
- goto deny_exit;
- }
- else if(strcmp(proto->method, "GET") == 0)
- {
- proto->type = GLOBUS_GASS_TRANSFER_REQUEST_TYPE_GET;
- }
- else if(strcmp(proto->method, "PUT") == 0)
- {
- proto->type = GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT;
- }
- else if(strcmp(proto->method, "POST") == 0 &&
- strncmp(proto->uri,
- GLOBUS_L_APPEND_URI,
- strlen(GLOBUS_L_APPEND_URI)) == 0)
- {
- globus_size_t append_len;
- globus_size_t uri_len;
- append_len = strlen(GLOBUS_L_APPEND_URI);
- uri_len = strlen(proto->uri) - strlen(GLOBUS_L_APPEND_URI);
- proto->type = GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND;
- memmove(proto->uri,
- proto->uri + append_len,
- uri_len);
- proto->uri[uri_len] = '\0';
- }
- else
- {
- /* Unknown/Unsupported method */
- goto deny_exit;
- }
- globus_gass_transfer_request_set_type(proto->request,
- proto->type);
- /* Construct URL for this request */
- if(strncmp(proto->uri, "https://", strlen("https://")) == 0 ||
- strncmp(proto->uri, "http://", strlen("http://")) == 0)
- {
- globus_gass_transfer_request_set_url(proto->request,
- proto->uri);
- }
- else
- {
- char * url_base;
- char * url;
- url_base = globus_gass_transfer_listener_get_base_url(l_proto->listener);
- url = globus_malloc(strlen(url_base) + strlen(proto->uri) + 1);
- sprintf(url, "%s%s", url_base, proto->uri);
- globus_gass_transfer_request_set_url(proto->request,
- url);
- }
- /*
- * Look to see if there are any headers we
- * care about
- */
- value = globus_i_gass_transfer_keyvalue_lookup(
- &proto->headers,
- "transfer-encoding");
- if(value)
- {
- char * tmp;
- for(tmp = value; *tmp != '\0'; tmp++)
- {
- if(! isspace(*tmp))
- {
- break;
- }
- }
- #ifndef TARGET_ARCH_WIN32
- if(strncasecmp(tmp, "chunked", strlen("chunked")) == 0)
- #else
- if(strnicmp(tmp, "chunked", strlen("chunked")) == 0)
- #endif
- {
- proto->recv_buffer =
- globus_l_gass_transfer_http_receive;
- proto->chunked = GLOBUS_TRUE;
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_SIZE;
- proto->length = 0;
- }
- }
- if(!proto->chunked)
- {
- /* If both
- * Transfer-Encoding: chunked and
- * Content-Length: <something>
- * are passed, the Content-length should be ignored,
- * according to RFC 2068
- */
- value = globus_i_gass_transfer_keyvalue_lookup(
- &proto->headers,
- "content-length");
- if(value)
- {
- int save_errno;
- char * tmp;
- for(tmp = value; *tmp != '\0'; tmp++)
- {
- if(! isspace(*tmp))
- {
- break;
- }
- }
- globus_libc_lock();
- errno=0;
- proto->length = strtoul(tmp,
- GLOBUS_NULL,
- 10);
- save_errno=errno;
- globus_libc_unlock();
- if(save_errno != 0)
- {
- proto->code = GLOBUS_L_PROTOCOL_FAILURE_CODE;
- proto->reason = globus_libc_strdup(
- GLOBUS_L_PROTOCOL_FAILURE_REASON);
- goto deny_exit;
- }
- if(proto->length == 0)
- {
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
- }
- else
- {
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_LENGTH;
- }
- }
- else
- {
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_EOF;
- }
-
- if(!proto->text_mode)
- {
- globus_gass_transfer_request_set_length(proto->request,
- proto->length);
-
- }
- }
- /*
- * The response buffer's residue may contain some
- * entity information, so let's keep it around.
- * Also, if we are in text mode, we'll have to copy
- * the data anyway (but should use the block_size)
- */
-
- if(proto->text_mode &&
- proto->block_size > proto->response_buflen)
- {
- globus_byte_t * tmp;
- tmp = globus_libc_realloc(proto->response_buffer,
- proto->block_size *
- sizeof(globus_byte_t));
- if(tmp != GLOBUS_NULL)
- {
- proto->response_buffer = tmp;
- proto->response_buflen = proto->block_size;
- }
- }
- /* We now have a request, callback to user */
- l_proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_STARTING;
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_IDLE;
- if(proto->connected_subject)
- {
- globus_gass_transfer_request_set_subject(proto->request,
- globus_libc_strdup(proto->connected_subject));
- }
- globus_l_gass_transfer_http_unlock();
- globus_gass_transfer_proto_new_listener_request(
- l_proto->listener,
- proto->request,
- (globus_gass_transfer_request_proto_t *) proto);
- debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_request_callback()\n")));
- return;
- repost_read:
- if(result != GLOBUS_NULL)
- {
- goto deny_exit;
- }
- /* Reallocate a larger buffer, if we need to */
- if(proto->response_buflen == proto->response_offset)
- {
- globus_byte_t * tmp;
- tmp = globus_libc_realloc(proto->response_buffer,
- proto->response_buflen *
- 2 *
- sizeof(globus_byte_t));
- if(tmp == GLOBUS_NULL)
- {
- proto->code = GLOBUS_L_MALLOC_FAILURE_CODE;
- proto->reason = globus_libc_strdup(GLOBUS_L_MALLOC_FAILURE_REASON);
- goto deny_exit;
- }
- else
- {
- proto->response_buffer = tmp;
- proto->response_buflen *= 2;
- }
- }
- /* Register another read */
- debug_printf(4,(_GTSL("%s(): Registering read on %p\n"),
- myname,
- &proto->handle));
- result = globus_io_register_read(&proto->handle,
- proto->response_buffer +
- proto->response_offset,
- proto->response_buflen -
- proto->response_offset,
- 1,
- globus_l_gass_transfer_http_request_callback,
- l_proto);
- if(result != GLOBUS_SUCCESS)
- {
- /* TODO interpret the error object */
- goto deny_exit;
- }
- globus_l_gass_transfer_http_unlock();
- debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_request_callback()\n")));
- return;
- deny_exit:
- if(err)
- {
- globus_object_free(err);
- }
- /*
- * Since we are the server we must fail this request by calling
- * new_listener with a NULL proto
- */
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_CLOSING;
- /*
- * Because the proto is not being returned in a request ready,
- * we must not wait for the GASS system to call the destroyed
- * method of the proto
- */
- proto->destroy_called=GLOBUS_TRUE;
- result = globus_l_gass_transfer_http_register_close(proto);
- if (result != GLOBUS_SUCCESS)
- {
- globus_l_gass_transfer_http_close(proto);
- }
-
- globus_l_gass_transfer_http_unlock();
- globus_gass_transfer_proto_new_listener_request(
- l_proto->listener,
- request,
- (globus_gass_transfer_request_proto_t *) GLOBUS_NULL);
- debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_request_callback()\n")));
- return;
- }
- /* globus_l_gass_transfer_http_request_callback() */
- static
- void
- globus_l_gass_transfer_http_callback_send_callback(
- void * arg)
- {
- globus_gass_transfer_http_request_proto_t * proto;
- MYNAME(globus_l_gass_transfer_http_callback_send_callback);
- debug_printf(3, (_GTSL("Entering %s()\n"),myname));
-
- proto = (globus_gass_transfer_http_request_proto_t *) arg;
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_send_complete()")));
- globus_gass_transfer_proto_send_complete(proto->request,
- proto->user_buffer,
- proto->user_offset,
- proto->failure_occurred,
- proto->failure_occurred);
- debug_printf(3, (_GTSL("Exiting globus_l_gass_transfer_http_callback_send_callback()\n")));
- }
- static
- void
- globus_l_gass_transfer_http_callback_ready_callback(
- void * arg)
- {
- globus_gass_transfer_http_request_proto_t * proto;
- proto = (globus_gass_transfer_http_request_proto_t *) arg;
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_ready")));
- globus_gass_transfer_proto_request_ready(proto->request,
- (globus_gass_transfer_request_proto_t *) proto);
- }
- /* globus_l_gass_transfer_http_callback_read_buffered_callback() */
- static
- void
- globus_l_gass_transfer_http_callback_read_buffered_callback(
- void * arg)
- {
- globus_gass_transfer_http_request_proto_t * proto;
- proto = (globus_gass_transfer_http_request_proto_t *) arg;
- globus_l_gass_transfer_http_lock();
- proto->oneshot_registered = GLOBUS_FALSE;
- proto->oneshot_active = GLOBUS_TRUE;
- globus_l_gass_transfer_http_unlock();
- globus_l_gass_transfer_http_read_buffered_callback(arg,
- &proto->handle,
- GLOBUS_SUCCESS,
- proto->response_buffer +
- proto->response_offset,
- 0);
- }
- /* globus_l_gass_transfer_http_callback_read_buffered_callback() */
- static
- void
- globus_l_gass_transfer_http_callback_listen_callback(
- void * arg)
- {
- globus_gass_transfer_http_listener_proto_t *proto;
- globus_gass_transfer_listener_t listener;
- proto = (globus_gass_transfer_http_listener_proto_t *) arg;
- globus_l_gass_transfer_http_lock();
- if(proto->state == GLOBUS_GASS_TRANSFER_HTTP_LISTENER_LISTENING)
- {
- proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_READY;
- }
- listener = proto->listener;
- globus_l_gass_transfer_http_unlock();
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_listener_ready()")));
- globus_gass_transfer_proto_listener_ready(listener);
- }
- /* globus_l_gass_transfer_http_callback_listen_callback() */
- static
- void
- globus_l_gass_transfer_http_accept(
- globus_gass_transfer_listener_proto_t * proto,
- globus_gass_transfer_listener_t listener,
- globus_gass_transfer_request_t request,
- globus_gass_transfer_requestattr_t * attr)
- {
- globus_result_t result;
- globus_io_attr_t tcp_attr;
- globus_gass_transfer_http_listener_proto_t *
- l_proto;
- int rc;
- int sndbuf;
- int rcvbuf;
- globus_bool_t nodelay;
- globus_gass_transfer_file_mode_t file_mode=GLOBUS_GASS_TRANSFER_FILE_MODE_BINARY;
- globus_io_secure_authorization_data_t data;
- globus_l_gass_transfer_failed_kickout_closure_t *kickout;
- globus_reltime_t delay_time;
- MYNAME(globus_l_gass_transfer_http_accept);
- debug_printf(1, (_GTSL("entering %s()\n"),myname));
- l_proto = (globus_gass_transfer_http_listener_proto_t *) proto;
- /* Allocate proto instance */
- l_proto->request = (globus_gass_transfer_http_request_proto_t *)
- globus_malloc(sizeof(globus_gass_transfer_http_request_proto_t));
- if(l_proto->request == GLOBUS_NULL)
- {
- goto error_exit;
- }
- result = globus_io_tcpattr_init(&tcp_attr);
- if(result != GLOBUS_SUCCESS)
- {
- goto proto_error;
- }
- globus_io_attr_set_socket_keepalive(&tcp_attr, GLOBUS_TRUE);
- if(attr != GLOBUS_NULL &&
- *attr != GLOBUS_NULL)
- {
- /* Check attributes we care about */
- rc = globus_gass_transfer_requestattr_get_socket_sndbuf(
- attr,
- &sndbuf);
- if(rc != GLOBUS_SUCCESS)
- {
- goto tcpattr_error;
- }
- else
- {
- if(sndbuf != 0)
- {
- globus_io_attr_set_socket_sndbuf(&tcp_attr,
- sndbuf);
- }
- }
- rc = globus_gass_transfer_requestattr_get_socket_rcvbuf(
- attr,
- &rcvbuf);
- if(rc != GLOBUS_SUCCESS)
- {
- goto tcpattr_error;
- }
- else
- {
- if(rcvbuf != 0)
- {
- globus_io_attr_set_socket_rcvbuf(&tcp_attr,
- rcvbuf);
- }
- }
- rc = globus_gass_transfer_requestattr_get_socket_nodelay(
- attr,
- &nodelay);
- if(rc != GLOBUS_SUCCESS)
- {
- goto tcpattr_error;
- }
- else
- {
- globus_io_attr_set_tcp_nodelay(&tcp_attr,
- nodelay);
- }
- /* File mode is important on Windows */
- rc = globus_gass_transfer_requestattr_get_file_mode(attr,
- &file_mode);
- if(rc != GLOBUS_SUCCESS)
- {
- goto tcpattr_error;
- }
- rc = globus_gass_transfer_requestattr_get_block_size(
- attr,
- &l_proto->request->block_size);
- if(rc != GLOBUS_SUCCESS)
- {
- goto tcpattr_error;
- }
- }
- /* If https, set security attributes for the request */
- if(l_proto->url_scheme == GLOBUS_URL_SCHEME_HTTPS)
- {
- globus_result_t result;
-
- globus_io_secure_authorization_data_initialize(&data);
- result = globus_io_attr_set_secure_authentication_mode(
- &tcp_attr,
- GLOBUS_IO_SECURE_AUTHENTICATION_MODE_MUTUAL,
- GLOBUS_NULL);
- if(result != GLOBUS_SUCCESS)
- {
- goto free_auth_data;
- }
- result = globus_io_attr_set_secure_channel_mode(
- &tcp_attr,
- GLOBUS_IO_SECURE_CHANNEL_MODE_SSL_WRAP);
- if(result != GLOBUS_SUCCESS)
- {
- goto free_auth_data;
- }
- if(attr != GLOBUS_NULL)
- {
- if(*attr != GLOBUS_NULL)
- {
- rc = globus_gass_transfer_secure_requestattr_get_authorization(
- attr,
- &l_proto->request->authorization_mode,
- &l_proto->request->authorized_subject);
- if(rc != GLOBUS_SUCCESS)
- {
- goto free_auth_data;
- }
- }
- }
- result = globus_io_secure_authorization_data_set_callback(
- &data,
- globus_l_gass_transfer_http_authorization_callback,
- proto);
-
- if(result != GLOBUS_SUCCESS)
- {
- goto free_auth_data;
- }
- result = globus_io_attr_set_secure_authorization_mode(
- &tcp_attr,
- GLOBUS_IO_SECURE_AUTHORIZATION_MODE_CALLBACK,
- &data);
- if(result != GLOBUS_SUCCESS)
- {
- goto free_auth_data;
- }
- globus_io_secure_authorization_data_destroy(&data);
- }
- /* Initialize the proto instance */
- l_proto->request->send_buffer= globus_l_gass_transfer_http_send;
- l_proto->request->recv_buffer = globus_l_gass_transfer_http_receive;
- l_proto->request->fail = globus_l_gass_transfer_http_fail;
- l_proto->request->deny = globus_l_gass_transfer_http_request_deny;
- l_proto->request->refer = globus_l_gass_transfer_http_request_refer;
- l_proto->request->authorize = globus_l_gass_transfer_http_request_authorize;
- l_proto->request->destroy = globus_l_gass_transfer_http_destroy;
- l_proto->request->text_mode = (file_mode == GLOBUS_GASS_TRANSFER_FILE_MODE_TEXT);
- l_proto->request->line_mode = GLOBUS_L_LINE_MODE_UNKNOWN;
- l_proto->request->state = GLOBUS_GASS_TRANSFER_HTTP_STATE_CONNECTING;
- l_proto->request->request = request;
- l_proto->request->type = globus_gass_transfer_request_get_type(request);
- l_proto->request->code = 0;
- l_proto->request->reason = 0;
- l_proto->request->parse_error = GLOBUS_FALSE;
- l_proto->request->destroy_called = GLOBUS_FALSE;
- l_proto->request->headers = GLOBUS_NULL;
- l_proto->request->response_buffer = GLOBUS_NULL;
- l_proto->request->length = 0;
- l_proto->request->handled = 0;
- l_proto->request->chunked = GLOBUS_FALSE;
- l_proto->request->chunk_left = 0;
- l_proto->request->failure_occurred = GLOBUS_FALSE;
- l_proto->request->oneshot_registered = GLOBUS_FALSE;
- l_proto->request->oneshot_active = GLOBUS_FALSE;
- l_proto->request->eof_read = GLOBUS_FALSE;
- l_proto->request->method = GLOBUS_NULL;
- l_proto->request->uri = GLOBUS_NULL;
- l_proto->request->response_offset = 0;
- l_proto->request->parsed_offset = 0;
- l_proto->request->client_side = GLOBUS_FALSE;
- l_proto->request->connected_subject = GLOBUS_NULL;
- /* Register accept with new request */
- l_proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_ACCEPTING;
- debug_printf(4,(_GTSL("%s(): Registering accept on %p\n"),
- myname,
- &l_proto->handle));
- result = globus_io_tcp_register_accept(&l_proto->handle,
- &tcp_attr,
- &l_proto->request->handle,
- globus_l_gass_transfer_http_accept_callback,
- l_proto);
- if(result != GLOBUS_SUCCESS)
- {
- goto tcpattr_error;
- }
- globus_io_tcpattr_destroy(&tcp_attr);
- debug_printf(1, (_GTSL("exiting %s()\n"),myname));
- return;
- free_auth_data:
- globus_io_secure_authorization_data_destroy(&data);
- tcpattr_error:
- globus_io_tcpattr_destroy(&tcp_attr);
- proto_error:
- globus_l_gass_transfer_http_proto_destroy(l_proto->request);
- l_proto->request = NULL;
- error_exit:
- l_proto->state = GLOBUS_GASS_TRANSFER_HTTP_LISTENER_STARTING;
- globus_l_gass_transfer_http_unlock();
- GlobusTimeReltimeSet(delay_time, 0, 0);
- debug_printf(4,(_GTSL("%s(): Registering oneshot\n"),
- myname));
- kickout = globus_libc_malloc(
- sizeof(globus_l_gass_transfer_failed_kickout_closure_t));
- kickout->l_proto = l_proto;
- kickout->request = request;
- globus_callback_register_oneshot(
- GLOBUS_NULL,
- &delay_time,
- globus_l_gass_transfer_http_accept_failed_kickout,
- kickout);
- debug_printf(1, (_GTSL("exiting %s()\n"),myname));
- }
- /* globus_l_gass_transfer_http_accept() */
- static
- globus_result_t
- globus_l_gass_transfer_http_register_read(
- globus_gass_transfer_http_request_proto_t * proto)
- {
- MYNAME(globus_l_gass_transfer_http_register_read);
-
- /*
- * If binary, and some chunk data is unread from the handle,
- * or we are not chunked, we can read directly into the user's
- * buffer. Otherwise, we must buffer the data and then copy it
- * to the user's buffer.
- */
- if(proto->text_mode == GLOBUS_FALSE &&
- (
- (proto->chunked &&
- proto->chunk_left > 0 &&
- proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_BODY) ||
- (proto->chunked == GLOBUS_FALSE)
- )
- )
- {
- globus_size_t minimum;
- globus_size_t maximum;
- minimum = proto->user_waitlen;
- if(minimum > proto->user_buflen - proto->user_offset)
- {
- minimum = proto->user_buflen - proto->user_offset;
- }
- if(proto->chunked && minimum > proto->chunk_left)
- {
- minimum = proto->chunk_left;
- }
- if(proto->length != 0 &&
- minimum > proto->length - proto->handled)
- {
- minimum = proto->length - proto->handled;
- }
- maximum = proto->user_buflen - proto->user_offset;
- if(proto->chunked && maximum > proto->chunk_left)
- {
- maximum = proto->chunk_left;
- }
- if(proto->length != 0 &&
- maximum > proto->length - proto->handled)
- {
- maximum = proto->length - proto->handled;
- }
- debug_printf(4,(_GTSL("%s(): Registering read on %p\n"),
- myname,
- &proto->handle));
- return
- globus_io_register_read(&proto->handle,
- proto->user_buffer +
- proto->user_offset,
- maximum,
- minimum,
- globus_l_gass_transfer_http_read_callback,
- proto);
- }
- else
- {
- /*
- * In text mode or in "chunked" mode, we will have
- * to buffer the data and then apply some transformation
- * to it upon receiving it.
- */
- globus_size_t smaller;
- smaller = proto->user_waitlen;
- if (proto->response_buflen - proto->response_offset == 0)
- {
- /* if buffer is full, shift unparsed data to buffer head */
- memmove(proto->response_buffer,
- proto->response_buffer + proto->parsed_offset,
- proto->response_offset - proto->parsed_offset);
- proto->response_offset -= proto->parsed_offset;
- proto->parsed_offset = 0;
- }
- if (proto->response_buflen - proto->response_offset == 0)
- {
- unsigned char * tmp;
- /* buffer still full... resize buffer */
- tmp = realloc(proto->response_buffer, proto->response_buflen * 2);
- if(tmp == GLOBUS_NULL)
- {
- proto->code = GLOBUS_L_MALLOC_FAILURE_CODE;
- proto->reason = globus_libc_strdup(GLOBUS_L_MALLOC_FAILURE_REASON);
- return GLOBUS_FAILURE;
- }
- else
- {
- proto->response_buffer = tmp;
- proto->response_buflen *= 2;
- }
- }
- if(smaller > proto->response_buflen - proto->response_offset)
- {
- smaller = proto->response_buflen - proto->response_offset;
- }
- debug_printf(4,(_GTSL("%s(): Registering read on %p\n"),
- myname,
- &proto->handle));
- return
- globus_io_register_read(&proto->handle,
- proto->response_buffer +
- proto->response_offset,
- proto->response_buflen -
- proto->response_offset,
- smaller,
- globus_l_gass_transfer_http_read_buffered_callback,
- proto);
- }
- }
- static
- char *
- globus_l_gass_transfer_http_hex_escape(
- const unsigned char * url)
- {
- unsigned char * new_url;
- const unsigned char * tmp_in;
- unsigned char * tmp_out;
- char hex[3];
- new_url = globus_libc_malloc(strlen((char *) url)*3+1);
- if (new_url == NULL)
- {
- return NULL;
- }
- tmp_in = url;
- tmp_out = new_url;
- while ((*tmp_in) != '\0')
- {
- if (isspace(*tmp_in))
- {
- sprintf(hex, "%2x", (unsigned int) *(tmp_in++));
- *(tmp_out++) = '%';
- *(tmp_out++) = hex[0];
- *(tmp_out++) = hex[1];
- }
- else
- {
- *(tmp_out++) = *(tmp_in++);
- }
- }
- *tmp_out = '\0';
- return (char *) new_url;
- }
- /* globus_l_gass_transfer_http_hex_escape() */
- static
- char *
- globus_l_gass_transfer_http_construct_request(
- globus_gass_transfer_http_request_proto_t * proto)
- {
- globus_size_t cmd_len;
- char * cmd = GLOBUS_NULL;
- globus_size_t length;
- char * url = GLOBUS_NULL;
- /* Construct the request string to send to the server */
- cmd_len = 3; /* for CRLF\0 termination */
- cmd_len += strlen(proto->url.host); /* Required for http/1.1*/
- if(proto->proxy_connect)
- {
- url = globus_l_gass_transfer_http_hex_escape((unsigned char *) proto->url_string);
- if (url == NULL)
- {
- return NULL;
- }
- cmd_len += strlen(url);
- }
- else
- {
- url = globus_l_gass_transfer_http_hex_escape((unsigned char *) proto->url.url_path);
- if (url == NULL)
- {
- return NULL;
- }
- cmd_len += strlen(url);
- }
- switch(proto->type)
- {
- case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_GET:
- cmd_len += strlen(GLOBUS_L_GET_COMMAND);
- cmd = globus_malloc(cmd_len * sizeof(globus_byte_t));
- if(cmd == GLOBUS_NULL)
- {
- globus_libc_free(url);
- return GLOBUS_NULL;
- }
-
- sprintf(cmd,
- GLOBUS_L_GET_COMMAND,
- url,
- proto->url.host);
- strcat(cmd,
- CRLF);
-
- globus_libc_free(url);
- return cmd;
- case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT:
- cmd_len += strlen(GLOBUS_L_PUT_COMMAND);
- cmd_len += 2;
- if(proto->text_mode == GLOBUS_TRUE)
- {
- cmd_len += strlen(GLOBUS_L_TEXT_HEADER);
- }
- else
- {
- cmd_len += strlen(GLOBUS_L_BINARY_HEADER);
- }
-
- length = globus_gass_transfer_request_get_length(proto->request);
- if(length != 0)
- {
- globus_size_t x = length;
- globus_size_t digits = 0;
- /* count the number of decimal digits in length */
- do
- {
- digits++;
- x /= 10;
- } while(x > 0);
-
- cmd_len += strlen(GLOBUS_L_CONTENT_LENGTH_HEADER);
- cmd_len += digits;
- cmd = globus_malloc(cmd_len * sizeof(globus_byte_t));
- if(cmd == GLOBUS_NULL)
- {
- globus_libc_free(url);
- return GLOBUS_NULL;
- }
-
- sprintf((char *) cmd,
- GLOBUS_L_PUT_COMMAND,
- url,
- proto->url.host);
- sprintf(cmd + strlen(cmd),
- GLOBUS_L_CONTENT_LENGTH_HEADER,
- length);
- }
- else
- {
- cmd_len += strlen(GLOBUS_L_CHUNKED_HEADER);
- cmd = globus_malloc(cmd_len * sizeof(globus_byte_t));
- proto->chunked = GLOBUS_TRUE;
- /* hex encoding of globus_size_t: two bytes to encode per 8 bits,
- * plus a CRLF to end the chunk header
- */
- proto->iov[0].iov_base = (void *)
- globus_malloc((sizeof(globus_size_t) * 2) + 2);
- /* This never changes */
- proto->iov[2].iov_base = CRLF;
- proto->iov[2].iov_len = 2;
- proto->iov[3].iov_base = "0" CRLF CRLF;
- proto->iov[3].iov_len = strlen("0" CRLF CRLF);
- if(cmd == GLOBUS_NULL)
- {
- globus_libc_free(url);
- return GLOBUS_NULL;
- }
-
- sprintf((char *) cmd,
- GLOBUS_L_PUT_COMMAND,
- url,
- proto->url.host);
-
- strcat(cmd,
- GLOBUS_L_CHUNKED_HEADER);
- }
- if(proto->text_mode)
- {
- strcat(cmd,
- GLOBUS_L_TEXT_HEADER);
- }
- else
- {
- strcat(cmd,
- GLOBUS_L_BINARY_HEADER);
- }
- strcat(cmd,
- CRLF);
- globus_libc_free(url);
- return cmd;
- case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND:
- cmd_len += strlen(GLOBUS_L_APPEND_COMMAND);
- cmd_len += 2;
- if(proto->text_mode == GLOBUS_TRUE)
- {
- cmd_len += strlen(GLOBUS_L_TEXT_HEADER);
- }
- else
- {
- cmd_len += strlen(GLOBUS_L_BINARY_HEADER);
- }
-
- length = globus_gass_transfer_request_get_length(proto->request);
- if(length != 0)
- {
- globus_size_t x = length;
- globus_size_t digits = 0;
- /* count the number of decimal digits in length */
- do
- {
- digits++;
- x /= 10;
- } while(x > 0);
-
- cmd_len += strlen(GLOBUS_L_CONTENT_LENGTH_HEADER);
- cmd_len += digits;
- cmd = globus_malloc(cmd_len * sizeof(globus_byte_t));
- if(cmd == GLOBUS_NULL)
- {
- globus_libc_free(url);
- return GLOBUS_NULL;
- }
-
- sprintf((char *) cmd,
- GLOBUS_L_APPEND_COMMAND,
- url,
- proto->url.host);
- sprintf((char *) cmd + strlen(cmd),
- GLOBUS_L_CONTENT_LENGTH_HEADER,
- length);
- }
- else
- {
- cmd_len += strlen(GLOBUS_L_CHUNKED_HEADER);
- cmd = globus_malloc(cmd_len * sizeof(globus_byte_t));
- proto->chunked = GLOBUS_TRUE;
- /* hex encoding of globus_size_t: two bytes to encode per 8 bits,
- * plus a CRLF to end the chunk header
- */
- proto->iov[0].iov_base = (void *)
- globus_malloc((sizeof(globus_size_t) * 2) + 2);
- /* This never changes */
- proto->iov[2].iov_base = CRLF;
- proto->iov[2].iov_len = 2;
- proto->iov[3].iov_base = "0" CRLF CRLF;
- proto->iov[3].iov_len = 5;
- if(cmd == GLOBUS_NULL)
- {
- globus_libc_free(url);
- return GLOBUS_NULL;
- }
-
- sprintf((char *) cmd,
- GLOBUS_L_APPEND_COMMAND,
- proto->url.url_path,
- proto->url.host);
-
- strcat(cmd,
- GLOBUS_L_CHUNKED_HEADER);
- }
- if(proto->text_mode)
- {
- strcat(cmd,
- GLOBUS_L_TEXT_HEADER);
- }
- else
- {
- strcat(cmd,
- GLOBUS_L_BINARY_HEADER);
- }
- strcat(cmd,
- CRLF);
- globus_libc_free(url);
- return cmd;
- case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_INVALID:
- default:
- globus_assert(proto->type !=
- GLOBUS_GASS_TRANSFER_REQUEST_TYPE_INVALID);
- globus_assert(GLOBUS_FALSE);
- globus_libc_free(url);
- return GLOBUS_NULL;
- }
- }
- #endif /* !parser only */
- /*
- * Function: globus_l_gass_transfer_http_parse_response()
- *
- * Description: Parse a byte array containing a (maybe)
- * partial response from the server.
- *
- * Parameters: Protocol module this pertains to
- *
- * Returns: GLOBUS_TRUE if more headers must be read.
- *
- */
- static
- globus_bool_t
- globus_l_gass_transfer_http_parse_response(
- globus_gass_transfer_http_request_proto_t * proto)
- {
- /*
- * Parse the HTTP Response
- *
- * Grammar (from RFC 2068)
- *
- * Response = Status-Line ; Section 6.1
- * *( general-header ; Section 4.5
- * | response-header ; Section 6.2
- * | entity-header ) ; Section 7.1
- * CRLF
- * [ message-body ] ; Section 7.2
- */
- if(proto->reason == GLOBUS_NULL)
- {
- if(globus_l_gass_transfer_http_parse_status_line(proto))
- {
- goto repost_read;
- }
- else if(proto->parse_error)
- {
- goto parse_error;
- }
- }
- if(globus_l_gass_transfer_http_parse_headers(proto))
- {
- goto repost_read;
- }
- else if(proto->parse_error)
- {
- goto parse_error;
- }
- return GLOBUS_FALSE;
- repost_read:
- return GLOBUS_TRUE;
- parse_error:
- return GLOBUS_FALSE;
- }
- /* globus_l_gass_transfer_http_parse_response() */
- static
- globus_bool_t
- globus_l_gass_transfer_http_parse_request(
- globus_gass_transfer_http_request_proto_t * proto)
- {
- /*
- * Parse the HTTP Request
- *
- * Request = Request-Line ; Section 5.1
- * *( general-header ; Section 4.5
- * | request-header ; Section 5.3
- * | entity-header ) ; Section 7.1
- * CRLF
- * [ message-body ] ; Section 7.2
- *
- */
- if(proto->method == GLOBUS_NULL)
- {
- if(globus_l_gass_transfer_http_parse_request_line(proto))
- {
- goto repost_read;
- }
- else if(proto->parse_error)
- {
- goto parse_error;
- }
- }
- if(globus_l_gass_transfer_http_parse_headers(proto))
- {
- goto repost_read;
- }
- else if(proto->parse_error)
- {
- goto parse_error;
- }
- return GLOBUS_FALSE;
- repost_read:
- return GLOBUS_TRUE;
- parse_error:
- return GLOBUS_FALSE;
- }
- /* globus_l_gass_transfer_http_parse_request() */
- static
- globus_bool_t
- globus_l_gass_transfer_http_parse_status_line(
- globus_gass_transfer_http_request_proto_t * proto)
- {
- globus_size_t offset;
- globus_size_t reason_offset;
- int r_offset;
- offset = 0;
- /*
- * Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
- * HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
- */
- if(!globus_l_gass_transfer_http_find_crlf(
- proto->response_buffer + proto->parsed_offset,
- proto->response_offset - proto->parsed_offset,
- &offset))
- {
- return GLOBUS_TRUE;
- }
- /* Replace CRLF with NULL */
- proto->response_buffer[proto->parsed_offset + offset] = '\0';
- if(sscanf((char *) proto->response_buffer + proto->parsed_offset,
- "HTTP/%d.%d %d %n",
- &proto->major,
- &proto->minor,
- &proto->code,
- &r_offset) != 3)
- {
- /* Not a HTTP response */
- if(proto->code == 0)
- {
- proto->code =
- GLOBUS_L_PROTOCOL_FAILURE_CODE;
- proto->reason =
- globus_libc_strdup(GLOBUS_L_PROTOCOL_FAILURE_REASON);
- }
- proto->parsed_offset += offset;
- /* skip the CRLF, as well */
- proto->parsed_offset+=2;
- goto parse_error;
- }
- reason_offset = (globus_size_t) r_offset;
- proto->reason = globus_libc_strdup((char *) (proto->response_buffer +
- proto->parsed_offset +
- reason_offset));
- proto->parsed_offset += offset;
- /* skip the CRLF, as well */
- proto->parsed_offset+=2;
- return GLOBUS_FALSE;
- parse_error:
- proto->parse_error = GLOBUS_TRUE;
- return GLOBUS_FALSE;
- }
- static
- globus_bool_t
- globus_l_gass_transfer_http_parse_request_line(
- globus_gass_transfer_http_request_proto_t * proto)
- {
- globus_size_t offset;
- offset = 0;
- /*
- * Request-Line = Method SP Request-URI SP HTTP-Version CRLF
- * Method = "OPTIONS" ; Section 9.2
- * | "GET" ; Section 9.3
- * | "HEAD" ; Section 9.4
- * | "POST" ; Section 9.5
- * | "PUT" ; Section 9.6
- * | "DELETE" ; Section 9.7
- * | "TRACE" ; Section 9.8
- * | extension-method
- *
- * extension-method = token
- */
- if(!globus_l_gass_transfer_http_find_crlf(
- proto->response_buffer + proto->parsed_offset,
- proto->response_offset - proto->parsed_offset,
- &offset))
- {
- return GLOBUS_TRUE;
- }
- /* Replace CRLF with NULL */
- proto->response_buffer[proto->parsed_offset + offset] = '\0';
- proto->method = globus_malloc(offset);
- proto->uri = globus_malloc(offset);
- if(sscanf((char *) proto->response_buffer + proto->parsed_offset,
- "%s %s HTTP/%d.%d",
- proto->method,
- proto->uri,
- &proto->major,
- &proto->minor) != 4)
- {
- /* Not a HTTP request */
- if(proto->code == 0)
- {
- proto->code =
- GLOBUS_L_PROTOCOL_FAILURE_CODE;
- proto->reason =
- globus_libc_strdup(GLOBUS_L_PROTOCOL_FAILURE_REASON);
- }
- proto->parsed_offset += offset;
- /* skip the CRLF, as well */
- proto->parsed_offset+=2;
- goto parse_error;
- }
- /* skip the CRLF, as well */
- proto->parsed_offset += offset + 2;
- return GLOBUS_FALSE;
- parse_error:
- proto->parse_error = GLOBUS_TRUE;
- return GLOBUS_FALSE;
- }
- static
- globus_bool_t
- globus_l_gass_transfer_http_parse_headers(
- globus_gass_transfer_http_request_proto_t * proto)
- {
- globus_bool_t all_headers = GLOBUS_FALSE;
- while(!all_headers)
- {
- if(globus_l_gass_transfer_http_parse_one_header(proto,
- &all_headers))
- {
- return GLOBUS_TRUE;
- }
- else if(proto->parse_error)
- {
- return GLOBUS_FALSE;
- }
- }
- return GLOBUS_FALSE;
- }
- /* globus_l_gass_transfer_http_parse_headers() */
- static
- globus_bool_t
- globus_l_gass_transfer_http_parse_one_header(
- globus_gass_transfer_http_request_proto_t * proto,
- globus_bool_t * last_header)
- {
- globus_size_t offset;
- globus_bool_t end_of_header;
- globus_size_t continuation=0;
- char * value;
- char * new_value;
- int i;
- /*
- * message-header = field-name ":" [ field-value ] CRLF
- *
- * field-name = token
- * field-value = *( field-content | LWS )
- * LWS = [CRLF] 1*( SP | HT )
- *
- * field-content = <the OCTETs making up the field-value
- * and consisting of either *TEXT or combinations
- * of token, tspecials, and quoted-string>
- * token = 1*<any CHAR except CTLs or tspecials>
- * CTL = <any US-ASCII control character
- * (octets 0 - 31) and DEL (127)>
- * tspecials = "(" | ")" | "<" | ">" | "@"
- * | "," | ";" | ":" | "\" | <">
- * | "/" | "[" | "]" | "?" | "="
- * | "{" | "}" | SP | HT
- *
- * This implementation is a little lax on the character restrictions...
- */
- end_of_header = GLOBUS_FALSE;
- /* Find the complete header (which may span multiple lines) */
- while(!end_of_header)
- {
- /* Find the end of this header line */
- if(! globus_l_gass_transfer_http_find_crlf(
- proto->response_buffer +
- proto->parsed_offset +
- continuation,
- proto->response_offset -
- proto->parsed_offset -
- continuation,
- &offset))
- {
- return GLOBUS_TRUE;
- }
- else if(offset == 0)
- {
- end_of_header = GLOBUS_TRUE;
- break;
- }
- /*
- * Reached end-of-read data before being able to detect a
- * continuation
- */
- if(proto->parsed_offset + continuation + offset + 2 >=
- proto->response_offset)
- {
- return GLOBUS_TRUE;
- }
- /* Check for continuation (LWS) */
- if(islws(proto->response_buffer[proto->parsed_offset +
- continuation + offset + 2]))
- {
- continuation += offset + 2;
- }
- else
- {
- /* No continuation, we have a header */
- end_of_header = GLOBUS_TRUE;
- }
- }
- /* This is the last header if it consists of CRLF only */
- if(proto->response_buffer[proto->parsed_offset] == CR &&
- proto->response_buffer[proto->parsed_offset + 1] == LF &&
- continuation + offset == 0)
- {
- *last_header = GLOBUS_TRUE;
- proto->parsed_offset += 2;
- return GLOBUS_FALSE;
- }
- /* Canonical form of header is lower-case */
- for(i = proto->parsed_offset; i < proto->parsed_offset + continuation + offset; i++)
- {
- if(proto->response_buffer[i] == ':')
- {
- break;
- }
- else
- {
- proto->response_buffer[i] =
- (char) tolower((int) (proto->response_buffer[i]));
- }
- }
- if(proto->response_buffer[i] != ':')
- {
- /* The header's name is illegal */
- proto->code = GLOBUS_L_PROTOCOL_FAILURE_CODE;
- if(proto->reason != GLOBUS_NULL)
- {
- globus_free(proto->reason);
- }
- proto->reason =
- globus_libc_strdup(GLOBUS_L_PROTOCOL_FAILURE_REASON);
- proto->parse_error = GLOBUS_TRUE;
- return GLOBUS_FALSE;
- }
- /* NULL-terminate the header's name */
- proto->response_buffer[i] = '\0';
- new_value = (char *) &proto->response_buffer[i+1];
- /* Make the header's value NULL terminated */
- proto->response_buffer[proto->parsed_offset+continuation+offset] = '\0';
- /*
- * Add header to table. If it already there, append a
- * comma and the new header's value.
- */
- value = (char *) globus_i_gass_transfer_keyvalue_lookup(
- &proto->headers,
- (char *) (proto->response_buffer + proto->parsed_offset));
- if(value == GLOBUS_NULL)
- {
- /* New header */
- globus_i_gass_transfer_keyvalue_insert(
- &proto->headers,
- globus_libc_strdup((char *) (proto->response_buffer +
- proto->parsed_offset)),
- globus_libc_strdup(new_value));
- }
- else
- {
- /* Existing header, append */
- globus_byte_t * new_ptr;
- new_ptr = globus_libc_realloc(value,
- (strlen(value) +
- strlen(new_value) + 2) *
- sizeof(globus_byte_t));
- strcat((char *) new_ptr,
- ",");
- strcat((char *) new_ptr,
- new_value);
- globus_i_gass_transfer_keyvalue_replace(
- &proto->headers,
- (char *) (proto->response_buffer + proto->parsed_offset),
- (char *) new_ptr);
- }
- /* Move the "parsed" pointer to the end of what we've just handled */
- proto->parsed_offset += continuation + offset + 2;
- return GLOBUS_FALSE;
- }
- /* globus_l_gass_transfer_http_parse_one_header() */
- static
- globus_bool_t
- globus_l_gass_transfer_http_find_crlf(
- globus_byte_t * bytes,
- globus_size_t len,
- globus_size_t * crlf_offset)
- {
- int i;
- if(len == 0)
- {
- return GLOBUS_FALSE;
- }
- /* See if we can find the end an http meta-information line */
- for (i = 0; i < len-1; i++)
- {
- if(bytes[i] == CR &&
- bytes[i+1] == LF)
- {
- *crlf_offset = i;
- return GLOBUS_TRUE;
- }
- }
- return GLOBUS_FALSE;
- }
- /* globus_l_gass_transfer_http_find_crlf() */
- /*
- * Function: globus_l_gass_transfer_http_copy_text_buffer()
- *
- * Description: Copy a text array from an HTTP-message to
- * a user's buffer, converting end-of-line characters
- * to the local host format. Determines the message
- * line format based on the first end-of-line it
- * reaches if it is unknown.
- *
- * Parameters:
- *
- * Returns:
- */
- void
- globus_l_gass_transfer_http_copy_text_buffer(
- globus_byte_t * output,
- globus_byte_t * input,
- globus_gass_transfer_http_line_mode_t * line_mode,
- globus_size_t max_input,
- globus_size_t max_output,
- globus_size_t * input_copied,
- globus_size_t * output_copied)
- {
- globus_size_t src;
- globus_size_t dst;
- src = 0;
- dst = 0;
- /* Need to determine the line terminator */
- if(*line_mode == GLOBUS_L_LINE_MODE_UNKNOWN)
- {
- while(src < max_input-1 && dst < max_output-1)
- {
- if(input[src] == CR && (*line_mode) ==
- GLOBUS_L_LINE_MODE_UNKNOWN)
- {
- if(input[src+1] == LF)
- {
- *line_mode = GLOBUS_L_LINE_MODE_CRLF;
- break;
- }
- else
- {
- *line_mode = GLOBUS_L_LINE_MODE_CR;
- break;
- }
- }
- else if(input[src] == LF && (*line_mode) ==
- GLOBUS_L_LINE_MODE_UNKNOWN)
- {
- *line_mode = GLOBUS_L_LINE_MODE_LF;
- break;
- }
- else
- {
- output[dst] = GLOBUS_L_TEXT_BYTE(input[src]);
- dst++;
- src++;
-
- continue;
- }
- }
- /* did we finish because we read the end-of-input or output? */
- if(src == max_input-1 ||
- dst == max_output-1)
- {
- *input_copied = src;
- *output_copied = dst;
- return;
- }
- }
- /*
- * Convert from *line_mode terminated text, to the local-machine's line
- * mode
- */
- while(src < max_input && dst < max_output)
- {
- if(input[src] == CR && input[src+1] == LF &&
- *line_mode == GLOBUS_L_LINE_MODE_CRLF)
- {
- switch(globus_l_gass_transfer_http_line_mode)
- {
- case GLOBUS_L_LINE_MODE_CR:
- /* CRLF to CR */
- output[dst] = CR;
- dst++;
- src += 2;
- break;
- case GLOBUS_L_LINE_MODE_CRLF:
- /* CRLF to CRLF */
- output[dst]= CR;
- dst++;
- output[dst]= LF;
- dst++;
- src += 2;
- break;
- case GLOBUS_L_LINE_MODE_LF:
- /* CRLF to LF */
- output[dst]= LF;
- dst++;
- src += 2;
- break;
- case GLOBUS_L_LINE_MODE_UNKNOWN:
- globus_assert(globus_l_gass_transfer_http_line_mode !=
- GLOBUS_L_LINE_MODE_UNKNOWN);
- }
- }
- else if(input[src] == CR && *line_mode == GLOBUS_L_LINE_MODE_CR)
- {
- switch(globus_l_gass_transfer_http_line_mode)
- {
- case GLOBUS_L_LINE_MODE_CR:
- /* CR to CR */
- output[dst] = CR;
- dst++;
- src++;
- break;
- case GLOBUS_L_LINE_MODE_CRLF:
- /* CR to CRLF */
- output[dst]= CR;
- dst++;
- output[dst]= LF;
- dst++;
- src++;
- break;
- case GLOBUS_L_LINE_MODE_LF:
- /* CRLF to LF */
- output[dst]= LF;
- dst++;
- src++;
- break;
- case GLOBUS_L_LINE_MODE_UNKNOWN:
- globus_assert(globus_l_gass_transfer_http_line_mode !=
- GLOBUS_L_LINE_MODE_UNKNOWN);
- }
- }
- else if(input[src] == LF && *line_mode == GLOBUS_L_LINE_MODE_LF)
- {
- switch(globus_l_gass_transfer_http_line_mode)
- {
- case GLOBUS_L_LINE_MODE_CR:
- /* LF to CR */
- output[dst] = CR;
- dst++;
- src++;
- break;
- case GLOBUS_L_LINE_MODE_CRLF:
- /* LF to CRLF */
- output[dst]= CR;
- dst++;
- output[dst]= LF;
- dst++;
- src++;
- break;
- case GLOBUS_L_LINE_MODE_LF:
- /* LF to LF */
- output[dst]= LF;
- dst++;
- src++;
- break;
- case GLOBUS_L_LINE_MODE_UNKNOWN:
- globus_assert(globus_l_gass_transfer_http_line_mode !=
- GLOBUS_L_LINE_MODE_UNKNOWN);
- }
- }
- else
- {
- output[dst] = GLOBUS_L_TEXT_BYTE(input[src]);
- dst++;
- src++;
-
- continue;
- }
- }
- *input_copied = src;
- *output_copied = dst;
- }
- /* globus_l_gass_transfer_http_copy_text_buffer() */
- static
- void
- globus_l_gass_transfer_unbuffer_text(
- globus_gass_transfer_http_request_proto_t * proto)
- {
- /*
- * Copy the text from the proto's response buffer to the
- * user's buffer
- */
- globus_size_t input_copied;
- globus_size_t output_copied;
- globus_size_t src_max;
- globus_bool_t redo = GLOBUS_FALSE;
- do
- {
- src_max = proto->response_offset - proto->parsed_offset;
- if(proto->chunked &&
- (src_max > proto->chunk_left))
- {
- src_max = proto->chunk_left;
- }
- /*
- * Copy the text, converting to 7-bit US-ASCII, and
- * converting the document's end-of-line to be the local
- * machine's end-of-line character
- */
- globus_l_gass_transfer_http_copy_text_buffer(
- proto->user_buffer + proto->user_offset,
- proto->response_buffer + proto->parsed_offset,
- &proto->line_mode,
- src_max,
- proto->user_buflen - proto->user_offset,
- &input_copied,
- &output_copied);
- proto->user_offset += output_copied;
- proto->parsed_offset += input_copied;
- proto->handled += input_copied;
- if(proto->chunked)
- {
- proto->chunk_left -= input_copied;
- }
- if(output_copied > proto->user_waitlen)
- {
- proto->user_waitlen = 0;
- }
- else
- {
- proto->user_waitlen -= output_copied;
- }
- if(proto->response_offset - proto->parsed_offset == 1 &&
- proto->line_mode == GLOBUS_L_LINE_MODE_UNKNOWN)
- {
- if(proto->response_buffer[proto->parsed_offset] == CR)
- {
- proto->line_mode = GLOBUS_L_LINE_MODE_CR;
- redo = GLOBUS_TRUE;
- }
- else if (proto->response_buffer[proto->parsed_offset] == LF)
- {
- proto->line_mode = GLOBUS_L_LINE_MODE_LF;
- redo = GLOBUS_TRUE;
- }
- else
- {
- /* doesn't matter, since the document contains no newlines */
- proto->line_mode = GLOBUS_L_LINE_MODE_LF;
- redo = GLOBUS_TRUE;
- }
- }
- else
- {
- redo = GLOBUS_FALSE;
- }
- } while(redo);
- /* Reset our buffer, if we've read it all */
- if(proto->parsed_offset == proto->response_offset)
- {
- proto->parsed_offset = 0;
- proto->response_offset = 0;
- }
- else if(proto->parsed_offset != 0)
- {
- /* This may not be necessary */
- memmove(proto->response_buffer,
- proto->response_buffer + proto->parsed_offset,
- proto->response_offset - proto->parsed_offset);
- proto->response_offset -= proto->parsed_offset;
- proto->parsed_offset = 0;
- }
- }
- /* globus_l_gass_transfer_unbuffer_text() */
- static
- void
- globus_l_gass_transfer_unbuffer_binary(
- globus_gass_transfer_http_request_proto_t * proto)
- {
- /*
- * Copy the binary from the proto's response buffer to the
- * user's buffer
- */
- globus_size_t smaller;
- smaller = proto->response_offset - proto->parsed_offset;
- if(smaller > proto->user_buflen - proto->user_offset)
- {
- smaller = proto->user_buflen - proto->user_offset;
- }
- if(proto->chunked &&
- smaller > proto->chunk_left)
- {
- smaller = proto->chunk_left;
- }
- memcpy(proto->user_buffer + proto->user_offset,
- proto->response_buffer + proto->parsed_offset,
- smaller);
- proto->user_offset += smaller;
- proto->parsed_offset += smaller;
- proto->handled += smaller;
- if(proto->chunked)
- {
- proto->chunk_left -= smaller;
- }
- if(smaller > proto->user_waitlen)
- {
- proto->user_waitlen = 0;
- }
- else
- {
- proto->user_waitlen -= smaller;
- }
- /* Reset our buffer, if we've read it all */
- if(proto->parsed_offset == proto->response_offset)
- {
- proto->parsed_offset = 0;
- proto->response_offset = 0;
- }
- else if(proto->parsed_offset != 0)
- {
- /* This may not be necessary */
- memmove(proto->response_buffer,
- proto->response_buffer + proto->parsed_offset,
- proto->response_offset - proto->parsed_offset);
- proto->response_offset -= proto->parsed_offset;
- proto->parsed_offset = 0;
- }
- }
- /* globus_l_gass_transfer_unbuffer_binary() */
- /* Code for parsing HTTP responses */
- static
- globus_bool_t
- islws(
- char byte)
- {
- return(byte == ' ' ||
- byte == '\t');
- }
- /* islws() */
- static
- globus_bool_t
- ischar(
- char byte)
- {
- return( (unsigned char) byte <= 127 );
- }
- /* ischar() */
- static
- globus_bool_t
- istspecial(
- char byte)
- {
- return (byte == '(' || byte == ')' || byte == '<' ||
- byte == '>' || byte == '@' || byte == ',' ||
- byte == ';' || byte == ':' || byte == '\\' ||
- byte == '"' || byte == '/' || byte == '[' ||
- byte == ']' || byte == '?' || byte == '=' ||
- byte == '{' || byte == '}' || byte == ' ' ||
- byte == '\t');
- }
- /* istspecial() */
- globus_bool_t
- isctl(
- char byte)
- {
- return ((byte >= (char) 0 && byte <= (char) 31) ||
- byte == (char) 127);
- }
- static
- globus_bool_t
- ishex(
- char byte)
- {
- return (byte == 'A' || byte == 'B' || byte == 'C' ||
- byte == 'D' || byte == 'E' || byte == 'F' ||
- byte == 'a' || byte == 'b' || byte == 'c' ||
- byte == 'd' || byte == 'e' || byte == 'f' ||
- byte == '0' || byte == '1' || byte == '2' ||
- byte == '3' || byte == '4' || byte == '5' ||
- byte == '6' || byte == '7' || byte == '8' ||
- byte == '9');
- }
- /*
- * all scan and parse functions return GLOBUS_TRUE if more data
- * is needed to read a complete token
- */
- static
- globus_bool_t
- globus_l_gass_transfer_http_scan_star_lws(
- globus_byte_t * input,
- globus_size_t max_to_scan,
- globus_size_t * end_of_token)
- {
- globus_size_t i;
- *end_of_token = 0;
- /*
- * an interesting note from the HTTP/1.1 RFC
- * implied *LWS
- * The grammar described by this specification is word-based. Except
- * where noted otherwise, linear whitespace (LWS) can be included
- * between any two adjacent words (token or quoted-string), and
- * between adjacent tokens and delimiters (tspecials), without
- * changing the interpretation of a field. At least one delimiter
- * (tspecials) must exist between any two tokens, since they would
- * otherwise be interpreted as a single token.
- *
- * And the definition of the LWS that we are parsing
- *
- * LWS = [CRLF] 1 *(SP | HT)
- * CRLF = CR LF
- * CR = <US-ASCII CR, carriage return (13)>
- * LF = <US-ASCII LF, linefeed (10)>
- * SP = <US-ASCII SP, space (32)>
- * HT = <US-ASCII HT, horizontal-tab (9)>
- */
- for(i = 0; i < max_to_scan; i++)
- {
- if(input[i] == ' ' || input[i] == '\t')
- {
- continue;
- }
- if(input[i] == CR)
- {
- if(i + 2 >= max_to_scan)
- {
- /* not enough data */
- return GLOBUS_TRUE;
- }
- else
- {
- if(input[i+1] == LF &&
- (input[i+2] == ' ' ||
- input[i+2] == '\t'))
- {
- /* pass over LF */
- i++;
- continue;
- }
- else
- {
- /* This CR doesn't match our pattern */
- if(i != 0)
- {
- /* If we've swallowed any whitespace, note it */
- *end_of_token = i;
- }
- return GLOBUS_FALSE;
- }
- }
- }
- else
- {
- /* end of match */
- if(i != 0)
- {
- *end_of_token = i;
- }
- return GLOBUS_FALSE;
- }
- }
- /*
- * If we haven't hit an end of the LWS by the end of input,
- * our (*LWS) can't be greedy, so we need more input
- */
- return GLOBUS_TRUE;
- }
- /* globus_l_gass_transfer_http_scan_star_lws() */
- static
- globus_bool_t
- globus_l_gass_transfer_http_scan_token(
- globus_byte_t * input,
- globus_size_t max_to_scan,
- globus_size_t * end_of_token)
- {
- globus_size_t i;
- *end_of_token = 0;
- /*
- * token = 1*<any CHAR except CTLs or tspecials>
- * CTL = <any US-ASCII control character
- * (octets 0 - 31) and DEL (127)>
- * tspecials = "(" | ")" | "<" | ">" | "@"
- * | "," | ";" | ":" | "\" | <">
- * | "/" | "[" | "]" | "?" | "="
- * | "{" | "}" | SP | HT
- */
- for(i = 0; i < max_to_scan; i++)
- {
- if(!ischar(input[i]) ||
- isctl(input[i]) ||
- istspecial(input[i]))
- {
- if(i != 0)
- {
- *end_of_token = i;
- }
- return GLOBUS_FALSE;
- }
- }
- return GLOBUS_TRUE; /* need more data */
- }
- /* globus_l_gass_transfer_http_scan_token() */
- static
- globus_bool_t
- globus_l_gass_transfer_http_scan_qdtext(
- globus_byte_t * input,
- globus_size_t max_to_scan,
- globus_size_t * end_of_qdtext)
- {
- globus_size_t i;
- globus_size_t j;
- /*
- * qdtext = <any TEXT except <">>
- * TEXT = <any OCTET except CTLs,
- * but including LWS>
- * quoted-pair = "\" CHAR
- * CHAR = <any US-ASCII character (octets 0 - 127)>
- */
- *end_of_qdtext = 0;
- for(i = 0; i < max_to_scan; i++)
- {
- /* Always absorb LWS in quotes */
- if(globus_l_gass_transfer_http_scan_star_lws(
- input + i,
- max_to_scan - i,
- &j))
- {
- return GLOBUS_TRUE; /* need more to scan */
- }
- else if(j != 0)
- {
- i += j; /* scanned some LWS */
- continue;
- }
- else if(input[i] == '\\')
- {
- /* absorb quoted-pair */
- if(i + 1 < max_to_scan)
- {
- if(ischar(input[i+1]))
- {
- i++;
-
- continue;
- }
- else
- {
- *end_of_qdtext = i;
- return GLOBUS_FALSE;
- }
- }
- else
- {
- return GLOBUS_TRUE; /* need more to scan */
- }
- }
- else if(!isctl(input[i]))
- {
- continue;
- }
- else if(i != 0)
- {
- *end_of_qdtext = i;
- return GLOBUS_FALSE;
- }
- else
- {
- return GLOBUS_FALSE;
- }
- }
- return GLOBUS_TRUE;
- }
- /* globus_l_gass_transfer_http_scan_qdtext() */
- static
- globus_bool_t
- globus_l_gass_transfer_http_scan_quoted_string(
- globus_byte_t * input,
- globus_size_t max_to_scan,
- globus_size_t * end_of_qtd_string)
- {
- globus_size_t i;
- /*
- * quoted-string = ( <"> *(qdtext) <"> )
- */
- *end_of_qtd_string = 0;
- if(max_to_scan == 0)
- {
- return GLOBUS_TRUE;
- }
- /* quoted text must begin with '"' */
- if(input[0] != '"')
- {
- return GLOBUS_FALSE;
- }
- if(globus_l_gass_transfer_http_scan_qdtext(
- input+1,
- max_to_scan-1,
- &i))
- {
- return GLOBUS_TRUE; /* need more data */
- }
- if(i == max_to_scan - 1)
- {
- return GLOBUS_TRUE; /* need more data */
- }
- /* quoted text must end with '"' */
- if(input[i] == '"')
- {
- *end_of_qtd_string = i+1;
- return GLOBUS_FALSE;
- }
- else
- {
- return GLOBUS_FALSE;
- }
- }
- /* globus_l_gass_transfer_http_scan_quoted_string() */
- static
- globus_bool_t
- globus_l_gass_transfer_http_scan_chunk_ext(
- globus_byte_t * input,
- globus_size_t max_to_scan,
- globus_size_t * end_of_chunk_ext)
- {
- globus_size_t i;
- globus_size_t j;
- globus_bool_t semicolon = GLOBUS_FALSE;
- /*
- * chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-value ] )
- * chunk-ext-name = token
- * chunk-ext-val = token | quoted-string
- */
- *end_of_chunk_ext = 0;
- i = 0;
- for(;;)
- {
- if(max_to_scan - i == 0)
- {
- return GLOBUS_TRUE;
- }
- else if (input[i] != CR)
- {
- /* Don't scan *LWS if the first character is a newline. Assume that no
- * client will stick \r\n\t; as a chunk extension start.
- */
- if(globus_l_gass_transfer_http_scan_star_lws(
- input + i,
- max_to_scan - i,
- &j))
- {
- return GLOBUS_TRUE; /* more to scan */
- }
- else if(input[i] != CR && j != 0)
- {
- i += j; /* scanned some leading LWS */
- }
- }
- if(i + 1 >= max_to_scan)
- {
- return GLOBUS_TRUE;
- }
- /*
- * Only consume LWS if there is a semicolon,
- * otherwise, we may consume part of CRLF/message body
- */
- if(input[i] != ';' && semicolon)
- {
- *end_of_chunk_ext = i;
- return GLOBUS_FALSE;
- }
- else if(input[i] != ';')
- {
- return GLOBUS_FALSE;
- }
- semicolon = GLOBUS_TRUE;
- /* pass over ';' */
- i++;
- /* skip any LWS */
- if(globus_l_gass_transfer_http_scan_star_lws(
- input + i,
- max_to_scan - i,
- &j))
- {
- return GLOBUS_TRUE; /* more to scan */
- }
- else if(j != 0)
- {
- i += j; /* scanned some LWS */
- }
- /* scan for chunk-ext-name */
- if(globus_l_gass_transfer_http_scan_token(
- input + i,
- max_to_scan - i,
- &j))
- {
- return GLOBUS_TRUE;
- }
- else if(j == 0) /* illegal, ';' but no token */
- {
- *end_of_chunk_ext = 0;
- return GLOBUS_FALSE;
- }
- else
- {
- i += j;
- }
- /* skip any LWS */
- if(globus_l_gass_transfer_http_scan_star_lws(
- input + i,
- max_to_scan - i,
- &j))
- {
- return GLOBUS_TRUE; /* more to scan */
- }
- else if(j != 0)
- {
- i += j; /* scanned some leading LWS */
- }
- /* check for '=' */
- if(i + 1 >= max_to_scan)
- {
- return GLOBUS_TRUE;
- }
- if(input[i] == ';') /* chunk-ext without chunk-ext-value */
- {
- continue;
- }
- else if(input[i] != '=')
- {
- *end_of_chunk_ext = i;
- return GLOBUS_FALSE;
- }
- /* pass over '=' */
- i++;
- /* skip any LWS */
- if(globus_l_gass_transfer_http_scan_star_lws(
- input+i,
- max_to_scan-i,
- &j))
- {
- return GLOBUS_TRUE; /* more to scan */
- }
- else if(j != 0)
- {
- i += j; /* scanned some LWS */
- }
- /* check for chunk-ext-value, either a token, or a quoted-string */
- if(globus_l_gass_transfer_http_scan_token(
- input + i,
- max_to_scan - i,
- &j))
- {
- return GLOBUS_TRUE; /* more to scan */
- }
- /* no token, try to scan quoted string */
- else if(j == 0 &&
- globus_l_gass_transfer_http_scan_quoted_string(
- input + i,
- max_to_scan - i,
- &j))
- {
- return GLOBUS_TRUE; /* more to scan */
- }
- else
- {
- i += j;
- }
- }
- }
- /* globus_l_gass_transfer_http_scan_chunk_ext() */
- static
- globus_bool_t
- globus_l_gass_transfer_http_scan_chunk_size(
- globus_byte_t * input,
- globus_size_t max_to_scan,
- globus_size_t * end_of_chunk_size)
- {
- globus_size_t i;
- /*
- * hex-no-zero = <HEX excluding "0">
- * chunk-size = hex-no-zero *HEX
- */
- *end_of_chunk_size = 0;
- i = 0;
- if(i >= max_to_scan)
- {
- return GLOBUS_TRUE;
- }
- if(input[i] == '0' &&
- i + 1 < max_to_scan)
- {
- *end_of_chunk_size = 1;
- return GLOBUS_FALSE;
- }
- for(; i < max_to_scan; i++)
- {
- if(input[i] == ' ' ||
- input[i] == '\t')
- {
- continue;
- }
- if(!ishex(input[i]))
- {
- *end_of_chunk_size = i;
- return GLOBUS_FALSE;
- }
- }
- return GLOBUS_TRUE;
- }
- /* globus_l_gass_transfer_http_scan_chunk_size() */
- /*
- * Function: globus_l_gass_transfer_http_handle_chunk()
- *
- * Description: Parse any chunk header/footer information, and
- * copy chunk data (with appropriate text-mode
- * translations) into the user's buffers
- *
- * Parameters:
- *
- * Returns:
- */
- static
- globus_bool_t
- globus_l_gass_transfer_http_handle_chunk(
- globus_gass_transfer_http_request_proto_t * proto)
- {
- globus_size_t i;
- if ( proto->response_offset - proto->parsed_offset == 0 )
- {
- if (!proto->eof_read )
- {
- return GLOBUS_TRUE;
- }
- else
- {
- switch(proto->recv_state)
- {
- case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_LENGTH:
- if (proto->length == proto->handled)
- {
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF;
- }
- else
- {
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
- }
- break;
- case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_EOF:
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF;
- break;
- default:
- proto->failure_occurred = GLOBUS_TRUE;
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
- break;
- }
- return GLOBUS_FALSE;
- }
- }
- while(proto->response_offset - proto->parsed_offset > 0)
- {
- switch(proto->recv_state)
- {
- case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_SIZE:
- if(globus_l_gass_transfer_http_scan_chunk_size(
- proto->response_buffer + proto->parsed_offset,
- proto->response_offset - proto->parsed_offset,
- &i))
- {
- /* true == need more data */
- return GLOBUS_TRUE;
- }
- else if(i == 0)
- {
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
- proto->failure_occurred =
- GLOBUS_TRUE;
- return GLOBUS_FALSE;
- }
- proto->chunk_left = strtoul((char *) proto->response_buffer +
- proto->parsed_offset,
- GLOBUS_NULL,
- 16);
- proto->parsed_offset += i;
- if(proto->chunk_left == 0)
- {
- /*
- * last chunk can not be followed by chunk-ext elements,
- * but may be followed by a set of footers
- */
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_FOOTER;
- break;
- }
- else
- {
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_EXT;
- }
- /* FALLSTHROUGH */
- case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_EXT:
- if(globus_l_gass_transfer_http_scan_chunk_ext(
- proto->response_buffer + proto->parsed_offset,
- proto->response_offset - proto->parsed_offset,
- &i))
- {
- /* true == need more data */
- return GLOBUS_TRUE;
- }
- else
- {
- proto->parsed_offset += i;
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_END_HEADER_CR;
- /* FALLSTHROUGH */
- }
- case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_END_HEADER_CR:
- if(proto->response_offset - proto->parsed_offset > 0)
- {
- if(proto->response_buffer[proto->parsed_offset] != CR)
- {
- proto->parse_error=GLOBUS_TRUE;
- proto->failure_occurred = GLOBUS_TRUE;
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
- return GLOBUS_FALSE;
- }
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_END_HEADER_LF;
- proto->parsed_offset++;
- }
- else
- {
- return GLOBUS_TRUE;
- }
- /* FALLSTHROUGH */
- case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_END_HEADER_LF:
- if(proto->response_offset - proto->parsed_offset > 0)
- {
- if(proto->response_buffer[proto->parsed_offset] != LF)
- {
- proto->parse_error=GLOBUS_TRUE;
- proto->failure_occurred=GLOBUS_TRUE;
- return GLOBUS_FALSE;
- }
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_BODY;
- proto->parsed_offset++;
- }
- else
- {
- return GLOBUS_TRUE;
- }
- /* FALLSTHROUGH */
- case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_BODY:
- if(proto->chunk_left == 0)
- {
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_END_BODY_CR;
- }
- else
- {
- break;
- }
- /* FALLSTHROUGH */
- case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_END_BODY_CR:
- if(proto->response_offset - proto->parsed_offset > 0)
- {
- if(proto->response_buffer[proto->parsed_offset] != CR)
- {
- proto->parse_error=GLOBUS_TRUE;
- proto->failure_occurred=GLOBUS_TRUE;
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
- return GLOBUS_FALSE;
- }
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_END_BODY_LF;
- proto->parsed_offset++;
- }
- else
- {
- return GLOBUS_TRUE;
- }
- /* FALLSTHROUGH */
- case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_END_BODY_LF:
- if(proto->response_offset - proto->parsed_offset > 0)
- {
- if(proto->response_buffer[proto->parsed_offset] != LF)
- {
- proto->parse_error=GLOBUS_TRUE;
- proto->failure_occurred=GLOBUS_TRUE;
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
- return GLOBUS_FALSE;
- }
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_SIZE;
- proto->parsed_offset++;
- break;
- }
- else
- {
- return GLOBUS_TRUE;
- }
- case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_FOOTER:
- if(globus_l_gass_transfer_http_parse_headers(proto))
- {
- /* need more data */
- return GLOBUS_TRUE;
- }
- else if(proto->parse_error)
- {
- proto->failure_occurred=GLOBUS_TRUE;
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
- return GLOBUS_FALSE;
- }
- else
- {
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF;
- return GLOBUS_FALSE;
- }
- case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_EOF:
- case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_LENGTH:
- break;
- case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR:
- case GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF:
- return GLOBUS_FALSE;
- }
- if(proto->recv_state ==
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_LENGTH ||
- proto->recv_state ==
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_EOF ||
- proto->recv_state ==
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_CHUNK_BODY)
- {
- if(proto->user_buflen > proto->user_offset &&
- proto->response_offset > proto->parsed_offset)
- {
- /* some room is in the user's buffer for new data */
- if(proto->text_mode)
- {
- globus_l_gass_transfer_unbuffer_text(proto);
- }
- else
- {
- globus_l_gass_transfer_unbuffer_binary(proto);
- }
- /* check to see if we've failed/completed because of this */
- if(proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_LENGTH &&
- proto->length == proto->handled)
- {
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF;
- }
- else if(proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_LENGTH &&
- proto->eof_read &&
- proto->response_offset - proto->parsed_offset == 0)
- {
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_ERROR;
- }
- else if(proto->recv_state == GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_UNTIL_EOF &&
- proto->eof_read &&
- proto->response_offset - proto->parsed_offset == 0)
- {
- proto->recv_state =
- GLOBUS_GASS_TRANSFER_HTTP_RECV_STATE_EOF;
- }
- }
- else
- {
- return GLOBUS_FALSE;
- }
- }
- }
- return GLOBUS_FALSE;
- }
- /* globus_l_gass_transfer_http_handle_chunk() */
- static
- void
- globus_l_gass_transfer_http_extract_referral(
- globus_gass_transfer_http_request_proto_t * proto,
- char *** referral,
- globus_size_t * referral_count)
- {
- char * location;
- char * p;
- location = globus_i_gass_transfer_keyvalue_lookup(
- &proto->headers,
- "location");
- if(location == GLOBUS_NULL)
- {
- *referral = GLOBUS_NULL;
- *referral_count = 0;
- }
- else
- {
- p = location;
- for(p=location; *p != '\0'; p++)
- {
- if(!isspace(*p))
- {
- break;
- }
- }
- *referral = (char **) globus_malloc(sizeof(char *));
- (*referral)[0] = globus_libc_strdup(p);
- *referral_count = 1;
- }
- return;
- }
- /* globus_l_gass_transfer_http_extract_referral() */
- static
- void
- globus_l_gass_transfer_http_accept_failed_kickout(
- void * arg)
- {
- globus_l_gass_transfer_failed_kickout_closure_t *
- closure;
- closure = (globus_l_gass_transfer_failed_kickout_closure_t *) arg;
- globus_gass_transfer_proto_new_listener_request(
- closure->l_proto->listener,
- closure->request,
- GLOBUS_NULL);
- globus_libc_free(closure);
- }
- #if !defined(GLOBUS_GASS_TRANSFER_HTTP_PARSER_TEST)
- static
- void
- globus_l_gass_transfer_http_callback_denied(
- void * arg)
- {
- globus_gass_transfer_request_t request;
- request = (globus_gass_transfer_request_t) arg;
-
- debug_printf(2, (_GTSL("calling globus_gass_transfer_proto_request_denied")));
- globus_gass_transfer_proto_request_denied(
- request,
- GLOBUS_L_DEFAULT_FAILURE_CODE,
- globus_libc_strdup(GLOBUS_L_DEFAULT_FAILURE_REASON));
- }
- #endif /* !GLOBUS_GASS_TRANSFER_HTTP_PARSER_TEST */
- #endif /* GLOBUS_DONT_DOCUMENT_INTERNAL */