<commit_before>#include <stutter/http/parser.h>
#include <stutter/http/message.h>
#include <stutter/http/request.h>
#include <stutter/http/reply.h>
#include <stutter/http/joyent/http_parser.h>

#include <string.h>
#include <cstdlib>
#include <iostream>

using namespace std;
using http::Parser;

#define MAX_UPLOAD_SIZE (1024*1024)
#define MAX_URI_LENGTH  (4096)

/* http-parser callbacks */

namespace http {
int
_http_on_url_cb(http_parser *p, const char *at, size_t sz)
{
	Parser *parser = reinterpret_cast<Parser*>(p->data);
	parser->add_url_fragment(at, sz);
	return 0;
}

int
_http_on_message_complete_cb(http_parser *p)
{
	Parser *parser = reinterpret_cast<Parser*>(p->data);
	parser->callback();
	return 0;
}

int
_http_on_header_field_cb(http_parser *p, const char *at, size_t sz)
{
	Parser *parser = reinterpret_cast<Parser*>(p->data);
	parser->save_last_header();
	parser->m_header_key.append(at, sz);
	return 0;
}

int
_http_on_header_value_cb(http_parser *p, const char *at, size_t sz)
{
	Parser *parser = reinterpret_cast<Parser*>(p->data);
	parser->m_header_val.append(at, sz);
	parser->m_header_gotval = true;
	return 0;
}

int
_http_on_body_cb(http_parser *p, const char *at, size_t sz)
{
	Parser *parser = reinterpret_cast<Parser*>(p->data);
	parser->add_body_fragment(at, sz);
	return 0;
}

int
_http_on_headers_complete_cb(http_parser *p)
{
	Parser *parser = reinterpret_cast<Parser*>(p->data);
	return parser->save_last_header();
}
}

int
Parser::save_last_header()
{
	if (m_header_gotval) {
		m_msg->add_header(m_header_key, m_header_val);

		m_header_key.clear();
		m_header_val.clear();
		m_header_gotval = false;
	}

	// check for large uploads
	if (m_mode == REQUEST) {
		string cl = m_request->get_header(Message::ContentLength);
		long sz = ::atol(cl.c_str());
		if (sz < 0 || sz > MAX_UPLOAD_SIZE) {
			m_error = PARSE_BODY_TOO_LARGE;
			return 0;
		}
	}

	// 100-continue
	if (m_mode == REQUEST && m_request->get_header(Message::Expect)
			== Message::OneHundredContinue) {
		m_error = PARSE_NEED_100_CONTINUE;
		return 0;
	}

	return 0;
}

void
Parser::add_url_fragment(const char *p, size_t sz)
{
	if (m_mode == REQUEST && m_error != PARSE_URI_TOO_LONG) {
		if (m_request->url().size() + sz > MAX_URI_LENGTH) {
			m_error = PARSE_URI_TOO_LONG;
		} else {
			m_request->add_url_fragment(p, sz);
		}
	}
}

void
Parser::add_body_fragment(const char *at, size_t sz)
{
	if (m_error != PARSE_BODY_TOO_LARGE)
		m_msg->add_body(at, sz);
}

void
Parser::callback()
{
	switch (m_mode) {
		case REQUEST: // handle Verb
			switch(m_parser->method) {
				case HTTP_GET:    m_request->set_verb(Request::GET);    break;
				case HTTP_POST:   m_request->set_verb(Request::POST);   break;
				case HTTP_PUT:    m_request->set_verb(Request::PUT);    break;
				case HTTP_HEAD:   m_request->set_verb(Request::HEAD);   break;
				case HTTP_DELETE: m_request->set_verb(Request::DELETE); break;
				default: break;
			}
			break;

		case RESPONSE: // handle status code
			// TODO: handle status line
			m_reply->set_status(m_parser->status_code, "");
			break;
	}

	m_fun(m_fun_data);
}

Parser::Parser(Mode m, http::Request *request, void (*fun)(void*), void *ptr)
	: m_mode(m)
	, m_request(request)
	, m_reply(0)
	, m_msg(m_request)
	, m_fun(fun)
	, m_fun_data(ptr)
{
	m_parser = new http_parser;
	m_parserconf = new http_parser_settings;
	reset();
}

Parser::Parser(Mode m, http::Reply *reply, void (*fun)(void*), void *ptr)
	: m_mode(m)
	, m_request(0)
	, m_reply(reply)
	, m_msg(m_reply)
	, m_fun(fun)
	, m_fun_data(ptr)
{
	m_parser = new http_parser;
	m_parserconf = new http_parser_settings;
	reset();
}

Parser::~Parser()
{
	delete m_parserconf;
	delete m_parser;
}

Parser::Error
Parser::add(const char *p, size_t sz)
{
	size_t nparsed = http_parser_execute(m_parser, m_parserconf, p, sz);
	if (nparsed == sz)
		return m_error;
	return PARSE_FAILURE; // invalid HTTP
}

Parser::Error
Parser::error() const
{
	return m_error;<commit_msg>Backed out changeset 0b771f478af5<commit_after>#include <stutter/http/parser.h>
#include <stutter/http/message.h>
#include <stutter/http/request.h>
#include <stutter/http/reply.h>
#include <stutter/http/joyent/http_parser.h>

#include <string.h>
#include <cstdlib>
#include <iostream>

using namespace std;
using http::Parser;

#define MAX_UPLOAD_SIZE (1024*1024)
#define MAX_URI_LENGTH  (4096)

/* http-parser callbacks */

namespace http {
int
_http_on_url_cb(http_parser *p, const char *at, size_t sz)
{
	Parser *parser = reinterpret_cast<Parser*>(p->data);
	parser->add_url_fragment(at, sz);
	return 0;
}

int
_http_on_message_complete_cb(http_parser *p)
{
	Parser *parser = reinterpret_cast<Parser*>(p->data);
	parser->callback();
	return 0;
}

int
_http_on_header_field_cb(http_parser *p, const char *at, size_t sz)
{
	Parser *parser = reinterpret_cast<Parser*>(p->data);
	parser->save_last_header();
	parser->m_header_key.append(at, sz);
	return 0;
}

int
_http_on_header_value_cb(http_parser *p, const char *at, size_t sz)
{
	Parser *parser = reinterpret_cast<Parser*>(p->data);
	parser->m_header_val.append(at, sz);
	parser->m_header_gotval = true;
	return 0;
}

int
_http_on_body_cb(http_parser *p, const char *at, size_t sz)
{
	Parser *parser = reinterpret_cast<Parser*>(p->data);
	parser->add_body_fragment(at, sz);
	return 0;
}

int
_http_on_headers_complete_cb(http_parser *p)
{
	Parser *parser = reinterpret_cast<Parser*>(p->data);
	return parser->save_last_header();
}
}

int
Parser::save_last_header()
{
	if (m_header_gotval) {
		m_msg->add_header(m_header_key, m_header_val);

		m_header_key.clear();
		m_header_val.clear();
		m_header_gotval = false;
	}

	// check for large uploads
	if (m_mode == REQUEST) {
		string cl = m_request->get_header(Message::ContentLength);
		long sz = ::atol(cl.c_str());
		if (sz < 0 || sz > MAX_UPLOAD_SIZE) {
			m_error = PARSE_BODY_TOO_LARGE;
			return 0;
		}
	}

	// 100-continue
	if (m_mode == REQUEST && m_request->get_header(Message::Expect)
			== Message::OneHundredContinue) {
		m_error = PARSE_NEED_100_CONTINUE;
		return 0;
	}

	return 0;
}

void
Parser::add_url_fragment(const char *p, size_t sz)
{
	if (m_mode == REQUEST && m_error != PARSE_URI_TOO_LONG) {
		if (m_request->url().size() + sz > MAX_URI_LENGTH) {
			m_error = PARSE_URI_TOO_LONG;
		} else {
			m_request->add_url_fragment(p, sz);
		}
	}
}

void
Parser::add_body_fragment(const char *at, size_t sz)
{
	if (m_error != PARSE_BODY_TOO_LARGE)
		m_msg->add_body(at, sz);
}

void
Parser::callback()
{
	switch (m_mode) {
		case REQUEST: // handle Verb
			switch(m_parser->method) {
				case HTTP_GET:    m_request->set_verb(Request::GET);    break;
				case HTTP_POST:   m_request->set_verb(Request::POST);   break;
				case HTTP_PUT:    m_request->set_verb(Request::PUT);    break;
				case HTTP_HEAD:   m_request->set_verb(Request::HEAD);   break;
				case HTTP_DELETE: m_request->set_verb(Request::DELETE); break;
				default: break;
			}
			break;

		case RESPONSE: // handle status code
			// TODO: handle status line
			m_reply->set_status(m_parser->status_code, "");
			break;
	}

	m_fun(m_fun_data);
}

Parser::Parser(Mode m, http::Request *request, void (*fun)(void*), void *ptr)
	: m_mode(m)
	, m_request(request)
	, m_reply(0)
	, m_msg(m_request)
	, m_fun(fun)
	, m_fun_data(ptr)
{
	m_parser = new http_parser;
	m_parserconf = new http_parser_settings;
	reset();
}

Parser::Parser(Mode m, http::Reply *reply, void (*fun)(void*), void *ptr)
	: m_mode(m)
	, m_request(0)
	, m_reply(reply)
	, m_msg(m_reply)
	, m_fun(fun)
	, m_fun_data(ptr)
{
	m_parser = new http_parser;
	m_parserconf = new http_parser_settings;
	reset();
}

Parser::~Parser()
{
	delete m_parserconf;
	delete m_parser;
}

Parser::Error
Parser::add(const char *p, size_t sz)
{
	m_error = PARSE_OK; // reset error state

	size_t nparsed = http_parser_execute(m_parser, m_parserconf, p, sz);
	if (nparsed == sz)
		return m_error;
	return PARSE_FAILURE; // invalid HTTP
}

Parser::Error
Parser::error() const
{
	return m_error;
{'fraction_non_alphanumeric': 0.14520376175548588, 'fraction_numerical': 0.008275862068965517, 'mean_word_length': 4.921306607275427, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 91, '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': '1843134', 'n_tokens_mistral': 3389, 'n_tokens_neox': 3209, 'n_words': 613}