Add support for HTTP transport errors callbacks (to end-user application).
This commit is contained in:
parent
203fe0e859
commit
94e401647f
|
@ -66,6 +66,7 @@ typedef enum thttp_action_type_e
|
|||
|
||||
/* common */
|
||||
atype_closed,
|
||||
atype_error,
|
||||
atype_close,
|
||||
atype_cancel,
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ typedef enum thttp_event_type_e
|
|||
thttp_event_message,
|
||||
thttp_event_auth_failed,
|
||||
thttp_event_closed,
|
||||
thttp_event_transport_error
|
||||
}
|
||||
thttp_event_type_t;
|
||||
|
||||
|
|
|
@ -194,7 +194,10 @@ TINYHTTP_API thttp_session_id_t thttp_session_get_id(const thttp_session_handle_
|
|||
TINYHTTP_API const void* thttp_session_get_userdata(const thttp_session_handle_t *self);
|
||||
|
||||
int thttp_session_update_challenges(thttp_session_t *self, const thttp_response_t* response, tsk_bool_t answered);
|
||||
|
||||
int thttp_session_signal_closed(thttp_session_t *self);
|
||||
int thttp_session_signal_error(thttp_session_t *self);
|
||||
|
||||
thttp_session_t* thttp_session_get_by_fd(thttp_sessions_L_t* sessions, tnet_fd_t fd);
|
||||
|
||||
|
||||
|
|
|
@ -270,6 +270,12 @@ static int thttp_transport_layer_stream_cb(const tnet_transport_event_t* e)
|
|||
}
|
||||
goto bail;
|
||||
|
||||
case event_error:
|
||||
// alert all dialogs
|
||||
if((session = thttp_session_get_by_fd(stack->sessions, e->fd))){
|
||||
ret = thttp_session_signal_error(session);
|
||||
}
|
||||
goto bail;
|
||||
case event_connected:
|
||||
default:{
|
||||
tsk_safeobj_unlock(stack);
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#define DEBUG_STATE_MACHINE 1
|
||||
#define THTTP_MESSAGE_DESCRIPTION(message) \
|
||||
THTTP_MESSAGE_IS_RESPONSE(message) ? THTTP_RESPONSE_PHRASE(message) : THTTP_REQUEST_METHOD(message)
|
||||
#define THTTP_DIALOG_TRANSPORT_ERROR_CODE -0xFF
|
||||
|
||||
/* ======================== internal functions ======================== */
|
||||
int thttp_dialog_send_request(thttp_dialog_t *self);
|
||||
|
@ -78,9 +79,9 @@ typedef enum _fsm_action_e
|
|||
_fsm_action_close = atype_close,
|
||||
_fsm_action_message = atype_i_message,
|
||||
_fsm_action_closed = atype_closed,
|
||||
_fsm_action_error = atype_error, // Transport error and not HTTP message error (e.g. 409)
|
||||
|
||||
_fsm_action_transporterror = 0xFF,
|
||||
_fsm_action_error,
|
||||
/* _fsm_action_any_other = 0xFF */
|
||||
}
|
||||
_fsm_action_t;
|
||||
|
||||
|
@ -151,7 +152,18 @@ int thttp_dialog_Transfering_2_Transfering_X_401_407(va_list *app)
|
|||
self->answered = tsk_true;
|
||||
|
||||
/* Retry with creadentials. */
|
||||
return thttp_dialog_send_request(self);
|
||||
ret = thttp_dialog_send_request(self);
|
||||
|
||||
/* very important: do not break the state machine for transport error events
|
||||
* => let the transport layer do it for us throught (transport_error).
|
||||
* => 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Transfering -> (1xx) -> Transfering */
|
||||
|
@ -183,11 +195,10 @@ int thttp_dialog_Any_2_Terminated_X_closed(va_list *app)
|
|||
{
|
||||
int ret = -2;
|
||||
thttp_dialog_t *self = va_arg(*app, thttp_dialog_t *);
|
||||
thttp_event_t* e = tsk_null;
|
||||
thttp_event_t* e;
|
||||
//self->fd = TNET_INVALID_FD; // to avoid close(fd) in the destructor
|
||||
|
||||
// alert the user
|
||||
/* Alert the user. */
|
||||
/* Alert the user */
|
||||
if((e = thttp_event_create(thttp_event_closed, self->session, "Connection closed", tsk_null))){
|
||||
ret = thttp_stack_alert(self->session->stack, e);
|
||||
TSK_OBJECT_SAFE_FREE(e);
|
||||
|
@ -199,6 +210,16 @@ int thttp_dialog_Any_2_Terminated_X_closed(va_list *app)
|
|||
/* Any -> (error) -> Terminated */
|
||||
int thttp_dialog_Any_2_Terminated_X_Error(va_list *app)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -348,7 +369,7 @@ int thttp_dialog_send_request(thttp_dialog_t *self)
|
|||
}
|
||||
else{
|
||||
TSK_DEBUG_INFO("Failed to sent HTTP/HTTPS message.");
|
||||
ret = -15;
|
||||
ret = THTTP_DIALOG_TRANSPORT_ERROR_CODE;
|
||||
}
|
||||
|
||||
bail:
|
||||
|
|
|
@ -40,6 +40,8 @@
|
|||
/**@defgroup thttp_session_group HTTP Session
|
||||
*/
|
||||
|
||||
int thttp_session_signal(thttp_session_t *self, thttp_action_type_t atype);
|
||||
|
||||
/**Sets parameters.
|
||||
*/
|
||||
int __thttp_session_set(thttp_session_t *self, va_list* app)
|
||||
|
@ -352,31 +354,51 @@ bail:
|
|||
|
||||
}
|
||||
|
||||
/** Signals to all dialogs that the connection have been closed.
|
||||
*/
|
||||
int thttp_session_signal_closed(thttp_session_t *self)
|
||||
/* internal function */
|
||||
int thttp_session_signal(thttp_session_t *self, thttp_action_type_t atype)
|
||||
{
|
||||
tsk_list_item_t *item;
|
||||
|
||||
if(!self){
|
||||
TSK_DEBUG_ERROR("Invalid parameter");
|
||||
return -1;
|
||||
}
|
||||
|
||||
tsk_safeobj_lock(self);
|
||||
|
||||
again:
|
||||
tsk_list_foreach(item, self->dialogs){
|
||||
// FIXME: not thread-safe
|
||||
//--thttp_dialog_fsm_act((thttp_dialog_t*)item->data, atype_closed, tsk_null, tsk_null);
|
||||
thttp_dialog_fsm_act((thttp_dialog_t*)item->data, atype, tsk_null, tsk_null);
|
||||
/* As the above action could terminate the dialog (which means change the content of self->dialogs)
|
||||
* => list becomes unsafe */
|
||||
goto again;
|
||||
}
|
||||
|
||||
switch(atype){
|
||||
case atype_closed:
|
||||
self->fd = TNET_INVALID_FD;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
self->fd = TNET_INVALID_FD;
|
||||
|
||||
tsk_safeobj_unlock(self);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Retrieves a session by fd.
|
||||
*/
|
||||
/** Signals to all dialogs that the connection have been closed. */
|
||||
int thttp_session_signal_closed(thttp_session_t *self)
|
||||
{
|
||||
return thttp_session_signal(self, atype_closed);
|
||||
}
|
||||
|
||||
/** Signals to all dialogss that we got an error */
|
||||
int thttp_session_signal_error(thttp_session_t *self)
|
||||
{
|
||||
return thttp_session_signal(self, atype_error);
|
||||
}
|
||||
|
||||
/** Retrieves a session by fd */
|
||||
thttp_session_t* thttp_session_get_by_fd(thttp_sessions_L_t* sessions, tnet_fd_t fd)
|
||||
{
|
||||
thttp_session_t* ret = tsk_null;
|
||||
|
|
|
@ -56,6 +56,12 @@ int test_stack_callback(const thttp_event_t *httpevent)
|
|||
TSK_DEBUG_INFO("closed sid=%llu", id);
|
||||
break;
|
||||
}
|
||||
|
||||
case thttp_event_transport_error: /* HTTP connection closed (informational) */
|
||||
{
|
||||
TSK_DEBUG_INFO("Transport sid=%llu", id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -103,7 +109,8 @@ void test_stack()
|
|||
|
||||
// session-level headers
|
||||
THTTP_SESSION_SET_HEADER("Pragma", "No-Cache"),
|
||||
THTTP_SESSION_SET_HEADER("Connection", "Keep-Alive"),
|
||||
//THTTP_SESSION_SET_HEADER("Connection", "Keep-Alive"),
|
||||
THTTP_SESSION_SET_HEADER("Connection", "close"),
|
||||
THTTP_SESSION_SET_HEADER("User-Agent", "doubango 1.0"),
|
||||
|
||||
THTTP_SESSION_SET_NULL()); /* MUST always be present */
|
||||
|
|
|
@ -492,6 +492,7 @@ void *tnet_transport_mainthread(void *param)
|
|||
|
||||
/* Get the network events flags */
|
||||
if (WSAEnumNetworkEvents(active_socket->fd, active_event, &networkEvents) == SOCKET_ERROR){
|
||||
TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
|
||||
TNET_PRINT_LAST_ERROR("WSAEnumNetworkEvents have failed.");
|
||||
|
||||
tsk_safeobj_unlock(context);
|
||||
|
@ -506,6 +507,7 @@ void *tnet_transport_mainthread(void *param)
|
|||
TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_ACCEPT", transport->description);
|
||||
|
||||
if(networkEvents.iErrorCode[FD_ACCEPT_BIT]){
|
||||
TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
|
||||
TNET_PRINT_LAST_ERROR("ACCEPT FAILED.");
|
||||
goto done;
|
||||
}
|
||||
|
@ -538,6 +540,7 @@ void *tnet_transport_mainthread(void *param)
|
|||
TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_CONNECT", transport->description);
|
||||
|
||||
if(networkEvents.iErrorCode[FD_CONNECT_BIT]){
|
||||
TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
|
||||
TNET_PRINT_LAST_ERROR("CONNECT FAILED.");
|
||||
goto done;
|
||||
}
|
||||
|
@ -557,6 +560,7 @@ void *tnet_transport_mainthread(void *param)
|
|||
TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_READ", transport->description);
|
||||
|
||||
if(networkEvents.iErrorCode[FD_READ_BIT]){
|
||||
TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
|
||||
TNET_PRINT_LAST_ERROR("READ FAILED.");
|
||||
goto done;
|
||||
}
|
||||
|
@ -592,8 +596,7 @@ void *tnet_transport_mainthread(void *param)
|
|||
ret = WSARecv(active_socket->fd, &wsaBuffer, 1, &readCount, &flags, 0, 0);
|
||||
}
|
||||
|
||||
if(ret)
|
||||
{
|
||||
if(ret){
|
||||
ret = WSAGetLastError();
|
||||
if(ret == WSAEWOULDBLOCK){
|
||||
TSK_DEBUG_WARN("WSAEWOULDBLOCK error for READ SSESSION");
|
||||
|
@ -630,6 +633,7 @@ void *tnet_transport_mainthread(void *param)
|
|||
TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_WRITE", transport->description);
|
||||
|
||||
if(networkEvents.iErrorCode[FD_WRITE_BIT]){
|
||||
TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
|
||||
TNET_PRINT_LAST_ERROR("WRITE FAILED.");
|
||||
goto done;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue