xref: /haiku/src/kits/network/libnetservices2/HttpResult.cpp (revision 52c4471a3024d2eb81fe88e2c3982b9f8daa5e56)
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 
16 using namespace BPrivate::Network;
17 
18 
19 // #pragma mark -- BHttpStatus
20 
21 
22 BHttpStatusClass
23 BHttpStatus::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 
43 BHttpStatusCode
44 BHttpStatus::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*/
149 BHttpResult::BHttpResult(std::shared_ptr<HttpResultPrivate> data)
150 	:
151 	fData(data)
152 {
153 }
154 
155 
156 BHttpResult::BHttpResult(BHttpResult&& other) noexcept = default;
157 
158 
159 BHttpResult::~BHttpResult()
160 {
161 	if (fData)
162 		fData->SetCancel();
163 }
164 
165 
166 BHttpResult& BHttpResult::operator=(BHttpResult&& other) noexcept = default;
167 
168 
169 const BHttpStatus&
170 BHttpResult::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 
189 const BHttpFields&
190 BHttpResult::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 
209 BHttpBody&
210 BHttpResult::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 
229 bool
230 BHttpResult::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 
238 bool
239 BHttpResult::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 
247 bool
248 BHttpResult::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 
256 bool
257 BHttpResult::IsCompleted() const
258 {
259 	if (!fData)
260 		throw BRuntimeError(__PRETTY_FUNCTION__, "The BHttpResult object is no longer valid");
261 	return HasBody();
262 }
263 
264 
265 int32
266 BHttpResult::Identity() const
267 {
268 	if (!fData)
269 		throw BRuntimeError(__PRETTY_FUNCTION__, "The BHttpResult object is no longer valid");
270 	return fData->id;
271 }
272