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

/*  Monkey HTTP Daemon
 *  ------------------
 *  Copyright (C) 2001-2012, <NAME>. <<EMAIL>>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#define _GNU_SOURCE

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "monkey.h"
#include "mk_memory.h"
#include "mk_http.h"
#include "mk_http_status.h"
#include "mk_clock.h"
#include "mk_file.h"
#include "mk_utils.h"
#include "mk_config.h"
#include "mk_string.h"
#include "mk_method.h"
#include "mk_socket.h"
#include "mk_mimetype.h"
#include "mk_header.h"
#include "mk_epoll.h"
#include "mk_plugin.h"
#include "mk_macros.h"

int mk_http_method_check(mk_pointer method)
{
    if (strncmp(method.data, HTTP_METHOD_GET_STR, method.len) == 0) {
        return HTTP_METHOD_GET;
    }

    if (strncmp(method.data, HTTP_METHOD_POST_STR, method.len) == 0) {
        return HTTP_METHOD_POST;
    }

    if (strncmp(method.data, HTTP_METHOD_HEAD_STR, method.len) == 0) {
        return HTTP_METHOD_HEAD;
    }

    if (strncmp(method.data, HTTP_METHOD_PUT_STR, method.len) == 0) {
        return HTTP_METHOD_PUT;
    }

    if (strncmp(method.data, HTTP_METHOD_DELETE_STR, method.len) == 0) {
        return HTTP_METHOD_DELETE;
    }

    return HTTP_METHOD_UNKNOWN;
}

mk_pointer mk_http_method_check_str(int method)
{
    switch (method) {
    case HTTP_METHOD_GET:
        return mk_http_method_get_p;

    case HTTP_METHOD_POST:
        return mk_http_method_post_p;

    case HTTP_METHOD_HEAD:
        return mk_http_method_head_p;
    case HTTP_METHOD_PUT:
        return mk_http_method_put_p;
    case HTTP_METHOD_DELETE:
        return mk_http_method_delete_p;
    }
    return mk_http_method_null_p;
}

int mk_http_method_get(char *body)
{
    int int_method, pos = 0;
    int max_len_method = 7;
    mk_pointer method;

    /* Max method length is 6 (GET/POST/HEAD/PUT/DELETE) */
    pos = mk_string_char_search(body, ' ', 7);
    if (pos <= 2 || pos >= max_len_method) {
        return HTTP_METHOD_UNKNOWN;
    }

    method.data = body;
    method.len = (unsigned long) pos;

    int_method = mk_http_method_check(method);

    return int_method;
}

int mk_http_protocol_check(char *protocol, int len)
{
    if (strncmp(protocol, HTTP_PROTOCOL_11_STR, len) == 0) {
        return HTTP_PROTOCOL_11;
    }
    if (strncmp(protocol, HTTP_PROTOCOL_10_STR, len) == 0) {
        return HTTP_PROTOCOL_10;
    }
    if (strncmp(protocol, HTTP_PROTOCOL_09_STR, len) == 0) {
        return HTTP_PROTOCOL_09;
    }

    return HTTP_PROTOCOL_UNKNOWN;
}

mk_pointer mk_http_protocol_check_str(int protocol)
{
    if (protocol == HTTP_PROTOCOL_11) {
        return mk_http_protocol_11_p;
    }
    if (protocol == HTTP_PROTOCOL_10) {
        return mk_http_protocol_10_p;
    }
    if (protocol == HTTP_PROTOCOL_09) {
        return mk_http_protocol_09_p;
    }

    return mk_http_protocol_null_p;
}

int mk_http_init(struct client_session *cs, struct session_request *sr)
{
    int ret;
    int bytes = 0;
    struct mimetype *mime;

    MK_TRACE("HTTP Protocol Init");

    /* Request to root path of the virtualhost in question */
    if (sr->uri_processed.len == 1 && sr->uri_processed.data[0] == '/') {
        sr->real_path.data = sr->host_conf->documentroot.data;
        sr->real_path.len = sr->host_conf->documentroot.len;
    }

    /* Compose real path */
    if (sr->user_home == MK_FALSE) {
        int len;

        len = sr->host_conf->documentroot.len + sr->uri_processed.len;
        if (len < MK_PATH_BASE) {
            memcpy(sr->real_path_static,
                   sr->host_conf->documentroot.data,
                   sr->host_conf->documentroot.len);
            memcpy(sr->real_path_static + sr->host_conf->documentroot.len,
                   sr->uri_processed.data,
                   sr->uri_processed.len);
            sr->real_path_static[len] = '\0';
            sr->real_path.data = sr->real_path_static;
            sr->real_path.len = len;
        }
        else {
            ret = mk_buffer_cat(&sr->real_path,
                                sr->host_conf->documentroot.data,
                                sr->host_conf->documentroot.len,
                                sr->uri_processed.data,
                                sr->uri_processed.len);

            if (ret < 0) {
                MK_TRACE("Error composing real path");
                return EXIT_ERROR;
            }
        }
    }

    /* Check backward directory request */
    if (memmem(sr->uri_processed.data, sr->uri_processed.len,
               HTTP_DIRECTORY_BACKWARD, sizeof(HTTP_DIRECTORY_BACKWARD) - 1)) {
        return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr);
    }


    if (mk_file_get_info(sr->real_path.data, &sr->file_info) != 0) {
        /* if the resource requested doesn't exists, let's
         * check if some plugin would like to handle it
         */
        MK_TRACE("No file, look for handler plugin");
        ret = mk_plugin_stage_run(MK_PLUGIN_STAGE_30, cs->socket, NULL, cs, sr);
        if (ret == MK_PLUGIN_RET_CLOSE_CONX) {
            return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr);
        }
        else if (ret == MK_PLUGIN_RET_CONTINUE) {
            return MK_PLUGIN_RET_CONTINUE;
        }
        else if (ret == MK_PLUGIN_RET_END) {
            return EXIT_NORMAL;
        }

        if (sr->file_info.exists == MK_FALSE) {
            return mk_request_error(MK_CLIENT_NOT_FOUND, cs, sr);
        }
        else {
            return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr);
        }
    }

    /* is it a valid directory ? */
    if (sr->file_info.is_directory == MK_TRUE) {
        /* Send redirect header if end slash is not found */
        if (mk_http_directory_redirect_check(cs, sr) == -1) {
            MK_TRACE("Directory Redirect");
<commit_msg>http: Check if plugin set status in http_init.<commit_after>/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*  Monkey HTTP Daemon
 *  ------------------
 *  Copyright (C) 2001-2012, <NAME>. <<EMAIL>>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#define _GNU_SOURCE

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "monkey.h"
#include "mk_memory.h"
#include "mk_http.h"
#include "mk_http_status.h"
#include "mk_clock.h"
#include "mk_file.h"
#include "mk_utils.h"
#include "mk_config.h"
#include "mk_string.h"
#include "mk_method.h"
#include "mk_socket.h"
#include "mk_mimetype.h"
#include "mk_header.h"
#include "mk_epoll.h"
#include "mk_plugin.h"
#include "mk_macros.h"

int mk_http_method_check(mk_pointer method)
{
    if (strncmp(method.data, HTTP_METHOD_GET_STR, method.len) == 0) {
        return HTTP_METHOD_GET;
    }

    if (strncmp(method.data, HTTP_METHOD_POST_STR, method.len) == 0) {
        return HTTP_METHOD_POST;
    }

    if (strncmp(method.data, HTTP_METHOD_HEAD_STR, method.len) == 0) {
        return HTTP_METHOD_HEAD;
    }

    if (strncmp(method.data, HTTP_METHOD_PUT_STR, method.len) == 0) {
        return HTTP_METHOD_PUT;
    }

    if (strncmp(method.data, HTTP_METHOD_DELETE_STR, method.len) == 0) {
        return HTTP_METHOD_DELETE;
    }

    return HTTP_METHOD_UNKNOWN;
}

mk_pointer mk_http_method_check_str(int method)
{
    switch (method) {
    case HTTP_METHOD_GET:
        return mk_http_method_get_p;

    case HTTP_METHOD_POST:
        return mk_http_method_post_p;

    case HTTP_METHOD_HEAD:
        return mk_http_method_head_p;
    case HTTP_METHOD_PUT:
        return mk_http_method_put_p;
    case HTTP_METHOD_DELETE:
        return mk_http_method_delete_p;
    }
    return mk_http_method_null_p;
}

int mk_http_method_get(char *body)
{
    int int_method, pos = 0;
    int max_len_method = 7;
    mk_pointer method;

    /* Max method length is 6 (GET/POST/HEAD/PUT/DELETE) */
    pos = mk_string_char_search(body, ' ', 7);
    if (pos <= 2 || pos >= max_len_method) {
        return HTTP_METHOD_UNKNOWN;
    }

    method.data = body;
    method.len = (unsigned long) pos;

    int_method = mk_http_method_check(method);

    return int_method;
}

int mk_http_protocol_check(char *protocol, int len)
{
    if (strncmp(protocol, HTTP_PROTOCOL_11_STR, len) == 0) {
        return HTTP_PROTOCOL_11;
    }
    if (strncmp(protocol, HTTP_PROTOCOL_10_STR, len) == 0) {
        return HTTP_PROTOCOL_10;
    }
    if (strncmp(protocol, HTTP_PROTOCOL_09_STR, len) == 0) {
        return HTTP_PROTOCOL_09;
    }

    return HTTP_PROTOCOL_UNKNOWN;
}

mk_pointer mk_http_protocol_check_str(int protocol)
{
    if (protocol == HTTP_PROTOCOL_11) {
        return mk_http_protocol_11_p;
    }
    if (protocol == HTTP_PROTOCOL_10) {
        return mk_http_protocol_10_p;
    }
    if (protocol == HTTP_PROTOCOL_09) {
        return mk_http_protocol_09_p;
    }

    return mk_http_protocol_null_p;
}

int mk_http_init(struct client_session *cs, struct session_request *sr)
{
    int ret;
    int bytes = 0;
    struct mimetype *mime;

    MK_TRACE("HTTP Protocol Init");

    /* Request to root path of the virtualhost in question */
    if (sr->uri_processed.len == 1 && sr->uri_processed.data[0] == '/') {
        sr->real_path.data = sr->host_conf->documentroot.data;
        sr->real_path.len = sr->host_conf->documentroot.len;
    }

    /* Compose real path */
    if (sr->user_home == MK_FALSE) {
        int len;

        len = sr->host_conf->documentroot.len + sr->uri_processed.len;
        if (len < MK_PATH_BASE) {
            memcpy(sr->real_path_static,
                   sr->host_conf->documentroot.data,
                   sr->host_conf->documentroot.len);
            memcpy(sr->real_path_static + sr->host_conf->documentroot.len,
                   sr->uri_processed.data,
                   sr->uri_processed.len);
            sr->real_path_static[len] = '\0';
            sr->real_path.data = sr->real_path_static;
            sr->real_path.len = len;
        }
        else {
            ret = mk_buffer_cat(&sr->real_path,
                                sr->host_conf->documentroot.data,
                                sr->host_conf->documentroot.len,
                                sr->uri_processed.data,
                                sr->uri_processed.len);

            if (ret < 0) {
                MK_TRACE("Error composing real path");
                return EXIT_ERROR;
            }
        }
    }

    /* Check backward directory request */
    if (memmem(sr->uri_processed.data, sr->uri_processed.len,
               HTTP_DIRECTORY_BACKWARD, sizeof(HTTP_DIRECTORY_BACKWARD) - 1)) {
        return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr);
    }


    if (mk_file_get_info(sr->real_path.data, &sr->file_info) != 0) {
        /* if the resource requested doesn't exists, let's
         * check if some plugin would like to handle it
         */
        MK_TRACE("No file, look for handler plugin");
        ret = mk_plugin_stage_run(MK_PLUGIN_STAGE_30, cs->socket, NULL, cs, sr);
        if (ret == MK_PLUGIN_RET_CLOSE_CONX) {
            if (sr->headers.status > 0) {
                return mk_request_error(sr->headers.status, cs, sr);
            }
            else {
                return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr);
            }
        }
        else if (ret == MK_PLUGIN_RET_CONTINUE) {
            return MK_PLUGIN_RET_CONTINUE;
        }
        else if (ret == MK_PLUGIN_RET_END) {
            return EXIT_NORMAL;
        }

        if (sr->file_info.exists == MK_FALSE) {
            return mk_request_error(MK_CLIENT_NOT_FOUND, cs, sr);
        }
        else {
            return mk_request_error(MK_CLIENT_FORBIDDEN, cs, sr);
        }
    }

    /* is it a valid directory ? */
    if (sr->file_info.is_directory == MK_TRUE) {
        /* Send redirect header if end slash is not found */
        if (mk_http_directory_redirect_check(cs, sr) == -1) {
            MK_TRACE("Directory Redirect");

{'fraction_non_alphanumeric': 0.10920436817472699, 'fraction_numerical': 0.010326127330807518, 'mean_word_length': 2.46780010303967, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 106, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '5235371', 'n_tokens_mistral': 4723, 'n_tokens_neox': 4456, 'n_words': 1031}