<commit_before>/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*  Monkey HTTP Server
 *  ==================
 *  Copyright 2001-2015 Monkey Software LLC <<EMAIL>>
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
#include <limits.h>

#include <monkey/mk_http.h>
#include <monkey/mk_http_parser.h>
#include <monkey/mk_http_status.h>

#define mark_end()                              \
    p->end = p->i;                              \
    p->chars = -1;

#define parse_next()                            \
    p->start = p->i + 1;                        \
    continue

#define field_len()   (p->end - p->start)
#define header_scope_eq(p, x) p->header_min = p->header_max = x

struct row_entry {
    int len;
    const char name[32];
};

struct row_entry mk_methods_table[] = {
    { 3, "GET"     },
    { 4, "POST"    },
    { 4, "HEAD"    },
    { 3, "PUT"     },
    { 6, "DELETE"  },
    { 7, "OPTIONS" }
};

struct row_entry mk_headers_table[] = {
    {  6, "accept"              },
    { 14, "accept-charset"      },
    { 15, "accept-encoding"     },
    { 15, "accept-language"     },
    { 13, "authorization"       },
    { 13, "cache-control"       },
    {  6, "cookie"              },
    { 10, "connection"          },
    { 14, "content-length"      },
    { 13, "content-range"       },
    { 12, "content-type"        },
    {  4, "host"                },
    { 17, "if-modified-since"   },
    { 13, "last-modified"       },
    { 19, "last-modified-since" },
    {  5, "range"               },
    {  7, "referer"             },
    {  7, "upgrade"             },
    { 10, "user-agent"          }
};

static inline int str_searchr(char *buf, char c, int len)
{
    int i;

    for (i = len - 1; i >= 0; i--) {
        if (buf[i] == c) {
            return i;
        }
    }

    return -1;
}

static inline int method_lookup(struct mk_http_request *req,
                                struct mk_http_parser *p, char *buffer)
{
    int i;
    int len;

    /* Method lenght */
    len = field_len();

    /* Point the buffer */
    req->method = MK_METHOD_UNKNOWN;
    req->method_p.data = buffer + p->start;
    req->method_p.len  = len;

    if (p->method >= 0) {
        if (strncmp(buffer + p->start + 1,
                    mk_methods_table[p->method].name + 1,
                    len - 1) == 0) {
            req->method = p->method;
            return req->method;
        }
    }

    for (i = 0; i < MK_METHOD_SIZEOF; i++) {
        if (len != mk_methods_table[i].len) {
            continue;
        }

        if (strncmp(buffer + p->start, mk_methods_table[i].name, len) == 0) {
            req->method = i;
            return i;
        }
    }

    return MK_METHOD_UNKNOWN;
}

static inline void request_set(mk_ptr_t *ptr, struct mk_http_parser *p, char *buffer)
{
    ptr->data = buffer + p->start;
    ptr->len  = field_len();
}

/*
 * expected: a known & expected value in lowercase
 * value   : the expected string value in the header
 * len     : the value string length.
 *
 * If it matches it return zero. Otherwise -1.
 */
static inline int header_cmp(const char *expected, char *value, int len)
{
    int i;

    for (i = 0; i < len; i++) {
        if (expected[i] != tolower(value[i])) {
            return -1;
        }
    }

    return 0;
}

static inline int header_lookup(struct mk_http_parser *p, char *buffer)
{
    int i;<commit_msg>HTTP: Parser: do pre-rolling check on header comparisson, performance improvement<commit_after>/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*  Monkey HTTP Server
 *  ==================
 *  Copyright 2001-2015 Monkey Software LLC <<EMAIL>>
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
#include <limits.h>

#include <monkey/mk_http.h>
#include <monkey/mk_http_parser.h>
#include <monkey/mk_http_status.h>

#define mark_end()                              \
    p->end = p->i;                              \
    p->chars = -1;

#define parse_next()                            \
    p->start = p->i + 1;                        \
    continue

#define field_len()   (p->end - p->start)
#define header_scope_eq(p, x) p->header_min = p->header_max = x

struct row_entry {
    int len;
    const char name[32];
};

struct row_entry mk_methods_table[] = {
    { 3, "GET"     },
    { 4, "POST"    },
    { 4, "HEAD"    },
    { 3, "PUT"     },
    { 6, "DELETE"  },
    { 7, "OPTIONS" }
};

struct row_entry mk_headers_table[] = {
    {  6, "accept"              },
    { 14, "accept-charset"      },
    { 15, "accept-encoding"     },
    { 15, "accept-language"     },
    { 13, "authorization"       },
    { 13, "cache-control"       },
    {  6, "cookie"              },
    { 10, "connection"          },
    { 14, "content-length"      },
    { 13, "content-range"       },
    { 12, "content-type"        },
    {  4, "host"                },
    { 17, "if-modified-since"   },
    { 13, "last-modified"       },
    { 19, "last-modified-since" },
    {  5, "range"               },
    {  7, "referer"             },
    {  7, "upgrade"             },
    { 10, "user-agent"          }
};

static inline int str_searchr(char *buf, char c, int len)
{
    int i;

    for (i = len - 1; i >= 0; i--) {
        if (buf[i] == c) {
            return i;
        }
    }

    return -1;
}

static inline int method_lookup(struct mk_http_request *req,
                                struct mk_http_parser *p, char *buffer)
{
    int i;
    int len;

    /* Method lenght */
    len = field_len();

    /* Point the buffer */
    req->method = MK_METHOD_UNKNOWN;
    req->method_p.data = buffer + p->start;
    req->method_p.len  = len;

    if (p->method >= 0) {
        if (strncmp(buffer + p->start + 1,
                    mk_methods_table[p->method].name + 1,
                    len - 1) == 0) {
            req->method = p->method;
            return req->method;
        }
    }

    for (i = 0; i < MK_METHOD_SIZEOF; i++) {
        if (len != mk_methods_table[i].len) {
            continue;
        }

        if (strncmp(buffer + p->start, mk_methods_table[i].name, len) == 0) {
            req->method = i;
            return i;
        }
    }

    return MK_METHOD_UNKNOWN;
}

static inline void request_set(mk_ptr_t *ptr, struct mk_http_parser *p, char *buffer)
{
    ptr->data = buffer + p->start;
    ptr->len  = field_len();
}

/*
 * expected: a known & expected value in lowercase
 * value   : the expected string value in the header
 * len     : the value string length.
 *
 * If it matches it return zero. Otherwise -1.
 */
static inline int header_cmp(const char *expected, char *value, int len)
{
    int i = 0;

    if (len >= 8) {
        if (expected[0] != tolower(value[0])) return -1;
        if (expected[1] != tolower(value[1])) return -1;
        if (expected[2] != tolower(value[2])) return -1;
        if (expected[3] != tolower(value[3])) return -1;
        if (expected[4] != tolower(value[4])) return -1;
        if (expected[5] != tolower(value[5])) return -1;
        if (expected[6] != tolower(value[6])) return -1;
        if (expected[7] != tolower(value[7])) return -1;
        i = 8;
    }

    for (; i < len; i++) {
        if (expected[i] != tolower(value[i])) {
            return -1;
        }
    }

    return 0;
}

static inline int header_lookup(struct mk_http_parser *p, char *buffer)
{
    int i;
{'fraction_non_alphanumeric': 0.14866273011462314, 'fraction_numerical': 0.019219636447840686, 'mean_word_length': 1.8593181065872229, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 78, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3701920', 'n_tokens_mistral': 3003, 'n_tokens_neox': 2851, 'n_words': 790}