Esempio n. 1
0
static int
compile_append_text(lwan_tpl_t *tpl, strbuf_t *buf)
{
    int length = strbuf_get_length(buf);
    if (!length)
        return 0;

    lwan_tpl_chunk_t *chunk = malloc(sizeof(*chunk));
    if (!chunk)
        return -ENOMEM;

    if (length == 1) {
        chunk->action = TPL_ACTION_APPEND_CHAR;
        chunk->data = (void *)((uintptr_t)strbuf_get_buffer(buf)[0]);
    } else {
        chunk->action = TPL_ACTION_APPEND;
        chunk->data = strdup(strbuf_get_buffer(buf));
    }

    chunk->next = tpl->chunks;
    tpl->chunks = chunk;
    tpl->minimum_size += strbuf_get_length(buf);
    strbuf_reset(buf);

    return 0;
}
Esempio n. 2
0
static int
compile_append_var(lwan_tpl_t *tpl, strbuf_t *buf)
{
    lwan_tpl_chunk_t *chunk = malloc(sizeof(*chunk));
    if (!chunk)
        return -ENOMEM;

    char *variable = strbuf_get_buffer(buf);
    int length = strbuf_get_length(buf) - 1;

    switch (*variable) {
    case '>': {
        char template_file[PATH_MAX];
        snprintf(template_file, sizeof(template_file), "%s.tpl", variable + 1);

        lwan_tpl_t *included = lwan_tpl_compile(template_file);
        if (!included)
            return -ENOENT;
        chunk->action = TPL_ACTION_APPLY_TPL;
        chunk->data = included;
        break;
    }
    case '#':
        chunk->action = TPL_ACTION_LIST_START_ITER;
        chunk->data = strdup(variable + 1);
        break;
    case '/':
        if (variable[length] == '?') {
            chunk->action = TPL_ACTION_END_IF_VARIABLE_NOT_EMPTY;
            variable[length] = '\0';
        } else {
            chunk->action = TPL_ACTION_LIST_END_ITER;
        }
        chunk->data = strdup(variable + 1);
        break;
    default:
        if (variable[length] == '?') {
            chunk->action = TPL_ACTION_IF_VARIABLE_NOT_EMPTY;
            variable[length] = '\0';
        } else {
            chunk->action = TPL_ACTION_VARIABLE;
        }
        chunk->data = strdup(variable);
    }

    chunk->next = tpl->chunks;
    tpl->chunks = chunk;
    tpl->minimum_size += strbuf_get_length(buf);
    strbuf_reset(buf);

    return 0;
}
Esempio n. 3
0
int main(int argc, char *argv[])
{
    if (argc < 2) {
        printf("Usage: %s file.tpl\n", argv[0]);
        return 1;
    }

    printf("*** Compiling template...\n");
    lwan_tpl_t *tpl = lwan_tpl_compile(argv[1]);
    if (!tpl)
        return 1;

    printf("*** Applying template...\n");
    strbuf_t *applied = lwan_tpl_apply(tpl, var_getter, NULL);
    puts(strbuf_get_buffer(applied));

    strbuf_free(applied);
    lwan_tpl_free(tpl);    
    return 0;
}
Esempio n. 4
0
    size_t header_len = lwan_prepare_response_header(request, status, headers, sizeof(headers));
    if (UNLIKELY(!header_len))
        return lwan_default_response(request, HTTP_INTERNAL_ERROR);

    if (request->method == HTTP_HEAD) {
        if (UNLIKELY(write(request->fd, headers, header_len) < 0)) {
            perror("write");
            return false;
        }
        return true;
    }

    struct iovec response_vec[] = {
        { .iov_base = headers, .iov_len = header_len },
        { .iov_base = strbuf_get_buffer(request->response.buffer), .iov_len = strbuf_get_length(request->response.buffer) }
    };

    if (UNLIKELY(writev(request->fd, response_vec, N_ELEMENTS(response_vec)) < 0)) {
        perror("writev");
        return false;
    }

    return true;
}

bool
lwan_default_response(lwan_request_t *request, lwan_http_status_t status)
{
    static const char *default_response = "<html><head><style>" \
        "body{" \
Esempio n. 5
0
lwan_tpl_chunk_t *
lwan_tpl_apply_until(lwan_tpl_chunk_t *chunks, strbuf_t *buf,
    char *(*var_get)(const char *name, void *data), void *var_get_data,
    bool (*until)(lwan_tpl_chunk_t *chunk, void *data), void *until_data)
{
    lwan_tpl_chunk_t *chunk = chunks;

    for (; chunk; chunk = chunk->next) {
        if (until(chunk, until_data))
            break;

        switch (chunk->action) {
        case TPL_ACTION_APPEND:
            strbuf_append_str(buf, chunk->data, 0);
            break;
        case TPL_ACTION_APPEND_CHAR:
            strbuf_append_char(buf, (char)(uintptr_t)chunk->data);
            break;
        case TPL_ACTION_VARIABLE:
            {
                char *tmp = var_get((const char*)chunk->data, var_get_data);
                strbuf_append_str(buf, tmp, 0);
                free(tmp);
            }
            break;
        case TPL_ACTION_LIST_START_ITER:
            strbuf_append_str(buf, "[begin_iter:", 0);
            strbuf_append_str(buf, chunk->data, 0);
            strbuf_append_str(buf, "]", 0);
            break;
        case TPL_ACTION_LIST_END_ITER:
            strbuf_append_str(buf, "[end_iter:", 0);
            strbuf_append_str(buf, chunk->data, 0);
            strbuf_append_str(buf, "]", 0);
            break;
        case TPL_ACTION_IF_VARIABLE_NOT_EMPTY:
            {
                const char *var_name = (const char*)chunk->data;
                char *tmp = var_get(var_name, var_get_data);
                if (tmp && *tmp) {
                    chunk = lwan_tpl_apply_until(chunk->next, buf, var_get, var_get_data, 
                                        until_not_empty, chunk->data);
                } else {
                    for (chunk = chunk->next; chunk; chunk = chunk->next) {
                        if (chunk->action == TPL_ACTION_END_IF_VARIABLE_NOT_EMPTY && !strcmp(chunk->data, var_name))
                            break;
                    }
                }
                free(tmp);
            }
            break;
        case TPL_ACTION_END_IF_VARIABLE_NOT_EMPTY:
            /* Shouldn't happen */
            break;
        case TPL_ACTION_APPLY_TPL:
            {
                strbuf_t *tmp = lwan_tpl_apply(chunk->data, var_get, var_get_data);
                strbuf_append_str(buf, strbuf_get_buffer(tmp), strbuf_get_length(tmp));
                strbuf_free(tmp);
            }
        }
    }

    return chunk;
}
Esempio n. 6
0
lwan_tpl_t *
lwan_tpl_compile(const char *filename)
{
    lwan_tpl_t *tpl;
    strbuf_t *buf;
    FILE *file;
    int state = STATE_DEFAULT;
    char error_msg[512];
    
    tpl = calloc(1, sizeof(*tpl));
    if (!tpl)
        return NULL;

    buf = strbuf_new();
    if (!buf) {
        free(tpl);
        return NULL;
    }
    
    file = fopen(filename, "r");
    if (!file) {
        strbuf_free(buf);
        free(tpl);
        return NULL;
    }

    int line = 1;
    int column = 1;
    char ch;
    while ((ch = fgetc(file)) != EOF) {
        if (ch == '\n') {
            if (state == STATE_DEFAULT)
                strbuf_append_char(buf, '\n');

            line++;
            column = 1;
            continue;
        }
        ++column;

        switch (state) {
        case STATE_DEFAULT:
            if (ch == '{') {
                state = STATE_FIRST_BRACE;
                continue;
            }

            strbuf_append_char(buf, ch);
            break;
        case STATE_FIRST_BRACE:
            if (ch == '{') {
                switch (compile_append_text(tpl, buf)) {
                case -ENOMEM:
                    PARSE_ERROR("Out of memory while appending text.");
                }

                state = STATE_SECOND_BRACE;
                continue;
            }

            strbuf_append_char(buf, '{');
            strbuf_append_char(buf, ch);
            state = STATE_DEFAULT;
            break;
        case STATE_SECOND_BRACE:
            if (ch == '{')
                PARSE_ERROR("Unexpected open brace.");

            if (ch == '}') {
                state = STATE_FIRST_CLOSING_BRACE;
                continue;
            }

            strbuf_append_char(buf, ch);
            break;
        case STATE_FIRST_CLOSING_BRACE:
            if (ch == '}') {
                state = STATE_SECOND_CLOSING_BRACE;
                continue;
            }
            PARSE_ERROR("Closing brace expected.");
        case STATE_SECOND_CLOSING_BRACE:
            if (ch == '}')
                PARSE_ERROR("Unexpected close brace.");

            if (strbuf_get_length(buf) == 0)
                PARSE_ERROR("Expecting variable name.");

            switch (compile_append_var(tpl, buf)) {
            case -ENOMEM:
                PARSE_ERROR("Out of memory while appending variable.");
            case -ENOENT:
                PARSE_ERROR("Cannot find included template: ``%s''.", strbuf_get_buffer(buf) + 1);
            }

            if (ch == '{') {
                state = STATE_FIRST_BRACE;
                continue;
            }

            strbuf_append_char(buf, ch);
            state = STATE_DEFAULT;
        }
    }

    switch (state) {
    case STATE_DEFAULT:
        switch (compile_append_text(tpl, buf)) {
        case -ENOMEM:
            PARSE_ERROR("Out of memory while appending text.");
        }
        break;
    case STATE_FIRST_BRACE:
    case STATE_SECOND_BRACE:
        PARSE_ERROR("Expecting close brace.");
    case STATE_FIRST_CLOSING_BRACE:
        PARSE_ERROR("Expecting second close brace.");
    case STATE_SECOND_CLOSING_BRACE:
        if (strbuf_get_length(buf) == 0)
            PARSE_ERROR("Expecting variable name.");

        switch (compile_append_var(tpl, buf)) {
        case -ENOMEM:
            PARSE_ERROR("Out of memory while appending variable.");
        case -ENOENT:
            PARSE_ERROR("Cannot find included template: ``%s''.", strbuf_get_buffer(buf));
        }
    }

    lwan_tpl_chunk_t *last = malloc(sizeof(*last));
    if (!last)
        goto error;
    last->action = TPL_ACTION_LAST;
    last->data = NULL;
    last->next = tpl->chunks;
    tpl->chunks = last;

    lwan_tpl_chunk_t *prev = NULL;
    while (tpl->chunks) {
        lwan_tpl_chunk_t *next = tpl->chunks->next;
        tpl->chunks->next = prev;
        prev = tpl->chunks;
        tpl->chunks = next;
    }
    tpl->chunks = prev;

    strbuf_free(buf);
    return tpl;

error:
    lwan_tpl_free(tpl);
    strbuf_free(buf);
    fclose(file);
    
    printf("Line %d, column %d: %s\n", line, column, error_msg);
    return NULL;
}
Esempio n. 7
0
static void *parse_key_value(struct parser *parser)
{
    struct config_line line = { .type = CONFIG_LINE_TYPE_LINE };
    struct lexeme *lexeme;
    size_t key_size;

    while (lexeme_buffer_consume(&parser->buffer, &lexeme)) {
        strbuf_append_str(&parser->strbuf, lexeme->value.value, lexeme->value.len);

        if (parser->buffer.population >= 1)
            strbuf_append_char(&parser->strbuf, '_');
    }
    key_size = strbuf_get_length(&parser->strbuf);
    strbuf_append_char(&parser->strbuf, '\0');

    while (lex_next(&parser->lexer, &lexeme)) {
        switch (lexeme->type) {
        case LEXEME_VARIABLE: {
            const char *value;

            value = secure_getenv_len(lexeme->value.value, lexeme->value.len);
            if (!value) {
                lwan_status_error("Variable '$%.*s' not defined in environment",
                    (int)lexeme->value.len, lexeme->value.value);
                return NULL;
            }

            strbuf_append_str(&parser->strbuf, value, 0);
            break;
        }

        case LEXEME_EQUAL:
            strbuf_append_char(&parser->strbuf, '=');
            break;

        case LEXEME_STRING:
            strbuf_append_str(&parser->strbuf, lexeme->value.value, lexeme->value.len);
            break;

        case LEXEME_CLOSE_BRACKET:
            backup(&parser->lexer);
            /* fallthrough */

        case LEXEME_LINEFEED:
            line.key = strbuf_get_buffer(&parser->strbuf);
            line.value = line.key + key_size + 1;
            if (!config_buffer_emit(&parser->items, &line))
                return NULL;

            return parse_config;

        default:
            lwan_status_error("Unexpected token while parsing key-value: %s",
                lexeme_type_str[lexeme->type]);
            return NULL;
        }
    }

    lwan_status_error("EOF while parsing key-value");
    return NULL;
}