<commit_before>/* <x0/HttpConnection.cpp>
 *
 * This file is part of the x0 web server project and is released under AGPL-3.
 * http://www.xzero.io/
 *
 * (c) 2009-2014 <NAME> <<EMAIL>>
 */

#include <x0/http/HttpConnection.h>
#include <x0/http/HttpRequest.h>
#include <x0/http/HttpWorker.h>
#include <x0/ServerSocket.h>
#include <x0/SocketDriver.h>
#include <x0/StackTrace.h>
#include <x0/Socket.h>
#include <x0/Types.h>
#include <x0/DebugLogger.h>
#include <x0/sysconfig.h>

#include <functional>
#include <cstdarg>

#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>

#if !defined(XZERO_NDEBUG)
#	define TRACE(level, msg...) XZERO_DEBUG("HttpConnection", (level), msg)
#else
#	define TRACE(msg...) do { } while (0)
#endif

namespace x0 {

/**
 * \class HttpConnection
 * \brief represents an HTTP connection handling incoming requests.
 *
 * The \p HttpConnection object is to be allocated once an HTTP client connects
 * to the HTTP server and was accepted by the \p ServerSocket.
 * It will also own the respective request and response objects created to serve
 * the requests passed through this connection.
 */

/* TODO
 * - should request bodies land in requestBuffer_? someone with a good line could flood us w/ streaming request bodies.
 */

/** initializes a new connection object, created by given listener.
 *
 * \param lst the listener object that created this connection.
 * \note This triggers the onConnectionOpen event.
 */
HttpConnection::HttpConnection(HttpWorker* w, unsigned long long id) :
	HttpMessageParser(HttpMessageParser::REQUEST),
	refCount_(0),
	state_(Undefined),
	listener_(nullptr),
	worker_(w),
	id_(id),
	requestCount_(0),
	flags_(0),
    requestBuffer_(worker().server().requestHeaderBufferSize()
                 + worker().server().requestBodyBufferSize()),
	requestParserOffset_(0),
	request_(nullptr),
	output_(),
	socket_(nullptr),
	sink_(nullptr),
	autoFlush_(true),
	abortHandler_(nullptr),
	abortData_(nullptr),
	prev_(nullptr),
	next_(nullptr)
{
}

/** releases all connection resources  and triggers the onConnectionClose event.
 */
HttpConnection::~HttpConnection()
{
	TRACE(1, "%d: destructing", id_);
	if (request_)
		delete request_;

	if (socket_)
		delete socket_;
}

/**
 * Frees up any resources and resets state of this connection.
 *
 * This method is invoked only after the connection has been closed and
 * this resource may now either be physically destructed or put into
 * a list of free connection objects for later use of newly incoming
 * connections (to avoid too many memory allocations).
 */
void HttpConnection::clear()
{
	TRACE(1, "clear(): refCount: %zu, conn.state: %s, pstate: %s", refCount_, state_str(), parserStateStr());
	//TRACE(1, "Stack Trace:\n%s", StackTrace().c_str());

	HttpMessageParser::reset();

	if (request_) {
		request_->clear();
	}

	clearCustomData();

	worker_->server_.onConnectionClose(this);
	delete socket_;
	socket_ = nullptr;
	requestCount_ = 0;

	requestParserOffset_ = 0;
	requestBuffer_.clear();
}

void HttpConnection::revive(unsigned long long id)
{
    id_ = id;
	flags_ = 0;
	socket_ = nullptr;
}

void HttpConnection::ref()
{
	++refCount_;
	TRACE(1, "ref() %u", refCount_);
}

void HttpConnection::unref()
{
	--refCount_;

	TRACE(1, "unref() %u (closed:%d, outputPending:%d)", refCount_, isClosed(), isOutputPending());

	if (refCount_ == 0) {
		clear();
		worker_->release(this);
	}
}

void HttpConnection::io(Socket *, int revents)
{
	TRACE(1, "io(revents=%04x) %s, %s, isHandlingRequest:%d",
        revents, state_str(), parserStateStr(), isHandlingRequest());

	ref();

	if (revents & ev::ERROR) {
		log(Severity::error, "Potential bug in connection I/O watching. Closing.");
		abort();
		goto done;
	}

	// socket is ready for read?
	if (revents & Socket::Read) {
        if (!readSome()) {
            log(Severity::error, "readSome() failed");
            goto done;
        }
    }

	// socket is ready for write?
	if (revents & Socket::Write) {
        if (!writeSome()) {
            log(Severity::error, "writeSome() failed");
            goto done;
        }
    }

done:
	unref();
}

void HttpConnection::timeout(Socket *)
{
	TRACE(1, "timeout(): cstate:%s, pstate:%s", state_str(), parserStateStr());

	switch (state()) {
	case Undefined:
	case ReadingRequest:
	case ProcessingRequest:
		// we do not want further out-timing requests on this conn: just close it.<commit_msg>http: remove unnecessary error messages<commit_after>/* <x0/HttpConnection.cpp>
 *
 * This file is part of the x0 web server project and is released under AGPL-3.
 * http://www.xzero.io/
 *
 * (c) 2009-2014 <NAME> <<EMAIL>>
 */

#include <x0/http/HttpConnection.h>
#include <x0/http/HttpRequest.h>
#include <x0/http/HttpWorker.h>
#include <x0/ServerSocket.h>
#include <x0/SocketDriver.h>
#include <x0/StackTrace.h>
#include <x0/Socket.h>
#include <x0/Types.h>
#include <x0/DebugLogger.h>
#include <x0/sysconfig.h>

#include <functional>
#include <cstdarg>

#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>

#if !defined(XZERO_NDEBUG)
#	define TRACE(level, msg...) XZERO_DEBUG("HttpConnection", (level), msg)
#else
#	define TRACE(msg...) do { } while (0)
#endif

namespace x0 {

/**
 * \class HttpConnection
 * \brief represents an HTTP connection handling incoming requests.
 *
 * The \p HttpConnection object is to be allocated once an HTTP client connects
 * to the HTTP server and was accepted by the \p ServerSocket.
 * It will also own the respective request and response objects created to serve
 * the requests passed through this connection.
 */

/* TODO
 * - should request bodies land in requestBuffer_? someone with a good line could flood us w/ streaming request bodies.
 */

/** initializes a new connection object, created by given listener.
 *
 * \param lst the listener object that created this connection.
 * \note This triggers the onConnectionOpen event.
 */
HttpConnection::HttpConnection(HttpWorker* w, unsigned long long id) :
	HttpMessageParser(HttpMessageParser::REQUEST),
	refCount_(0),
	state_(Undefined),
	listener_(nullptr),
	worker_(w),
	id_(id),
	requestCount_(0),
	flags_(0),
    requestBuffer_(worker().server().requestHeaderBufferSize()
                 + worker().server().requestBodyBufferSize()),
	requestParserOffset_(0),
	request_(nullptr),
	output_(),
	socket_(nullptr),
	sink_(nullptr),
	autoFlush_(true),
	abortHandler_(nullptr),
	abortData_(nullptr),
	prev_(nullptr),
	next_(nullptr)
{
}

/** releases all connection resources  and triggers the onConnectionClose event.
 */
HttpConnection::~HttpConnection()
{
	TRACE(1, "%d: destructing", id_);
	if (request_)
		delete request_;

	if (socket_)
		delete socket_;
}

/**
 * Frees up any resources and resets state of this connection.
 *
 * This method is invoked only after the connection has been closed and
 * this resource may now either be physically destructed or put into
 * a list of free connection objects for later use of newly incoming
 * connections (to avoid too many memory allocations).
 */
void HttpConnection::clear()
{
	TRACE(1, "clear(): refCount: %zu, conn.state: %s, pstate: %s", refCount_, state_str(), parserStateStr());
	//TRACE(1, "Stack Trace:\n%s", StackTrace().c_str());

	HttpMessageParser::reset();

	if (request_) {
		request_->clear();
	}

	clearCustomData();

	worker_->server_.onConnectionClose(this);
	delete socket_;
	socket_ = nullptr;
	requestCount_ = 0;

	requestParserOffset_ = 0;
	requestBuffer_.clear();
}

void HttpConnection::revive(unsigned long long id)
{
    id_ = id;
	flags_ = 0;
	socket_ = nullptr;
}

void HttpConnection::ref()
{
	++refCount_;
	TRACE(1, "ref() %u", refCount_);
}

void HttpConnection::unref()
{
	--refCount_;

	TRACE(1, "unref() %u (closed:%d, outputPending:%d)", refCount_, isClosed(), isOutputPending());

	if (refCount_ == 0) {
		clear();
		worker_->release(this);
	}
}

void HttpConnection::io(Socket *, int revents)
{
	TRACE(1, "io(revents=%04x) %s, %s, isHandlingRequest:%d",
        revents, state_str(), parserStateStr(), isHandlingRequest());

	ref();

	if (revents & ev::ERROR) {
		log(Severity::error, "Potential bug in connection I/O watching. Closing.");
		abort();
		goto done;
	}

	// socket is ready for read?
	if (revents & Socket::Read) {
        if (!readSome()) {
            goto done;
        }
    }

	// socket is ready for write?
	if (revents & Socket::Write) {
        if (!writeSome()) {
            goto done;
        }
    }

done:
	unref();
}

void HttpConnection::timeout(Socket *)
{
	TRACE(1, "timeout(): cstate:%s, pstate:%s", state_str(), parserStateStr());

	switch (state()) {
	case Undefined:
	case ReadingRequest:
	case ProcessingRequest:
		// we do not want further out-timing requests on this conn: just close it.
{'fraction_non_alphanumeric': 0.14100670378366095, 'fraction_numerical': 0.009089876150437451, 'mean_word_length': 4.174603174603175, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 49, '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': '6510495', 'n_tokens_mistral': 2883, 'n_tokens_neox': 2832, 'n_words': 841}