<commit_before>#include "query_parser.h"

#include "urlencode.h"

namespace simpleServer {



QueryParser::QueryParser(StrViewA vpath) {
	parse(vpath);
}

QueryParser::ParamMap::const_iterator QueryParser::begin() const {
	return pmap.begin();
}

QueryParser::ParamMap::const_iterator QueryParser::end() const {
	return pmap.end();
}

HeaderValue QueryParser::operator [](StrViewA key) const {
	Item srch;
	srch.first = key;
	auto itr = std::lower_bound(pmap.begin(), pmap.end(), srch, &orderItems);
	if (itr == pmap.end() || itr->first != key) return HeaderValue();
	else return HeaderValue(itr->second);
}

void QueryParser::clear() {
}

typedef std::pair<std::size_t, std::size_t> Part;
typedef std::pair<Part, Part> KeyValuePart;

void QueryParser::parse(StrViewA vpath) {

	enum State {
		readingPath,
		readingKey,
		readingValue
	};


	clear();
	std::vector<KeyValuePart> parts;
	std::vector<char> data;

	Part pathPart;
	Part keyPart;
	State state =readingPath;


	auto iter = vpath.begin();
	auto e = vpath.end();
	std::size_t mark = data.size();

	auto wrfn = [&](char c) {
		data.push_back(c);
	};

	auto commitData = [&] {
		Part p(mark, data.size() - mark);
		data.push_back((char)0);
		mark = data.size();
		return p;
	};

	UrlDecode<decltype(wrfn)> urlDecode(wrfn);

	while (iter != e) {
		char c = *iter++;

		switch (state) {
		case readingPath:
			if (c == '?') {
				pathPart = commitData();
				state = readingKey;
			} else{
				wrfn(c);
			}
			break;
		case readingKey:
			if (c == '&') {
				keyPart = commitData();
				parts.push_back(KeyValuePart(keyPart,Part(0,0)));
			} else if (c == '=') {
				keyPart = commitData();
				state = readingValue;
			} else {
				wrfn(c);
			}
			break;
		case readingValue:
			if (c == '&') {
				Part v = commitData();
				parts.push_back(KeyValuePart(keyPart, v));
				state = readingKey;
			} else {
				wrfn(c);
			}
			break;
		}
	}

	switch (state) {
	case readingPath:
		pathPart = commitData();
		break;
	case readingKey:
		keyPart = commitData();
		parts.push_back(KeyValuePart(keyPart,Part(0,0)));
		break;
	case readingValue:
		Part v = commitData();
		parts.push_back(KeyValuePart(keyPart, v));
		break;
	}

	pmap.clear();
	pmap.reserve(parts.size());<commit_msg>fix query parser<commit_after>#include "query_parser.h"

#include "urlencode.h"

namespace simpleServer {



QueryParser::QueryParser(StrViewA vpath) {
	parse(vpath);
}

QueryParser::ParamMap::const_iterator QueryParser::begin() const {
	return pmap.begin();
}

QueryParser::ParamMap::const_iterator QueryParser::end() const {
	return pmap.end();
}

HeaderValue QueryParser::operator [](StrViewA key) const {
	Item srch;
	srch.first = key;
	auto itr = std::lower_bound(pmap.begin(), pmap.end(), srch, &orderItems);
	if (itr == pmap.end() || itr->first != key) return HeaderValue();
	else return HeaderValue(itr->second);
}

void QueryParser::clear() {
}

typedef std::pair<std::size_t, std::size_t> Part;
typedef std::pair<Part, Part> KeyValuePart;

static inline int fromHexDigit(char c) {
	return c>='A' && c <='F'?c-'A'+10
			:c>='a' && c <='f'?c-'a'+10
			:c>='0' && c <= '9'?c-'0'
			:0;
}

void QueryParser::parse(StrViewA vpath) {

	enum State {
		readingPath,
		readingKey,
		readingValue,
		readingSpecChar1,
		readingSpecChar2
	};


	clear();
	std::vector<KeyValuePart> parts;
	std::vector<char> data;

	Part pathPart;
	Part keyPart;
	State state =readingPath;
	State nxstate = readingPath;


	auto iter = vpath.begin();
	auto e = vpath.end();
	std::size_t mark = data.size();
	int specCharBuff;

	auto wrfn = [&](char c) {
		data.push_back(c);
	};

	auto commitData = [&] {
		Part p(mark, data.size() - mark);
		data.push_back((char)0);
		mark = data.size();
		return p;
	};

	UrlDecode<decltype(wrfn)> urlDecode(wrfn);

	while (iter != e) {
		char c = *iter++;

		if (c == '+') {
			wrfn(' ');
		} else if (c == '%') {
			nxstate = state;
			state = readingSpecChar1;
		} else {
			switch (state) {
			case readingPath:
				if (c == '?') {
					pathPart = commitData();
					state = readingKey;
				} else{
					wrfn(c);
				}
				break;
			case readingKey:
				if (c == '&') {
					keyPart = commitData();
					parts.push_back(KeyValuePart(keyPart,Part(0,0)));
				} else if (c == '=') {
					keyPart = commitData();
					state = readingValue;
				} else {
					wrfn(c);
				}
				break;
			case readingValue:
				if (c == '&') {
					Part v = commitData();
					parts.push_back(KeyValuePart(keyPart, v));
					state = readingKey;
				} else {
					wrfn(c);
				}
				break;
			case readingSpecChar1:
				specCharBuff = fromHexDigit(c) * 16;
				state = readingSpecChar2;
				break;
			case readingSpecChar2:
				specCharBuff |= fromHexDigit(c) ;
				wrfn((char)specCharBuff);
				state = nxstate;
				break;
			}

		}
	}

	if (state == readingSpecChar1 || state == readingSpecChar2) {
		state = nxstate;
	}

	switch (state) {
	case readingPath:
		pathPart = commitData();
		break;
	case readingKey:
		keyPart = commitData();
		parts.push_back(KeyValuePart(keyPart,Part(0,0)));
		break;
	case readingValue: {
			Part v = commitData();
			parts.push_back(KeyValuePart(keyPart, v));
		}
		break;

	default:
		break;
	}

	pmap.clear();
	pmap.reserve(parts.size());
{'fraction_non_alphanumeric': 0.16679462571976966, 'fraction_numerical': 0.005374280230326296, 'mean_word_length': 3.640249332146037, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 20, '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': '3847967', 'n_tokens_mistral': 2250, 'n_tokens_neox': 1941, 'n_words': 408}