1/*
2 * Copyright 2022 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6#ifndef _B_HTTP_PARSER_H_
7#define _B_HTTP_PARSER_H_
8
9
10#include <functional>
11#include <optional>
12
13#include <HttpResult.h>
14
15#include "HttpBuffer.h"
16
17class BMallocIO;
18
19namespace BPrivate {
20
21namespace Network {
22
23using HttpTransferFunction = std::function<size_t(const std::byte*, size_t)>;
24
25
26enum class HttpInputStreamState { StatusLine, Fields, Body, Done };
27
28
29enum class HttpBodyType { NoContent, Chunked, FixedSize, VariableSize };
30
31
32struct BodyParseResult {
33			size_t		bytesParsed;
34			size_t		bytesWritten;
35			bool		complete;
36};
37
38
39class HttpBodyParser;
40
41
42class HttpParser
43{
44public:
45								HttpParser(){};
46
47	// Explicitly mark request as having no content
48			void				SetNoContent() noexcept;
49
50	// Parse data from response
51			bool				ParseStatus(HttpBuffer& buffer, BHttpStatus& status);
52			bool				ParseFields(HttpBuffer& buffer, BHttpFields& fields);
53			size_t				ParseBody(HttpBuffer& buffer, HttpTransferFunction writeToBody,
54									bool readEnd);
55			HttpInputStreamState State() const noexcept { return fStreamState; }
56
57	// Details on the body status
58			bool				HasContent() const noexcept;
59			std::optional<off_t> BodyBytesTotal() const noexcept;
60			off_t				BodyBytesTransferred() const noexcept;
61			bool				Complete() const noexcept;
62
63private:
64			off_t				fHeaderBytes = 0;
65			BHttpStatus			fStatus;
66			HttpInputStreamState fStreamState = HttpInputStreamState::StatusLine;
67
68	// Body
69			HttpBodyType		fBodyType = HttpBodyType::VariableSize;
70			std::unique_ptr<HttpBodyParser> fBodyParser = nullptr;
71};
72
73
74class HttpBodyParser
75{
76public:
77	virtual						BodyParseResult ParseBody(HttpBuffer& buffer,
78									HttpTransferFunction writeToBody, bool readEnd) = 0;
79
80	virtual	std::optional<off_t> TotalBodySize() const noexcept;
81
82			off_t				TransferredBodySize() const noexcept;
83
84protected:
85			off_t				fTransferredBodySize = 0;
86};
87
88
89class HttpRawBodyParser : public HttpBodyParser
90{
91public:
92								HttpRawBodyParser();
93								HttpRawBodyParser(off_t bodyBytesTotal);
94	virtual	BodyParseResult		ParseBody(HttpBuffer& buffer, HttpTransferFunction writeToBody,
95									bool readEnd) override;
96	virtual	std::optional<off_t> TotalBodySize() const noexcept override;
97
98private:
99			std::optional<off_t> fBodyBytesTotal;
100};
101
102
103class HttpChunkedBodyParser : public HttpBodyParser
104{
105public:
106	virtual BodyParseResult ParseBody(
107		HttpBuffer& buffer, HttpTransferFunction writeToBody, bool readEnd) override;
108
109private:
110	enum { ChunkSize, ChunkEnd, Chunk, Trailers, Complete } fChunkParserState = ChunkSize;
111	off_t fRemainingChunkSize = 0;
112	bool fLastChunk = false;
113};
114
115
116class HttpBodyDecompression : public HttpBodyParser
117{
118public:
119								HttpBodyDecompression(std::unique_ptr<HttpBodyParser> bodyParser);
120	virtual	BodyParseResult		ParseBody(HttpBuffer& buffer, HttpTransferFunction writeToBody,
121									bool readEnd) override;
122
123	virtual	std::optional<off_t> TotalBodySize() const noexcept;
124
125private:
126			std::unique_ptr<HttpBodyParser> fBodyParser;
127			std::unique_ptr<BMallocIO> fDecompressorStorage;
128			std::unique_ptr<BDataIO> fDecompressingStream;
129};
130
131
132} // namespace Network
133
134} // namespace BPrivate
135
136#endif // _B_HTTP_PARSER_H_
137