Esempio n. 1
0
int Jupiter::HTTP::Server::Data::process_request(HTTPSession &session)
{
	Jupiter::ReadableString::TokenizeResult<Jupiter::Reference_String> lines = Jupiter::ReferenceString::tokenize(session.request, STRING_LITERAL_AS_REFERENCE(ENDL));
	HTTPCommand command = HTTPCommand::NONE_SPECIFIED;
	Content *content = nullptr;
	Jupiter::ReferenceString query_string;
	Jupiter::ReferenceString first_token;
	size_t index = 0;
	size_t span;

	auto get_line_offset = [&session, &lines](size_t index)
	{
		size_t offset = 0;
		while (index != 0)
			offset += lines.tokens[--index].size() + 2;
		return offset;
	};

	while (index != lines.token_count)
	{
		Jupiter::ReferenceString &line = lines.tokens[index++];

		// trim front-end spaces.
		span = line.span(" "_jrs);
		if (span != 0)
			line.shiftRight(span);

		if (line.isEmpty()) // end of http request
		{
			Jupiter::String result(256);
			switch (command)
			{
			case HTTPCommand::GET:
			case HTTPCommand::HEAD:
				if (content != nullptr)
				{
					// 200 (success)
					Jupiter::ReadableString *content_result = content->execute(query_string);

					switch (session.version)
					{
					default:
					case HTTPVersion::HTTP_1_0:
						result = "HTTP/1.0 200 OK"_jrs ENDL;
						break;
					case HTTPVersion::HTTP_1_1:
						result = "HTTP/1.1 200 OK"_jrs ENDL;
						break;
					}

					result += "Date: "_jrs;
					char *time_header = html_time();
					result += time_header;
					delete[] time_header;
					result += ENDL;

					result += "Server: "_jrs JUPITER_VERSION ENDL;

					result += Jupiter::StringS::Format("Content-Length: %u" ENDL, content_result->size());

					if (session.keep_alive)
						result += "Connection: keep-alive"_jrs ENDL;
					else
						result += "Connection: close"_jrs ENDL;

					result += "Content-Type: "_jrs;
					if (content->type == nullptr)
						result += Jupiter::HTTP::Content::Type::Text::PLAIN;
					else
						result += *content->type;
					if (content->charset != nullptr)
					{
						result += "; charset="_jrs;
						result += *content->charset;
					}
					result += ENDL;

					if (content->language != nullptr)
					{
						result += "Content-Language: "_jrs;
						result += *content->language;
						result += ENDL;
					}

					result += ENDL;
					if (command == HTTPCommand::GET)
						result += *content_result;

					if (content->free_result)
						delete content_result;

					session.sock.send(result);
				}
				else
				{
					// 404 (not found)

					switch (session.version)
					{
					default:
					case HTTPVersion::HTTP_1_0:
						result = "HTTP/1.0 404 Not Found"_jrs ENDL;
						break;
					case HTTPVersion::HTTP_1_1:
						result = "HTTP/1.1 404 Not Found"_jrs ENDL;
						break;
					}

					char *time_header = html_time();
					result += "Date: "_jrs ENDL;
					result += time_header;
					delete[] time_header;

					result += "Server: "_jrs JUPITER_VERSION ENDL;

					result += "Content-Length: 0"_jrs ENDL;

					if (session.keep_alive)
						result += "Connection: keep-alive"_jrs ENDL;
					else
						result += "Connection: close"_jrs ENDL;

					result += ENDL ENDL;
					session.sock.send(result);
				}
				break;
			default:
				break;
			}

			if (session.keep_alive == false) // not keep-alive -- will be destroyed on return
				break;
			if (index == lines.token_count) // end of packet
				session.request.erase();
			else // end of request -- another request is following
				session.request.shiftRight(get_line_offset(index));

			if (session.request.find(HTTP_REQUEST_ENDING) != Jupiter::INVALID_INDEX) // there's another full request already received
				return Jupiter::HTTP::Server::Data::process_request(session);
			break;
		}

		// Not empty
		first_token = line.getToken(0, ' ');

		if (first_token.get(first_token.size() - 1) == ':') // header field
		{
			first_token.truncate(1); // trim trailing ':'
			if (first_token.equalsi("HOST"_jrs))
				session.host = Jupiter::HTTP::Server::Data::find_host(line.getWord(1, " "));
			else if (first_token.equalsi("CONNECTION"_jrs))
			{
				Jupiter::ReferenceString connection_type = line.getWord(1, " ");
				if (connection_type.equalsi("keep-alive"_jrs))
					session.keep_alive = Jupiter::HTTP::Server::Data::permit_keept_alive;
			}
		}
		else // command
		{
			if (first_token.equals("GET"_jrs))
			{
				command = HTTPCommand::GET;
				
				query_string = line.getWord(1, " ");
				span = query_string.find('?'); // repurposing 'span'
				if (span == Jupiter::INVALID_INDEX)
				{
					if (session.host == nullptr)
						content = Jupiter::HTTP::Server::Data::find(query_string);
					else
						content = session.host->find(query_string);
					query_string.erase();
				}
				else
				{
					if (session.host == nullptr)
						content = Jupiter::HTTP::Server::Data::find(query_string.substring(size_t{ 0 }, span));
					else
						content = session.host->find(query_string.substring(size_t{ 0 }, span));
					query_string.shiftRight(span + 1);
					// decode query_string here
				}

				Jupiter::ReferenceString protocol_str = line.getWord(2, " ");
				if (protocol_str.equalsi("http/1.0"_jrs))
					session.version = HTTPVersion::HTTP_1_0;
				else if (protocol_str.equalsi("http/1.1"_jrs))
				{
					session.version = HTTPVersion::HTTP_1_1;
					session.keep_alive = Jupiter::HTTP::Server::Data::permit_keept_alive;
				}
			}
			else if (first_token.equals("HEAD"_jrs))
			{
				command = HTTPCommand::HEAD;
				
				query_string = line.getWord(1, " ");
				span = query_string.find('?'); // repurposing 'span'
				if (span == Jupiter::INVALID_INDEX)
				{
					if (session.host == nullptr)
						content = Jupiter::HTTP::Server::Data::find(query_string);
					else
						content = session.host->find(query_string);
					query_string.erase();
				}
				else
				{
					if (session.host == nullptr)
						content = Jupiter::HTTP::Server::Data::find(query_string.substring(size_t{ 0 }, span));
					else
						content = session.host->find(query_string.substring(size_t{ 0 }, span));
					query_string.shiftRight(span + 1);
					// decode query_string here
				}

				Jupiter::ReferenceString protocol_str = line.getWord(2, " ");
				if (protocol_str.equalsi("http/1.0"_jrs))
					session.version = HTTPVersion::HTTP_1_0;
				else if (protocol_str.equalsi("http/1.1"_jrs))
				{
					session.version = HTTPVersion::HTTP_1_1;
					session.keep_alive = Jupiter::HTTP::Server::Data::permit_keept_alive;
				}
			}
			else
				command = HTTPCommand::UNKNOWN;
		}
	}
	return 0;
}