// SPDX-License-Identifier: GPL-3.0-or-later

#include "../libnetdata.h"

ENUM_STR_MAP_DEFINE(HTTP_REQUEST_MODE) =
{
        { .name = "OPTIONS", .id = HTTP_REQUEST_MODE_OPTIONS },
        { .name = "GET", .id = HTTP_REQUEST_MODE_GET },
        { .name = "FILECOPY", .id = HTTP_REQUEST_MODE_FILECOPY },
        { .name = "POST", .id = HTTP_REQUEST_MODE_POST },
        { .name = "PUT", .id = HTTP_REQUEST_MODE_PUT },
        { .name = "DELETE", .id = HTTP_REQUEST_MODE_DELETE },
        { .name = "STREAM", .id = HTTP_REQUEST_MODE_STREAM },

        // terminator
        { .name = NULL, .id = 0 }
};

ENUM_STR_DEFINE_FUNCTIONS(HTTP_REQUEST_MODE, 0, "UNKNOWN");

const char *http_response_code2string(int code) {
    switch(code) {
        case 100:
            return "Continue";
        case 101:
            return "Switching Protocols";
        case 102:
            return "Processing";
        case 103:
            return "Early Hints";

        case 200:
            return "OK";
        case 201:
            return "Created";
        case 202:
            return "Accepted";
        case 203:
            return "Non-Authoritative Information";
        case 204:
            return "No Content";
        case 205:
            return "Reset Content";
        case 206:
            return "Partial Content";
        case 207:
            return "Multi-Status";
        case 208:
            return "Already Reported";
        case 226:
            return "IM Used";

        case 300:
            return "Multiple Choices";
        case 301:
            return "Moved Permanently";
        case 302:
            return "Found";
        case 303:
            return "See Other";
        case 304:
            return "Not Modified";
        case 305:
            return "Use Proxy";
        case 306:
            return "Switch Proxy";
        case 307:
            return "Temporary Redirect";
        case 308:
            return "Permanent Redirect";

        case 400:
            return "Bad Request";
        case 401:
            return "Unauthorized";
        case 402:
            return "Payment Required";
        case 403:
            return "Forbidden";
        case 404:
            return "Not Found";
        case 405:
            return "Method Not Allowed";
        case 406:
            return "Not Acceptable";
        case 407:
            return "Proxy Authentication Required";
        case 408:
            return "Request Timeout";
        case 409:
            return "Conflict";
        case 410:
            return "Gone";
        case 411:
            return "Length Required";
        case 412:
            return "Precondition Failed";
        case 413:
            return "Payload Too Large";
        case 414:
            return "URI Too Long";
        case 415:
            return "Unsupported Media Type";
        case 416:
            return "Range Not Satisfiable";
        case 417:
            return "Expectation Failed";
        case 418:
            return "I'm a teapot";
        case 421:
            return "Misdirected Request";
        case 422:
            return "Unprocessable Entity";
        case 423:
            return "Locked";
        case 424:
            return "Failed Dependency";
        case 425:
            return "Too Early";
        case 426:
            return "Upgrade Required";
        case 428:
            return "Precondition Required";
        case 429:
            return "Too Many Requests";
        case 431:
            return "Request Header Fields Too Large";
        case 451:
            return "Unavailable For Legal Reasons";
        case 499: // nginx's extension to the standard
            return "Client Closed Request";

        case 500:
            return "Internal Server Error";
        case 501:
            return "Not Implemented";
        case 502:
            return "Bad Gateway";
        case 503:
            return "Service Unavailable";
        case 504:
            return "Gateway Timeout";
        case 505:
            return "HTTP Version Not Supported";
        case 506:
            return "Variant Also Negotiates";
        case 507:
            return "Insufficient Storage";
        case 508:
            return "Loop Detected";
        case 510:
            return "Not Extended";
        case 511:
            return "Network Authentication Required";

        default:
            if(code >= 100 && code < 200)
                return "Informational";

            if(code >= 200 && code < 300)
                return "Successful";

            if(code >= 300 && code < 400)
                return "Redirection";

            if(code >= 400 && code < 500)
                return "Client Error";

            if(code >= 500 && code < 600)
                return "Server Error";

            return "Undefined Error";
    }
}


static struct {
    const char *extension;
    uint32_t hash;
    HTTP_CONTENT_TYPE contenttype;
} mime_types[] = {
          { "html" , 0    , CT_TEXT_HTML }
        , { "js"   , 0    , CT_APPLICATION_X_JAVASCRIPT }
        , { "css"  , 0    , CT_TEXT_CSS }
        , { "xml"  , 0    , CT_TEXT_XML }
        , { "xsl"  , 0    , CT_TEXT_XSL }
        , { "txt"  , 0    , CT_TEXT_PLAIN }
        , { "svg"  , 0    , CT_IMAGE_SVG_XML }
        , { "ttf"  , 0    , CT_APPLICATION_X_FONT_TRUETYPE }
        , { "otf"  , 0    , CT_APPLICATION_X_FONT_OPENTYPE }
        , { "woff2", 0    , CT_APPLICATION_FONT_WOFF2 }
        , { "woff" , 0    , CT_APPLICATION_FONT_WOFF }
        , { "eot"  , 0    , CT_APPLICATION_VND_MS_FONTOBJ }
        , { "png"  , 0    , CT_IMAGE_PNG }
        , { "jpg"  , 0    , CT_IMAGE_JPG }
        , { "jpeg" , 0    , CT_IMAGE_JPG }
        , { "gif"  , 0    , CT_IMAGE_GIF }
        , { "bmp"  , 0    , CT_IMAGE_BMP }
        , { "ico"  , 0    , CT_IMAGE_XICON }
        , { "icns" , 0    , CT_IMAGE_ICNS }

        // terminator
        , { NULL   , 0    , 0 }
};

HTTP_CONTENT_TYPE contenttype_for_filename(const char *filename) {
    // netdata_log_info("checking filename '%s'", filename);

    static int initialized = 0;
    int i;

    if(unlikely(!initialized)) {
        for (i = 0; mime_types[i].extension; i++)
            mime_types[i].hash = simple_hash(mime_types[i].extension);

        initialized = 1;
    }

    const char *s = filename, *last_dot = NULL;

    // find the last dot
    while(*s) {
        if(unlikely(*s == '.')) last_dot = s;
        s++;
    }

    if(unlikely(!last_dot || !*last_dot || !last_dot[1])) {
        // netdata_log_info("no extension for filename '%s'", filename);
        return CT_APPLICATION_OCTET_STREAM;
    }
    last_dot++;

    // netdata_log_info("extension for filename '%s' is '%s'", filename, last_dot);

    uint32_t hash = simple_hash(last_dot);
    for(i = 0; mime_types[i].extension ; i++) {
        if(unlikely(hash == mime_types[i].hash && !strcmp(last_dot, mime_types[i].extension))) {
            // netdata_log_info("matched extension for filename '%s': '%s'", filename, last_dot);
            return mime_types[i].contenttype;
        }
    }

    // netdata_log_info("not matched extension for filename '%s': '%s'", filename, last_dot);
    return CT_APPLICATION_OCTET_STREAM;
}
