<commit_before>// SPDX-License-Identifier: BSD-2-Clause
//
// Copyright (c) 2016-2019, NetApp, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#include <fcntl.h>
#include <inttypes.h>
#include <net/if.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>

#ifndef __linux__
#include <sys/types.h>
#endif

#include <http_parser.h>

#include <quant/quant.h>
#include <warpcore/warpcore.h>

struct q_conn;


static void __attribute__((noreturn)) usage(const char * const name,
                                            const char * const ifname,
                                            const uint16_t port,
                                            const char * const dir,
                                            const char * const cert,
                                            const char * const key,
                                            const uint64_t timeout,
                                            const uint64_t num_bufs)
{
    printf("%s [options]\n", name);
    printf("\t[-i interface]\tinterface to run over; default %s\n", ifname);
    printf("\t[-p port]\tdestination port; default %d\n", port);
    printf("\t[-d dir]\tserver root directory; default %s\n", dir);
    printf("\t[-c cert]\tTLS certificate; default %s\n", cert);
    printf("\t[-k key]\tTLS key; default %s\n", key);
    printf("\t[-t timeout]\tidle timeout in seconds; default %" PRIu64 "\n",
           timeout);
    printf(
        "\t[-b bufs]\tnumber of network buffers to allocate; default %" PRIu64
        "\n",
        num_bufs);
#ifndef NDEBUG
    printf("\t[-v verbosity]\tverbosity level (0-%d, default %d)\n", DLEVEL,
           util_dlevel);
#endif
    exit(0);
}


struct cb_data {
    struct q_stream * s;
    struct q_conn * c;
    struct w_engine * w;
    int dir;
    uint32_t _dummy;
};


static bool send_err(const struct cb_data * const d, const uint16_t code)
{
    const char * msg;
    bool close = false;

    switch (code) {
    case 400:
        msg = "400 Bad Request";
        close = true;
        break;
    case 403:
        msg = "403 Forbidden";
        break;
    case 404:
        msg = "404 Not Found";
        break;
    case 505:
        msg = "505 HTTP Version Not Supported";
        close = true;
        break;
    default:
        msg = "500 Internal Server Error";
    }

    if (close)
        q_close(d->c, 0x0003, msg);
    else
        q_write_str(d->w, d->s, msg, strlen(msg), true);
    return close;
}


static int serve_cb(http_parser * parser, const char * at, size_t len)
{
    (void)parser;
    const struct cb_data * const d = parser->data;
    warn(INF, "conn %s str %" PRId64 " serving URL %.*s", q_cid(d->c),
         q_sid(d->s), (int)len, at);

    char path[MAXPATHLEN] = ".";
    strncpy(&path[*at == '/' ? 1 : 0], at, MIN(len, sizeof(path) - 1));

    // hacky way to prevent directory traversals
    if (strstr(path, ".."))
        return send_err(d, 403);

    // check if this is a "GET /n" request for random data
    const uint64_t n = (uint32_t)MIN(UINT64_MAX, strtoul(&path[2], 0, 10));
    if (n) {
        struct w_iov_sq out = w_iov_sq_initializer(out);
        q_alloc(d->w, &out, n);
        // check whether we managed to allow enough buffers
        if (w_iov_sq_len(&out) != n) {
            warn(ERR,
                 "could only allocate %" PRIu64 "/%" PRIu64 " bytes of buffer",
                 w_iov_sq_len(&out), n);
            q_free(&out);
            return send_err(d, 500);
        }

        // randomize data
        struct w_iov * v = 0;
        char c = 'A';
        sq_foreach (v, &out, next) {
            memset(v->buf, c, v->len);
            c = (char)(c == 'Z' ? 'A' : c + 1);
        }
        q_write(d->s, &out, true);
        q_free(&out);
        return 0;
    }

    struct stat info;
    if (fstatat(d->dir, path, &info, 0) == -1)
        return send_err(d, 404);<commit_msg>For release builds, don't bother with memset<commit_after>// SPDX-License-Identifier: BSD-2-Clause
//
// Copyright (c) 2016-2019, NetApp, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#include <fcntl.h>
#include <inttypes.h>
#include <net/if.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>

#ifndef __linux__
#include <sys/types.h>
#endif

#include <http_parser.h>

#include <quant/quant.h>
#include <warpcore/warpcore.h>

struct q_conn;


static void __attribute__((noreturn)) usage(const char * const name,
                                            const char * const ifname,
                                            const uint16_t port,
                                            const char * const dir,
                                            const char * const cert,
                                            const char * const key,
                                            const uint64_t timeout,
                                            const uint64_t num_bufs)
{
    printf("%s [options]\n", name);
    printf("\t[-i interface]\tinterface to run over; default %s\n", ifname);
    printf("\t[-p port]\tdestination port; default %d\n", port);
    printf("\t[-d dir]\tserver root directory; default %s\n", dir);
    printf("\t[-c cert]\tTLS certificate; default %s\n", cert);
    printf("\t[-k key]\tTLS key; default %s\n", key);
    printf("\t[-t timeout]\tidle timeout in seconds; default %" PRIu64 "\n",
           timeout);
    printf(
        "\t[-b bufs]\tnumber of network buffers to allocate; default %" PRIu64
        "\n",
        num_bufs);
#ifndef NDEBUG
    printf("\t[-v verbosity]\tverbosity level (0-%d, default %d)\n", DLEVEL,
           util_dlevel);
#endif
    exit(0);
}


struct cb_data {
    struct q_stream * s;
    struct q_conn * c;
    struct w_engine * w;
    int dir;
    uint32_t _dummy;
};


static bool send_err(const struct cb_data * const d, const uint16_t code)
{
    const char * msg;
    bool close = false;

    switch (code) {
    case 400:
        msg = "400 Bad Request";
        close = true;
        break;
    case 403:
        msg = "403 Forbidden";
        break;
    case 404:
        msg = "404 Not Found";
        break;
    case 505:
        msg = "505 HTTP Version Not Supported";
        close = true;
        break;
    default:
        msg = "500 Internal Server Error";
    }

    if (close)
        q_close(d->c, 0x0003, msg);
    else
        q_write_str(d->w, d->s, msg, strlen(msg), true);
    return close;
}


static int serve_cb(http_parser * parser, const char * at, size_t len)
{
    (void)parser;
    const struct cb_data * const d = parser->data;
    warn(INF, "conn %s str %" PRId64 " serving URL %.*s", q_cid(d->c),
         q_sid(d->s), (int)len, at);

    char path[MAXPATHLEN] = ".";
    strncpy(&path[*at == '/' ? 1 : 0], at, MIN(len, sizeof(path) - 1));

    // hacky way to prevent directory traversals
    if (strstr(path, ".."))
        return send_err(d, 403);

    // check if this is a "GET /n" request for random data
    const uint64_t n = (uint32_t)MIN(UINT64_MAX, strtoul(&path[2], 0, 10));
    if (n) {
        struct w_iov_sq out = w_iov_sq_initializer(out);
        q_alloc(d->w, &out, n);
        // check whether we managed to allow enough buffers
        if (w_iov_sq_len(&out) != n) {
            warn(ERR,
                 "could only allocate %" PRIu64 "/%" PRIu64 " bytes of buffer",
                 w_iov_sq_len(&out), n);
            q_free(&out);
            return send_err(d, 500);
        }

#ifndef NDEBUG
        // randomize data
        struct w_iov * v = 0;
        char c = 'A';
        sq_foreach (v, &out, next) {
            memset(v->buf, c, v->len);
            c = (char)(c == 'Z' ? 'A' : c + 1);
        }
#endif

        q_write(d->s, &out, true);
        q_free(&out);
        return 0;
    }

    struct stat info;
    if (fstatat(d->dir, path, &info, 0) == -1)
        return send_err(d, 404);
{'fraction_non_alphanumeric': 0.12036862892608614, 'fraction_numerical': 0.017302990408124882, 'mean_word_length': 2.1755747984472977, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 28, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '560708', 'n_tokens_mistral': 3442, 'n_tokens_neox': 3194, 'n_words': 1124}