/*
 * Copyright 2022 Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Niels Sascha Reedijk, niels.reedijk@gmail.com
 *
 * Corresponds to:
 *		headers/private/netservices2/HttpRequest.h			hrev?????
 *		src/kits/network/libnetservices2/HttpRequest.cpp	hrev?????
 */


#if __cplusplus >= 201703L


/*!
	\file HttpRequest.h
	\ingroup netservices
	\brief Provides the classes and tools to build HTTP Requests.

	\since Haiku R1
*/


namespace BPrivate {

namespace Network {


/*!
	\class BHttpMethod
	\ingroup netservices
	\brief Represent a HTTP method.

	The <a href="https://datatracker.ietf.org/doc/html/rfc7231#section-4.1">HTTP standard</a>
	specifies that HTTP requests have a method. Common methods are \c GET and \c HEAD methods.
	Standardized and common methods are in the form of \em verbs and are in capitalized letters
	from the ASCII token set, though any valid token can be used.

	It is most likely that you will not use the methods of this class directly, instead you will
	use the implicit constructors while interacting with the \ref BHttpRequest class.

	\code
	auto url = BUrl("https://www.haiku-os.org/");
	// implicitly construct a standard get request
	auto standard = BHttpRequest(url, BHttpMethod::Get);
	// implicitly construct a nonstandard patch request
	auto custom = BHttpRequest(url, "PATCH"sv);
	\endcode

	\note When you are using the standard list of verbs, there will never be an exception when
		creating objects of this type. When you create a custom method, exceptions may be raised
		when the system runs out of memory, or when your custom method contains invalid characters.
		In almost all cases, you can probably safely assume you will not run into these exceptions,
		except for cases where you use user input to create methods or you are very defensive
		about memory management.

	\since Haiku R1
*/


/*!
	\class BHttpMethod::InvalidMethod
	\ingroup netservices
	\brief Error that represents when a custom method does not conform to the HTTP standard.

	\since Haiku R1
*/


/*!
	\var BString BHttpMethod::InvalidMethod::input
	\brief The input that contains the invalid contents.

	\since Haiku R1
*/


/*!
	\fn BHttpMethod::InvalidMethod::InvalidMethod(const char *origin, BString input)
	\brief Constructor that sets the \a origin and the invalid \a input.

	\since Haiku R1
*/


/*!
	\enum BHttpMethod::Verb
	\ingroup netservices
	\brief A list of standard HTTP methods.

	\since Haiku R1
*/


/*!
	\var BHttpMethod::Verb BHttpMethod::Get
	\brief Represents the \c GET method.

	\since Haiku R1
*/


/*!
	\var BHttpMethod::Verb BHttpMethod::Head
	\brief Represents the \c HEAD method.

	\since Haiku R1
*/


/*!
	\var BHttpMethod::Verb BHttpMethod::Post
	\brief Represents the \c POST method.

	\since Haiku R1
*/


/*!
	\var BHttpMethod::Verb BHttpMethod::Put
	\brief Represents the \c PUT method.

	\since Haiku R1
*/


/*!
	\var BHttpMethod::Verb BHttpMethod::Delete
	\brief Represents the \c DELETE method.

	\since Haiku R1
*/


/*!
	\var BHttpMethod::Verb BHttpMethod::Connect
	\brief Represents the \c CONNECT method.

	\since Haiku R1
*/


/*!
	\var BHttpMethod::Verb BHttpMethod::Options
	\brief Represents the \c OPTIONS method.

	\since Haiku R1
*/


/*!
	\var BHttpMethod::Verb BHttpMethod::Trace
	\brief Represents the \c TRACE method.

	\since Haiku R1
*/


/*!
	\fn BHttpMethod::BHttpMethod(BHttpMethod &&other) noexcept
	\brief Move constructor.

	Moves the data from the \a other to this object. The \a other object will be set to
	\ref BHttpMethod::Get.

	\since Haiku R1
*/


/*!
	\fn BHttpMethod::BHttpMethod(const BHttpMethod &other)
	\brief Copy constructor.

	Copy data from an \a other object.

	\exception std::bad_alloc When the \a other object contains a custom verb, this exception
		will be raised if it is impossible to allocate memory.

	\since Haiku R1
*/


/*!
	\fn BHttpMethod::BHttpMethod(const std::string_view &method)
	\brief Construct a custom method.

	\param method The verb for the method.

	\exception std::bad_alloc In case it is not possible to allocate memory for the custom string.
	\exception BHttpMethod::InvalidMethod In case the \a method is empty or contains invalid
		characters.

	\since Haiku R1
*/


/*!
	\fn BHttpMethod::BHttpMethod(Verb verb) noexcept
	\brief Construct a standard method.

	\param verb The chosen method.

	\since Haiku R1
*/


/*!
	\fn BHttpMethod::~BHttpMethod()
	\brief Destructor.

	\since Haiku R1
*/


/*!
	\fn bool BHttpMethod::operator==(const Verb &other) const noexcept
	\brief Comparison operator.

	\param other The verb to compare to.

	\retval true This method is equal to \a other.
	\retval false This method is different from \a other.

	\since Haiku R1
*/


/*!
	\fn bool BHttpMethod::operator!=(const Verb &other) const noexcept
	\brief Comparison operator.

	\param other The verb to compare to.

	\retval true This method is different from \a other.
	\retval false This method is equal to \a other.

	\since Haiku R1
*/


/*!
	\fn const std::string_view BHttpMethod::Method() const noexcept
	\brief Get a string representation of the method.

	\return A \c std::string_view that is a string representation of the standard or custom method
		in this object. The lifetime of the string view is bound to the lifetime of this method.

	\since Haiku R1
*/


/*!
	\fn BHttpMethod& BHttpMethod::operator=(BHttpMethod &&other) noexcept
	\brief Move assignment.
	Moves the data from the \a other to this object. The \a other object will be set to
	\ref BHttpMethod::Get.

	\since Haiku R1
*/


/*!
	\fn BHttpMethod& BHttpMethod::operator=(const BHttpMethod &other)
	\brief Copy assignment.

	Copy data from an \a other object.

	\exception std::bad_alloc When the \a other object contains a custom verb, this exception
		will be raised if it is impossible to allocate memory.

	\since Haiku R1
*/


/*!
	\struct BHttpAuthentication
	\ingroup netservices
	\brief Describe username and password for basic authentication for the request.

	\see These options are used by \ref BHttpRequest::Authentication() and
		\ref BHttpRequest::SetAuthentication()

	\since Haiku R1
*/


/*!
	\var BString BHttpAuthentication::username
	\brief The username for the request.

	\since Haiku R1
*/


/*!
	\var BString BHttpAuthentication::password
	\brief The password for the request.

	\since Haiku R1
*/


/*!
	\struct BHttpRequest::Body
	\ingroup netservices
	\brief Describe the body for a network request

	\since Haiku R1
*/


/*!
	\var std::unique_ptr<BDataIO> BHttpRequest::Body::input
	\brief The \ref BDataIO object that holds the contents of the body.

	\since Haiku R1
*/


/*!
	\var BString BHttpRequest::Body::mimeType
	\brief The mimetype of the body.

	The \c Content-Type header field of the request is set to this value.

	\since Haiku R1
*/


/*!
	\var std::optional<off_t> BHttpRequest::Body::size
	\brief The size of the content, if known.

	\since Haiku R1
*/


/*!
	\var std::optional<off_t> BHttpRequest::Body::startPosition
	\brief If the input is a \ref BPositionIO, this is the current position when the body was set.

	This value is used to rewind the input when it needs to be resubmitted, for example in the case
	of a redirection.

	\since Haiku R1
*/


/*!
	\class BHttpRequest
	\ingroup netservices
	\brief Represent a HTTP request.

	This class can be used to construct HTTP requests that can be executed by the Network Services
	Kit. A request has two states, either it is is a valid request, or it is an empty request. The
	criterium is whether or not the request has a URL.
	This class has all kinds of convenience methods set and retrieve particular options. Most
	options are wrapped in specialized container classes that do some form of validation.

	The default options are:
	<table>
		<tr><th>Getter</th><th>Setter</th><th>Description</th><th>Default</th></tr>
		<tr>
			<td> \ref Url() </td>
			<td> \ref SetUrl() </td>
			<td> The URL. This must start with http or https. </td>
			<td> Defaults to an empty \ref BUrl </td>
		</tr>
		<tr>
			<td> \ref Fields() </td>
			<td> \ref SetFields() </td>
			<td> Additional fields set in the request header. </td>
			<td> Defaults with no additional fields </td>
		</tr>
		<tr>
			<td> \ref Method() </td>
			<td> \ref SetMethod() </td>
			<td> The HTTP method for the request </td>
			<td> Defaults to \ref BHttpMethod::Get </td>
		</tr>
		<tr>
			<td> \ref MaxRedirections() </td>
			<td> \ref SetMaxRedirections() </td>
			<td> How many redirections should be followed. Set to 0 to disable. </td>
			<td> Defaults to 8 redirections per request </td>
		</tr>
		<tr>
			<td> \ref RequestBody() </td>
			<td> \ref SetRequestBody() </td>
			<td> Body contents that is sent with the request. </td>
			<td> Defaults to an empty body </td>
		</tr>
		<tr>
			<td> \ref StopOnError() </td>
			<td> \ref SetStopOnError() </td>
			<td> Stop parsing the server response when there is a client or server error. </td>
			<td> Defaults to \a false </td>
		</tr>
		<tr>
			<td> \ref Timeout() </td>
			<td> \ref SetTimeout() </td>
			<td> The timeout determines how long is waited for the server to respond </td>
			<td> \c B_INFINITE_TIMEOUT </td>
		</tr>
	</table>

	\since Haiku R1
*/


/*!
	\name Constructors and Destructor
*/


//! @{


/*!
	\fn BHttpRequest::BHttpRequest()
	\brief Construct an empty HTTP request.

	\exception std::bad_alloc This exception may be raised if it is impossible to allocate memory.

	\since Haiku R1
*/


/*!
	\fn BHttpRequest::BHttpRequest(const BUrl &url)
	\brief Construct a HTTP request for an \a url.

	\param url A valid URL with the \c http or \c https protocol.

	\exception std::bad_alloc This exception may be raised if it is impossible to allocate memory.
	\exception BUnsupportedProtocol This exception is raised when the protocol of the URL cannot be
		handled.
	\exception BInvalidUrl This exception is raised when the \a url is invalid.

	\since Haiku R1
*/


/*!
	\fn BHttpRequest::BHttpRequest(const BHttpRequest &other)=delete
	\brief Copying is not allowed.

	\since Haiku R1
*/


/*!
	\fn BHttpRequest::BHttpRequest(BHttpRequest &&other) noexcept
	\brief Move constructor.

	After a move, the \a other object is left in an empty state.

	\param other The request to move data from.

	\since Haiku R1
*/


/*!
	\fn BPrivate::Network::BHttpRequest::~BHttpRequest()
	\brief Destructor

	\since Haiku R1
*/


//! @}


/*!
	\name Assignment operators
*/


//! @{


/*!
	\fn BHttpRequest& BHttpRequest::operator=(const BHttpRequest &other)=delete
	\brief Copy assignment is not allowed.

	\since Haiku R1
*/


/*!
	\fn BHttpRequest& BHttpRequest::operator=(BHttpRequest &&other) noexcept
	\brief Move assignment

	After a move, the \a other object is left in an empty state.

	\param other The request to move data from.

	\since Haiku R1
*/


//! @}


/*!
	\name Valid or empty
*/


//! @{


/*!
	\fn bool BHttpRequest::IsEmpty() const noexcept
	\brief Check if the request is valid or empty

	\retval true The request is empty.
	\retval false The request is valid.

	\since Haiku R1
*/


//! @}


/*!
	\name Current Options
*/


//! @{


/*!
	\fn const BHttpAuthentication* BHttpRequest::Authentication() const noexcept
	\brief Get the credentials for the authentication for the request.

	\return When no credentials are set for this request, the method returns a \c nullptr.
		Otherwise, it will return a pointer to the current BHttpAuthentication data set for this
		request.

	\since Haiku R1
*/


/*!
	\fn const BHttpFields& BHttpRequest::Fields() const noexcept
	\brief Get the additional header fields set for the request.

	The returned header fields may be empty if no additional header fields were set.

	\since Haiku R1
*/


/*!
	\fn const BHttpMethod& BHttpRequest::Method() const noexcept
	\brief Get the current method for the request.

	This will either return the custom value set for this request, or the default as is listed in
	the overview documentation of this class.

	\since Haiku R1
*/


/*!
	\fn uint8 BHttpRequest::MaxRedirections() const noexcept
	\brief Get the current redirection options for this request.

	\see \ref BHttpRequest::SetMaxRedirections() for details on the options.

	\since Haiku R1
*/


/*!
	\fn const BHttpRequest::Body* BHttpRequest::RequestBody() const noexcept
	\brief Get the details of the custom body set for the request.

	\return When no body is set for this request, the method returns a \c nullptr.
		Otherwise, it will return a pointer to a struct that describes the current body.

	\since Haiku R1
*/


/*!
	\fn bool BHttpRequest::StopOnError() const noexcept
	\brief Is the request set to parse the full response on error.

	\retval true When encountering a HTTP status of the client error class (4xx) or server error
		class (5xx), then the response will not be parsed.
	\retval false The full response will be parsed, even with an error status code.

	\since Haiku R1
*/


/*!
	\fn bigtime_t BHttpRequest::Timeout() const noexcept
	\brief Get the current timeout for the server to respond.

	\since Haiku R1
*/


/*!
	\fn const BUrl& BHttpRequest::Url() const noexcept
	\brief Get the current Url for the request.

	This will either return the custom value set for this request, or the default as is listed in
	the overview documentation of this class.

	\since Haiku R1
*/


//! @}


/*!
	\name Setting Options
*/


//! @{


/*!
	\fn void BHttpRequest::SetAuthentication(const BHttpAuthentication &authentication)
	\brief Set the credentials to enable basic authentication for the request.

	The Basic authorization line is added to the request upon setting the request details. There is
	no support for other authentication schemes, like digest authentication.

	\param authentication The credentials to apply to the request.

	\exception std::bad_alloc This exception may be raised if it is impossible to allocate memory.

	\since Haiku R1
*/


/*!
	\fn void BHttpRequest::SetFields(const BHttpFields &fields)
	\brief Set additional header \a fields for this request.

	There are a few reserved fields, which cannot be set as optional fields. These currently are:
	* \c Host
	* \c Accept-Encoding
	* \c Connection
	* \c Content-Type
	* \c Content-Length

	\param fields Additional fields for the header of the request.

	\exception std::bad_alloc This exception may be raised if it is impossible to allocate memory.
	\exception BHttpFields::InvalidData This exception is raised when the \a fields contain
		reserved fields.

	\since Haiku R1
*/


/*!
	\fn void BHttpRequest::SetMethod(const BHttpMethod &method)
	\brief Set the \a method for this request.

	Note that there currently is no additional validation done on any semantical incompatibilities.
	This means that it is currently allowed to do a \c GET or \c HEAD request with data, while that
	is forbidden by the standard.

	\param method The method to use for the request.

	\exception std::bad_alloc This exception may be raised if it is impossible to allocate memory.

	\since Haiku R1
*/


/*!
	\fn void BHttpRequest::SetMaxRedirections(uint8 maxRedirections)
	\brief Set the redirection options for this request.

	The HTTP protocol allows the server to redirect requests if the resources have moved to a new
	location. For your convenience, you can instruct the network services kit to follow these
	redirections. You can set how many redirects should be followed. The maximum value is that of
	an unsigned 8 bit int, so maximum is 256 redirects. This prevents the request from staying
	stuck in a redirection loop.

	If redirects are set to 0, or the maximum number of redirects have been processed, then the
	response will be set to the actual (last) received redirection response.

	\param maxRedirections The number of redirections to follow. Set to 0 to disable.

	\exception std::bad_alloc This exception may be raised if it is impossible to allocate memory.

	\since Haiku R1
*/


/*!
	\fn void BHttpRequest::SetRequestBody(std::unique_ptr<BDataIO> input, BString mimeType,
		std::optional<off_t> size)
	\brief Set a body for this request.

	When the requests needs a body, this method can be used to set the contents of that body.

	\param input The input is an owned pointer to an input. The lifetime of the input is guaranteed
		up to the point that the request is sent for execution.
	\param mimeType A valid mimetype, with a class and a subtype. For example \c text/plain is a
		valid mime type.
	\param size When the content size is set, the request will have a \c Content-Length header
		field. If the \a input has less data in the buffer, this will cause the request to
		error out. However, if the input has more data, it is only read up to size. If the actual
		size of the data is unknown, this can be made optional. The request body will
		then be sent as a so-called chunked transfer, sending data until the input is at the end.

	\exception std::bad_alloc This exception may be raised if it is impossible to allocate memory.
	\exception std::invalid_argument This exception is raised when the \a mimeType is invalid or
		when \a input is a \c nullptr.

	\since Haiku R1
*/


/*!
	\fn void BHttpRequest::SetStopOnError(bool stopOnError)
	\brief Set whether the entire response will be parsed on a client or server error.

	When the server encounters an error processing a request, it may respond with an error code.
	Error responses can be either an error with the request, like the 404 Not Found error, or
	errors on the server side, like a 500 Internal Server Error. Error responses may still have
	header fields and bodies.

	If your application is not interested in the rest of the response in case a client error or
	a server error occurs, you can set this option to stop parsing. This will allow you to use the
	\ref BHttpResult object as normal, but the response fields will be empty, and there will be no
	body data.

	\param stopOnError Set to \c true to stop parsing the HTTP response when a client error or
		server error occurs.

	\exception std::bad_alloc This exception may be raised if it is impossible to allocate memory.

	\since Haiku R1
*/


/*!
	\fn void BHttpRequest::SetTimeout(bigtime_t timeout)
	\brief Set the maximum time waiting for the server to respond.

	If the request times out, then the response will hold the \ref BNetworkRequestError of the
	\c NetworkError type. By default, the request does not time out.

	\param timeout The timeout in milliseconds. 

	\exception std::bad_alloc This exception may be raised if it is impossible to allocate memory.

	\since Haiku R1
*/


/*!
	\fn void BHttpRequest::SetUrl(const BUrl &url)
	\brief Set the \a url for this request.

	\param url A valid URL with the \c http or \c https protocol.

	\exception std::bad_alloc This exception may be raised if it is impossible to allocate memory.
	\exception BUnsupportedProtocol This exception is raised when the protocol of the URL cannot be
		handled.
	\exception BInvalidUrl This exception is raised when the \a url is invalid.

	\since Haiku R1
*/


//! @}


/*!
	\name Clearing options
*/


//! @{


/*!
	\fn void BHttpRequest::ClearAuthentication() noexcept
	\brief Clear any authentication details previously set with \ref SetAuthentication().

	If there is no authentication data set, this method does nothing.

	\since Haiku R1
*/


/*!
	\fn std::unique_ptr<BDataIO> BHttpRequest::ClearRequestBody() noexcept
	\brief Clear any request body previously set with \ref SetRequestBody().

	\return Returns the previously set input \ref BDataIO object. If there is no request body set,
		this method returns \c nullptr.

	\since Haiku R1
*/


//! @}


/*!
	\name Serialization
*/


//! @{


/*!
	\fn BString BHttpRequest::HeaderToString() const
	\brief Serialize the HTTP Header of this request to a string.

	The HTTP header consists of the request line, and the fields, serialized as text according to
	the HTTP specification.

	This method can be used to debug requests.

	\return A new string that represents the HTTP request.

	\exception std::bad_alloc In case it is not possible to allocate memory for the output string.

	\since Haiku R1
*/


//! @}


} // namespace Network

} // namespace BPrivate

#endif
