/**
 * Modify the state of an HTTP attribute
 * @ingroup globus_i_xio_http_attr
 *
 * Modify the state of an attribute. This is called by the XIO driver via
 * globus_xio_attr_cntl().
 *
 * @param driver_attr
 *     Void pointer to a #globus_i_xio_http_attr_t structure containing
 *     the attribute's values.
 * @param cmd
 *     Integer value indicating which attribute will be changed. Valid
 *     commands values are in the set defined by  #globus_xio_http_attr_cmd_t
 * @param ap
 *     Variable-length argument list containing any cmd-specific parameters.
 *
 * @retval GLOBUS_SUCCESS
 *     Attribute successfully modified.
 * @retval GLOBUS_XIO_ERROR_MEMORY
 *     Attribute control failed due to memory constraints.
 * @retval GLOBUS_XIO_ERROR_PARAMETER
 *     Invalid @a cmd parameter or invalid value for cmd-specific parameters
 *     in @a ap.
 */
globus_result_t
globus_i_xio_http_attr_cntl(
    void *                              driver_attr,
    int                                 cmd,
    va_list                             ap)
{
    globus_result_t                     res = GLOBUS_SUCCESS;
    globus_i_xio_http_attr_t *          attr = driver_attr;
    char *                              in_string;
    char *                              save_string;
    globus_xio_http_version_t           in_http_version;
    char *                              in_header_name;
    char *                              in_header_value;
    char **                             out_method;
    char **                             out_uri;
    globus_xio_http_version_t *         out_http_version;
    globus_hashtable_t *                out_headers;
    int *                               out_status_code;
    char **                             out_reason_phrase;

    GlobusXIOName(globus_i_xio_http_attr_cntl);

    switch (cmd)
    {
        case GLOBUS_XIO_HTTP_ATTR_SET_REQUEST_METHOD:
            save_string = attr->request.method;

            in_string = va_arg(ap, char *);

            if (in_string == NULL)
            {
                res = GlobusXIOErrorParameter("method");
                break;
            }

            attr->request.method = globus_libc_strdup(in_string);
            if (attr->request.method == NULL)
            {
                attr->request.method = save_string;
                res = GlobusXIOErrorMemory("method");
                break;
            }

            if (save_string != NULL)
            {
                globus_libc_free(save_string);
            }
            break;

        case GLOBUS_XIO_HTTP_ATTR_SET_REQUEST_HTTP_VERSION:
            in_http_version = va_arg(ap, globus_xio_http_version_t);

            if (in_http_version != GLOBUS_XIO_HTTP_VERSION_1_0 &&
                    in_http_version != GLOBUS_XIO_HTTP_VERSION_1_1)
            {
                res = GlobusXIOErrorParameter("version");
                break;
            }
            attr->request.http_version = in_http_version;
            break;

        case GLOBUS_XIO_HTTP_ATTR_SET_REQUEST_HEADER:
            in_header_name = va_arg(ap, char *);
            if (in_header_name == NULL)
            {
                res = GlobusXIOErrorParameter("name");
                break;
            }

            in_header_value = va_arg(ap, char *);
            if (in_header_value == NULL)
            {
                res = GlobusXIOErrorParameter("value");
                break;
            }

            res = globus_i_xio_http_header_info_set_header(
                    &attr->request.headers,
                    in_header_name,
                    in_header_value,
                    GLOBUS_FALSE);
            break;

        case GLOBUS_XIO_HTTP_ATTR_DELAY_WRITE_HEADER:
            attr->delay_write_header = 1;
            break;

        case GLOBUS_XIO_HTTP_GET_REQUEST:
            out_method = va_arg(ap, char **);
            out_uri = va_arg(ap, char **);
            out_http_version = va_arg(ap, globus_xio_http_version_t *);
            out_headers = va_arg(ap, globus_hashtable_t *);

            if (out_method != NULL)
            {
                *out_method = attr->request.method;
            }
            if (out_uri != NULL)
            {
                *out_uri = attr->request.uri;
            }
            if (out_http_version != NULL)
            {
                *out_http_version = attr->request.http_version;
            }
            if (out_headers != NULL)
            {
                *out_headers = attr->request.headers.headers;
            }
            break;
        case GLOBUS_XIO_HTTP_GET_RESPONSE:
            out_status_code = va_arg(ap, int *);
            out_reason_phrase = va_arg(ap, char **);
            out_http_version = va_arg(ap, globus_xio_http_version_t *);
            out_headers = va_arg(ap, globus_hashtable_t *);

            if (out_status_code != NULL)
            {
                *out_status_code = attr->response.status_code;
            }
            if (out_reason_phrase != NULL)
            {
                *out_reason_phrase = attr->response.reason_phrase;
            }
            if (out_http_version != NULL)
            {
                *out_http_version = attr->response.http_version;
            }
            if (out_headers != NULL)
            {
                *out_headers = attr->response.headers.headers;
            }
            break;
        default:
            res = GlobusXIOErrorParameter("cmd");
    }

    return res;
}
/**
 * Modify the state of an HTTP handle
 * @ingroup globus_i_xio_http_handle
 *
 * Modify the state of an HTTP handle. This is called by the XIO driver via
 * globus_xio_handle_cntl().
 *
 * @param handle
 *     Void pointer to a #globus_i_xio_http_handle_t structure containing
 *     information an HTTP request/response transaction.
 * @param cmd
 *     Integer value indicating what command will be executed on the handle.
 *     Valid command values are in the set defined by
 *     #globus_xio_http_handle_cmd_t.
 * @param ap
 *     Variable-length argument list containing any cmd-specific parameters.
 *
 * @retval GLOBUS_SUCCESS
 *     The command was sucessfully executed.
 * @retval GLOBUS_XIO_ERROR_MEMORY
 *     The command failed due to memory constraints.
 * @retval GLOBUS_XIO_ERROR_PARAMETER
 *     Invalid @a cmd parameter or invlaid value of cmd-specific parameters 
 *     in @a ap
 */
globus_result_t
globus_i_xio_http_handle_cntl(
    void *                              handle,
    int                                 cmd,
    va_list                             ap)
{
    char *                              in_header_name;
    char *                              in_header_value;
    globus_result_t                     result = GLOBUS_SUCCESS;
    globus_i_xio_http_handle_t *        http_handle = handle;
    char *                              in_str;
    char *                              in_str2;
    char *                              save_str;
    int                                 in_int;
    GlobusXIOName(globus_i_xio_http_handle_cntl);

    globus_mutex_lock(&http_handle->mutex);

    switch (cmd)
    {
        case GLOBUS_XIO_HTTP_HANDLE_SET_RESPONSE_HEADER:
            if (http_handle->target_info.is_client)
            {
                result = GlobusXIOErrorParameter("handle");
                break;
            }

            if (http_handle->send_state != GLOBUS_XIO_HTTP_STATUS_LINE)
            {
                result = GlobusXIOErrorParameter("handle");
                break;
            }
            in_str = va_arg(ap, char *);
            in_str2 = va_arg(ap, char *);

            result = globus_i_xio_http_header_info_set_header(
                    &http_handle->response_info.headers,
                    in_str,
                    in_str2);

            break;

        case GLOBUS_XIO_HTTP_HANDLE_SET_RESPONSE_STATUS_CODE:
            if (http_handle->target_info.is_client)
            {
                result = GlobusXIOErrorParameter("handle");
                break;
            }

            if (http_handle->send_state != GLOBUS_XIO_HTTP_STATUS_LINE)
            {
                result = GlobusXIOErrorParameter("handle");
                break;
            }
            in_int = va_arg(ap, int);

            if (in_int < 100 || in_int > 599)
            {
                result = GlobusXIOErrorParameter("status_code");
                break;
            }

            http_handle->response_info.status_code = in_int;

            break;

        case GLOBUS_XIO_HTTP_HANDLE_SET_RESPONSE_REASON_PHRASE:
            if (http_handle->target_info.is_client)
            {
                result = GlobusXIOErrorParameter("handle");
                break;
            }

            if (http_handle->send_state != GLOBUS_XIO_HTTP_STATUS_LINE)
            {
                result = GlobusXIOErrorParameter("handle");
                break;
            }
            in_str = va_arg(ap, char *);

            if (in_str == NULL)
            {
                result = GlobusXIOErrorParameter("reason_phrase");
            }
            save_str = http_handle->response_info.reason_phrase;

            http_handle->response_info.reason_phrase =
                    globus_libc_strdup(in_str);

            if (http_handle->response_info.reason_phrase == NULL)
            {
                result = GlobusXIOErrorMemory("reason_phrase");
                break;
            }

            if (save_str)
            {
                globus_libc_free(save_str);
            }
            break;
        case GLOBUS_XIO_HTTP_HANDLE_SET_RESPONSE_HTTP_VERSION:
            if (http_handle->target_info.is_client)
            {
                result = GlobusXIOErrorParameter("handle");
                break;
            }

            if (http_handle->send_state != GLOBUS_XIO_HTTP_STATUS_LINE)
            {
                result = GlobusXIOErrorParameter("handle");
                break;
            }

            http_handle->response_info.http_version =
                    va_arg(ap, globus_xio_http_version_t);
            break;
        case GLOBUS_XIO_HTTP_HANDLE_SET_END_OF_ENTITY:
            result = globus_i_xio_http_set_end_of_entity(http_handle);

            break;

        case GLOBUS_XIO_HTTP_HANDLE_SET_REQUEST_HEADER:
            in_header_name = va_arg(ap, char *);
            if (in_header_name == NULL)
            {
                result = GlobusXIOErrorParameter("name");
                break;
            }

            in_header_value = va_arg(ap, char *);
            if (in_header_value == NULL)
            {
                result = GlobusXIOErrorParameter("value");
                break;
            }

            result = globus_i_xio_http_header_info_set_header(
                    &http_handle->request_info.headers,
                    in_header_name,
                    in_header_value);
            break;

        default:
            result = GlobusXIOErrorParameter("cmd");
            break;
    }
    globus_mutex_unlock(&http_handle->mutex);
    return result;
}