Beispiel #1
0
/* Return a struct with method, URI , protocol version
and all static headers defined here sent in request */
static int mk_request_header_process(struct session_request *sr)
{
    int uri_init = 0, uri_end = 0;
    int query_init = 0;
    int prot_init = 0, prot_end = 0, pos_sep = 0;
    int fh_limit;
    char *headers;
    char *temp = 0;
    mk_ptr_t host;

    /* Method */
    sr->method_p = mk_http_method_check_str(sr->method);

    /* Request URI */
    temp = index(sr->body.data, ' ');
    if (mk_unlikely(!temp)) {
        MK_TRACE("Error, invalid first header");
        return -1;
    }
    uri_init = (temp - sr->body.data) + 1;

    temp = index(sr->body.data, '\n');
    if (mk_unlikely(!temp)) {
        MK_TRACE("Error, invalid header CRLF");
        return -1;
    }
    fh_limit = (temp - sr->body.data);

    uri_end = mk_string_char_search_r(sr->body.data, ' ', fh_limit) - 1;
    if (mk_unlikely(uri_end <= 0)) {
        MK_TRACE("Error, first header bad formed");
        return -1;
    }

    prot_init = uri_end + 2;

    if (mk_unlikely(uri_end < uri_init)) {
        return -1;
    }

    /* Query String */
    query_init = mk_string_char_search(sr->body.data + uri_init, '?', prot_init);
    if (query_init > 0) {
        int init, end;

        init = query_init + uri_init;
        if (init <= uri_end) {
            end = uri_end;
            uri_end = init - 1;

            sr->query_string = mk_ptr_create(sr->body.data,
                                                 init + 1, end + 1);
        }
    }

    /* Request URI Part 2 */
    sr->uri = mk_ptr_create(sr->body.data, uri_init, uri_end + 1);
    if (mk_unlikely(sr->uri.len < 1)) {
        return -1;
    }

    /* HTTP Version */
    prot_end = fh_limit - 1;
    if (mk_unlikely(prot_init == prot_end)) {
        return  -1;
    }

    if (prot_end != prot_init && prot_end > 0) {
        sr->protocol = mk_http_protocol_check(sr->body.data + prot_init,
                                              prot_end - prot_init);
        sr->protocol_p = mk_http_protocol_check_str(sr->protocol);
    }

    headers = sr->body.data + prot_end + mk_crlf.len;

    /*
     * Process URI, if it contains ASCII encoded strings like '%20',
     * it will return a new memory buffer with the decoded string, otherwise
     * it returns NULL
     */
    temp = mk_utils_url_decode(sr->uri);
    if (temp) {
        sr->uri_processed.data = temp;
        sr->uri_processed.len  = strlen(temp);
    }
    else {
        sr->uri_processed.data = sr->uri.data;
        sr->uri_processed.len  = sr->uri.len;
    }

    /* Creating Table of Content (index) for HTTP headers */
    sr->headers_len = sr->body.len - (prot_end + mk_crlf.len);
    if (mk_request_header_toc_parse(&sr->headers_toc, headers, sr->headers_len) < 0) {
        MK_TRACE("Invalid headers");
        return -1;
    }

    /* Host */
    host = mk_request_header_get(&sr->headers_toc,
                                 mk_rh_host.data,
                                 mk_rh_host.len);
    if (host.data) {
        if ((pos_sep = mk_string_char_search_r(host.data, ':', host.len)) >= 0) {
            /* TCP port should not be higher than 65535 */
            char *p;
            short int port_len, port_size = 6;
            char port[port_size];

            /* just the host */
            sr->host.data = host.data;
            sr->host.len = pos_sep;

            /* including the port */
            sr->host_port = host;

            /* Port string length */
            port_len = (host.len - pos_sep - 1);
            if (port_len >= port_size) {
                return -1;
            }

            /* Copy to buffer */
            memcpy(port, host.data + pos_sep + 1, port_len);
            port[port_len] = '\0';

            /* Validate that the input port is numeric */
            p = port;
            while (*p) {
                if (!isdigit(*p)) return -1;
                p++;
            }

            /* Convert to base 10 */
            errno = 0;
            sr->port = strtol(port, (char **) NULL, 10);
            if ((errno == ERANGE && (sr->port == LONG_MAX || sr->port == LONG_MIN))
                || sr->port == 0) {
                return -1;
            }
        }
        else {
            sr->host = host;    /* maybe null */
            sr->port = config->standard_port;
        }
    }
    else {
        sr->host.data = NULL;
    }

    /* Looking for headers that ONLY Monkey uses */
    sr->connection = mk_request_header_get(&sr->headers_toc,
                                           mk_rh_connection.data,
                                           mk_rh_connection.len);

    sr->range = mk_request_header_get(&sr->headers_toc,
                                      mk_rh_range.data,
                                      mk_rh_range.len);

    sr->if_modified_since = mk_request_header_get(&sr->headers_toc,
                                                  mk_rh_if_modified_since.data,
                                                  mk_rh_if_modified_since.len);

    /* Default Keepalive is off */
    if (sr->protocol == MK_HTTP_PROTOCOL_10) {
        sr->keep_alive = MK_FALSE;
        sr->close_now = MK_TRUE;
    }
    else if(sr->protocol == MK_HTTP_PROTOCOL_11) {
        sr->keep_alive = MK_TRUE;
        sr->close_now = MK_FALSE;
    }

    if (sr->connection.data) {
        if (mk_string_search_n(sr->connection.data, "Keep-Alive",
                               MK_STR_INSENSITIVE, sr->connection.len) >= 0) {
            sr->keep_alive = MK_TRUE;
            sr->close_now = MK_FALSE;
        }
        else if (mk_string_search_n(sr->connection.data, "Close",
                                    MK_STR_INSENSITIVE, sr->connection.len) >= 0) {
            sr->keep_alive = MK_FALSE;
            sr->close_now = MK_TRUE;
        }
        else {
            /* Set as a non-valid connection header value */
            sr->connection.len = 0;
        }
    }

    return 0;
}
Beispiel #2
0
static inline int header_lookup(struct mk_http_parser *p, char *buffer)
{
    int i;
    int len;
    int pos;
    long val;
    char *endptr;
    char *tmp;

    struct mk_http_header *header;
    struct mk_http_header *header_extra;
    struct row_entry *h;

    len = (p->header_sep - p->header_key);

    for (i = p->header_min; i <= p->header_max; i++) {
        h = &mk_headers_table[i];

        /* Check string length first */
        if (h->len != len) {
            continue;
        }

        if (header_cmp(h->name + 1, buffer + p->header_key + 1, len - 1) == 0) {
            /* We got a header match, register the header index */
            header = &p->headers[i];
            header->type = i;
            header->key.data = buffer + p->header_key;
            header->key.len  = len;
            header->val.data = buffer + p->header_val;
            header->val.len  = p->end - p->header_val;
            p->header_count++;
            mk_list_add(&header->_head, &p->header_list);

            if (i == MK_HEADER_HOST) {
                /* Handle a possible port number in the Host header */
                int sep = str_searchr(header->val.data, ':', header->val.len);
                if (sep > 0) {
                    int plen;
                    short int port_size = 6;
                    char port[port_size];

                    plen = header->val.len - sep - 1;
                    if (plen <= 0 || plen >= port_size) {
                        return -MK_CLIENT_BAD_REQUEST;
                    }
                    memcpy(&port, header->val.data + sep + 1, plen);
                    port[plen] = '\0';

                    errno = 0;
                    val = strtol(port, &endptr, 10);
                    if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
                        || (errno != 0 && val == 0)) {
                        return -MK_CLIENT_BAD_REQUEST;
                    }

                    if (endptr == port || *endptr != '\0') {
                        return -MK_CLIENT_BAD_REQUEST;
                    }

                    p->header_host_port = val;

                    /* Re-set the Host header value without port */
                    header->val.len = sep;
                }
            }
            else if (i == MK_HEADER_CONTENT_LENGTH) {
                errno = 0;
                val = strtol(header->val.data, &endptr, 10);
                if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
                    || (errno != 0 && val == 0)) {
                    return -MK_CLIENT_REQUEST_ENTITY_TOO_LARGE;
                }
                if (endptr == header->val.data) {
                    return -1;
                }
                if (val < 0) {
                    return -1;
                }

                p->header_content_length = val;
            }
            else if (i == MK_HEADER_CONNECTION) {
                /* Check Connection: Keep-Alive */
                if (header->val.len == sizeof(MK_CONN_KEEP_ALIVE) - 1) {
                    if (header_cmp(MK_CONN_KEEP_ALIVE,
                                   header->val.data,
                                   header->val.len ) == 0) {
                        p->header_connection = MK_HTTP_PARSER_CONN_KA;
                    }
                }
                /* Check Connection: Close */
                else if (header->val.len == sizeof(MK_CONN_CLOSE) -1) {
                    if (header_cmp(MK_CONN_CLOSE,
                                   header->val.data, header->val.len) == 0) {
                        p->header_connection = MK_HTTP_PARSER_CONN_CLOSE;
                    }
                }
                else {
                    p->header_connection = MK_HTTP_PARSER_CONN_UNKNOWN;

                    /* Try to find some known values */

                    /* Connection: upgrade */
                    pos = mk_string_search_n(header->val.data,
                                             "Upgrade",
                                             MK_STR_INSENSITIVE,
                                             header->val.len);
                    if (pos >= 0) {
                        p->header_connection = MK_HTTP_PARSER_CONN_UPGRADE;
                    }

                    /* Connection: HTTP2-Settings */
                    pos = mk_string_search_n(header->val.data,
                                             "HTTP2-Settings",
                                             MK_STR_INSENSITIVE,
                                             header->val.len);
                    if (pos >= 0) {
                        p->header_connection |= MK_HTTP_PARSER_CONN_HTTP2_SE;
                    }
                }
            }
            else if (i == MK_HEADER_UPGRADE) {
                    if (header_cmp(MK_UPGRADE_H2C,
                                   header->val.data, header->val.len) == 0) {
                        p->header_upgrade = MK_HTTP_PARSER_UPGRADE_H2C;
                    }
            }

            return 0;
        }
    }

    /*
     * The header_lookup did not match any known header, so we register this
     * entry into the headers_extra array.
     */
    if (p->headers_extra_count < MK_HEADER_EXTRA_SIZE) {
        header_extra = &p->headers_extra[p->headers_extra_count];
        header_extra->key.data = tmp = (buffer + p->header_key);
        header_extra->key.len  = len;

        /* Transform the header key string to lowercase */
        for (i = 0; i < len; i++) {
            tmp[i] = tolower(tmp[i]);
        }

        header_extra->val.data = buffer + p->header_val;
        header_extra->val.len  = p->end - p->header_val;
        p->headers_extra_count++;
        p->header_count++;
        mk_list_add(&header_extra->_head, &p->header_list);
        return 0;
    }

    /*
     * Header is unknown and we cannot store it on our extra headers
     * list as it's already full. Request is too large.
     */
    return -MK_CLIENT_REQUEST_ENTITY_TOO_LARGE;
}