1/*
2 * Copyright 2022 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Niels Sascha Reedijk, niels.reedijk@gmail.com
7 */
8
9
10#include <ErrorsExt.h>
11#include <HttpFields.h>
12#include <HttpResult.h>
13
14#include "HttpResultPrivate.h"
15
16using namespace BPrivate::Network;
17
18
19// #pragma mark -- BHttpStatus
20
21
22BHttpStatusClass
23BHttpStatus::StatusClass() const noexcept
24{
25	switch (code / 100) {
26		case 1:
27			return BHttpStatusClass::Informational;
28		case 2:
29			return BHttpStatusClass::Success;
30		case 3:
31			return BHttpStatusClass::Redirection;
32		case 4:
33			return BHttpStatusClass::ClientError;
34		case 5:
35			return BHttpStatusClass::ServerError;
36		default:
37			break;
38	}
39	return BHttpStatusClass::Invalid;
40}
41
42
43BHttpStatusCode
44BHttpStatus::StatusCode() const noexcept
45{
46	switch (static_cast<BHttpStatusCode>(code)) {
47		// 1xx
48		case BHttpStatusCode::Continue:
49			[[fallthrough]];
50		case BHttpStatusCode::SwitchingProtocols:
51			[[fallthrough]];
52
53		// 2xx
54		case BHttpStatusCode::Ok:
55			[[fallthrough]];
56		case BHttpStatusCode::Created:
57			[[fallthrough]];
58		case BHttpStatusCode::Accepted:
59			[[fallthrough]];
60		case BHttpStatusCode::NonAuthoritativeInformation:
61			[[fallthrough]];
62		case BHttpStatusCode::NoContent:
63			[[fallthrough]];
64		case BHttpStatusCode::ResetContent:
65			[[fallthrough]];
66		case BHttpStatusCode::PartialContent:
67			[[fallthrough]];
68
69		// 3xx
70		case BHttpStatusCode::MultipleChoice:
71			[[fallthrough]];
72		case BHttpStatusCode::MovedPermanently:
73			[[fallthrough]];
74		case BHttpStatusCode::Found:
75			[[fallthrough]];
76		case BHttpStatusCode::SeeOther:
77			[[fallthrough]];
78		case BHttpStatusCode::NotModified:
79			[[fallthrough]];
80		case BHttpStatusCode::UseProxy:
81			[[fallthrough]];
82		case BHttpStatusCode::TemporaryRedirect:
83			[[fallthrough]];
84		case BHttpStatusCode::PermanentRedirect:
85			[[fallthrough]];
86
87		// 4xx
88		case BHttpStatusCode::BadRequest:
89			[[fallthrough]];
90		case BHttpStatusCode::Unauthorized:
91			[[fallthrough]];
92		case BHttpStatusCode::PaymentRequired:
93			[[fallthrough]];
94		case BHttpStatusCode::Forbidden:
95			[[fallthrough]];
96		case BHttpStatusCode::NotFound:
97			[[fallthrough]];
98		case BHttpStatusCode::MethodNotAllowed:
99			[[fallthrough]];
100		case BHttpStatusCode::NotAcceptable:
101			[[fallthrough]];
102		case BHttpStatusCode::ProxyAuthenticationRequired:
103			[[fallthrough]];
104		case BHttpStatusCode::RequestTimeout:
105			[[fallthrough]];
106		case BHttpStatusCode::Conflict:
107			[[fallthrough]];
108		case BHttpStatusCode::Gone:
109			[[fallthrough]];
110		case BHttpStatusCode::LengthRequired:
111			[[fallthrough]];
112		case BHttpStatusCode::PreconditionFailed:
113			[[fallthrough]];
114		case BHttpStatusCode::RequestEntityTooLarge:
115			[[fallthrough]];
116		case BHttpStatusCode::RequestUriTooLarge:
117			[[fallthrough]];
118		case BHttpStatusCode::UnsupportedMediaType:
119			[[fallthrough]];
120		case BHttpStatusCode::RequestedRangeNotSatisfiable:
121			[[fallthrough]];
122		case BHttpStatusCode::ExpectationFailed:
123			[[fallthrough]];
124
125		// 5xx
126		case BHttpStatusCode::InternalServerError:
127			[[fallthrough]];
128		case BHttpStatusCode::NotImplemented:
129			[[fallthrough]];
130		case BHttpStatusCode::BadGateway:
131			[[fallthrough]];
132		case BHttpStatusCode::ServiceUnavailable:
133			[[fallthrough]];
134		case BHttpStatusCode::GatewayTimeout:
135			return static_cast<BHttpStatusCode>(code);
136
137		default:
138			break;
139	}
140
141	return BHttpStatusCode::Unknown;
142}
143
144
145// #pragma mark -- BHttpResult
146
147
148/*private*/
149BHttpResult::BHttpResult(std::shared_ptr<HttpResultPrivate> data)
150	:
151	fData(data)
152{
153}
154
155
156BHttpResult::BHttpResult(BHttpResult&& other) noexcept = default;
157
158
159BHttpResult::~BHttpResult()
160{
161	if (fData)
162		fData->SetCancel();
163}
164
165
166BHttpResult& BHttpResult::operator=(BHttpResult&& other) noexcept = default;
167
168
169const BHttpStatus&
170BHttpResult::Status() const
171{
172	if (!fData)
173		throw BRuntimeError(__PRETTY_FUNCTION__, "The BHttpResult object is no longer valid");
174	status_t status = B_OK;
175	while (status == B_INTERRUPTED || status == B_OK) {
176		auto dataStatus = fData->GetStatusAtomic();
177		if (dataStatus == HttpResultPrivate::kError)
178			std::rethrow_exception(*(fData->error));
179
180		if (dataStatus >= HttpResultPrivate::kStatusReady)
181			return fData->status.value();
182
183		status = acquire_sem(fData->data_wait);
184	}
185	throw BRuntimeError(__PRETTY_FUNCTION__, "Unexpected error waiting for status!");
186}
187
188
189const BHttpFields&
190BHttpResult::Fields() const
191{
192	if (!fData)
193		throw BRuntimeError(__PRETTY_FUNCTION__, "The BHttpResult object is no longer valid");
194	status_t status = B_OK;
195	while (status == B_INTERRUPTED || status == B_OK) {
196		auto dataStatus = fData->GetStatusAtomic();
197		if (dataStatus == HttpResultPrivate::kError)
198			std::rethrow_exception(*(fData->error));
199
200		if (dataStatus >= HttpResultPrivate::kHeadersReady)
201			return *(fData->fields);
202
203		status = acquire_sem(fData->data_wait);
204	}
205	throw BRuntimeError(__PRETTY_FUNCTION__, "Unexpected error waiting for fields!");
206}
207
208
209BHttpBody&
210BHttpResult::Body() const
211{
212	if (!fData)
213		throw BRuntimeError(__PRETTY_FUNCTION__, "The BHttpResult object is no longer valid");
214	status_t status = B_OK;
215	while (status == B_INTERRUPTED || status == B_OK) {
216		auto dataStatus = fData->GetStatusAtomic();
217		if (dataStatus == HttpResultPrivate::kError)
218			std::rethrow_exception(*(fData->error));
219
220		if (dataStatus >= HttpResultPrivate::kBodyReady)
221			return *(fData->body);
222
223		status = acquire_sem(fData->data_wait);
224	}
225	throw BRuntimeError(__PRETTY_FUNCTION__, "Unexpected error waiting for the body!");
226}
227
228
229bool
230BHttpResult::HasStatus() const
231{
232	if (!fData)
233		throw BRuntimeError(__PRETTY_FUNCTION__, "The BHttpResult object is no longer valid");
234	return fData->GetStatusAtomic() >= HttpResultPrivate::kStatusReady;
235}
236
237
238bool
239BHttpResult::HasFields() const
240{
241	if (!fData)
242		throw BRuntimeError(__PRETTY_FUNCTION__, "The BHttpResult object is no longer valid");
243	return fData->GetStatusAtomic() >= HttpResultPrivate::kHeadersReady;
244}
245
246
247bool
248BHttpResult::HasBody() const
249{
250	if (!fData)
251		throw BRuntimeError(__PRETTY_FUNCTION__, "The BHttpResult object is no longer valid");
252	return fData->GetStatusAtomic() >= HttpResultPrivate::kBodyReady;
253}
254
255
256bool
257BHttpResult::IsCompleted() const
258{
259	if (!fData)
260		throw BRuntimeError(__PRETTY_FUNCTION__, "The BHttpResult object is no longer valid");
261	return HasBody();
262}
263
264
265int32
266BHttpResult::Identity() const
267{
268	if (!fData)
269		throw BRuntimeError(__PRETTY_FUNCTION__, "The BHttpResult object is no longer valid");
270	return fData->id;
271}
272