Refactored client module

This commit is contained in:
Ilja Kartašov 2019-03-12 09:26:44 +01:00
parent 0b05984f85
commit a49e32dff8
7 changed files with 352 additions and 258 deletions

View File

@ -14,6 +14,10 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#ifndef AISL_WITHOUT_SSL
#include <openssl/ssl.h>
#endif
/* type casts */ /* type casts */
#define AISL_CALLBACK(x) ((aisl_callback_t) x) #define AISL_CALLBACK(x) ((aisl_callback_t) x)
@ -37,10 +41,12 @@ typedef struct aisl_stream * aisl_stream_t;
typedef void typedef void
(* aisl_callback_t) (void); (* aisl_callback_t) (void);
/* status return codes */ /* status return codes */
typedef enum typedef enum
{ {
AISL_EXTCALL_ERROR = -3 AISL_INPUT_ERROR = -4
, AISL_EXTCALL_ERROR = -3
, AISL_SYSCALL_ERROR = -2 , AISL_SYSCALL_ERROR = -2
, AISL_MALLOC_ERROR = -1 , AISL_MALLOC_ERROR = -1

View File

@ -8,13 +8,18 @@
struct buffer struct buffer
{ {
char * data; char * data;
size_t size; int32_t size;
int32_t length;
}; };
typedef struct buffer * buffer_t; typedef struct buffer * buffer_t;
#define BUFFER_EOB ( ~0L ) #define BUFFER_EOB ( ~0L )
int
buffer_init( buffer_t buffer, int32_t size );
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
buffer_t buffer_t

View File

@ -6,9 +6,14 @@
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#ifndef AISL_WITHOUT_SSL
#include <openssl/err.h>
#endif
#include <aisl/aisl.h> #include <aisl/aisl.h>
#include "list.h"
#include "stream.h" #include "stream.h"
#include "http.h"
#include "buffer.h"
#include "client.h" #include "client.h"
#define FLAG_KEEPALIVE (1<<0) #define FLAG_KEEPALIVE (1<<0)
@ -16,32 +21,30 @@
#define FLAG_CAN_READ (1<<2) #define FLAG_CAN_READ (1<<2)
#define FLAG_CAN_WRITE (1<<3) #define FLAG_CAN_WRITE (1<<3)
#define BUFFER_SIZE (16*1024)
struct aisl_client struct aisl_client
{ {
struct sockaddr_in address; /**< Client's address structure */ struct sockaddr_in address; /**< Client's address structure. */
aisl_server_t server; /**< Server instance associated with client */ aisl_server_t server; /**< Server instance. */
list_t streams; /**< list of client streams */ struct buffer in; /**< Client's input buffer. */
struct buffer in; /**< Client's input buffer */ struct buffer out; /**< Client's output buffer. */
struct buffer out; /**< Client's output buffer */
#ifndef AISL_WITHOUT_SSL #ifndef AISL_WITHOUT_SSL
SSL * ssl; /**< SSL pointer for encrypted connections */ SSL * ssl; /**< SSL pointer for HTTPS. */
#endif #endif
time_t timestamp; /**< Last communication timestamp */ time_t timestamp; /**< Last communication timestamp. */
aisl_stream_t stream; /**< Pending client's stream */ aisl_stream_t stream; /**< Pending client's stream. */
/* int next_id; / **< stream id generator (even)*/ int next_id; /**< Stream id generator (even). */
/* int istream; / **< input stream id */ int flags; /**< Client's flag bitmask. */
/* int ostream; / **< output stream id */ int fd; /**< Client's socket descriptor. */
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 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; bool result;
va_list vl_args; va_list vl_args;
@ -57,52 +60,73 @@ aisl_client_raise_event(aisl_client_t client, aisl_event_t event, ...)
static aisl_status_t 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 */ aisl_stream_t s;
while ( p_status == PARSER_PENDING ) http_parser_t p = HTTP_PARSER_PENDING;
{
switch(s->state) int32_t bytes_left = size;
switch (client->http_version)
{
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);
break;
case STREAM_REQUEST_HEADER_KEY: switch ( aisl_stream_get_state(s) )
p_status = parse_request_header_key(client, &ptr, &l); {
break; case AISL_STREAM_STATE_IDLE:
case STREAM_REQUEST_HEADER_VALUE: p = http_10_parse_request(data, &size, client);
p_status = parse_request_header_value(client, &ptr, &l); break;
break;
case STREAM_REQUEST_CONTENT: case AISL_STREAM_STATE_WAIT_HEADER:
p_status = parse_request_content(client, &ptr, &l); p = http_10_parse_header(data, &size, client);
break; break;
default: case AISL_STREAM_STATE_WAIT_BODY:
p_status = PARSER_FINISHED; p = http_10_parse_body(data, &size, client);
/* this is error actually */ break;
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)
{ {
/* reply Bad Request here */ client->flags &= ~FLAG_CAN_READ;
client_close(client); client->flags |= FLAG_CAN_WRITE;
} }
else if (l)
{ break;
buffer_shift(s->buffer, s->buffer->size-l); /* reset buffer */
} case AISL_HTTP_2_0:
break;
}
if (p == HTTP_PARSER_ERROR)
{
/* reply Bad Request here */
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) aisl_client_input(aisl_client_t client)
{ {
int l; int l;
parser_status_t p_status = PARSER_PENDING;
aisl_stream_t s = client->stream;
char * data = &client->in.data[ client->in.length ]; 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 #ifndef AISL_WITHOUT_SSL
if (client->ssl) if (client->ssl)
@ -174,40 +196,30 @@ aisl_client_input(aisl_client_t client)
/* both: client disconnect + on read error */ /* both: client disconnect + on read error */
/* todo: raise client error here */ /* todo: raise client error here */
client_close(client); aisl_client_close(client);
return AISL_SYSCALL_ERROR; return AISL_SYSCALL_ERROR;
} }
static bool static aisl_status_t
aisl_client_output(aisl_client_t client) aisl_client_output(aisl_client_t client)
{ {
if (client->fd < 0) int l;
{ char * data;
fprintf(stderr, "[aisl] assertion !(client->fd<0) failed\n");
return true;
}
stream_t s; aisl_stream_t s = client->stream;
int l;
s = list_index(client->streams, client->ostream);
/*
if (!s->c_length_unknown && s->buffer && s->buffer->len)
buffer_move(gBuffer, s->buffer);
*/
/* while stream is not flushed, we should raise event */ /* 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 ) /* in case of chunked output ( subscription for AISL_STREAM_OUTPUT event )
* stream buffer will be initialized with OUTPUT_BUFFER_SIZE size, but * stream buffer will be initialized with OUTPUT_BUFFER_SIZE size, but
* buffer->size will be used to carry amount of stored bytes * 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 (bsz < OUTPUT_BUFFER_SIZE)
{ {
if (buffer_clear(s->buffer, OUTPUT_BUFFER_SIZE) == 0) if (buffer_clear(s->buffer, OUTPUT_BUFFER_SIZE) == 0)
@ -216,90 +228,108 @@ aisl_client_output(aisl_client_t client)
s->buffer->size = bsz; s->buffer->size = bsz;
bsz = OUTPUT_BUFFER_SIZE; bsz = OUTPUT_BUFFER_SIZE;
} }
*/
if ( (l = bsz - s->buffer->size) > OUTPUT_BUFFER_SIZE / 2 ) if ( !(l < aisl_stream_get_buffer_size(s) / 2) )
aisl_raise_event( client->server->owner, s, AISL_STREAM_OUTPUT, l); aisl_raise(
aisl_server_get_instance(client->server),
s,
AISL_EVENT_STREAM_OUTPUT,
l
);
} }
if (s->buffer->size == 0) aisl_stream_get_buffer(s, &data, &l);
return false;
if ( !l )
return AISL_IDLE;
l = (client->ssl) ? l = (client->ssl) ?
SSL_write(client->ssl, s->buffer->data, s->buffer->size) : SSL_write(client->ssl, data, l) :
send( client->fd, s->buffer->data, s->buffer->size, 0); send( client->fd, data, l, 0);
if (l > 0) if (l > 0)
{ {
buffer_shift(s->buffer, l); aisl_stream_shift(s, l);
if (s->state == STREAM_RESPONSE_READY && /* flushed */
s->buffer->size == 0) /* all sent */ /*
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 */ /* data has been sent */
/*
if (client->protocol == AISL_HTTP_2_0)
{
} if (client->flags & FLAG_KEEPALIVE)
else*/
if (client->flags & CLIENT_FLAG_KEEPALIVE)
{ {
list_remove(client->streams, s); aisl_stream_free(s);
stream_free(s);
s = stream_new((struct sockaddr_in *) client, client->next_id++, STREAM_REQUEST_METHOD ); client->stream = aisl_stream_new(client, client->next_id++);
list_append(client->streams, s); if (client->stream != NULL )
} return AISL_SUCCESS;
else
{ /* in case of malloc error it will not be error as long as request was
client_close(client); * handled and we just close the connection.
*/
} }
aisl_client_close(client);
} }
return true;
return AISL_SUCCESS;
} }
/* l < 0 */ /* l < 0 */
if (client->ssl) if (client->ssl)
{ {
if ( SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_WRITE ) if ( SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_WRITE )
return false; return AISL_IDLE;
} }
else else
{ {
if (errno == EWOULDBLOCK) 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_t
aisl_client_new( aisl_server_t server, aisl_client_new( aisl_server_t server,
int fd, int fd,
struct sockaddr_in * addr, struct sockaddr_in * addr,
SSL_CTX * ssl_ctx ) 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_client_t client;
aisl_stream_t stream; 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)); memcpy(&client->address, addr, sizeof(struct sockaddr_in));
client->server = server;
client->fd = fd; client->fd = fd;
client->next_id = 2; client->next_id = 2;
client->protocol = AISL_HTTP_1_0; client->http_version = AISL_HTTP_1_0;
client->timestamp = time(NULL); client->timestamp = time(NULL);
client->flags = FLAG_KEEPALIVE | FLAG_HANDSHAKE | FLAG_CAN_READ; 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) 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 */ /* 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); free(client);
} }
@ -355,26 +386,26 @@ aisl_client_free(aisl_client_t client)
aisl_status_t aisl_status_t
aisl_client_touch(aisl_client_t client) aisl_client_touch(aisl_client_t client)
{ {
aisl_status_t result, status; aisl_status_t result = AISL_IDLE,
aisl_stream_t s = client->stream; status = AISL_IDLE;
/* input */ /* input */
if (client->flags & FLAG_CAN_READ) if (client->flags & FLAG_CAN_READ)
{ {
if ( (result = client_input(client)) < 0 ) if ( (result = aisl_client_input(client)) < 0 )
return result; return result;
} }
/* output */ /* output */
if (client->flags & FLAG_CAN_WRITE) if (client->flags & FLAG_CAN_WRITE)
{ {
if ( (status = client_output(client)) < 0 ) if ( (status = aisl_client_output(client)) < 0 )
return status; 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; (client_input(client)) ) result = true;
*/ */
/* output */ /* output */
@ -389,7 +420,7 @@ aisl_client_touch(aisl_client_t client)
if (result == AISL_IDLE) if (result == AISL_IDLE)
result = status; result = status;
if (result = AISL_SUCCESS) if (result == AISL_SUCCESS)
client->timestamp = time(NULL); client->timestamp = time(NULL);
return result; return result;
@ -405,7 +436,7 @@ aisl_client_is_timed_out(aisl_client_t client, uint32_t timeout)
if ( !(now - client->timestamp < 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); aisl_client_close(client);
return true; return true;
} }
@ -449,7 +480,7 @@ aisl_client_close(aisl_client_t client)
{ {
if (client->fd != -1) if (client->fd != -1)
{ {
aisl_client_raise_event( client, AISL_CLIENT_DISCONNECT ); aisl_client_raise( client, AISL_EVENT_CLIENT_DISCONNECT );
close(client->fd); close(client->fd);
shutdown(client->fd, SHUT_RDWR); shutdown(client->fd, SHUT_RDWR);

View File

@ -7,7 +7,7 @@
#define AISL_CLIENT(x) ((aisl_client_t) x) #define AISL_CLIENT(x) ((aisl_client_t) x)
#ifndef AISL_WITHOUT_SSL
/** /**
* @brief Constructor for #aisl_client_t instance. * @brief Constructor for #aisl_client_t instance.
* @param server an #aisl_server_t instance pointer. * @param server an #aisl_server_t instance pointer.
@ -20,6 +20,20 @@ aisl_client_new( aisl_server_t server,
int fd, int fd,
struct sockaddr_in * addr, struct sockaddr_in * addr,
SSL_CTX * ssl_ctx); 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
/** /**

42
src/http.h Normal file
View File

@ -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 */

View File

@ -2,141 +2,142 @@
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include "buffer.h"
#include "stream.h" #include "stream.h"
#include "globals.h"
#include "client.h" #define FLAG_OUTPUT_READY (1<<0)
#include "handle.h" #define FLAG_OUTPUT_CHUNKED (1<<1)
struct stream
struct aisl_stream
{ {
struct aisl_stream _public; aisl_client_t client;
/* private data */ struct buffer buffer;
list_t headers; /* request headers */
buffer_t buffer;
const char *c_type; const char *content_type;
aisl_http_response_t response; size_t content_length;
stream_state_t state; int32_t content_offset;
uint32_t c_length;
uint32_t c_offset;
int id; int id;
int flags; int flags;
aisl_http_response_t response;
aisl_stream_state_t state;
bool c_length_unknown; bool c_length_unknown;
}; };
static void 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(stream->key) free(stream->key);
if(self->value) free(self->value); if(stream->value) free(stream->value);
free(self); free(stream);
} }
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
stream_t aisl_stream_t
stream_new(struct sockaddr_in *client, int id, stream_state_t state) 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 */ /* public data */
ASTREAM(self)->client = client; ASTREAM(stream)->client = client;
ASTREAM(self)->host = NULL; ASTREAM(stream)->host = NULL;
ASTREAM(self)->path = NULL; ASTREAM(stream)->path = NULL;
ASTREAM(self)->query = NULL; ASTREAM(stream)->query = NULL;
ASTREAM(self)->scheme = NULL; ASTREAM(stream)->scheme = NULL;
ASTREAM(self)->u_ptr = NULL; ASTREAM(stream)->u_ptr = NULL;
ASTREAM(self)->request_method = AISL_HTTP_GET; ASTREAM(stream)->request_method = AISL_HTTP_GET;
/* private data */ /* private data */
self->headers = NULL; /* request headers */ stream->headers = NULL; /* request headers */
self->buffer = buffer_new(0); stream->buffer = buffer_new(0);
self->c_type = NULL; stream->c_type = NULL;
self->response = AISL_HTTP_OK; stream->response = AISL_HTTP_OK;
self->state = STREAM_REQUEST_METHOD; stream->state = STREAM_REQUEST_METHOD;
self->c_length = 0; stream->c_length = 0;
self->c_offset = 0; /* headers length */ stream->c_offset = 0; /* headers length */
self->id = id; stream->id = id;
self->c_length_unknown = true; stream->c_length_unknown = true;
self->flags = 0; stream->flags = 0;
} }
return self; return stream;
} }
/* /*
stream_t aisl_stream_t
stream_reset(stream_t self) stream_reset(aisl_stream_t stream)
{ {
if (ASTREAM(self)->path) if (ASTREAM(stream)->path)
{ {
free( (char*) ASTREAM(self)->path); free( (char*) ASTREAM(stream)->path);
ASTREAM(self)->path = NULL; ASTREAM(stream)->path = NULL;
} }
if (ASTREAM(self)->query) if (ASTREAM(stream)->query)
{ {
free( (char*) ASTREAM(self)->query); free( (char*) ASTREAM(stream)->query);
ASTREAM(self)->query = NULL; ASTREAM(stream)->query = NULL;
} }
ASTREAM(self)->u_ptr = NULL; ASTREAM(stream)->u_ptr = NULL;
ASTREAM(self)->request_method = AISL_HTTP_GET; ASTREAM(stream)->request_method = AISL_HTTP_GET;
if (self->headers) if (stream->headers)
{ {
list_free(self->headers, (list_destructor_t) pair_free); list_free(stream->headers, (list_destructor_t) pair_free);
self->headers = NULL; stream->headers = NULL;
} }
self->c_type = NULL; stream->c_type = NULL;
self->response = AISL_HTTP_OK; stream->response = AISL_HTTP_OK;
self->state = STREAM_REQUEST_METHOD; stream->state = STREAM_REQUEST_METHOD;
self->c_length = 0; stream->c_length = 0;
self->c_offset = 0; / * headers length * / stream->c_offset = 0; / * headers length * /
self->c_length_unknown = true; stream->c_length_unknown = true;
self->flags = 0; stream->flags = 0;
return self; return stream;
} }
*/ */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
void void
stream_free(stream_t self) stream_free(aisl_stream_t stream)
{ {
if (self->buffer) buffer_free(self->buffer); if (stream->buffer) buffer_free(stream->buffer);
if (self->headers) list_free(self->headers, (list_destructor_t) pair_free); if (stream->headers) list_free(stream->headers, (list_destructor_t) pair_free);
if (ASTREAM(self)->path) free( (char*) ASTREAM(self)->path); if (ASTREAM(stream)->path) free( (char*) ASTREAM(stream)->path);
if (ASTREAM(self)->query) free( (char*) ASTREAM(self)->query); if (ASTREAM(stream)->query) free( (char*) ASTREAM(stream)->query);
aisl_handle_t hd = ((client_t) ASTREAM(self)->client)->server->owner; aisl_handle_t hd = ((client_t) ASTREAM(stream)->client)->server->owner;
aisl_raise_event(hd, self, AISL_STREAM_CLOSE); aisl_raise_event(hd, stream, AISL_STREAM_CLOSE);
ASTREAM(self)->u_ptr = NULL; ASTREAM(stream)->u_ptr = NULL;
aisl_remove_listeners_for(hd, self); aisl_remove_listeners_for(hd, stream);
free(self); free(stream);
} }
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
int 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") )) __attribute__ ((visibility ("default") ))
void void
aisl_cancel(aisl_stream_t s) aisl_cancel(aisl_aisl_stream_t s)
{ {
client_close( (client_t) s->client ); client_close( (client_t) s->client );
} }
@ -145,7 +146,7 @@ aisl_cancel(aisl_stream_t s)
__attribute__ ((visibility ("default") )) __attribute__ ((visibility ("default") ))
bool bool
aisl_is_secure(aisl_stream_t s) aisl_is_secure(aisl_aisl_stream_t s)
{ {
client_t cli = (client_t) s->client; client_t cli = (client_t) s->client;
@ -156,7 +157,7 @@ aisl_is_secure(aisl_stream_t s)
__attribute__ ((visibility ("default") )) __attribute__ ((visibility ("default") ))
void * void *
aisl_get_context(aisl_stream_t s) aisl_get_context(aisl_aisl_stream_t s)
{ {
return s->u_ptr; return s->u_ptr;
} }
@ -165,7 +166,7 @@ aisl_get_context(aisl_stream_t s)
__attribute__ ((visibility ("default") )) __attribute__ ((visibility ("default") ))
void 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; s->u_ptr = u_ptr;
} }
@ -174,7 +175,7 @@ aisl_set_context(aisl_stream_t s, void * u_ptr)
__attribute__ ((visibility ("default") )) __attribute__ ((visibility ("default") ))
aisl_client_t aisl_client_t
aisl_get_client(aisl_stream_t s) aisl_get_client(aisl_aisl_stream_t s)
{ {
return s->client; return s->client;
} }
@ -183,7 +184,7 @@ aisl_get_client(aisl_stream_t s)
__attribute__ ((visibility ("default") )) __attribute__ ((visibility ("default") ))
aisl_server_t 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); return (aisl_server_t) (((client_t) s->client)->server);
} }
@ -193,7 +194,7 @@ aisl_get_server(aisl_stream_t s)
__attribute__ ((visibility ("default") )) __attribute__ ((visibility ("default") ))
aisl_http_version_t 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; client_t cli = (client_t) s->client;
@ -204,7 +205,7 @@ aisl_get_http_version(aisl_stream_t s)
__attribute__ ((visibility ("default") )) __attribute__ ((visibility ("default") ))
void void
aisl_reject(aisl_stream_t s) aisl_reject(aisl_aisl_stream_t s)
{ {
client_t cli = (client_t) s->client; client_t cli = (client_t) s->client;
@ -216,7 +217,7 @@ aisl_reject(aisl_stream_t s)
static char * static char *
get_response_begin(stream_t stream) get_response_begin(aisl_stream_t stream)
{ {
char * r; char * r;
client_t cli = CLIENT(ASTREAM(stream)->client); client_t cli = CLIENT(ASTREAM(stream)->client);
@ -236,7 +237,7 @@ get_response_begin(stream_t stream)
__attribute__ ((visibility ("default") )) __attribute__ ((visibility ("default") ))
aisl_status_t 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, const char *content_type,
uint32_t content_length) uint32_t content_length)
{ {
@ -284,9 +285,9 @@ aisl_response(aisl_stream_t stream, aisl_http_response_t status_code,
__attribute__ ((visibility ("default") )) __attribute__ ((visibility ("default") ))
aisl_status_t 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 ) if ( ! s->c_length )
{ {
s->c_length = s->buffer->size - s->c_offset - 2; s->c_length = s->buffer->size - s->c_offset - 2;
@ -309,7 +310,7 @@ aisl_flush(aisl_stream_t stream)
__attribute__ ((visibility ("default") )) __attribute__ ((visibility ("default") ))
int 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; int ret;
char * pch; char * pch;
@ -340,7 +341,7 @@ aisl_header(aisl_stream_t stream, const char *key, const char *value)
__attribute__ ((visibility ("default") )) __attribute__ ((visibility ("default") ))
int 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, ...) const char *f_value, ...)
{ {
int ret; int ret;
@ -358,7 +359,7 @@ aisl_header_printf(aisl_stream_t stream, const char *key,
__attribute__ ((visibility ("default") )) __attribute__ ((visibility ("default") ))
int 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, const char *format,
va_list args) va_list args)
{ {
@ -379,7 +380,7 @@ aisl_header_vprintf(aisl_stream_t stream, const char *key,
__attribute__ ((visibility ("default") )) __attribute__ ((visibility ("default") ))
int int
aisl_printf(aisl_stream_t stream, const char *format, ...) aisl_printf(aisl_aisl_stream_t stream, const char *format, ...)
{ {
va_list arg; va_list arg;
va_start(arg, format); va_start(arg, format);
@ -402,7 +403,7 @@ aisl_printf(aisl_stream_t stream, const char *format, ...)
__attribute__ ((visibility ("default") )) __attribute__ ((visibility ("default") ))
int 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; int result;
char * r; char * r;
@ -424,7 +425,7 @@ aisl_vprintf(aisl_stream_t stream, const char *format, va_list args)
__attribute__ ((visibility ("default") )) __attribute__ ((visibility ("default") ))
int 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) if (d_len < 0)
d_len = strlen(data); d_len = strlen(data);
@ -438,7 +439,7 @@ aisl_write(aisl_stream_t stream, const char *data, int d_len)
__attribute__ ((visibility ("default") )) __attribute__ ((visibility ("default") ))
int 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)); return aisl_write( stream, str, strlen(str));
} }

View File

@ -3,74 +3,69 @@
#include <aisl/types.h> #include <aisl/types.h>
#include <aisl/stream.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) typedef enum
#define STREAM_FLAG_OUTPUT_CHUNKED (1<<1)
/* -------------------------------------------------------------------------- */
struct pair
{ {
char *key; AISL_STREAM_STATE_IDLE
char *value;
};
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, , AISL_STREAM_STATE_DONE
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_t; } aisl_stream_state_t;
/* real wrapper for aisl_stream_t */
#define STREAM(x) ((aisl_stream_t) x)
/* -------------------------------------------------------------------------- */
aisl_stream_t 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 void
aisl_stream_free(aisl_stream_t self); aisl_stream_free(aisl_stream_t stream);
/* -------------------------------------------------------------------------- */
aisl_stream_t /* to be removed ??
aisl_stream_reset(aisl_stream_t self); * aisl_stream_t
* aisl_stream_reset(aisl_stream_t stream);
*/
/* -------------------------------------------------------------------------- */
void 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 */ #endif /* !AISL_STREAM_H */