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; }
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; }