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 23 namespace BPrivate { 24 25 namespace Network { 26 27 struct 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 60 inline 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 71 inline int32 72 HttpResultPrivate::GetStatusAtomic() 73 { 74 return atomic_get(&requestStatus); 75 } 76 77 78 inline bool 79 HttpResultPrivate::CanCancel() 80 { 81 return atomic_get(&canCancel) == 1; 82 } 83 84 85 inline void 86 HttpResultPrivate::SetCancel() 87 { 88 atomic_set(&canCancel, 1); 89 } 90 91 92 inline void 93 HttpResultPrivate::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 104 inline void 105 HttpResultPrivate::SetStatus(BHttpStatus&& s) 106 { 107 status = std::move(s); 108 atomic_set(&requestStatus, kStatusReady); 109 release_sem(data_wait); 110 } 111 112 113 inline void 114 HttpResultPrivate::SetFields(BHttpFields&& f) 115 { 116 fields = std::move(f); 117 atomic_set(&requestStatus, kHeadersReady); 118 release_sem(data_wait); 119 } 120 121 122 inline void 123 HttpResultPrivate::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 136 inline size_t 137 HttpResultPrivate::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