<commit_before>#include "cache.h"
#include "refs.h"
#include "pkt-line.h"
#include "object.h"
#include "tag.h"
#include "exec_cmd.h"
#include "run-command.h"
#include "string-list.h"

static const char content_type[] = "Content-Type";
static const char content_length[] = "Content-Length";
static const char last_modified[] = "Last-Modified";
static int getanyfile = 1;

static struct string_list *query_params;

struct rpc_service {
	const char *name;
	const char *config_name;
	signed enabled : 2;
};

static struct rpc_service rpc_service[] = {
	{ "upload-pack", "uploadpack", 1 },
	{ "receive-pack", "receivepack", -1 },
};

static int decode_char(const char *q)
{
	int i;
	unsigned char val = 0;
	for (i = 0; i < 2; i++) {
		unsigned char c = *q++;
		val <<= 4;
		if (c >= '0' && c <= '9')
			val += c - '0';
		else if (c >= 'a' && c <= 'f')
			val += c - 'a' + 10;
		else if (c >= 'A' && c <= 'F')
			val += c - 'A' + 10;
		else
			return -1;
	}
	return val;
}

static char *decode_parameter(const char **query, int is_name)
{
	const char *q = *query;
	struct strbuf out;

	strbuf_init(&out, 16);
	do {
		unsigned char c = *q;

		if (!c)
			break;
		if (c == '&' || (is_name && c == '=')) {
			q++;
			break;
		}

		if (c == '%') {
			int val = decode_char(q + 1);
			if (0 <= val) {
				strbuf_addch(&out, val);
				q += 3;
				continue;
			}
		}

		if (c == '+')
			strbuf_addch(&out, ' ');
		else
			strbuf_addch(&out, c);
		q++;
	} while (1);
	*query = q;
	return strbuf_detach(&out, NULL);
}

static struct string_list *get_parameters(void)
{
	if (!query_params) {
		const char *query = getenv("QUERY_STRING");

		query_params = xcalloc(1, sizeof(*query_params));
		while (query && *query) {
			char *name = decode_parameter(&query, 1);
			char *value = decode_parameter(&query, 0);
			struct string_list_item *i;

			i = string_list_lookup(name, query_params);
			if (!i)
				i = string_list_insert(name, query_params);
			else
				free(i->util);
			i->util = value;
		}
	}
	return query_params;
}

static const char *get_parameter(const char *name)
{
	struct string_list_item *i;
	i = string_list_lookup(name, get_parameters());
	return i ? i->util : NULL;
}

static void format_write(int fd, const char *fmt, ...)
{
	static char buffer[1024];

	va_list args;
	unsigned n;

	va_start(args, fmt);
	n = vsnprintf(buffer, sizeof(buffer), fmt, args);
	va_end(args);
	if (n >= sizeof(buffer))
		die("protocol error: impossibly long line");

	safe_write(fd, buffer, n);
}

static void http_status(unsigned code, const char *msg)
{
	format_write(1, "Status: %u %s\r\n", code, msg);
}

static void hdr_str(const char *name, const char *value)
{
	format_write(1, "%s: %s\r\n", name, value);
}

static void hdr_int(const char *name, uintmax_t value)
{
	format_write(1, "%s: %" PRIuMAX "\r\n", name, value);
}

static void hdr_date(const char *name, unsigned long when)
{
	const char *value = show_date(when, 0, DATE_RFC2822);
	hdr_str(name, value);
}

static void hdr_nocache(void)
{
	hdr_str("Expires", "Fri, 01 Jan 1980 00:00:00 GMT");
	hdr_str("Pragma", "no-cache");
	hdr_str("Cache-Control", "no-cache, max-age=0, must-revalidate");
}

static void hdr_cache_forever(void)
{
	unsigned long now = time(NULL);
	hdr_date("Date", now);
	hdr_date("Expires", now + 31536000);
	hdr_str("Cache-Control", "public, max-age=31536000");
}

static void end_headers(void)
{
	safe_write(1, "\r\n", 2);
}

static NORETURN void not_found(const char *err, ...)
{
	va_list params;

	http_status(404, "Not Found");
	hdr_nocache();
	end_headers();

	va_start(params, err);
	if (err && *err)
		vfprintf(stderr, err, params);
	va_end(params);
	exit(0);
}
<commit_msg>http-backend: Let gcc check the format of more printf-type functions.<commit_after>#include "cache.h"
#include "refs.h"
#include "pkt-line.h"
#include "object.h"
#include "tag.h"
#include "exec_cmd.h"
#include "run-command.h"
#include "string-list.h"

static const char content_type[] = "Content-Type";
static const char content_length[] = "Content-Length";
static const char last_modified[] = "Last-Modified";
static int getanyfile = 1;

static struct string_list *query_params;

struct rpc_service {
	const char *name;
	const char *config_name;
	signed enabled : 2;
};

static struct rpc_service rpc_service[] = {
	{ "upload-pack", "uploadpack", 1 },
	{ "receive-pack", "receivepack", -1 },
};

static int decode_char(const char *q)
{
	int i;
	unsigned char val = 0;
	for (i = 0; i < 2; i++) {
		unsigned char c = *q++;
		val <<= 4;
		if (c >= '0' && c <= '9')
			val += c - '0';
		else if (c >= 'a' && c <= 'f')
			val += c - 'a' + 10;
		else if (c >= 'A' && c <= 'F')
			val += c - 'A' + 10;
		else
			return -1;
	}
	return val;
}

static char *decode_parameter(const char **query, int is_name)
{
	const char *q = *query;
	struct strbuf out;

	strbuf_init(&out, 16);
	do {
		unsigned char c = *q;

		if (!c)
			break;
		if (c == '&' || (is_name && c == '=')) {
			q++;
			break;
		}

		if (c == '%') {
			int val = decode_char(q + 1);
			if (0 <= val) {
				strbuf_addch(&out, val);
				q += 3;
				continue;
			}
		}

		if (c == '+')
			strbuf_addch(&out, ' ');
		else
			strbuf_addch(&out, c);
		q++;
	} while (1);
	*query = q;
	return strbuf_detach(&out, NULL);
}

static struct string_list *get_parameters(void)
{
	if (!query_params) {
		const char *query = getenv("QUERY_STRING");

		query_params = xcalloc(1, sizeof(*query_params));
		while (query && *query) {
			char *name = decode_parameter(&query, 1);
			char *value = decode_parameter(&query, 0);
			struct string_list_item *i;

			i = string_list_lookup(name, query_params);
			if (!i)
				i = string_list_insert(name, query_params);
			else
				free(i->util);
			i->util = value;
		}
	}
	return query_params;
}

static const char *get_parameter(const char *name)
{
	struct string_list_item *i;
	i = string_list_lookup(name, get_parameters());
	return i ? i->util : NULL;
}

__attribute__((format (printf, 2, 3)))
static void format_write(int fd, const char *fmt, ...)
{
	static char buffer[1024];

	va_list args;
	unsigned n;

	va_start(args, fmt);
	n = vsnprintf(buffer, sizeof(buffer), fmt, args);
	va_end(args);
	if (n >= sizeof(buffer))
		die("protocol error: impossibly long line");

	safe_write(fd, buffer, n);
}

static void http_status(unsigned code, const char *msg)
{
	format_write(1, "Status: %u %s\r\n", code, msg);
}

static void hdr_str(const char *name, const char *value)
{
	format_write(1, "%s: %s\r\n", name, value);
}

static void hdr_int(const char *name, uintmax_t value)
{
	format_write(1, "%s: %" PRIuMAX "\r\n", name, value);
}

static void hdr_date(const char *name, unsigned long when)
{
	const char *value = show_date(when, 0, DATE_RFC2822);
	hdr_str(name, value);
}

static void hdr_nocache(void)
{
	hdr_str("Expires", "Fri, 01 Jan 1980 00:00:00 GMT");
	hdr_str("Pragma", "no-cache");
	hdr_str("Cache-Control", "no-cache, max-age=0, must-revalidate");
}

static void hdr_cache_forever(void)
{
	unsigned long now = time(NULL);
	hdr_date("Date", now);
	hdr_date("Expires", now + 31536000);
	hdr_str("Cache-Control", "public, max-age=31536000");
}

static void end_headers(void)
{
	safe_write(1, "\r\n", 2);
}

__attribute__((format (printf, 1, 2)))
static NORETURN void not_found(const char *err, ...)
{
	va_list params;

	http_status(404, "Not Found");
	hdr_nocache();
	end_headers();

	va_start(params, err);
	if (err && *err)
		vfprintf(stderr, err, params);
	va_end(params);
	exit(0);
}

__attribute__((format (printf, 1, 2)))
{'fraction_non_alphanumeric': 0.17529773852535796, 'fraction_numerical': 0.02007226013649137, 'mean_word_length': 3.979347101932045, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, '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': '5724978', 'n_tokens_mistral': 3205, 'n_tokens_neox': 2921, 'n_words': 779}