Esempio n. 1
0
static struct log_element_t *compile_log_format(const char *fmt, size_t *_num_elements)
{
    struct log_element_t *elements = NULL;
    size_t fmt_len = strlen(fmt), num_elements = 0;
    const char *pt = fmt;

/* suffix buffer is always guaranteed to be larger than the fmt + (sizeof('\n') - 1) (so that they would be no buffer overruns) */
#define NEW_ELEMENT(ty)                                                                                                            \
    do {                                                                                                                           \
        elements = h2o_mem_realloc(elements, sizeof(*elements) * (num_elements + 1));                                              \
        elements[num_elements].type = ty;                                                                                          \
        elements[num_elements].suffix = h2o_iovec_init(h2o_mem_alloc(fmt_len + 1), 0);                                             \
        ++num_elements;                                                                                                            \
    } while (0)

    while (*pt != '\0') {
        if (*pt == '%') {
            ++pt;
            if (*pt == '%') {
                /* skip */
            } else if (*pt == '{') {
                const h2o_token_t *token;
                const char *quote_end = strchr(++pt, '}');
                if (quote_end == NULL) {
                    fprintf(stderr, "failed to compile log format: unterminated header name starting at: \"%16s\"\n", pt);
                    goto Error;
                }
                h2o_iovec_t name = strdup_lowercased(pt, quote_end - pt);
                token = h2o_lookup_token(name.base, name.len);
                switch (quote_end[1]) {
                case 'i':
                    if (token != NULL) {
                        free(name.base);
                        NEW_ELEMENT(ELEMENT_TYPE_IN_HEADER_TOKEN);
                        elements[num_elements - 1].data.header_token = token;
                    } else {
                        NEW_ELEMENT(ELEMENT_TYPE_IN_HEADER_STRING);
                        elements[num_elements - 1].data.header_string = name;
                    }
                    break;
                case 'o':
                    if (token != NULL) {
                        free(name.base);
                        NEW_ELEMENT(ELEMENT_TYPE_OUT_HEADER_TOKEN);
                        elements[num_elements - 1].data.header_token = token;
                    } else {
                        NEW_ELEMENT(ELEMENT_TYPE_OUT_HEADER_STRING);
                        elements[num_elements - 1].data.header_string = name;
                    }
                    break;
                default:
                    free(name.base);
                    fprintf(stderr, "failed to compile log format: header name is not followed by either `i` or `o`\n");
                    goto Error;
                }
                pt = quote_end + 2;
                continue;
            } else {
                unsigned type = NUM_ELEMENT_TYPES;
                switch (*pt++) {
#define TYPE_MAP(ch, ty)                                                                                                           \
    case ch:                                                                                                                       \
        type = ty;                                                                                                                 \
        break
                    TYPE_MAP('b', ELEMENT_TYPE_BYTES_SENT);
                    TYPE_MAP('H', ELEMENT_TYPE_PROTOCOL);
                    TYPE_MAP('h', ELEMENT_TYPE_REMOTE_ADDR);
                    TYPE_MAP('l', ELEMENT_TYPE_LOGNAME);
                    TYPE_MAP('m', ELEMENT_TYPE_METHOD);
                    TYPE_MAP('q', ELEMENT_TYPE_QUERY);
                    TYPE_MAP('r', ELEMENT_TYPE_REQUEST_LINE);
                    TYPE_MAP('s', ELEMENT_TYPE_STATUS);
                    TYPE_MAP('t', ELEMENT_TYPE_TIMESTAMP);
                    TYPE_MAP('U', ELEMENT_TYPE_URL_PATH);
                    TYPE_MAP('u', ELEMENT_TYPE_REMOTE_USER);
                    TYPE_MAP('V', ELEMENT_TYPE_AUTHORITY);
                    TYPE_MAP('v', ELEMENT_TYPE_HOSTCONF);
#undef TYPE_MAP
                default:
                    fprintf(stderr, "failed to compile log format: unknown escape sequence: %%%c\n", pt[-1]);
                    goto Error;
                }
                NEW_ELEMENT(type);
                continue;
            }
        }
        /* emit current char */
        if (elements == NULL)
            NEW_ELEMENT(ELEMENT_TYPE_EMPTY);
        elements[num_elements - 1].suffix.base[elements[num_elements - 1].suffix.len++] = *pt++;
    }

    /* emit end-of-line */
    if (elements == NULL)
        NEW_ELEMENT(ELEMENT_TYPE_EMPTY);
    elements[num_elements - 1].suffix.base[elements[num_elements - 1].suffix.len++] = '\n';

#undef NEW_ELEMENT

    *_num_elements = num_elements;
    return elements;

Error:
    free(elements);
    return NULL;
}
Esempio n. 2
0
static struct log_element_t *compile_log_format(const char *fmt, size_t *_num_elements)
{
    struct log_element_t *elements = NULL;
    size_t fmt_len = strlen(fmt), num_elements = 0;
    const char *pt = fmt;

    /* suffix buffer is always guaranteed to be larger than the fmt + (sizeof('\n') - 1) (so that they would be no buffer overruns) */
#define NEW_ELEMENT(ty) \
    do { \
        elements = h2o_realloc(elements, sizeof(*elements) * (num_elements + 1)); \
        elements[num_elements].type = ty; \
        elements[num_elements].suffix = h2o_buf_init(h2o_malloc(fmt_len + 1), 0); \
        ++num_elements; \
    } while (0)

    while (*pt != '\0') {
        if (*pt == '%') {
            ++pt;
            if (*pt != '%') {
                unsigned type = NUM_ELEMENT_TYPES;
                switch (*pt++) {
#define TYPE_MAP(ch, ty) case ch: type = ty; break
                TYPE_MAP('h', ELEMENT_TYPE_REMOTE_ADDR);
                TYPE_MAP('l', ELEMENT_TYPE_LOGNAME);
                TYPE_MAP('u', ELEMENT_TYPE_REMOTE_USER);
                TYPE_MAP('t', ELEMENT_TYPE_TIMESTAMP);
                TYPE_MAP('r', ELEMENT_TYPE_REQUEST_LINE);
                TYPE_MAP('s', ELEMENT_TYPE_STATUS);
                TYPE_MAP('b', ELEMENT_TYPE_BYTES_SENT);
#undef TYPE_MAP
                default:
                    goto SyntaxError;
                }
                NEW_ELEMENT(type);
                continue;
            }
        }
        /* emit current char */
        if (elements == NULL)
            NEW_ELEMENT(ELEMENT_TYPE_EMPTY);
        elements[num_elements - 1].suffix.base[elements[num_elements - 1].suffix.len++] = *pt++;

    Next:
        ;
    }

    /* emit end-of-line */
    if (elements == NULL)
        NEW_ELEMENT(ELEMENT_TYPE_EMPTY);
    elements[num_elements - 1].suffix.base[elements[num_elements - 1].suffix.len++] = '\n';

#undef NEW_ELEMENT

    *_num_elements = num_elements;
    return elements;

SyntaxError:
    fprintf(stderr, "failed to compile log format: unknown escape sequence: %%%c\n", pt[-1]);
    free(elements);
    return NULL;
}