<commit_before>#include "http.h"
#include "server.h"
#include "worker.h"
#include "client.h"
#include "slog.h"

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

/* HTTP Response */

#define DEFAULT_HEADERS_ARRAY_SIZE 9

static void
http_response_allocate_headers(struct http_response *r) {
	r->headers_array_size = DEFAULT_HEADERS_ARRAY_SIZE;
	r->headers = calloc(r->headers_array_size, sizeof(struct http_header));
}

struct http_response *
http_response_init(struct worker *w, int code, const char *msg) {

	/* create object */
	struct http_response *r = calloc(1, sizeof(struct http_response));
	if(!r) {
		if(w && w->s) slog(w->s, WEBDIS_ERROR, "Failed to allocate http_response", 0);
		return NULL;
	}

	r->code = code;
	r->msg = msg;
	r->w = w;
	r->keep_alive = 0; /* default */

	/* pre-allocate array for headers */
	http_response_allocate_headers(r);
	if(!r->headers) {
		if(w && w->s) slog(w->s, WEBDIS_ERROR, "Failed to allocate http_response headers", 0);
		free(r);
		return NULL;
	}

	http_response_set_header(r, "Server", "Webdis", HEADER_COPY_NONE);

	/* Cross-Origin Resource Sharing, CORS. */
	http_response_set_header(r, "Allow", "GET,POST,PUT,OPTIONS", HEADER_COPY_NONE);
	/*
	Chrome doesn't support Allow and requires 
	Access-Control-Allow-Methods
	*/
	http_response_set_header(r, "Access-Control-Allow-Methods", "GET,POST,PUT,OPTIONS", HEADER_COPY_NONE);
	http_response_set_header(r, "Access-Control-Allow-Origin", "*", HEADER_COPY_NONE);
	/* 
	According to 
	http://www.w3.org/TR/cors/#access-control-allow-headers-response-header
	Access-Control-Allow-Headers cannot be a wildcard and must be set
	with explicit names
	*/
	http_response_set_header(r, "Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Authorization", HEADER_COPY_NONE);

	return r;
}

struct http_response *
http_response_init_with_buffer(struct worker *w, char *data, size_t data_sz, int keep_alive) {

	struct http_response *r = calloc(1, sizeof(struct http_response));
	if(!r) {
		if(w && w->s) slog(w->s, WEBDIS_ERROR, "Failed to allocate http_response with buffer", 0);
		return NULL;
	}
	r->w = w;

	/* pre-allocate array for headers */
	http_response_allocate_headers(r);
	if(!r->headers) {
		if(w && w->s) slog(w->s, WEBDIS_ERROR, "Failed to allocate http_response headers", 0);
		free(r);
		return NULL;
	}

	/* provide buffer directly */
	r->out = data;
	r->out_sz = data_sz;
	r->sent = 0;
	r->keep_alive = keep_alive;
	return r;
}


void
http_response_set_header(struct http_response *r, const char *k, const char *v, header_copy copy) {

	int i, pos = r->header_count;
	size_t key_sz = strlen(k);
	size_t val_sz = strlen(v);

	if(copy & HEADER_CHECK_DUPE) {
		for(i = 0; i < r->header_count; ++i) {
			if(strncmp(r->headers[i].key, k, key_sz) == 0) {
				pos = i;
				/* free old value before replacing it. */
				if(r->headers[i].copy & HEADER_COPY_KEY) free(r->headers[i].key);
				if(r->headers[i].copy & HEADER_COPY_VALUE) free(r->headers[i].val);
				break;
			}
		}
	}

	/* extend array */
	if(pos == r->headers_array_size) {
		/* FIXME: allocation could fail */
		r->headers = realloc(r->headers,
				sizeof(struct http_header)*(r->headers_array_size + 1));
		r->headers_array_size++;
	}
	r->header_count++;

	/* copy key if needed */
	if(copy & HEADER_COPY_KEY) {
		r->headers[pos].key = calloc(key_sz + 1, 1);
		memcpy(r->headers[pos].key, k, key_sz);
	} else {
		r->headers[pos].key = (char *)k;
	}
	r->headers[pos].key_sz = key_sz;

	/* copy val */
	if(copy & HEADER_COPY_VALUE) {
		r->headers[pos].val = calloc(val_sz + 1, 1);
		memcpy(r->headers[pos].val, v, val_sz);
	} else {<commit_msg>Preserve header count when a value is replaced<commit_after>#include "http.h"
#include "server.h"
#include "worker.h"
#include "client.h"
#include "slog.h"

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

/* HTTP Response */

#define DEFAULT_HEADERS_ARRAY_SIZE 9

static void
http_response_allocate_headers(struct http_response *r) {
	r->headers_array_size = DEFAULT_HEADERS_ARRAY_SIZE;
	r->headers = calloc(r->headers_array_size, sizeof(struct http_header));
}

struct http_response *
http_response_init(struct worker *w, int code, const char *msg) {

	/* create object */
	struct http_response *r = calloc(1, sizeof(struct http_response));
	if(!r) {
		if(w && w->s) slog(w->s, WEBDIS_ERROR, "Failed to allocate http_response", 0);
		return NULL;
	}

	r->code = code;
	r->msg = msg;
	r->w = w;
	r->keep_alive = 0; /* default */

	/* pre-allocate array for headers */
	http_response_allocate_headers(r);
	if(!r->headers) {
		if(w && w->s) slog(w->s, WEBDIS_ERROR, "Failed to allocate http_response headers", 0);
		free(r);
		return NULL;
	}

	http_response_set_header(r, "Server", "Webdis", HEADER_COPY_NONE);

	/* Cross-Origin Resource Sharing, CORS. */
	http_response_set_header(r, "Allow", "GET,POST,PUT,OPTIONS", HEADER_COPY_NONE);
	/*
	Chrome doesn't support Allow and requires 
	Access-Control-Allow-Methods
	*/
	http_response_set_header(r, "Access-Control-Allow-Methods", "GET,POST,PUT,OPTIONS", HEADER_COPY_NONE);
	http_response_set_header(r, "Access-Control-Allow-Origin", "*", HEADER_COPY_NONE);
	/* 
	According to 
	http://www.w3.org/TR/cors/#access-control-allow-headers-response-header
	Access-Control-Allow-Headers cannot be a wildcard and must be set
	with explicit names
	*/
	http_response_set_header(r, "Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Authorization", HEADER_COPY_NONE);

	return r;
}

struct http_response *
http_response_init_with_buffer(struct worker *w, char *data, size_t data_sz, int keep_alive) {

	struct http_response *r = calloc(1, sizeof(struct http_response));
	if(!r) {
		if(w && w->s) slog(w->s, WEBDIS_ERROR, "Failed to allocate http_response with buffer", 0);
		return NULL;
	}
	r->w = w;

	/* pre-allocate array for headers */
	http_response_allocate_headers(r);
	if(!r->headers) {
		if(w && w->s) slog(w->s, WEBDIS_ERROR, "Failed to allocate http_response headers", 0);
		free(r);
		return NULL;
	}

	/* provide buffer directly */
	r->out = data;
	r->out_sz = data_sz;
	r->sent = 0;
	r->keep_alive = keep_alive;
	return r;
}


void
http_response_set_header(struct http_response *r, const char *k, const char *v, header_copy copy) {

	int i, pos = r->header_count;
	int replaced = 0; /* whether we overwrote a previous value */
	size_t key_sz = strlen(k);
	size_t val_sz = strlen(v);

	if(copy & HEADER_CHECK_DUPE) {
		for(i = 0; i < r->header_count; ++i) {
			if(strncmp(r->headers[i].key, k, key_sz) == 0) {
				pos = i;
				/* free old value before replacing it. */
				if(r->headers[i].copy & HEADER_COPY_KEY) free(r->headers[i].key);
				if(r->headers[i].copy & HEADER_COPY_VALUE) free(r->headers[i].val);
				replaced = 1;
				break;
			}
		}
	}

	/* extend array */
	if(pos == r->headers_array_size) {
		/* FIXME: allocation could fail */
		r->headers = realloc(r->headers,
				sizeof(struct http_header)*(r->headers_array_size + 1));
		r->headers_array_size++;
	}
	if(!replaced) {
		r->header_count++;
	}

	/* copy key if needed */
	if(copy & HEADER_COPY_KEY) {
		r->headers[pos].key = calloc(key_sz + 1, 1);
		memcpy(r->headers[pos].key, k, key_sz);
	} else {
		r->headers[pos].key = (char *)k;
	}
	r->headers[pos].key_sz = key_sz;

	/* copy val */
	if(copy & HEADER_COPY_VALUE) {
		r->headers[pos].val = calloc(val_sz + 1, 1);
		memcpy(r->headers[pos].val, v, val_sz);
	} else {
{'fraction_non_alphanumeric': 0.1598762942046524, 'fraction_numerical': 0.004840661557079467, 'mean_word_length': 4.335724533715926, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 93, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '4753759', 'n_tokens_mistral': 3014, 'n_tokens_neox': 2812, 'n_words': 621}