Refactored client module
This commit is contained in:
parent
0b05984f85
commit
a49e32dff8
|
@ -14,6 +14,10 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
#include <openssl/ssl.h>
|
||||
#endif
|
||||
|
||||
/* type casts */
|
||||
#define AISL_CALLBACK(x) ((aisl_callback_t) x)
|
||||
|
||||
|
@ -37,10 +41,12 @@ typedef struct aisl_stream * aisl_stream_t;
|
|||
typedef void
|
||||
(* aisl_callback_t) (void);
|
||||
|
||||
|
||||
/* status return codes */
|
||||
typedef enum
|
||||
{
|
||||
AISL_EXTCALL_ERROR = -3
|
||||
AISL_INPUT_ERROR = -4
|
||||
, AISL_EXTCALL_ERROR = -3
|
||||
, AISL_SYSCALL_ERROR = -2
|
||||
, AISL_MALLOC_ERROR = -1
|
||||
|
||||
|
|
|
@ -8,13 +8,18 @@
|
|||
struct buffer
|
||||
{
|
||||
char * data;
|
||||
size_t size;
|
||||
int32_t size;
|
||||
int32_t length;
|
||||
};
|
||||
|
||||
typedef struct buffer * buffer_t;
|
||||
|
||||
#define BUFFER_EOB ( ~0L )
|
||||
|
||||
|
||||
int
|
||||
buffer_init( buffer_t buffer, int32_t size );
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
buffer_t
|
||||
|
|
247
src/client.c
247
src/client.c
|
@ -6,9 +6,14 @@
|
|||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
#include <openssl/err.h>
|
||||
#endif
|
||||
|
||||
#include <aisl/aisl.h>
|
||||
#include "list.h"
|
||||
#include "stream.h"
|
||||
#include "http.h"
|
||||
#include "buffer.h"
|
||||
#include "client.h"
|
||||
|
||||
#define FLAG_KEEPALIVE (1<<0)
|
||||
|
@ -16,32 +21,30 @@
|
|||
#define FLAG_CAN_READ (1<<2)
|
||||
#define FLAG_CAN_WRITE (1<<3)
|
||||
|
||||
#define BUFFER_SIZE (16*1024)
|
||||
|
||||
struct aisl_client
|
||||
{
|
||||
struct sockaddr_in address; /**< Client's address structure */
|
||||
aisl_server_t server; /**< Server instance associated with client */
|
||||
list_t streams; /**< list of client streams */
|
||||
struct buffer in; /**< Client's input buffer */
|
||||
struct buffer out; /**< Client's output buffer */
|
||||
struct sockaddr_in address; /**< Client's address structure. */
|
||||
aisl_server_t server; /**< Server instance. */
|
||||
struct buffer in; /**< Client's input buffer. */
|
||||
struct buffer out; /**< Client's output buffer. */
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
SSL * ssl; /**< SSL pointer for encrypted connections */
|
||||
SSL * ssl; /**< SSL pointer for HTTPS. */
|
||||
#endif
|
||||
time_t timestamp; /**< Last communication timestamp */
|
||||
time_t timestamp; /**< Last communication timestamp. */
|
||||
|
||||
aisl_stream_t stream; /**< Pending client's stream */
|
||||
/* int next_id; / **< stream id generator (even)*/
|
||||
/* int istream; / **< input stream id */
|
||||
/* int ostream; / **< output stream id */
|
||||
int flags; /**< Client's flag bitmask */
|
||||
int fd; /**< Client's socket descriptor */
|
||||
aisl_stream_t stream; /**< Pending client's stream. */
|
||||
int next_id; /**< Stream id generator (even). */
|
||||
int flags; /**< Client's flag bitmask. */
|
||||
int fd; /**< Client's socket descriptor. */
|
||||
|
||||
aisl_http_version_t protocol; /**< Client's protocol version */
|
||||
aisl_http_version_t http_version; /**< Client's http_version version. */
|
||||
};
|
||||
|
||||
|
||||
static bool
|
||||
aisl_client_raise_event(aisl_client_t client, aisl_event_t event, ...)
|
||||
aisl_client_raise(aisl_client_t client, aisl_event_t event, ...)
|
||||
{
|
||||
bool result;
|
||||
va_list vl_args;
|
||||
|
@ -57,52 +60,73 @@ aisl_client_raise_event(aisl_client_t client, aisl_event_t event, ...)
|
|||
|
||||
|
||||
static aisl_status_t
|
||||
aisl_client_parse(aisl_client_t client, char * data, size_t size)
|
||||
aisl_client_parse(aisl_client_t client, char * data, int32_t size)
|
||||
{
|
||||
/* parse next data chunk */
|
||||
while ( p_status == PARSER_PENDING )
|
||||
aisl_stream_t s;
|
||||
http_parser_t p = HTTP_PARSER_PENDING;
|
||||
|
||||
int32_t bytes_left = size;
|
||||
|
||||
switch (client->http_version)
|
||||
{
|
||||
switch(s->state)
|
||||
case AISL_HTTP_1_0:
|
||||
case AISL_HTTP_1_1:
|
||||
|
||||
s = client->stream;
|
||||
|
||||
while ( p == HTTP_PARSER_PENDING )
|
||||
{
|
||||
case STREAM_REQUEST_METHOD:
|
||||
p_status = parse_request_method(client, &ptr, &l);
|
||||
break;
|
||||
case STREAM_REQUEST_PATH:
|
||||
p_status = parse_request_path(client, &ptr, &l);
|
||||
break;
|
||||
case STREAM_REQUEST_PROTOCOL:
|
||||
p_status = parse_request_protocol(client, &ptr, &l);
|
||||
|
||||
switch ( aisl_stream_get_state(s) )
|
||||
{
|
||||
case AISL_STREAM_STATE_IDLE:
|
||||
p = http_10_parse_request(data, &size, client);
|
||||
break;
|
||||
|
||||
case STREAM_REQUEST_HEADER_KEY:
|
||||
p_status = parse_request_header_key(client, &ptr, &l);
|
||||
break;
|
||||
case STREAM_REQUEST_HEADER_VALUE:
|
||||
p_status = parse_request_header_value(client, &ptr, &l);
|
||||
case AISL_STREAM_STATE_WAIT_HEADER:
|
||||
p = http_10_parse_header(data, &size, client);
|
||||
break;
|
||||
|
||||
case STREAM_REQUEST_CONTENT:
|
||||
p_status = parse_request_content(client, &ptr, &l);
|
||||
case AISL_STREAM_STATE_WAIT_BODY:
|
||||
p = http_10_parse_body(data, &size, client);
|
||||
break;
|
||||
|
||||
default:
|
||||
p_status = PARSER_FINISHED;
|
||||
/* this is error actually */
|
||||
|
||||
default: /* has input data, but request was already parsed */
|
||||
p = HTTP_PARSER_ERROR;
|
||||
continue;
|
||||
}
|
||||
// size now has number of parsed bytes
|
||||
data += size;
|
||||
bytes_left -= size;
|
||||
size = bytes_left;
|
||||
}
|
||||
|
||||
if (p_status == PARSER_FAILED)
|
||||
if (p == HTTP_PARSER_FINISHED)
|
||||
{
|
||||
client->flags &= ~FLAG_CAN_READ;
|
||||
client->flags |= FLAG_CAN_WRITE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case AISL_HTTP_2_0:
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (p == HTTP_PARSER_ERROR)
|
||||
{
|
||||
/* reply Bad Request here */
|
||||
client_close(client);
|
||||
}
|
||||
else if (l)
|
||||
{
|
||||
buffer_shift(s->buffer, s->buffer->size-l); /* reset buffer */
|
||||
aisl_client_close(client);
|
||||
|
||||
return AISL_INPUT_ERROR;
|
||||
}
|
||||
|
||||
|
||||
if (size)
|
||||
buffer_shift(&client->in, client->in.length - size); /* reset buffer */
|
||||
|
||||
return AISL_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
@ -114,11 +138,9 @@ static aisl_status_t
|
|||
aisl_client_input(aisl_client_t client)
|
||||
{
|
||||
int l;
|
||||
parser_status_t p_status = PARSER_PENDING;
|
||||
aisl_stream_t s = client->stream;
|
||||
|
||||
char * data = &client->in.data[ client->in.length ];
|
||||
size_t size = client->in.size - client.in.length;
|
||||
int32_t size = client->in.size - client->in.length;
|
||||
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
if (client->ssl)
|
||||
|
@ -174,40 +196,30 @@ aisl_client_input(aisl_client_t client)
|
|||
|
||||
/* both: client disconnect + on read error */
|
||||
/* todo: raise client error here */
|
||||
client_close(client);
|
||||
aisl_client_close(client);
|
||||
|
||||
return AISL_SYSCALL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
static aisl_status_t
|
||||
aisl_client_output(aisl_client_t client)
|
||||
{
|
||||
if (client->fd < 0)
|
||||
{
|
||||
fprintf(stderr, "[aisl] assertion !(client->fd<0) failed\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
stream_t s;
|
||||
int l;
|
||||
char * data;
|
||||
|
||||
s = list_index(client->streams, client->ostream);
|
||||
|
||||
/*
|
||||
if (!s->c_length_unknown && s->buffer && s->buffer->len)
|
||||
buffer_move(gBuffer, s->buffer);
|
||||
*/
|
||||
aisl_stream_t s = client->stream;
|
||||
|
||||
/* while stream is not flushed, we should raise event */
|
||||
if(s->flags & STREAM_FLAG_OUTPUT_CHUNKED)
|
||||
if( aisl_stream_get_chunked_output(s) )
|
||||
{
|
||||
/* in case of chunked output ( subscription for AISL_STREAM_OUTPUT event )
|
||||
* stream buffer will be initialized with OUTPUT_BUFFER_SIZE size, but
|
||||
* buffer->size will be used to carry amount of stored bytes
|
||||
* */
|
||||
size_t bsz = s->buffer->size;
|
||||
l = aisl_stream_get_buffer_space(s);
|
||||
|
||||
/*
|
||||
if (bsz < OUTPUT_BUFFER_SIZE)
|
||||
{
|
||||
if (buffer_clear(s->buffer, OUTPUT_BUFFER_SIZE) == 0)
|
||||
|
@ -216,90 +228,108 @@ aisl_client_output(aisl_client_t client)
|
|||
s->buffer->size = bsz;
|
||||
bsz = OUTPUT_BUFFER_SIZE;
|
||||
}
|
||||
*/
|
||||
|
||||
if ( (l = bsz - s->buffer->size) > OUTPUT_BUFFER_SIZE / 2 )
|
||||
aisl_raise_event( client->server->owner, s, AISL_STREAM_OUTPUT, l);
|
||||
if ( !(l < aisl_stream_get_buffer_size(s) / 2) )
|
||||
aisl_raise(
|
||||
aisl_server_get_instance(client->server),
|
||||
s,
|
||||
AISL_EVENT_STREAM_OUTPUT,
|
||||
l
|
||||
);
|
||||
}
|
||||
|
||||
if (s->buffer->size == 0)
|
||||
return false;
|
||||
aisl_stream_get_buffer(s, &data, &l);
|
||||
|
||||
if ( !l )
|
||||
return AISL_IDLE;
|
||||
|
||||
l = (client->ssl) ?
|
||||
SSL_write(client->ssl, s->buffer->data, s->buffer->size) :
|
||||
send( client->fd, s->buffer->data, s->buffer->size, 0);
|
||||
SSL_write(client->ssl, data, l) :
|
||||
send( client->fd, data, l, 0);
|
||||
|
||||
if (l > 0)
|
||||
{
|
||||
buffer_shift(s->buffer, l);
|
||||
if (s->state == STREAM_RESPONSE_READY && /* flushed */
|
||||
s->buffer->size == 0) /* all sent */
|
||||
aisl_stream_shift(s, l);
|
||||
|
||||
/*
|
||||
if (s->state == STREAM_RESPONSE_READY && / * flushed * /
|
||||
s->buffer->size == 0) / * all sent * /
|
||||
*/
|
||||
if ( ! aisl_stream_has_data(s) )
|
||||
{
|
||||
buffer_clear(s->buffer, 0);
|
||||
/* buffer_clear(s->buffer, 0); */
|
||||
|
||||
/* data has been sent */
|
||||
/*
|
||||
if (client->protocol == AISL_HTTP_2_0)
|
||||
{
|
||||
|
||||
}
|
||||
else*/
|
||||
if (client->flags & CLIENT_FLAG_KEEPALIVE)
|
||||
if (client->flags & FLAG_KEEPALIVE)
|
||||
{
|
||||
list_remove(client->streams, s);
|
||||
stream_free(s);
|
||||
aisl_stream_free(s);
|
||||
|
||||
s = stream_new((struct sockaddr_in *) client, client->next_id++, STREAM_REQUEST_METHOD );
|
||||
list_append(client->streams, s);
|
||||
client->stream = aisl_stream_new(client, client->next_id++);
|
||||
if (client->stream != NULL )
|
||||
return AISL_SUCCESS;
|
||||
|
||||
/* in case of malloc error it will not be error as long as request was
|
||||
* handled and we just close the connection.
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
client_close(client);
|
||||
|
||||
aisl_client_close(client);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
return AISL_SUCCESS;
|
||||
}
|
||||
|
||||
/* l < 0 */
|
||||
if (client->ssl)
|
||||
{
|
||||
if ( SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_WRITE )
|
||||
return false;
|
||||
return AISL_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (errno == EWOULDBLOCK)
|
||||
return false;
|
||||
return AISL_IDLE;
|
||||
}
|
||||
|
||||
client_close(client);
|
||||
aisl_client_close(client);
|
||||
|
||||
return true;
|
||||
return AISL_SYSCALL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
aisl_client_t
|
||||
aisl_client_new( aisl_server_t server,
|
||||
int fd,
|
||||
struct sockaddr_in * addr,
|
||||
SSL_CTX * ssl_ctx )
|
||||
#else
|
||||
aisl_client_t
|
||||
aisl_client_new( aisl_server_t server,
|
||||
int fd,
|
||||
struct sockaddr_in * addr )
|
||||
#endif
|
||||
{
|
||||
aisl_client_t client;
|
||||
aisl_stream_t stream;
|
||||
|
||||
if ( (client = calloc(1, sizeof(struct client))) != NULL )
|
||||
if ( (client = calloc(1, sizeof(struct aisl_client))) != NULL )
|
||||
{
|
||||
memcpy(&client->address, addr, sizeof(struct sockaddr_in));
|
||||
client->server = server;
|
||||
client->fd = fd;
|
||||
client->next_id = 2;
|
||||
client->protocol = AISL_HTTP_1_0;
|
||||
client->http_version = AISL_HTTP_1_0;
|
||||
client->timestamp = time(NULL);
|
||||
client->flags = FLAG_KEEPALIVE | FLAG_HANDSHAKE | FLAG_CAN_READ;
|
||||
|
||||
if (buffer_init(client->in, 2*BUFFER_SIZE) == 0)
|
||||
if (buffer_init(&client->in, 2*BUFFER_SIZE) == 0)
|
||||
{
|
||||
memcpy(&client->out, client->in, sizeof(struct buffer));
|
||||
memcpy(&client->out, &client->in, sizeof(struct buffer));
|
||||
|
||||
stream = aisl_stream_new(client, 0, STREAM_REQUEST_METHOD);
|
||||
stream = aisl_stream_new(client, 0);
|
||||
|
||||
if (stream != NULL)
|
||||
{
|
||||
|
@ -346,7 +376,8 @@ aisl_client_free(aisl_client_t client)
|
|||
|
||||
/* out buffer is a shared part of input buffer, so no need to free it */
|
||||
|
||||
list_free(client->streams, (list_destructor_t)aisl_stream_free);
|
||||
if (client->stream)
|
||||
aisl_stream_free(client->stream);
|
||||
|
||||
free(client);
|
||||
}
|
||||
|
@ -355,26 +386,26 @@ aisl_client_free(aisl_client_t client)
|
|||
aisl_status_t
|
||||
aisl_client_touch(aisl_client_t client)
|
||||
{
|
||||
aisl_status_t result, status;
|
||||
aisl_stream_t s = client->stream;
|
||||
aisl_status_t result = AISL_IDLE,
|
||||
status = AISL_IDLE;
|
||||
|
||||
/* input */
|
||||
if (client->flags & FLAG_CAN_READ)
|
||||
{
|
||||
if ( (result = client_input(client)) < 0 )
|
||||
if ( (result = aisl_client_input(client)) < 0 )
|
||||
return result;
|
||||
}
|
||||
|
||||
/* output */
|
||||
if (client->flags & FLAG_CAN_WRITE)
|
||||
{
|
||||
if ( (status = client_output(client)) < 0 )
|
||||
if ( (status = aisl_client_output(client)) < 0 )
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
if ((client->protocol==AISL_HTTP_2_0 || s->state<STREAM_REQUEST_READY) &&
|
||||
if ((client->http_version==AISL_HTTP_2_0 || s->state<STREAM_REQUEST_READY) &&
|
||||
(client_input(client)) ) result = true;
|
||||
*/
|
||||
/* output */
|
||||
|
@ -389,7 +420,7 @@ aisl_client_touch(aisl_client_t client)
|
|||
if (result == AISL_IDLE)
|
||||
result = status;
|
||||
|
||||
if (result = AISL_SUCCESS)
|
||||
if (result == AISL_SUCCESS)
|
||||
client->timestamp = time(NULL);
|
||||
|
||||
return result;
|
||||
|
@ -405,7 +436,7 @@ aisl_client_is_timed_out(aisl_client_t client, uint32_t timeout)
|
|||
|
||||
if ( !(now - client->timestamp < timeout) )
|
||||
{
|
||||
aisl_client_raise_event( client, AISL_CLIENT_TIMEOUT );
|
||||
aisl_client_raise(client, AISL_EVENT_CLIENT_TIMEOUT);
|
||||
aisl_client_close(client);
|
||||
return true;
|
||||
}
|
||||
|
@ -449,7 +480,7 @@ aisl_client_close(aisl_client_t client)
|
|||
{
|
||||
if (client->fd != -1)
|
||||
{
|
||||
aisl_client_raise_event( client, AISL_CLIENT_DISCONNECT );
|
||||
aisl_client_raise( client, AISL_EVENT_CLIENT_DISCONNECT );
|
||||
|
||||
close(client->fd);
|
||||
shutdown(client->fd, SHUT_RDWR);
|
||||
|
|
16
src/client.h
16
src/client.h
|
@ -7,7 +7,7 @@
|
|||
|
||||
#define AISL_CLIENT(x) ((aisl_client_t) x)
|
||||
|
||||
|
||||
#ifndef AISL_WITHOUT_SSL
|
||||
/**
|
||||
* @brief Constructor for #aisl_client_t instance.
|
||||
* @param server an #aisl_server_t instance pointer.
|
||||
|
@ -20,6 +20,20 @@ aisl_client_new( aisl_server_t server,
|
|||
int fd,
|
||||
struct sockaddr_in * addr,
|
||||
SSL_CTX * ssl_ctx);
|
||||
#else
|
||||
|
||||
/**
|
||||
* @brief Constructor for #aisl_client_t instance.
|
||||
* @param server an #aisl_server_t instance pointer.
|
||||
* @param fd a client socket descriptor.
|
||||
* @param addr a pointer to client's address structure.
|
||||
* @param ssl_ctx a pointer to SSL context or NULL if encryption is disabled
|
||||
*/
|
||||
aisl_client_t
|
||||
aisl_client_new( aisl_server_t server,
|
||||
int fd,
|
||||
struct sockaddr_in * addr );
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-%YEAR% by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file http.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief Declarations of HTTP parser module
|
||||
*
|
||||
* @see https://lowenware.com/aisl/
|
||||
*/
|
||||
|
||||
#ifndef AISL_HTTP_H_E2921FF1_6BD3_4E60_B599_ACA1A494CD01
|
||||
#define AISL_HTTP_H_E2921FF1_6BD3_4E60_B599_ACA1A494CD01
|
||||
|
||||
#include <aisl/types.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
HTTP_PARSER_PENDING
|
||||
, HTTP_PARSER_ERROR
|
||||
, HTTP_PARSER_FINISHED
|
||||
|
||||
} http_parser_t;
|
||||
|
||||
|
||||
http_parser_t
|
||||
http_10_parse_request(char * data, int32_t * size, aisl_client_t client);
|
||||
|
||||
|
||||
http_parser_t
|
||||
http_10_parse_header(char * data, int32_t * size, aisl_client_t client);
|
||||
|
||||
|
||||
http_parser_t
|
||||
http_10_parse_body(char * data, int32_t * size, aisl_client_t client);
|
||||
|
||||
|
||||
#endif /* !AISL_HTTP_H */
|
183
src/stream.c
183
src/stream.c
|
@ -2,141 +2,142 @@
|
|||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "buffer.h"
|
||||
#include "stream.h"
|
||||
#include "globals.h"
|
||||
#include "client.h"
|
||||
#include "handle.h"
|
||||
struct stream
|
||||
|
||||
#define FLAG_OUTPUT_READY (1<<0)
|
||||
#define FLAG_OUTPUT_CHUNKED (1<<1)
|
||||
|
||||
struct aisl_stream
|
||||
{
|
||||
struct aisl_stream _public;
|
||||
aisl_client_t client;
|
||||
|
||||
/* private data */
|
||||
list_t headers; /* request headers */
|
||||
buffer_t buffer;
|
||||
struct buffer buffer;
|
||||
|
||||
const char *c_type;
|
||||
const char *content_type;
|
||||
|
||||
aisl_http_response_t response;
|
||||
stream_state_t state;
|
||||
uint32_t c_length;
|
||||
uint32_t c_offset;
|
||||
size_t content_length;
|
||||
int32_t content_offset;
|
||||
int id;
|
||||
int flags;
|
||||
|
||||
aisl_http_response_t response;
|
||||
aisl_stream_state_t state;
|
||||
|
||||
bool c_length_unknown;
|
||||
|
||||
};
|
||||
static void
|
||||
pair_free( pair_t self )
|
||||
pair_free( pair_t stream )
|
||||
{
|
||||
if (!self) return;
|
||||
if (!stream) return;
|
||||
|
||||
if(self->key) free(self->key);
|
||||
if(self->value) free(self->value);
|
||||
free(self);
|
||||
if(stream->key) free(stream->key);
|
||||
if(stream->value) free(stream->value);
|
||||
free(stream);
|
||||
}
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
stream_t
|
||||
aisl_stream_t
|
||||
stream_new(struct sockaddr_in *client, int id, stream_state_t state)
|
||||
{
|
||||
stream_t self = malloc(sizeof(struct stream));
|
||||
aisl_stream_t stream = malloc(sizeof(struct aisl_stream));
|
||||
|
||||
if (self)
|
||||
if (stream)
|
||||
{
|
||||
/* public data */
|
||||
ASTREAM(self)->client = client;
|
||||
ASTREAM(self)->host = NULL;
|
||||
ASTREAM(self)->path = NULL;
|
||||
ASTREAM(self)->query = NULL;
|
||||
ASTREAM(self)->scheme = NULL;
|
||||
ASTREAM(self)->u_ptr = NULL;
|
||||
ASTREAM(self)->request_method = AISL_HTTP_GET;
|
||||
ASTREAM(stream)->client = client;
|
||||
ASTREAM(stream)->host = NULL;
|
||||
ASTREAM(stream)->path = NULL;
|
||||
ASTREAM(stream)->query = NULL;
|
||||
ASTREAM(stream)->scheme = NULL;
|
||||
ASTREAM(stream)->u_ptr = NULL;
|
||||
ASTREAM(stream)->request_method = AISL_HTTP_GET;
|
||||
|
||||
/* private data */
|
||||
self->headers = NULL; /* request headers */
|
||||
self->buffer = buffer_new(0);
|
||||
stream->headers = NULL; /* request headers */
|
||||
stream->buffer = buffer_new(0);
|
||||
|
||||
self->c_type = NULL;
|
||||
stream->c_type = NULL;
|
||||
|
||||
self->response = AISL_HTTP_OK;
|
||||
self->state = STREAM_REQUEST_METHOD;
|
||||
self->c_length = 0;
|
||||
self->c_offset = 0; /* headers length */
|
||||
self->id = id;
|
||||
self->c_length_unknown = true;
|
||||
self->flags = 0;
|
||||
stream->response = AISL_HTTP_OK;
|
||||
stream->state = STREAM_REQUEST_METHOD;
|
||||
stream->c_length = 0;
|
||||
stream->c_offset = 0; /* headers length */
|
||||
stream->id = id;
|
||||
stream->c_length_unknown = true;
|
||||
stream->flags = 0;
|
||||
}
|
||||
return self;
|
||||
return stream;
|
||||
}
|
||||
|
||||
/*
|
||||
stream_t
|
||||
stream_reset(stream_t self)
|
||||
aisl_stream_t
|
||||
stream_reset(aisl_stream_t stream)
|
||||
{
|
||||
if (ASTREAM(self)->path)
|
||||
if (ASTREAM(stream)->path)
|
||||
{
|
||||
free( (char*) ASTREAM(self)->path);
|
||||
ASTREAM(self)->path = NULL;
|
||||
free( (char*) ASTREAM(stream)->path);
|
||||
ASTREAM(stream)->path = NULL;
|
||||
}
|
||||
|
||||
if (ASTREAM(self)->query)
|
||||
if (ASTREAM(stream)->query)
|
||||
{
|
||||
free( (char*) ASTREAM(self)->query);
|
||||
ASTREAM(self)->query = NULL;
|
||||
free( (char*) ASTREAM(stream)->query);
|
||||
ASTREAM(stream)->query = NULL;
|
||||
}
|
||||
|
||||
ASTREAM(self)->u_ptr = NULL;
|
||||
ASTREAM(self)->request_method = AISL_HTTP_GET;
|
||||
ASTREAM(stream)->u_ptr = NULL;
|
||||
ASTREAM(stream)->request_method = AISL_HTTP_GET;
|
||||
|
||||
if (self->headers)
|
||||
if (stream->headers)
|
||||
{
|
||||
list_free(self->headers, (list_destructor_t) pair_free);
|
||||
self->headers = NULL;
|
||||
list_free(stream->headers, (list_destructor_t) pair_free);
|
||||
stream->headers = NULL;
|
||||
}
|
||||
|
||||
self->c_type = NULL;
|
||||
self->response = AISL_HTTP_OK;
|
||||
self->state = STREAM_REQUEST_METHOD;
|
||||
self->c_length = 0;
|
||||
self->c_offset = 0; / * headers length * /
|
||||
self->c_length_unknown = true;
|
||||
self->flags = 0;
|
||||
stream->c_type = NULL;
|
||||
stream->response = AISL_HTTP_OK;
|
||||
stream->state = STREAM_REQUEST_METHOD;
|
||||
stream->c_length = 0;
|
||||
stream->c_offset = 0; / * headers length * /
|
||||
stream->c_length_unknown = true;
|
||||
stream->flags = 0;
|
||||
|
||||
return self;
|
||||
return stream;
|
||||
}
|
||||
*/
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void
|
||||
stream_free(stream_t self)
|
||||
stream_free(aisl_stream_t stream)
|
||||
{
|
||||
if (self->buffer) buffer_free(self->buffer);
|
||||
if (self->headers) list_free(self->headers, (list_destructor_t) pair_free);
|
||||
if (stream->buffer) buffer_free(stream->buffer);
|
||||
if (stream->headers) list_free(stream->headers, (list_destructor_t) pair_free);
|
||||
|
||||
if (ASTREAM(self)->path) free( (char*) ASTREAM(self)->path);
|
||||
if (ASTREAM(self)->query) free( (char*) ASTREAM(self)->query);
|
||||
if (ASTREAM(stream)->path) free( (char*) ASTREAM(stream)->path);
|
||||
if (ASTREAM(stream)->query) free( (char*) ASTREAM(stream)->query);
|
||||
|
||||
aisl_handle_t hd = ((client_t) ASTREAM(self)->client)->server->owner;
|
||||
aisl_raise_event(hd, self, AISL_STREAM_CLOSE);
|
||||
ASTREAM(self)->u_ptr = NULL;
|
||||
aisl_remove_listeners_for(hd, self);
|
||||
free(self);
|
||||
aisl_handle_t hd = ((client_t) ASTREAM(stream)->client)->server->owner;
|
||||
aisl_raise_event(hd, stream, AISL_STREAM_CLOSE);
|
||||
ASTREAM(stream)->u_ptr = NULL;
|
||||
aisl_remove_listeners_for(hd, stream);
|
||||
free(stream);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int
|
||||
stream_write(stream_t self, const char * data, uint32_t d_len)
|
||||
stream_write(aisl_stream_t stream, const char * data, uint32_t d_len)
|
||||
{
|
||||
return buffer_add( self->buffer, data, d_len);
|
||||
return buffer_add( stream->buffer, data, d_len);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
void
|
||||
aisl_cancel(aisl_stream_t s)
|
||||
aisl_cancel(aisl_aisl_stream_t s)
|
||||
{
|
||||
client_close( (client_t) s->client );
|
||||
}
|
||||
|
@ -145,7 +146,7 @@ aisl_cancel(aisl_stream_t s)
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
bool
|
||||
aisl_is_secure(aisl_stream_t s)
|
||||
aisl_is_secure(aisl_aisl_stream_t s)
|
||||
{
|
||||
client_t cli = (client_t) s->client;
|
||||
|
||||
|
@ -156,7 +157,7 @@ aisl_is_secure(aisl_stream_t s)
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
void *
|
||||
aisl_get_context(aisl_stream_t s)
|
||||
aisl_get_context(aisl_aisl_stream_t s)
|
||||
{
|
||||
return s->u_ptr;
|
||||
}
|
||||
|
@ -165,7 +166,7 @@ aisl_get_context(aisl_stream_t s)
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
void
|
||||
aisl_set_context(aisl_stream_t s, void * u_ptr)
|
||||
aisl_set_context(aisl_aisl_stream_t s, void * u_ptr)
|
||||
{
|
||||
s->u_ptr = u_ptr;
|
||||
}
|
||||
|
@ -174,7 +175,7 @@ aisl_set_context(aisl_stream_t s, void * u_ptr)
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
aisl_client_t
|
||||
aisl_get_client(aisl_stream_t s)
|
||||
aisl_get_client(aisl_aisl_stream_t s)
|
||||
{
|
||||
return s->client;
|
||||
}
|
||||
|
@ -183,7 +184,7 @@ aisl_get_client(aisl_stream_t s)
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
aisl_server_t
|
||||
aisl_get_server(aisl_stream_t s)
|
||||
aisl_get_server(aisl_aisl_stream_t s)
|
||||
{
|
||||
return (aisl_server_t) (((client_t) s->client)->server);
|
||||
}
|
||||
|
@ -193,7 +194,7 @@ aisl_get_server(aisl_stream_t s)
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
aisl_http_version_t
|
||||
aisl_get_http_version(aisl_stream_t s)
|
||||
aisl_get_http_version(aisl_aisl_stream_t s)
|
||||
{
|
||||
client_t cli = (client_t) s->client;
|
||||
|
||||
|
@ -204,7 +205,7 @@ aisl_get_http_version(aisl_stream_t s)
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
void
|
||||
aisl_reject(aisl_stream_t s)
|
||||
aisl_reject(aisl_aisl_stream_t s)
|
||||
{
|
||||
client_t cli = (client_t) s->client;
|
||||
|
||||
|
@ -216,7 +217,7 @@ aisl_reject(aisl_stream_t s)
|
|||
|
||||
|
||||
static char *
|
||||
get_response_begin(stream_t stream)
|
||||
get_response_begin(aisl_stream_t stream)
|
||||
{
|
||||
char * r;
|
||||
client_t cli = CLIENT(ASTREAM(stream)->client);
|
||||
|
@ -236,7 +237,7 @@ get_response_begin(stream_t stream)
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
aisl_status_t
|
||||
aisl_response(aisl_stream_t stream, aisl_http_response_t status_code,
|
||||
aisl_response(aisl_aisl_stream_t stream, aisl_http_response_t status_code,
|
||||
const char *content_type,
|
||||
uint32_t content_length)
|
||||
{
|
||||
|
@ -284,9 +285,9 @@ aisl_response(aisl_stream_t stream, aisl_http_response_t status_code,
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
aisl_status_t
|
||||
aisl_flush(aisl_stream_t stream)
|
||||
aisl_flush(aisl_aisl_stream_t stream)
|
||||
{
|
||||
stream_t s = STREAM(stream);
|
||||
aisl_stream_t s = STREAM(stream);
|
||||
if ( ! s->c_length )
|
||||
{
|
||||
s->c_length = s->buffer->size - s->c_offset - 2;
|
||||
|
@ -309,7 +310,7 @@ aisl_flush(aisl_stream_t stream)
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
int
|
||||
aisl_header(aisl_stream_t stream, const char *key, const char *value)
|
||||
aisl_header(aisl_aisl_stream_t stream, const char *key, const char *value)
|
||||
{
|
||||
int ret;
|
||||
char * pch;
|
||||
|
@ -340,7 +341,7 @@ aisl_header(aisl_stream_t stream, const char *key, const char *value)
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
int
|
||||
aisl_header_printf(aisl_stream_t stream, const char *key,
|
||||
aisl_header_printf(aisl_aisl_stream_t stream, const char *key,
|
||||
const char *f_value, ...)
|
||||
{
|
||||
int ret;
|
||||
|
@ -358,7 +359,7 @@ aisl_header_printf(aisl_stream_t stream, const char *key,
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
int
|
||||
aisl_header_vprintf(aisl_stream_t stream, const char *key,
|
||||
aisl_header_vprintf(aisl_aisl_stream_t stream, const char *key,
|
||||
const char *format,
|
||||
va_list args)
|
||||
{
|
||||
|
@ -379,7 +380,7 @@ aisl_header_vprintf(aisl_stream_t stream, const char *key,
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
int
|
||||
aisl_printf(aisl_stream_t stream, const char *format, ...)
|
||||
aisl_printf(aisl_aisl_stream_t stream, const char *format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
|
@ -402,7 +403,7 @@ aisl_printf(aisl_stream_t stream, const char *format, ...)
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
int
|
||||
aisl_vprintf(aisl_stream_t stream, const char *format, va_list args)
|
||||
aisl_vprintf(aisl_aisl_stream_t stream, const char *format, va_list args)
|
||||
{
|
||||
int result;
|
||||
char * r;
|
||||
|
@ -424,7 +425,7 @@ aisl_vprintf(aisl_stream_t stream, const char *format, va_list args)
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
int
|
||||
aisl_write(aisl_stream_t stream, const char *data, int d_len)
|
||||
aisl_write(aisl_aisl_stream_t stream, const char *data, int d_len)
|
||||
{
|
||||
if (d_len < 0)
|
||||
d_len = strlen(data);
|
||||
|
@ -438,7 +439,7 @@ aisl_write(aisl_stream_t stream, const char *data, int d_len)
|
|||
|
||||
__attribute__ ((visibility ("default") ))
|
||||
int
|
||||
aisl_puts(const char *str, aisl_stream_t stream)
|
||||
aisl_puts(const char *str, aisl_aisl_stream_t stream)
|
||||
{
|
||||
return aisl_write( stream, str, strlen(str));
|
||||
}
|
||||
|
|
91
src/stream.h
91
src/stream.h
|
@ -3,74 +3,69 @@
|
|||
|
||||
#include <aisl/types.h>
|
||||
#include <aisl/stream.h>
|
||||
#include "list.h"
|
||||
#include "buffer.h"
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
#define AISL_STREAM(x) ((aisl_stream_t) x)
|
||||
|
||||
#define STREAM_FLAG_OUTPUT_READY (1<<0)
|
||||
#define STREAM_FLAG_OUTPUT_CHUNKED (1<<1)
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
struct pair
|
||||
typedef enum
|
||||
{
|
||||
char *key;
|
||||
char *value;
|
||||
};
|
||||
AISL_STREAM_STATE_IDLE
|
||||
|
||||
typedef struct pair * pair_t;
|
||||
, AISL_STREAM_STATE_WAIT_HEADER
|
||||
, AISL_STREAM_STATE_WAIT_BODY
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
, AISL_STREAM_STATE_READY
|
||||
|
||||
typedef enum {
|
||||
, AISL_STREAM_STATE_SEND_HEADER
|
||||
, AISL_STREAM_STATE_SEND_BODY
|
||||
|
||||
STREAM_REQUEST_METHOD,
|
||||
STREAM_REQUEST_PATH,
|
||||
STREAM_REQUEST_PROTOCOL,
|
||||
|
||||
STREAM_REQUEST_HEADER_KEY, /* HTTP1 header key */
|
||||
STREAM_REQUEST_HEADER_VALUE, /* HTTP1 header value */
|
||||
|
||||
STREAM_REQUEST_CONTENT, /* HTTP1 data value */
|
||||
|
||||
/* states below show stream state
|
||||
* and do not show what data was sent to client
|
||||
* */
|
||||
STREAM_REQUEST_READY,
|
||||
|
||||
STREAM_RESPONSE_HEADER,
|
||||
STREAM_RESPONSE_CONTENT,
|
||||
STREAM_RESPONSE_READY
|
||||
, AISL_STREAM_STATE_DONE
|
||||
|
||||
} aisl_stream_state_t;
|
||||
|
||||
|
||||
/* real wrapper for aisl_stream_t */
|
||||
|
||||
|
||||
#define STREAM(x) ((aisl_stream_t) x)
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
aisl_stream_t
|
||||
aisl_stream_new(struct sockaddr_in *client, int id, aisl_stream_state_t state);
|
||||
aisl_stream_new(aisl_client_t client, int id );
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void
|
||||
aisl_stream_free(aisl_stream_t self);
|
||||
aisl_stream_free(aisl_stream_t stream);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
aisl_stream_t
|
||||
aisl_stream_reset(aisl_stream_t self);
|
||||
/* to be removed ??
|
||||
* aisl_stream_t
|
||||
* aisl_stream_reset(aisl_stream_t stream);
|
||||
*/
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void
|
||||
aisl_stream_set_chunked_output(aisl_stream_t self, bool value);
|
||||
aisl_stream_set_chunked_output(aisl_stream_t stream, bool value);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
bool
|
||||
aisl_stream_get_chunked_output(aisl_stream_t stream);
|
||||
|
||||
|
||||
int32_t
|
||||
aisl_stream_get_buffer_space(aisl_stream_t stream);
|
||||
|
||||
|
||||
int32_t
|
||||
aisl_stream_get_buffer_size(aisl_stream_t stream);
|
||||
|
||||
|
||||
void
|
||||
aisl_stream_get_buffer(aisl_stream_t stream, char ** data, int32_t * size);
|
||||
|
||||
|
||||
void
|
||||
aisl_stream_shift(aisl_stream_t stream, int32_t offset);
|
||||
|
||||
|
||||
bool
|
||||
aisl_stream_has_data(aisl_stream_t stream);
|
||||
|
||||
|
||||
aisl_stream_state_t
|
||||
aisl_stream_get_state(aisl_stream_t stream);
|
||||
|
||||
#endif /* !AISL_STREAM_H */
|
||||
|
|
Loading…
Reference in New Issue