diff --git a/library.mk b/library.mk deleted file mode 100644 index 580e0df..0000000 --- a/library.mk +++ /dev/null @@ -1,65 +0,0 @@ -# -# config.mk -# Löwenware Makefile Config, 2019-03-02 17:35 -# - -PREFIX ?= /usr/local -PKG_CONFIG ?= pkg-config - -PROJECT_NAME = aisl - -# Version - -PROJECT_VERSION_MAJOR = 1 -PROJECT_VERSION_MINOR = 0 -PROJECT_VERSION_TWEAK = 5 -PROJECT_VERSION_LABEL = 0 - -#SRC_DIR = src -#SDK_DIR = sdk -#OUT_DIR = ./build - - -# Source files - -PROJECT_SOURCES := \ - $(SRC_DIR)/instance.c \ - $(SRC_DIR)/server.c \ - $(SRC_DIR)/client.c \ - $(SRC_DIR)/stream.c \ - $(SRC_DIR)/http.c \ - $(SRC_DIR)/ssl.c \ - $(SRC_DIR)/list.c \ - $(SRC_DIR)/str-utils.c \ - $(SRC_DIR)/buffer.c \ - $(SRC_DIR)/types.c \ - - -# includes -PROJECT_INCLUDES = -I./ \ - -I./include \ - `$(PKG_CONFIG) --cflags openssl` \ - -# libraries -PROJECT_LIBRARIES = \ - `$(PKG_CONFIG) --libs openssl` \ - - -# compilation macro options: - -AISL_WITH_DEBUG ?= 0 # disable debug output -AISL_WITH_SSL ?= 1 # enable SSL support -AISL_WITH_STRINGIFIERS ?= 1 # enable *_to_string functions - - -# flags -PROJECT_CFLAGS = -D_POSIX_C_SOURCE=200809L -PROJECT_CFLAGS += -DAISL_WITH_DEBUG=$(AISL_WITH_DEBUG) -PROJECT_CFLAGS += -DAISL_WITH_SSL=$(AISL_WITH_SSL) -PROJECT_CFLAGS += -DAISL_WITH_STRINGIFIERS=$(AISL_WITH_STRINGIFIERS) - -# PROJECT_LDFLAGS = -L - - -# vim:ft=make -# diff --git a/library/) b/library/) deleted file mode 100644 index 2a5d491..0000000 --- a/library/) +++ /dev/null @@ -1,539 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#ifndef AISL_WITHOUT_SSL -#include -#endif - -#include -#include "debug.h" -#include "stream.h" -#include "http.h" -#include "server.h" -#include "instance.h" -#include "client.h" - -#define FLAG_KEEPALIVE (1<<0) -#define FLAG_HANDSHAKE (1<<1) -#define FLAG_CAN_READ (1<<2) -#define FLAG_CAN_WRITE (1<<3) - -#define BUFFER_SIZE (16*1024) - - -static void -aisl_client_close(AislClient client, AislStatus status) -{ - if (client->fd != -1) - { - aisl_raise( - client->server->instance - , (void *)client - , AISL_EVENT_CLIENT_DISCONNECT - , status - ); - - close(client->fd); - shutdown(client->fd, SHUT_RDWR); - client->fd = -1; - } -} - - -static AislStatus -aisl_client_parse(AislClient client, char * data, int32_t size) -{ - AislStatus result = AISL_SUCCESS; - AislStream s = client->stream; - ParserStatus p = HTTP_PARSER_SUCCESS; - - - int32_t bytes_left = size; - - switch (client->http_version) - { - case AISL_HTTP_0_9: - case AISL_HTTP_1_0: - case AISL_HTTP_1_1: - - /* s = client->stream; */ - - while ( p == HTTP_PARSER_SUCCESS ) - { - - switch ( aisl_stream_get_state(s) ) - { - case AISL_STREAM_STATE_IDLE: - p = http_10_parse_request(data, &size, client->stream); - break; - - case AISL_STREAM_STATE_WAIT_HEADER: - p = http_10_parse_header(data, &size, client->stream); - break; - - case AISL_STREAM_STATE_WAIT_BODY: - p = http_10_parse_body(data, &size, client->stream); - 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; - } - - - - break; - - case AISL_HTTP_2_0: - - break; - } - - switch(p) - { - case HTTP_PARSER_READY: - client->flags &= ~FLAG_CAN_READ; - client->flags |= FLAG_CAN_WRITE; - - aisl_raise( - client->server->instance - , (void *) s - , AISL_EVENT_STREAM_REQUEST - , result - ); - break; - - case HTTP_PARSER_ERROR: - /* reply Bad Request here */ - client->stream->http_response = AISL_HTTP_BAD_REQUEST; - - aisl_raise( - client->server->instance - , (void *) s - , AISL_EVENT_STREAM_ERROR - , result - ); - - aisl_client_close(client, result); - - return result; - - default: - break; - } - - if (size) - buffer_shift(&client->in, client->in.used - size); /* reset buffer */ - - return result; -} - - -/* In HTTP 2.0 client->stream will be NULL if stream related data was completely - * parsed. If it is not NULL, then stream expects additional data -> same like - * in mono stream HTTP 1.0 - */ -static AislStatus -aisl_client_input(AislClient client) -{ - int l; - - char * data = &client->in.data[ client->in.used ]; - int32_t size = client->in.size - client->in.used; - - #ifndef AISL_WITHOUT_SSL - if (client->ssl) - { - DPRINTF("SSL_read"); - if ( !(client->flags & FLAG_HANDSHAKE) ) - { - if ( (l = SSL_accept(client->ssl)) != 1 ) - { - l = SSL_get_error(client->ssl, l); - - if (l == SSL_ERROR_WANT_READ || l == SSL_ERROR_WANT_WRITE) - return AISL_IDLE; - - DPRINTF("SSL handshake fail: %s\n", ERR_error_string(l, NULL) ); - - aisl_client_close(client, AISL_EXTCALL_ERROR); - return AISL_EXTCALL_ERROR; - } - - client->flags &= ~FLAG_HANDSHAKE; - } - - l = SSL_read(client->ssl, data, size) ; - } - else - #endif - l = recv( client->fd, data, size, 0); - - if (l > 0) - { - DPRINTF("%d bytes received from client", l); - - data = client->in.data; - size = client->in.used + l; - - client->in.used = size; - - return aisl_client_parse(client, data, size); - } - else if (l<0) - { - #ifndef AISL_WITHOUT_SSL - if (client->ssl) - { - if (SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_READ) - return AISL_IDLE; - } - else - #endif - { - if(errno == EWOULDBLOCK) - return AISL_IDLE; - - DPRINTF("client - %s", strerror(errno)); - } - } - - /* both: client disconnect + on read error */ - /* todo: raise client error here */ - aisl_client_close(client, AISL_SYSCALL_ERROR); - - return AISL_SYSCALL_ERROR; -} - - -static AislStatus -aisl_client_output(AislClient client) -{ - int l; - char * data; - - AislStream s = client->stream; - - /* while stream is not flushed, we should raise event */ - if( aisl_get_output_event(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 - * */ - l = aisl_stream_get_buffer_space(s); - - /* - if (bsz < OUTPUT_BUFFER_SIZE) - { - if (buffer_clear(s->buffer, OUTPUT_BUFFER_SIZE) == 0) - return false; - - s->buffer->size = bsz; - bsz = OUTPUT_BUFFER_SIZE; - } - */ - - if ( !(l < aisl_stream_get_buffer_size(s) / 2) ) - { - aisl_raise( - client->server->instance - , (void*)s - , AISL_EVENT_STREAM_OUTPUT - , AISL_SUCCESS - ); - } - } - - data = aisl_stream_get_data(s, &l); - - if ( !l ) - return AISL_IDLE; - - #ifdef AISL_WITHOUT_SSL - l = send( client->fd, data, l, 0); - #else - l = (client->ssl) ? - SSL_write(client->ssl, data, l) : - send( client->fd, data, l, 0); - #endif - - if (l > 0) - { - aisl_stream_shift(s, l); - - /* - if (s->state == STREAM_RESPONSE_READY && / * flushed * / - s->buffer->size == 0) / * all sent * / - */ - if ( aisl_stream_is_done(s) ) - { - /* buffer_clear(s->buffer, 0); */ - - /* data has been sent */ - - if (client->flags & FLAG_KEEPALIVE) - { - aisl_stream_free(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. - */ - } - - aisl_client_close(client, AISL_SUCCESS); - } - - return AISL_SUCCESS; - } - - /* l < 0 */ - #ifndef AISL_WITHOUT_SSL - if (client->ssl) - { - if ( SSL_get_error(client->ssl, l) == SSL_ERROR_WANT_WRITE ) - return AISL_IDLE; - } - else - #endif - { - if (errno == EWOULDBLOCK) - return AISL_IDLE; - } - - aisl_client_close(client, AISL_SYSCALL_ERROR); - - return AISL_SYSCALL_ERROR; -} - - -AislClient -aisl_client_new( AislServer server, - int fd, - struct sockaddr_in * addr ) -{ - AislClient client; - AislStream stream; - - if ( (client = calloc(1, sizeof (struct aisl_client))) != NULL ) - { - DPRINTF("client alocated"); - memcpy(&client->address, addr, sizeof (struct sockaddr_in)); - client->server = server; - client->fd = fd; - client->next_id = 2; - 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) != -1) - { - DPRINTF("client buffer alocated"); - memcpy(&client->out, &client->in, sizeof (struct buffer)); - - stream = aisl_stream_new(client, 0); - - if (stream != NULL) - { - client->stream = stream; - - DPRINTF("client stream alocated"); - - #ifdef AISL_WITHOUT_SSL - - return client; - - #else - - SSL_CTX * ssl_ctx; - - if ( !server->ssl ) - return client; - - ssl_ctx = aisl_get_ssl_ctx(server->instance, NULL); - - if ((client->ssl = SSL_new(ssl_ctx)) != NULL ) - { - SSL_set_fd(client->ssl, fd); - return client; - } - - #endif - } - } - aisl_client_free(client); - - } - - return NULL; -} - - -void -aisl_client_free(AislClient client) -{ - aisl_client_close(client, AISL_SUCCESS); - - #ifndef AISL_WITHOUT_SSL - if (client->ssl) - SSL_free(client->ssl); - #endif - - if (client->in.data) - free(client->in.data); - - /* out buffer is a shared part of input buffer, so no need to free it */ - - if (client->stream) - aisl_stream_free(client->stream); - - free(client); -} - - -AislStatus -AislClientouch(AislClient client, int32_t timeout) -{ - AislStatus result = AISL_IDLE, - status = AISL_IDLE; - - /* input */ - if (client->flags & FLAG_CAN_READ) - { - if ( (result = aisl_client_input(client)) < 0 ) - return result; - } - - /* output */ - if (client->flags & FLAG_CAN_WRITE) - { - if ( (status = aisl_client_output(client)) < 0 ) - return status; - } - - - /* - if ((client->http_version==AISL_HTTP_2_0 || s->statestreams, client->ostream); - - if ( s->flags & (STREAM_FLAG_OUTPUT_READY | STREAM_FLAG_OUTPUT_CHUNKED) ) - result = client_output(client); - */ - /* update timestamp */ - - if (result == AISL_IDLE) - result = status; - - if (result == AISL_SUCCESS) - client->timestamp = time(NULL); - else - { - time_t now; - time(&now); - - if ( !(now - client->timestamp < timeout) ) - { - aisl_client_close(client, result); - } - } - - - return result; -} - - -int -aisl_client_get_socket(AislClient client) -{ - return client->fd; -} - - -bool -aisl_client_get_keepalive(AislClient client) -{ - return (client->flags & FLAG_KEEPALIVE); -} - - -void -aisl_client_set_keepalive(AislClient client, bool value) -{ - if (value) - client->flags |= FLAG_KEEPALIVE; - else - client->flags &= ~FLAG_KEEPALIVE; -} - - - -/* API Level ---------------------------------------------------------------- */ - -__attribute__ ((visibility ("default") )) -AislServer -aisl_client_get_server(AislClient client) -{ - return client->server; -} - - -__attribute__ ((visibility ("default") )) -bool -aisl_client_is_secure(AislClient client) -{ - #ifdef AISL_WITHOUT_SSL - return false; - #else - return (client->ssl == NULL) ? false : true; - #endif -} - - -__attribute__ ((visibility ("default") )) -bool -aisl_client_is_online(AislClient client) -{ - return (client->fd == -1) ? false : true; -} - - -__attribute__ ((visibility ("default") )) -void -aisl_client_disconnect(AislClient client) -{ - aisl_client_close(client, AISL_SUCCESS); -} - - -__attribute__ ((visibility ("default") )) -AislHttpVersion -aisl_client_get_http_version(AislClient client) -{ - return client->http_version; -} - - -__attribute__ ((visibility ("default") )) -void -aisl_client_get_address( AislClient client, struct sockaddr_in * address) -{ - memcpy(address, &client->address, sizeof (struct sockaddr_in)); -} diff --git a/sdk b/sdk index b9e247b..e00ffe6 160000 --- a/sdk +++ b/sdk @@ -1 +1 @@ -Subproject commit b9e247b88f43dfeae69ac1371a78787950d859ed +Subproject commit e00ffe6f708f1460ca1d2b00d94c739ebb2cb184 diff --git a/tool/compose.c b/tool/compose.c new file mode 100644 index 0000000..e53ef5d --- /dev/null +++ b/tool/compose.c @@ -0,0 +1,84 @@ +/****************************************************************************** + * + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information + * + ******************************************************************************/ + +/** + * @file compose.c + * @author Ilja Kartašov + * @brief + * + * @see https://lowenware.com/ + */ + +#include +#include +#include +#include + +#include "option.h" +#include "compose.h" + + +static int +compose_help(void) +{ + printf("NAME\n"); + printf("\taisl-compose - Compose plain text resource\n\n"); + printf("SYNOPSIS\n"); + printf("\taisl compose [--format=auto|html|js|css] \n\n"); + printf("DESCRIPTION\n"); + printf("\tComposes a plain text resource to its production version."); + printf("OPTIONS\n"); + printf("\t--format=auto|html|js|css\n"); + printf("\t Manually set format for the composer. Usefull when file " + "extension does not allow to determine type automatically.\n\n"); + return 0; +} + + +int +compose_execute(int argc, char **argv) +{ + int result; + struct cstuff_list list; + struct ax_html_options opts = {0}; + + if (g_options & OPTION_FLAG_HELP) { + return compose_help(); + } + + result = -1; + + if (!(argc == 1 || argc == 2)) { + return result; + } + + g_source = argv[0]; + + if (argc == 2) { + g_target = argv[1]; + } + + opts.offset = "\t"; + opts.path = g_target ? g_target : "."; + opts.name = "html"; + opts.minimize = true; + + if (!cstuff_list_init(&list, 128)) { + if (ax_html_import(&list, g_source) == AISL_SUCCESS) { + if (ax_html_export(&list, &opts) == AISL_SUCCESS) { + result = 0; + } else { + fprintf(stderr, "Export failed\n"); + } + } else { + fprintf(stderr, "Import failed: %s\n", strerror(errno)); + } + cstuff_list_release(&list, (CStuffListFree)ax_html_free); + } + + return result; +} diff --git a/tool/compose.h b/tool/compose.h new file mode 100644 index 0000000..d5e04fc --- /dev/null +++ b/tool/compose.h @@ -0,0 +1,23 @@ +/****************************************************************************** + * + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information + * + ******************************************************************************/ + +/** + * @file compose.h + * @author Ilja Kartašov + * @brief + * + * @see https://lowenware.com/ + */ + +#ifndef COMPOSE_H_006245E9_DAFB_4160_AB48_2268FA6E0769 +#define COMPOSE_H_006245E9_DAFB_4160_AB48_2268FA6E0769 + + +int +compose_execute(int argc, char **argv); + +#endif /* !COMPOSE_H */ diff --git a/tool/globals.h b/tool/globals.h new file mode 100644 index 0000000..1b2c782 --- /dev/null +++ b/tool/globals.h @@ -0,0 +1,23 @@ +/****************************************************************************** + * + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information + * + ******************************************************************************/ + +/** + * @file globals.h + * @author Ilja Kartašov + * @brief + * + * @see https://lowenware.com/ + */ + +#ifndef GLOBALS_H_ECAB54AF_855F_408C_9CC1_65B994859848 +#define GLOBALS_H_ECAB54AF_855F_408C_9CC1_65B994859848 + +#include + +extern uint32_t g_options; + +#endif /* !GLOBALS_H */ diff --git a/tool/main.c b/tool/main.c new file mode 100644 index 0000000..fd1c666 --- /dev/null +++ b/tool/main.c @@ -0,0 +1,40 @@ +/****************************************************************************** + * + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information + * + ******************************************************************************/ + +/** + * @file main.c + * @author Ilja Kartašov + * @brief + * + * @see https://lowenware.com/ + */ + +#include +#include "option.h" +#include "compose.h" + + + +int +main(int argc, char **argv) +{ + int result; + + if ((result = option_read_args(argc, argv)) != -1) { + switch (g_options & 0xFF) { + case OPTION_COMMAND_COMPOSE: + if (!compose_execute(argc - result, &argv[result])) + return 0; + break; + default: + result = -1; + break; + } + } + printf("For usage guideance run `%s --help`\n", argv[0]); + return result; +} diff --git a/tool/option.c b/tool/option.c new file mode 100644 index 0000000..32b3f7c --- /dev/null +++ b/tool/option.c @@ -0,0 +1,72 @@ +/****************************************************************************** + * + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information + * + ******************************************************************************/ + +/** + * @file option.c + * @author Ilja Kartašov + * @brief + * + * @see https://lowenware.com/ + */ + +#include +#include +#include +#include "option.h" + +uint32_t g_options = 0; +const char *g_format = NULL; +const char *g_source = NULL; +const char *g_target = NULL; + + +static void +option_set_command(int command) +{ + if (!(g_options & 0xFF)) { + g_options |= command; + } +} + + +int +option_read_args(int argc, char **argv) +{ + int i; + char c = 0; + + for (i = 1; i < argc; i++) { + switch (c) { + case 'f': + g_format = argv[i]; + break; + + default: + if (strcmp(argv[i], "-f") == 0) { + c = 'f'; + } else if (!strncmp(argv[i], "--format=", 9)) { + g_format = &argv[i][9]; + } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { + g_options |= OPTION_FLAG_HELP; + } else if (!strcmp(argv[i], "compose")) { + option_set_command(OPTION_COMMAND_COMPOSE); + } else { + return i; + } + continue; + } + c = 0; + } + + if (c) { + fprintf(stderr, "No value for -%c argument", c); + return -1; + } + + return i - 1; +} + diff --git a/tool/option.h b/tool/option.h new file mode 100644 index 0000000..a888b98 --- /dev/null +++ b/tool/option.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information + * + ******************************************************************************/ + +/** + * @file option.h + * @author Ilja Kartašov + * @brief + * + * @see https://lowenware.com/ + */ + +#ifndef OPTION_H_FC8ABD38_1EF9_4DD2_A94A_3C4F53E0A437 +#define OPTION_H_FC8ABD38_1EF9_4DD2_A94A_3C4F53E0A437 + +#include + + +#define OPTION_FLAG_HELP (1 << 16) + +enum { + OPTION_COMMAND_UNKNOWN + , OPTION_COMMAND_COMPOSE +}; + + +extern uint32_t g_options; +extern const char *g_format; +extern const char *g_source; +extern const char *g_target; + + +int +option_read_args(int argc, char **argv); + +#endif /* !OPTION_H */