/** Copy an HTTP attribute * @ingroup globus_i_xio_http_attr * * Copies all values associated with the @a src http attribute to * a newly allocated attribute in @a dst. If this function returns a * failure, then the @a dst should be considered uninitiailized. This is * called by the XIO driver via globus_xio_attr_copy(). * * @param dst * Void ** which will be set to point to a newly allocated attribute * with equivalent values to those in @a src. * @param src * Void * pointing to a #globus_i_xio_http_attr_t which contains the * attributes we want to copy. * * @return * This function returns GLOBUS_SUCCESS or GLOBUS_XIO_ERROR_MEMORY itself. * Other errors generated by globus_i_xio_http_request_copy() may be * returned as well. * * @retval GLOBUS_SUCCESS * Attribute successfully copied. * @retval GLOBUS_XIO_ERROR_MEMORY * Attribute copy failed due to memory constraints. */ globus_result_t globus_i_xio_http_attr_copy( void ** dst, void * src) { globus_result_t result; globus_i_xio_http_attr_t * http_dst; globus_i_xio_http_attr_t * http_src = src; GlobusXIOName(globus_i_xio_http_attr_copy); /* * Don't use globus_i_xio_http_request_init() here or the call to * globus_i_xio_http_request_copy() below will leak. */ http_dst = globus_libc_malloc(sizeof(globus_i_xio_http_attr_t)); if (http_dst == NULL) { result = GlobusXIOErrorMemory(dst); goto error_exit; } /* Copy request attrs */ result = globus_i_xio_http_request_copy( &http_dst->request, &http_src->request); if (result != GLOBUS_SUCCESS) { goto free_http_dst_exit; } /* Copy response attrs */ result = globus_i_xio_http_response_copy( &http_dst->response, &http_src->response); if (result != GLOBUS_SUCCESS) { goto free_http_dst_request_exit; } http_dst->delay_write_header = http_src->delay_write_header; *dst = http_dst; return GLOBUS_SUCCESS; free_http_dst_request_exit: globus_i_xio_http_request_destroy(&http_dst->request); free_http_dst_exit: globus_libc_free(http_dst); error_exit: return result; }
/** * Allocate and initialize an HTTP handle * @ingroup globus_i_xio_http_handle * * Creates a new handle with values derived from the attr and target. This * is called internally by the HTTP driver's open implementation. * * @param http_handle * Pointer to an uninitialized handle. * @param attr * HTTP attributes associated with open operation. * @param target * Target which is being opened. * * This function may return GLOBUS_SUCCESS, or an error generated by * globus_i_xio_http_response_init(), globus_i_xio_http_request_copy(), * or globus_i_xio_http_target_copy(). */ globus_result_t globus_i_xio_http_handle_init( globus_i_xio_http_handle_t * http_handle, globus_i_xio_http_attr_t * attr, globus_i_xio_http_target_t * target) { globus_result_t result; int rc; GlobusXIOName(globus_i_xio_http_handle_init); rc = globus_mutex_init(&http_handle->mutex, NULL); if (rc != 0) { result = GlobusXIOErrorMemory("mutex"); goto error_exit; } if (target->is_client && attr != NULL) { result = globus_i_xio_http_request_copy( &http_handle->request_info, &attr->request); } else { result = globus_i_xio_http_request_init(&http_handle->request_info); } if (target->is_client) { http_handle->parse_state = GLOBUS_XIO_HTTP_STATUS_LINE; http_handle->send_state = GLOBUS_XIO_HTTP_PRE_REQUEST_LINE; } else { http_handle->parse_state = GLOBUS_XIO_HTTP_PRE_REQUEST_LINE; http_handle->send_state = GLOBUS_XIO_HTTP_STATUS_LINE; } if (result != GLOBUS_SUCCESS) { goto free_mutex_exit; } result = globus_i_xio_http_response_init(&http_handle->response_info); if (result != GLOBUS_SUCCESS) { goto free_request_exit; } result = globus_i_xio_http_target_copy(&http_handle->target_info, target); if (result != GLOBUS_SUCCESS) { goto free_response_exit; } http_handle->header_iovec = NULL; http_handle->header_iovcnt = 0; http_handle->read_buffer.iov_base = NULL; http_handle->read_buffer.iov_len = 0; http_handle->close_operation = NULL; http_handle->response_read_operation = NULL; http_handle->read_operation.iov = NULL; http_handle->read_operation.iovcnt = 0; http_handle->read_operation.operation = NULL; http_handle->read_operation.driver_handle = NULL; http_handle->read_operation.nbytes = 0; http_handle->write_operation.iov = NULL; http_handle->write_operation.iovcnt = 0; http_handle->write_operation.operation = NULL; http_handle->write_operation.driver_handle = NULL; http_handle->write_operation.nbytes = 0; http_handle->user_close = GLOBUS_FALSE; http_handle->read_response = GLOBUS_FALSE; return GLOBUS_SUCCESS; free_response_exit: globus_i_xio_http_response_destroy(&http_handle->response_info); free_request_exit: globus_i_xio_http_request_destroy(&http_handle->request_info); free_mutex_exit: globus_mutex_destroy(&http_handle->mutex); error_exit: return result; }
void globus_i_xio_http_server_read_request_callback( globus_xio_operation_t op, globus_result_t result, globus_size_t nbytes, void * user_arg) { globus_i_xio_http_handle_t * http_handle = user_arg; globus_bool_t done; globus_result_t eof_result = GLOBUS_SUCCESS; globus_i_xio_http_attr_t * descriptor; globus_bool_t registered_again = GLOBUS_FALSE; GlobusXIOName(globus_i_xio_http_server_read_request_callback); globus_mutex_lock(&http_handle->mutex); if (result != GLOBUS_SUCCESS) { if (globus_xio_error_is_eof(result)) { eof_result = result; } else { goto error_exit; } } /* Haven't parsed request and headers yet */ http_handle->read_buffer_valid += nbytes; result = globus_l_xio_http_server_parse_request(http_handle, &done); if (result == GLOBUS_SUCCESS && !done) { goto reregister_read; } else if (result != GLOBUS_SUCCESS) { goto error_exit; } /* Determine whether we should expect an entity along with the * request */ if ((http_handle->request_info.http_version == GLOBUS_XIO_HTTP_VERSION_1_1) && (http_handle->request_info.headers.transfer_encoding == GLOBUS_XIO_HTTP_TRANSFER_ENCODING_CHUNKED)) { http_handle->parse_state = GLOBUS_XIO_HTTP_CHUNK_LINE; } else if (GLOBUS_I_XIO_HTTP_HEADER_IS_CONTENT_LENGTH_SET( &http_handle->request_info.headers)) { http_handle->parse_state = GLOBUS_XIO_HTTP_IDENTITY_BODY; } if (GLOBUS_I_XIO_HTTP_HEADER_IS_CONNECTION_CLOSE( &http_handle->request_info.headers)) { http_handle->response_info.headers.flags |= GLOBUS_I_XIO_HTTP_HEADER_CONNECTION_CLOSE; } http_handle->send_state = GLOBUS_XIO_HTTP_STATUS_LINE; descriptor = globus_xio_operation_get_data_descriptor(op, GLOBUS_TRUE); if (descriptor == NULL) { result = GlobusXIOErrorMemory("descriptor"); goto error_exit; } globus_i_xio_http_request_destroy(&descriptor->request); result = globus_i_xio_http_request_copy( &descriptor->request, &http_handle->request_info); if (result != GLOBUS_SUCCESS) { goto error_exit; } result = globus_i_xio_http_parse_residue(http_handle, ®istered_again); if ((http_handle->read_operation.wait_for <= 0 && !registered_again) || result != GLOBUS_SUCCESS) { if (http_handle->response_info.headers.transfer_encoding != GLOBUS_XIO_HTTP_TRANSFER_ENCODING_CHUNKED && GLOBUS_I_XIO_HTTP_HEADER_IS_CONTENT_LENGTH_SET( &http_handle->response_info.headers) && http_handle->response_info.headers.content_length == 0) { /* Synthesize EOF if we've read all of the entity content */ result = GlobusXIOErrorEOF(); } /* * Either we've read enough, hit end of chunk, no entity was present, * or pass to transport failed. Call finished_read */ nbytes = http_handle->read_operation.nbytes; globus_libc_free(http_handle->read_operation.iov); http_handle->read_operation.iov = NULL; http_handle->read_operation.iovcnt = 0; http_handle->read_operation.operation = NULL; http_handle->read_operation.driver_handle = NULL; http_handle->read_operation.nbytes = 0; globus_mutex_unlock(&http_handle->mutex); globus_xio_driver_finished_read(op, result, nbytes); return; } else if (registered_again) { globus_mutex_unlock(&http_handle->mutex); return; } /* FALLSTHROUGH */ reregister_read: globus_assert(op == http_handle->read_operation.operation); if (eof_result != GLOBUS_SUCCESS) { /* Header block wasn't complete before eof */ result = eof_result; goto error_exit; } result = globus_i_xio_http_clean_read_buffer(http_handle); if (result != GLOBUS_SUCCESS) { goto error_exit; } result = globus_xio_driver_pass_read( op, &http_handle->read_iovec, 1, 1, globus_i_xio_http_server_read_request_callback, http_handle); if (result != GLOBUS_SUCCESS) { goto error_exit; } globus_mutex_unlock(&http_handle->mutex); return; error_exit: globus_libc_free(http_handle->read_operation.iov); http_handle->read_operation.iov = NULL; http_handle->read_operation.iovcnt = 0; http_handle->read_operation.operation = NULL; http_handle->read_operation.driver_handle = NULL; http_handle->read_operation.nbytes = 0; globus_mutex_unlock(&http_handle->mutex); globus_xio_driver_finished_read(op, result, 0); }
globus_result_t globus_i_xio_http_handle_reinit( globus_i_xio_http_handle_t * http_handle, globus_i_xio_http_attr_t * http_attr, globus_i_xio_http_target_t * http_target) { globus_result_t result; GlobusXIOName(globus_i_xio_http_handle_reinit); if (http_target && http_target->is_client && http_attr != NULL) { globus_i_xio_http_request_destroy(&http_handle->request_info); result = globus_i_xio_http_request_copy( &http_handle->request_info, &http_attr->request); } else { globus_i_xio_http_request_destroy(&http_handle->request_info); result = globus_i_xio_http_request_init(&http_handle->request_info); } if (http_target && http_target->is_client) { http_handle->send_state = GLOBUS_XIO_HTTP_PRE_REQUEST_LINE; } else { http_handle->send_state = GLOBUS_XIO_HTTP_STATUS_LINE; } if (result != GLOBUS_SUCCESS) { goto free_mutex_exit; } globus_i_xio_http_response_destroy(&http_handle->response_info); result = globus_i_xio_http_response_init(&http_handle->response_info); if (result != GLOBUS_SUCCESS) { goto free_request_exit; } globus_i_xio_http_target_destroy_internal(&http_handle->target_info); if (http_target) { result = globus_i_xio_http_target_copy( &http_handle->target_info, http_target); if (result != GLOBUS_SUCCESS) { goto free_response_exit; } } http_handle->header_iovec = NULL; http_handle->header_iovcnt = 0; http_handle->close_operation = NULL; http_handle->read_operation.iov = NULL; http_handle->read_operation.iovcnt = 0; http_handle->read_operation.operation = NULL; http_handle->read_operation.driver_handle = NULL; http_handle->read_operation.nbytes = 0; http_handle->write_operation.iov = NULL; http_handle->write_operation.iovcnt = 0; http_handle->write_operation.operation = NULL; http_handle->write_operation.driver_handle = NULL; http_handle->write_operation.nbytes = 0; http_handle->user_close = GLOBUS_FALSE; http_handle->read_response = GLOBUS_FALSE; return GLOBUS_SUCCESS; free_response_exit: globus_i_xio_http_response_destroy(&http_handle->response_info); free_request_exit: globus_i_xio_http_request_destroy(&http_handle->request_info); free_mutex_exit: globus_mutex_destroy(&http_handle->mutex); return result; }