<commit_before>/* <x0/response.cpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 *
 * (c) 2009 <NAME> <<EMAIL>>
 */

#include <x0/response.hpp>
#include <x0/server.hpp>
#include <x0/io/file.hpp>
#include <x0/io/file_source.hpp>
#include <x0/io/buffer_source.hpp>
#include <x0/io/chunked_filter.hpp>
#include <x0/strutils.hpp>
#include <x0/types.hpp>

#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <strings.h>						// strcasecmp
#include <string>
#include <algorithm>

namespace x0 {

using boost::algorithm::iequals;

char response::status_codes[512][4];

response::~response()
{
	//DEBUG("~response(%p, conn=%p)", this, connection_);
}

template<typename T>
inline std::string make_str(T value)
{
	return boost::lexical_cast<std::string>(value);
}

source_ptr response::make_default_content()
{
	if (content_forbidden()) // || !equals(request_->method, "GET"))
		return source_ptr();

	std::string filename(connection_->server().config()["ErrorDocuments"][make_str(status)].as<std::string>());
	fileinfo_ptr fi(connection_->server().fileinfo(filename));
	if (fi->exists())
	{
		file_ptr f(new file(fi));

		headers.set("Content-Type", fi->mimetype());
		headers.set("Content-Length", boost::lexical_cast<std::string>(fi->size()));

		return std::make_shared<file_source>(f);
	}
	else
	{
		const char *codeStr = status_cstr(status);
		char buf[1024];

		int nwritten = snprintf(buf, sizeof(buf),
			"<html>"
			"<head><title>%s</title></head>"
			"<body><h1>%d %s</h1></body>"
			"</html>\r\n",
			codeStr, status(), codeStr
		);

		headers.set("Content-Type", "text/html");
		headers.set("Content-Length", boost::lexical_cast<std::string>(nwritten));

		return std::make_shared<buffer_source>(buffer::from_copy(buf, nwritten));
	}
}

source_ptr response::serialize()
{
	buffer buffers;

	if (!status)
	{
		status = response::ok;
	}

	if (!headers.contains("Content-Type"))
	{
		headers.push_back("Content-Type", "text/plain"); //!< \todo pass "default" content-type instead!
	}

	if (!headers.contains("Content-Length") && !content_forbidden())
	{
		headers.set("Connection", "closed");
	}
	else if (!headers.contains("Connection"))
	{
		if (iequals(request_->header("Connection"), "keep-alive"))
			headers.push_back("Connection", "keep-alive");
		else
			headers.push_back("Connection", "closed");
	}

	// post-response hook
	connection_->server().post_process(const_cast<x0::request *>(request_), this);

	// enable chunked transfer encoding if required and possible
	if (!headers.contains("Content-Length"))
	{
		if (request_->supports_protocol(1, 1)
			&& !headers.contains("Transfer-Encoding")
			&& !content_forbidden())
		{
			headers.push_back("Transfer-Encoding", "chunked");
			filter_chain.push_back(std::make_shared<chunked_filter>());
		}
		else
		{
			headers.set("Connection", "closed");
		}
	}

	if (request_->supports_protocol(1, 1))
		buffers.push_back("HTTP/1.1 ");
	else if (request_->supports_protocol(1, 0))
		buffers.push_back("HTTP/1.0 ");
	else
		buffers.push_back("HTTP/0.9 ");

	buffers.push_back(status_codes[status]);
	buffers.push_back(' ');
	buffers.push_back(status_cstr(status));<commit_msg>core: fixes a few typos wrt "Connection: close" response header.<commit_after>/* <x0/response.cpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 *
 * (c) 2009 <NAME> <<EMAIL>>
 */

#include <x0/response.hpp>
#include <x0/server.hpp>
#include <x0/io/file.hpp>
#include <x0/io/file_source.hpp>
#include <x0/io/buffer_source.hpp>
#include <x0/io/chunked_filter.hpp>
#include <x0/strutils.hpp>
#include <x0/types.hpp>

#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <strings.h>						// strcasecmp
#include <string>
#include <algorithm>

namespace x0 {

using boost::algorithm::iequals;

char response::status_codes[512][4];

response::~response()
{
	//DEBUG("~response(%p, conn=%p)", this, connection_);
}

template<typename T>
inline std::string make_str(T value)
{
	return boost::lexical_cast<std::string>(value);
}

source_ptr response::make_default_content()
{
	if (content_forbidden()) // || !equals(request_->method, "GET"))
		return source_ptr();

	std::string filename(connection_->server().config()["ErrorDocuments"][make_str(status)].as<std::string>());
	fileinfo_ptr fi(connection_->server().fileinfo(filename));
	if (fi->exists())
	{
		file_ptr f(new file(fi));

		headers.set("Content-Type", fi->mimetype());
		headers.set("Content-Length", boost::lexical_cast<std::string>(fi->size()));

		return std::make_shared<file_source>(f);
	}
	else
	{
		const char *codeStr = status_cstr(status);
		char buf[1024];

		int nwritten = snprintf(buf, sizeof(buf),
			"<html>"
			"<head><title>%s</title></head>"
			"<body><h1>%d %s</h1></body>"
			"</html>\r\n",
			codeStr, status(), codeStr
		);

		headers.set("Content-Type", "text/html");
		headers.set("Content-Length", boost::lexical_cast<std::string>(nwritten));

		return std::make_shared<buffer_source>(buffer::from_copy(buf, nwritten));
	}
}

source_ptr response::serialize()
{
	buffer buffers;

	if (!status)
	{
		status = response::ok;
	}

	if (!headers.contains("Content-Type"))
	{
		headers.push_back("Content-Type", "text/plain"); //!< \todo pass "default" content-type instead!
	}

	if (!headers.contains("Content-Length") && !content_forbidden())
	{
		headers.set("Connection", "close");
	}
	else if (!headers.contains("Connection"))
	{
		if (iequals(request_->header("Connection"), "keep-alive"))
			headers.push_back("Connection", "keep-alive");
		else
			headers.push_back("Connection", "close");
	}

	// post-response hook
	connection_->server().post_process(const_cast<x0::request *>(request_), this);

	// enable chunked transfer encoding if required and possible
	if (!headers.contains("Content-Length"))
	{
		if (request_->supports_protocol(1, 1)
			&& !headers.contains("Transfer-Encoding")
			&& !content_forbidden())
		{
			headers.push_back("Transfer-Encoding", "chunked");
			filter_chain.push_back(std::make_shared<chunked_filter>());
		}
		else
		{
			headers.set("Connection", "close");
		}
	}

	if (request_->supports_protocol(1, 1))
		buffers.push_back("HTTP/1.1 ");
	else if (request_->supports_protocol(1, 0))
		buffers.push_back("HTTP/1.0 ");
	else
		buffers.push_back("HTTP/0.9 ");

	buffers.push_back(status_codes[status]);
	buffers.push_back(' ');
	buffers.push_back(status_cstr(status));
{'fraction_non_alphanumeric': 0.1918424317617866, 'fraction_numerical': 0.012096774193548387, 'mean_word_length': 5.341199606686333, 'pattern_counts': {'":': 0, '<': 77, '<?xml version=': 0, '>': 97, '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': '6301994', 'n_tokens_mistral': 2437, 'n_tokens_neox': 2282, 'n_words': 386}