2010-04-19 00:26:24 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2009 Mamadou Diop.
|
|
|
|
*
|
|
|
|
* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
|
|
|
|
*
|
|
|
|
* This file is part of Open Source Doubango Framework.
|
|
|
|
*
|
|
|
|
* DOUBANGO is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* DOUBANGO is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with DOUBANGO.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**@file thttp_dialog.c
|
|
|
|
* @brief HTTP Dialog.
|
|
|
|
*
|
|
|
|
* @author Mamadou Diop <diopmamadou(at)doubango.org>
|
|
|
|
*
|
|
|
|
* @date Created: Sat Nov 8 16:54:58 2009 mdiop
|
|
|
|
*/
|
2010-05-04 11:55:25 +00:00
|
|
|
#include "tinyhttp/thttp_dialog.h"
|
2010-04-19 00:26:24 +00:00
|
|
|
|
|
|
|
#include "thttp.h"
|
|
|
|
|
2010-05-04 11:55:25 +00:00
|
|
|
#include "tinyhttp/thttp_action.h"
|
|
|
|
#include "tinyhttp/thttp_session.h"
|
|
|
|
#include "tinyhttp/thttp_url.h"
|
|
|
|
#include "tinyhttp/parsers/thttp_parser_url.h"
|
2010-04-19 00:26:24 +00:00
|
|
|
|
2010-05-04 11:55:25 +00:00
|
|
|
#include "tinyhttp/headers/thttp_header_Dummy.h"
|
2010-04-19 00:26:24 +00:00
|
|
|
|
|
|
|
#include "tnet_utils.h"
|
|
|
|
|
|
|
|
#include "tsk_debug.h"
|
|
|
|
|
|
|
|
#define DEBUG_STATE_MACHINE 1
|
2010-04-06 00:57:03 +00:00
|
|
|
#define THTTP_MESSAGE_DESCRIPTION(message) \
|
2010-04-19 00:26:24 +00:00
|
|
|
THTTP_MESSAGE_IS_RESPONSE(message) ? THTTP_RESPONSE_PHRASE(message) : THTTP_REQUEST_METHOD(message)
|
2010-05-26 10:44:08 +00:00
|
|
|
#define THTTP_DIALOG_TRANSPORT_ERROR_CODE -0xFF
|
2010-04-19 00:26:24 +00:00
|
|
|
|
|
|
|
/* ======================== internal functions ======================== */
|
|
|
|
int thttp_dialog_send_request(thttp_dialog_t *self);
|
|
|
|
int thttp_dialog_update_timestamp(thttp_dialog_t *self);
|
|
|
|
int thttp_dialog_OnTerminated(thttp_dialog_t *self);
|
|
|
|
|
2010-04-06 00:57:03 +00:00
|
|
|
///* ======================== external functions ======================== */
|
2010-04-19 00:26:24 +00:00
|
|
|
extern int thttp_stack_alert(const thttp_stack_t *self, const thttp_event_t* e);
|
|
|
|
|
2010-04-06 00:57:03 +00:00
|
|
|
/* ======================== transitions ======================== */
|
|
|
|
int thttp_dialog_Started_2_Transfering_X_request(va_list *app);
|
|
|
|
int thttp_dialog_Transfering_2_Transfering_X_401_407(va_list *app);
|
2010-04-06 16:28:35 +00:00
|
|
|
int thttp_dialog_Transfering_2_Transfering_X_1xx(va_list *app);
|
2010-04-06 00:57:03 +00:00
|
|
|
int thttp_dialog_Transfering_2_Terminated_X_message(va_list *app); /* Any other HTTP message except 401/407 */
|
|
|
|
int thttp_dialog_Any_2_Terminated_X_closed(va_list *app);
|
|
|
|
int thttp_dialog_Any_2_Terminated_X_Error(va_list *app);
|
|
|
|
|
|
|
|
/* ======================== conds ======================== */
|
2010-04-19 00:26:24 +00:00
|
|
|
tsk_bool_t _fsm_cond_i_401_407(thttp_dialog_t* self, thttp_message_t* message)
|
|
|
|
{
|
|
|
|
return (THTTP_RESPONSE_CODE(message) == 401 || THTTP_RESPONSE_CODE(message) == 407);
|
2010-04-06 00:57:03 +00:00
|
|
|
}
|
2010-04-19 00:26:24 +00:00
|
|
|
tsk_bool_t _fsm_cond_i_1xx(thttp_dialog_t* self, thttp_message_t* message)
|
|
|
|
{
|
|
|
|
return THTTP_RESPONSE_IS_1XX(message);
|
2010-04-06 00:57:03 +00:00
|
|
|
}
|
|
|
|
/* ======================== actions ======================== */
|
|
|
|
typedef enum _fsm_action_e
|
|
|
|
{
|
|
|
|
_fsm_action_request = atype_o_request,
|
|
|
|
_fsm_action_close = atype_close,
|
|
|
|
_fsm_action_message = atype_i_message,
|
|
|
|
_fsm_action_closed = atype_closed,
|
2010-05-26 10:44:08 +00:00
|
|
|
_fsm_action_error = atype_error, // Transport error and not HTTP message error (e.g. 409)
|
2010-04-06 00:57:03 +00:00
|
|
|
|
2010-05-26 10:44:08 +00:00
|
|
|
/* _fsm_action_any_other = 0xFF */
|
2010-04-06 00:57:03 +00:00
|
|
|
}
|
|
|
|
_fsm_action_t;
|
|
|
|
|
|
|
|
/* ======================== states ======================== */
|
|
|
|
typedef enum _fsm_state_e
|
|
|
|
{
|
|
|
|
_fsm_state_Started,
|
|
|
|
_fsm_state_Transfering,
|
|
|
|
_fsm_state_Terminated
|
|
|
|
}
|
2010-04-19 00:26:24 +00:00
|
|
|
_fsm_state_t;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-04-22 23:35:29 +00:00
|
|
|
thttp_dialog_t* thttp_dialog_create(struct thttp_session_s* session)
|
|
|
|
{
|
|
|
|
return tsk_object_new(thttp_dialog_def_t, session);
|
|
|
|
}
|
2010-04-19 00:26:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------
|
|
|
|
// == STATE MACHINE BEGIN ==
|
|
|
|
//--------------------------------------------------------
|
|
|
|
|
|
|
|
/* Started -> (request) -> Transfering */
|
2010-04-06 00:57:03 +00:00
|
|
|
int thttp_dialog_Started_2_Transfering_X_request(va_list *app)
|
|
|
|
{
|
2010-04-19 00:26:24 +00:00
|
|
|
thttp_dialog_t *self;
|
|
|
|
const thttp_action_t* action;
|
|
|
|
|
|
|
|
self = va_arg(*app, thttp_dialog_t *);
|
|
|
|
va_arg(*app, const thttp_message_t *);
|
|
|
|
action = va_arg(*app, const thttp_action_t *);
|
|
|
|
|
|
|
|
if(!self->action){
|
|
|
|
self->action = tsk_object_ref((void*)action);
|
|
|
|
}
|
|
|
|
|
2010-04-06 00:57:03 +00:00
|
|
|
return thttp_dialog_send_request(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Transfering -> (401/407) -> Transfering */
|
|
|
|
int thttp_dialog_Transfering_2_Transfering_X_401_407(va_list *app)
|
|
|
|
{
|
|
|
|
int ret;
|
2010-04-19 00:26:24 +00:00
|
|
|
thttp_dialog_t *self;
|
2010-04-06 00:57:03 +00:00
|
|
|
const thttp_response_t* response;
|
|
|
|
|
|
|
|
self = va_arg(*app, thttp_dialog_t*);
|
|
|
|
response = va_arg(*app, const thttp_response_t *);
|
|
|
|
// will use the current action parameters
|
|
|
|
|
2010-04-09 20:17:10 +00:00
|
|
|
if((ret = thttp_session_update_challenges(self->session, response, self->answered))){
|
2010-04-06 00:57:03 +00:00
|
|
|
thttp_event_t* e = tsk_null;
|
|
|
|
TSK_DEBUG_ERROR("HTTP authentication failed.");
|
|
|
|
|
2010-04-19 00:26:24 +00:00
|
|
|
if((e = thttp_event_create(thttp_event_auth_failed, self->session, "Authentication Failed.", tsk_null))){
|
2010-04-06 00:57:03 +00:00
|
|
|
thttp_stack_alert(self->session->stack, e);
|
|
|
|
TSK_OBJECT_SAFE_FREE(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-04-09 20:17:10 +00:00
|
|
|
self->answered = tsk_true;
|
2010-04-06 00:57:03 +00:00
|
|
|
|
|
|
|
/* Retry with creadentials. */
|
2010-05-26 10:44:08 +00:00
|
|
|
ret = thttp_dialog_send_request(self);
|
|
|
|
|
|
|
|
/* very important: do not break the state machine for transport error events
|
2010-05-26 15:31:50 +00:00
|
|
|
* => let the transport layer do it for us (throught tnet_transport_error event).
|
2010-05-26 10:44:08 +00:00
|
|
|
* => transport_error event will be queued and sent after this event (i_message)
|
|
|
|
*/
|
|
|
|
if(ret == THTTP_DIALOG_TRANSPORT_ERROR_CODE){
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
return ret;
|
|
|
|
}
|
2010-04-06 00:57:03 +00:00
|
|
|
}
|
|
|
|
|
2010-04-06 16:28:35 +00:00
|
|
|
/* Transfering -> (1xx) -> Transfering */
|
|
|
|
int thttp_dialog_Transfering_2_Transfering_X_1xx(va_list *app)
|
|
|
|
{
|
|
|
|
// reset timer?
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-04-06 00:57:03 +00:00
|
|
|
/* Transfering -> (message) -> Terminated */
|
|
|
|
int thttp_dialog_Transfering_2_Terminated_X_message(va_list *app)
|
|
|
|
{
|
|
|
|
thttp_dialog_t *self = va_arg(*app, thttp_dialog_t*);
|
|
|
|
const thttp_message_t *message = va_arg(*app, const thttp_message_t *);
|
|
|
|
thttp_event_t* e = tsk_null;
|
|
|
|
int ret = -2;
|
|
|
|
|
|
|
|
/* Alert the user. */
|
2010-04-19 00:26:24 +00:00
|
|
|
if((e = thttp_event_create(thttp_event_message, self->session, THTTP_MESSAGE_DESCRIPTION(message), message))){
|
2010-04-06 00:57:03 +00:00
|
|
|
ret = thttp_stack_alert(self->session->stack, e);
|
|
|
|
TSK_OBJECT_SAFE_FREE(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Any -> (closed) -> Terminated */
|
|
|
|
int thttp_dialog_Any_2_Terminated_X_closed(va_list *app)
|
|
|
|
{
|
|
|
|
int ret = -2;
|
|
|
|
thttp_dialog_t *self = va_arg(*app, thttp_dialog_t *);
|
2010-05-26 10:44:08 +00:00
|
|
|
thttp_event_t* e;
|
2010-04-06 00:57:03 +00:00
|
|
|
//self->fd = TNET_INVALID_FD; // to avoid close(fd) in the destructor
|
|
|
|
|
2010-05-26 10:44:08 +00:00
|
|
|
/* Alert the user */
|
2010-04-19 00:26:24 +00:00
|
|
|
if((e = thttp_event_create(thttp_event_closed, self->session, "Connection closed", tsk_null))){
|
2010-04-06 00:57:03 +00:00
|
|
|
ret = thttp_stack_alert(self->session->stack, e);
|
|
|
|
TSK_OBJECT_SAFE_FREE(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Any -> (error) -> Terminated */
|
|
|
|
int thttp_dialog_Any_2_Terminated_X_Error(va_list *app)
|
|
|
|
{
|
2010-05-26 10:44:08 +00:00
|
|
|
int ret = -2;
|
|
|
|
thttp_dialog_t *self = va_arg(*app, thttp_dialog_t *);
|
|
|
|
thttp_event_t* e;
|
|
|
|
|
|
|
|
/* Alert the user */
|
|
|
|
if((e = thttp_event_create(thttp_event_transport_error, self->session, "Transport error", tsk_null))){
|
|
|
|
ret = thttp_stack_alert(self->session->stack, e);
|
|
|
|
TSK_OBJECT_SAFE_FREE(e);
|
|
|
|
}
|
|
|
|
|
2010-04-06 00:57:03 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2010-04-19 00:26:24 +00:00
|
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
// == STATE MACHINE END ==
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
|
|
|
|
/** Execute action (moves the FSM).
|
|
|
|
*/
|
|
|
|
int thttp_dialog_fsm_act(thttp_dialog_t* self, tsk_fsm_action_id action_id, const thttp_message_t* message, const thttp_action_t* action)
|
|
|
|
{
|
|
|
|
if(!self || !self->fsm){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return tsk_fsm_act(self->fsm, action_id, self, message, self, message, action);
|
|
|
|
}
|
|
|
|
|
|
|
|
// create new dialog and add it to the stack's list of dialogs
|
|
|
|
// you must free the returned object
|
|
|
|
thttp_dialog_t* thttp_dialog_new(thttp_session_t* session)
|
|
|
|
{
|
|
|
|
thttp_dialog_t* ret = tsk_null;
|
|
|
|
thttp_dialog_t* dialog;
|
|
|
|
if(session && session->stack){
|
|
|
|
if((dialog = thttp_dialog_create(session))){
|
|
|
|
ret = tsk_object_ref(dialog);
|
|
|
|
tsk_list_push_back_data(session->dialogs, (void**)&dialog);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns the oldest dialog.
|
|
|
|
*/
|
|
|
|
thttp_dialog_t* thttp_dialog_get_oldest(thttp_dialogs_L_t* dialogs)
|
|
|
|
{
|
|
|
|
thttp_dialog_t* ret = tsk_null;
|
|
|
|
thttp_dialog_t* dialog = tsk_null;
|
|
|
|
const tsk_list_item_t *item;
|
|
|
|
if(dialogs){
|
|
|
|
tsk_list_foreach(item, dialogs){
|
|
|
|
if(!dialog || (dialog->timestamp >=((thttp_dialog_t*)item->data)->timestamp)){
|
|
|
|
dialog = (thttp_dialog_t*)item->data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret = tsk_object_ref(dialog);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Sends a request.
|
|
|
|
*/
|
|
|
|
int thttp_dialog_send_request(thttp_dialog_t *self)
|
|
|
|
{
|
2010-04-06 00:57:03 +00:00
|
|
|
int ret = -1;
|
2010-04-19 00:26:24 +00:00
|
|
|
const tsk_list_item_t* item;
|
|
|
|
thttp_request_t* request = tsk_null;
|
|
|
|
tsk_buffer_t* output = tsk_null;
|
|
|
|
thttp_url_t* url;
|
|
|
|
tnet_socket_type_t type;
|
|
|
|
|
|
|
|
if(!self || !self->session || !self->action){
|
|
|
|
return -1;
|
2010-04-06 00:57:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(!self->action->method || !self->action->url){
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
2010-04-22 23:35:29 +00:00
|
|
|
if((url = thttp_url_parse(self->action->url, tsk_strlen(self->action->url)))){
|
2010-04-19 00:26:24 +00:00
|
|
|
request = thttp_request_create(self->action->method, url);
|
2010-04-06 00:57:03 +00:00
|
|
|
TSK_OBJECT_SAFE_FREE(url);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
TSK_DEBUG_ERROR("%s is an invalid HTTP/HTTPS URL.", self->action->url);
|
|
|
|
ret = -3;
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ==Add headers associated to the session== */
|
|
|
|
tsk_list_foreach(item, self->session->headers){
|
|
|
|
THTTP_MESSAGE_ADD_HEADER(request, THTTP_HEADER_DUMMY_VA_ARGS(TSK_PARAM(item->data)->name, TSK_PARAM(item->data)->value));
|
|
|
|
}
|
|
|
|
|
2010-04-06 16:28:35 +00:00
|
|
|
/* ==Add headers and content associated to the action== */
|
2010-04-06 00:57:03 +00:00
|
|
|
if(self->action){
|
2010-04-06 16:28:35 +00:00
|
|
|
if(self->action->payload){
|
|
|
|
thttp_message_add_content(request, tsk_null, self->action->payload->data, self->action->payload->size);
|
|
|
|
}
|
2010-04-06 00:57:03 +00:00
|
|
|
tsk_list_foreach(item, self->action->headers){
|
|
|
|
THTTP_MESSAGE_ADD_HEADER(request, THTTP_HEADER_DUMMY_VA_ARGS(TSK_PARAM(item->data)->name, TSK_PARAM(item->data)->value));
|
|
|
|
}
|
2010-04-06 16:28:35 +00:00
|
|
|
}
|
2010-04-06 00:57:03 +00:00
|
|
|
|
|
|
|
/* ==Add creadentials== */
|
|
|
|
if(!TSK_LIST_IS_EMPTY(self->session->challenges))
|
|
|
|
{
|
|
|
|
thttp_challenge_t *challenge;
|
|
|
|
thttp_header_t* auth_hdr;
|
2010-04-09 20:17:10 +00:00
|
|
|
tsk_list_foreach(item, self->session->challenges){
|
2010-04-06 00:57:03 +00:00
|
|
|
challenge = item->data;
|
|
|
|
if((auth_hdr = thttp_challenge_create_header_authorization(challenge, self->session->cred.usename, self->session->cred.password, request))){
|
|
|
|
thttp_message_add_header(request, auth_hdr);
|
|
|
|
tsk_object_unref(auth_hdr), auth_hdr = tsk_null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ==Sends the request== */
|
2010-04-19 00:26:24 +00:00
|
|
|
output = tsk_buffer_create_null();
|
|
|
|
type = tnet_transport_get_type(self->session->stack->transport);
|
|
|
|
|
|
|
|
/* Serialize the message and send it */
|
|
|
|
if((ret = thttp_message_serialize(request, output))){
|
|
|
|
TSK_DEBUG_ERROR("Failed to serialize the HTTP request.");
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
else{
|
2010-05-25 10:10:15 +00:00
|
|
|
if(request->line.request.url->type == url_https){
|
2010-04-19 00:26:24 +00:00
|
|
|
TNET_SOCKET_TYPE_SET_TLS(type);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
TNET_SOCKET_TYPE_SET_TCP(type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* connect to the server not already done */
|
|
|
|
if(self->session->fd == TNET_INVALID_FD){
|
2010-05-25 10:10:15 +00:00
|
|
|
if((self->session->fd = tnet_transport_connectto(self->session->stack->transport, request->line.request.url->host, request->line.request.url->port, type)) == TNET_INVALID_FD){
|
|
|
|
TSK_DEBUG_ERROR("Failed to connect to %s:%d.", request->line.request.url->host, request->line.request.url->port);
|
2010-04-19 00:26:24 +00:00
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
/* Wait for the socket for writability */
|
|
|
|
if((ret = tnet_sockfd_waitUntilWritable(self->session->fd, TNET_CONNECT_TIMEOUT))){
|
|
|
|
TSK_DEBUG_ERROR("%d milliseconds elapsed and the socket is still not connected.", TNET_CONNECT_TIMEOUT);
|
|
|
|
if(tnet_transport_remove_socket(self->session->stack->transport, &self->session->fd)){
|
|
|
|
tnet_sockfd_close(&self->session->fd);
|
|
|
|
}
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(tnet_transport_send(self->session->stack->transport, self->session->fd, output->data, output->size)){
|
|
|
|
TSK_DEBUG_INFO("HTTP/HTTPS message successfully sent.");
|
|
|
|
thttp_dialog_update_timestamp(self);
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
TSK_DEBUG_INFO("Failed to sent HTTP/HTTPS message.");
|
2010-05-26 10:44:08 +00:00
|
|
|
ret = THTTP_DIALOG_TRANSPORT_ERROR_CODE;
|
2010-04-06 00:57:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bail:
|
|
|
|
TSK_OBJECT_SAFE_FREE(request);
|
|
|
|
TSK_OBJECT_SAFE_FREE(output);
|
|
|
|
|
2010-04-19 00:26:24 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Update timestamp (used to match requests with responses)
|
|
|
|
*/
|
|
|
|
int thttp_dialog_update_timestamp(thttp_dialog_t *self)
|
|
|
|
{
|
|
|
|
static uint64_t timestamp = 0;
|
|
|
|
if(self){
|
|
|
|
self->timestamp = timestamp++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Called by the FSM manager when the dialog enters in the terminal state.
|
|
|
|
*/
|
|
|
|
int thttp_dialog_OnTerminated(thttp_dialog_t *self)
|
|
|
|
{
|
|
|
|
TSK_DEBUG_INFO("=== HTTP/HTTPS Dialog terminated ===");
|
|
|
|
|
|
|
|
/* removes the dialog from the session */
|
|
|
|
if(self->session){
|
|
|
|
tsk_list_remove_item_by_data(self->session->dialogs, self);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-04-06 00:57:03 +00:00
|
|
|
//=================================================================================================
|
|
|
|
// HTTP Dialog object definition
|
|
|
|
//
|
2010-04-19 00:26:24 +00:00
|
|
|
static tsk_object_t* thttp_dialog_ctor(tsk_object_t * self, va_list * app)
|
2010-04-06 00:57:03 +00:00
|
|
|
{
|
|
|
|
thttp_dialog_t *dialog = self;
|
|
|
|
static thttp_dialog_id_t unique_id = 0;
|
|
|
|
if(dialog){
|
|
|
|
dialog->id = ++unique_id;
|
|
|
|
dialog->session = tsk_object_ref(va_arg(*app, thttp_session_t*));
|
|
|
|
|
2010-04-19 00:26:24 +00:00
|
|
|
dialog->buf = tsk_buffer_create_null();
|
2010-04-06 00:57:03 +00:00
|
|
|
|
|
|
|
/* create and init FSM */
|
2010-04-19 00:26:24 +00:00
|
|
|
dialog->fsm = tsk_fsm_create(_fsm_state_Started, _fsm_state_Terminated);
|
2010-04-06 00:57:03 +00:00
|
|
|
dialog->fsm->debug = DEBUG_STATE_MACHINE;
|
|
|
|
tsk_fsm_set_callback_terminated(dialog->fsm, TSK_FSM_ONTERMINATED_F(thttp_dialog_OnTerminated), dialog);
|
|
|
|
tsk_fsm_set(dialog->fsm,
|
|
|
|
|
|
|
|
/*=======================
|
|
|
|
* === Started ===
|
|
|
|
*/
|
|
|
|
// Started -> (request) -> Transfering
|
|
|
|
TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_request, _fsm_state_Transfering, thttp_dialog_Started_2_Transfering_X_request, "thttp_dialog_Started_2_Transfering_X_request"),
|
|
|
|
// Started -> (Any) -> Started
|
|
|
|
TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Started, "thttp_dialog_Started_2_Started_X_any"),
|
|
|
|
|
|
|
|
|
|
|
|
/*=======================
|
|
|
|
* === Transfering ===
|
|
|
|
*/
|
|
|
|
// Transfering -> (401/407) -> Transfering
|
|
|
|
TSK_FSM_ADD(_fsm_state_Transfering, _fsm_action_message, _fsm_cond_i_401_407, _fsm_state_Transfering, thttp_dialog_Transfering_2_Transfering_X_401_407, "thttp_dialog_Transfering_2_Transfering_X_401_407"),
|
2010-04-06 16:28:35 +00:00
|
|
|
// Transfering -> (1xx) -> Transfering
|
|
|
|
TSK_FSM_ADD(_fsm_state_Transfering, _fsm_action_message, _fsm_cond_i_1xx, _fsm_state_Transfering, thttp_dialog_Transfering_2_Transfering_X_1xx, "thttp_dialog_Transfering_2_Transfering_X_1xx"),
|
|
|
|
// Transfering -> (any other response) -> Terminated
|
|
|
|
TSK_FSM_ADD_ALWAYS(_fsm_state_Transfering, _fsm_action_message, _fsm_state_Terminated, thttp_dialog_Transfering_2_Terminated_X_message, "thttp_dialog_Transfering_2_Terminated_X_message"),
|
2010-04-06 00:57:03 +00:00
|
|
|
/*=======================
|
|
|
|
* === Any ===
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Any -> (closed) -> Terminated
|
|
|
|
TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_closed, _fsm_state_Terminated, thttp_dialog_Any_2_Terminated_X_closed, "thttp_dialog_Any_2_Terminated_X_closed"),
|
|
|
|
// Any -> (error) -> Terminated
|
|
|
|
TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_error, _fsm_state_Terminated, thttp_dialog_Any_2_Terminated_X_Error, "thttp_dialog_Any_2_Terminated_X_Error"),
|
|
|
|
|
|
|
|
TSK_FSM_ADD_NULL());
|
|
|
|
|
|
|
|
thttp_dialog_update_timestamp(self);
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2010-04-19 00:26:24 +00:00
|
|
|
static tsk_object_t* thttp_dialog_dtor(tsk_object_t * self)
|
2010-04-06 00:57:03 +00:00
|
|
|
{
|
|
|
|
thttp_dialog_t *dialog = self;
|
|
|
|
if(dialog){
|
|
|
|
TSK_DEBUG_INFO("*** HTTP/HTTPS Dialog destroyed ***");
|
|
|
|
|
2010-04-19 00:26:24 +00:00
|
|
|
TSK_OBJECT_SAFE_FREE(dialog->fsm);
|
|
|
|
|
|
|
|
TSK_OBJECT_SAFE_FREE(dialog->session);
|
2010-04-06 00:57:03 +00:00
|
|
|
TSK_OBJECT_SAFE_FREE(dialog->action);
|
|
|
|
|
|
|
|
TSK_OBJECT_SAFE_FREE(dialog->buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int thttp_dialog_cmp(const tsk_object_t *_d1, const tsk_object_t *_d2)
|
|
|
|
{
|
|
|
|
const thttp_dialog_t *d1 = _d1;
|
|
|
|
const thttp_dialog_t *d2 = _d2;
|
|
|
|
|
|
|
|
if(d1 && d2){
|
|
|
|
return (int)(d1->id-d2->id);
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const tsk_object_def_t thttp_dialog_def_s =
|
|
|
|
{
|
|
|
|
sizeof(thttp_dialog_t),
|
2010-04-19 00:26:24 +00:00
|
|
|
thttp_dialog_ctor,
|
|
|
|
thttp_dialog_dtor,
|
2010-04-06 00:57:03 +00:00
|
|
|
thttp_dialog_cmp,
|
|
|
|
};
|
|
|
|
const tsk_object_def_t *thttp_dialog_def_t = &thttp_dialog_def_s;
|
|
|
|
|