xref: /haiku/src/kits/network/libnetservices2/HttpResultPrivate.h (revision 3af8011358bd4c624a0979336d48dabb466171ed)
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