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#ifndef _HTTP_RESULT_PRIVATE_H_ 10#define _HTTP_RESULT_PRIVATE_H_ 11 12 13#include <memory> 14#include <optional> 15#include <string> 16 17#include <DataIO.h> 18#include <ExclusiveBorrow.h> 19#include <OS.h> 20#include <String.h> 21 22 23namespace BPrivate { 24 25namespace Network { 26 27struct HttpResultPrivate { 28 // Read-only properties (multi-thread safe) 29 const int32 id; 30 31 // Locking and atomic variables 32 enum { kNoData = 0, kStatusReady, kHeadersReady, kBodyReady, kError }; 33 int32 requestStatus = kNoData; 34 int32 canCancel = 0; 35 sem_id data_wait; 36 37 // Data 38 std::optional<BHttpStatus> status; 39 std::optional<BHttpFields> fields; 40 std::optional<BHttpBody> body; 41 std::optional<std::exception_ptr> error; 42 43 // Interim body storage (used while the request is running) 44 BString bodyString; 45 BBorrow<BDataIO> bodyTarget; 46 47 // Utility functions 48 HttpResultPrivate(int32 identifier); 49 int32 GetStatusAtomic(); 50 bool CanCancel(); 51 void SetCancel(); 52 void SetError(std::exception_ptr e); 53 void SetStatus(BHttpStatus&& s); 54 void SetFields(BHttpFields&& f); 55 void SetBody(); 56 size_t WriteToBody(const void* buffer, size_t size); 57}; 58 59 60inline HttpResultPrivate::HttpResultPrivate(int32 identifier) 61 : 62 id(identifier) 63{ 64 std::string name = "httpresult:" + std::to_string(identifier); 65 data_wait = create_sem(1, name.c_str()); 66 if (data_wait < B_OK) 67 throw BRuntimeError(__PRETTY_FUNCTION__, "Cannot create internal sem for httpresult"); 68} 69 70 71inline int32 72HttpResultPrivate::GetStatusAtomic() 73{ 74 return atomic_get(&requestStatus); 75} 76 77 78inline bool 79HttpResultPrivate::CanCancel() 80{ 81 return atomic_get(&canCancel) == 1; 82} 83 84 85inline void 86HttpResultPrivate::SetCancel() 87{ 88 atomic_set(&canCancel, 1); 89} 90 91 92inline void 93HttpResultPrivate::SetError(std::exception_ptr e) 94{ 95 // Release any held body target borrow 96 bodyTarget.Return(); 97 98 error = e; 99 atomic_set(&requestStatus, kError); 100 release_sem(data_wait); 101} 102 103 104inline void 105HttpResultPrivate::SetStatus(BHttpStatus&& s) 106{ 107 status = std::move(s); 108 atomic_set(&requestStatus, kStatusReady); 109 release_sem(data_wait); 110} 111 112 113inline void 114HttpResultPrivate::SetFields(BHttpFields&& f) 115{ 116 fields = std::move(f); 117 atomic_set(&requestStatus, kHeadersReady); 118 release_sem(data_wait); 119} 120 121 122inline void 123HttpResultPrivate::SetBody() 124{ 125 if (bodyTarget.HasValue()) { 126 body = BHttpBody{}; 127 bodyTarget.Return(); 128 } else 129 body = BHttpBody{std::move(bodyString)}; 130 131 atomic_set(&requestStatus, kBodyReady); 132 release_sem(data_wait); 133} 134 135 136inline size_t 137HttpResultPrivate::WriteToBody(const void* buffer, size_t size) 138{ 139 // TODO: when the support for a shared BMemoryRingIO is here, choose 140 // between one or the other depending on which one is available. 141 if (bodyTarget.HasValue()) { 142 auto result = bodyTarget->Write(buffer, size); 143 if (result < 0) 144 throw BSystemError("BDataIO::Write()", result); 145 return result; 146 } else { 147 bodyString.Append(reinterpret_cast<const char*>(buffer), size); 148 return size; 149 } 150} 151 152 153} // namespace Network 154 155} // namespace BPrivate 156 157#endif // _HTTP_RESULT_PRIVATE_H_ 158