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