19#include "AUI/IO/AEOFException.h"
20#include "AUI/IO/IInputStream.h"
21#include "AUI/Traits/values.h"
22#include "AFormMultipart.h"
23#include <AUI/IO/APipe.h>
24#include <AUI/Common/AByteBufferView.h>
25#include <AUI/Common/AByteBuffer.h>
26#include <AUI/Common/ASignal.h>
27#include <AUI/Reflect/AEnumerate.h>
28#include <AUI/Thread/AFuture.h>
41class API_AUI_CURL ACurl:
public AObject {
42friend class ACurlMulti;
52 VERSION_2_PRIOR_KNOWLEDGE,
59 enum class ResponseCode {
60 HTTP_100_CONTINUE = 100,
61 HTTP_101_SWITCHING_PROTOCOL = 101,
62 HTTP_102_PROCESSING = 102,
63 HTTP_103_EARLY_HINTS = 103,
65 HTTP_201_CREATED = 201,
66 HTTP_202_ACCEPTED = 202,
67 HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203,
68 HTTP_204_NO_CONTENT = 204,
69 HTTP_205_RESET_CONTENT = 205,
70 HTTP_206_PARTIAL_CONTENT = 206,
71 HTTP_300_MULTIPLE_CHOICE = 300,
72 HTTP_301_MOVED_PERMANENTLY = 301,
74 HTTP_303_SEE_OTHER = 303,
75 HTTP_304_NOT_MODIFIED = 304,
76 HTTP_305_USE_PROXY = 305,
77 HTTP_306_SWITCH_PROXY = 306,
78 HTTP_307_TEMPORARY_REDIRECT = 307,
79 HTTP_308_PERMANENT_REDIRECT = 308,
80 HTTP_400_BAD_REQUEST = 400,
81 HTTP_401_UNAUTHORIZED = 401,
82 HTTP_402_PAYMENT_REQUIRED = 402,
83 HTTP_403_FORBIDDEN = 403,
84 HTTP_404_NOT_FOUND = 404,
85 HTTP_405_METHOD_NOT_ALLOWED = 405,
86 HTTP_406_NOT_ACCEPTABLE = 406,
87 HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407,
88 HTTP_408_REQUEST_TIMEOUT = 408,
89 HTTP_409_CONFLICT = 409,
91 HTTP_411_LENGTH_REQUIRED = 411,
92 HTTP_412_PRECONDITION_FAILED = 412,
93 HTTP_413_REQUEST_ENTITY_TOO_LARGE = 413,
94 HTTP_414_REQUEST_URI_TOO_LONG = 414,
95 HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415,
96 HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE = 416,
97 HTTP_417_EXPECTATION_FAILED = 417,
98 HTTP_500_INTERNAL_SERVER_ERROR = 500,
99 HTTP_501_NOT_IMPLEMENTED = 501,
100 HTTP_502_BAD_GATEWAY = 502,
101 HTTP_503_SERVICE_UNAVAILABLE = 503,
102 HTTP_504_GATEWAY_TIMEOUT = 504,
103 HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505,
129 void throwException()
const;
154 using ReadCallback = std::function<std::size_t(
char* dst,
size_t maxLen)>;
156 using ErrorCallback = std::function<void(
const ErrorDescription& description)>;
159 class Exception:
public AIOException {
161 using AIOException::AIOException;
162 Exception(
const ErrorDescription& errorDescription): AIOException(errorDescription.description),
163 mCurlStatus(errorDescription.curlStatus) {
168 int curlStatus()
const noexcept {
176 class API_AUI_CURL Builder {
182 ErrorCallback mErrorCallback;
183 HeaderCallback mHeaderCallback;
184 bool mThrowExceptionOnError =
false;
187 Method mMethod = Method::HTTP_GET;
188 std::function<void(ACurl&)> mOnSuccess;
192 Builder(
const Builder&) =
delete;
202 AUI_ASSERTX(mWriteCallback ==
nullptr,
"write callback already set");
203 mWriteCallback = std::move(callback);
215 mHeaders.push_back(
"Content-Type: multipart/form-data; boundary={}"_format(multipart.boundary()));
225 AUI_ASSERTX(mReadCallback ==
nullptr,
"write callback already set");
226 mReadCallback = std::move(callback);
236 withBody([inputStream = std::move(inputStream)](
char* dst, std::size_t length) {
237 auto v = inputStream->read(dst, length);
250 Builder& withTimeout(std::chrono::seconds timeout);
256 AUI_ASSERTX(mReadCallback ==
nullptr,
"write callback already set");
259 explicit Body(std::string b) : contents(std::move(b)), i(contents.begin()) {}
261 std::string contents;
262 std::string::iterator i;
264 auto b = _new<Body>(std::move(contents));
266 mReadCallback = [body = std::move(b)](
char* dst, std::size_t length)
mutable {
267 if (body->i == body->contents.end()) {
270 std::size_t remaining = std::distance(body->i, body->contents.end());
271 length = glm::min(length, remaining);
272 std::memcpy(dst, &*body->i, length);
286 mHeaderCallback = std::move(headerCallback);
294 AUI_ASSERTX(mErrorCallback ==
nullptr,
"error callback already set");
295 mErrorCallback = std::move(callback);
306 Builder& withOutputStream(_<IOutputStream> dst) {
307 return withWriteCallback([dst = std::move(dst)](AByteBufferView b) {
313 Builder& throwExceptionOnError(
bool throwExceptionOnError)
noexcept {
314 mThrowExceptionOnError = throwExceptionOnError;
325 Builder& withRanges(
size_t begin,
size_t end);
342 Builder& withLowSpeedLimit(
size_t speed);
349 Builder& withLowSpeedTime(std::chrono::seconds duration);
352 Builder& withHttpVersion(Http version);
353 Builder& withUpload(
bool upload);
355 Builder& withOnSuccess(std::function<
void(ACurl&)> onSuccess) {
356 mOnSuccess = std::move(onSuccess);
360 template<aui::invocable OnSuccess>
361 Builder& withOnSuccess(OnSuccess&& onSuccess) {
362 mOnSuccess = [onSuccess = std::forward<OnSuccess>(onSuccess)](
ACurl&) {
387 Builder& withParams(
const AVector<std::pair<AString /* key */, AString /* value */>>& params);
397 mParams = std::move(params);
402 mHeaders = std::move(headers);
412 _unique<IInputStream> toInputStream();
420 Response runBlocking();
435 explicit ACurl(Builder& builder):
436 ACurl(std::move(builder))
440 explicit ACurl(Builder&& builder)
noexcept {
441 operator=(std::move(builder));
443 ACurl(ACurl&& o)
noexcept {
444 operator=(std::move(o));
449 ACurl& operator=(Builder&& o)
noexcept;
450 ACurl& operator=(ACurl&& o)
noexcept;
452 int64_t getContentLength()
const;
453 int64_t getNumberOfBytesDownloaded()
const;
454 AString getContentType()
const;
472 virtual void close();
475 void* handle() const noexcept {
480 ResponseCode getResponseCode()
const;
483 AString getErrorString() const noexcept {
484 return AString::fromLatin1(mErrorBuffer);
489 struct curl_slist* mCurlHeaders =
nullptr;
490 char mErrorBuffer[256];
491 bool mCloseRequested =
false;
492 std::string mPostFieldsStorage;
494 static size_t writeCallback(
char* ptr,
size_t size,
size_t nmemb,
void* userdata)
noexcept;
495 static size_t readCallback(
char* ptr,
size_t size,
size_t nmemb,
void* userdata)
noexcept;
496 static size_t headerCallback(
char *buffer,
size_t size,
size_t nitems,
void *userdata)
noexcept;
498 WriteCallback mWriteCallback;
499 ReadCallback mReadCallback;
500 HeaderCallback mHeaderCallback;
502 void reportSuccess() {
506 void reportFail(
int statusCode) {
507 emit fail(ErrorDescription{statusCode, AString::fromLatin1(mErrorBuffer)});
510 template<
typename Ret>
511 Ret getInfo(
int curlInfo)
const;
536 ACurl::ResponseCode::HTTP_100_CONTINUE,
537 ACurl::ResponseCode::HTTP_101_SWITCHING_PROTOCOL,
538 ACurl::ResponseCode::HTTP_102_PROCESSING,
539 ACurl::ResponseCode::HTTP_103_EARLY_HINTS,
540 ACurl::ResponseCode::HTTP_200_OK,
541 ACurl::ResponseCode::HTTP_201_CREATED,
542 ACurl::ResponseCode::HTTP_202_ACCEPTED,
543 ACurl::ResponseCode::HTTP_203_NON_AUTHORITATIVE_INFORMATION,
544 ACurl::ResponseCode::HTTP_204_NO_CONTENT,
545 ACurl::ResponseCode::HTTP_205_RESET_CONTENT,
546 ACurl::ResponseCode::HTTP_206_PARTIAL_CONTENT,
547 ACurl::ResponseCode::HTTP_300_MULTIPLE_CHOICE,
548 ACurl::ResponseCode::HTTP_301_MOVED_PERMANENTLY,
549 ACurl::ResponseCode::HTTP_302_FOUND,
550 ACurl::ResponseCode::HTTP_303_SEE_OTHER,
551 ACurl::ResponseCode::HTTP_304_NOT_MODIFIED,
552 ACurl::ResponseCode::HTTP_305_USE_PROXY,
553 ACurl::ResponseCode::HTTP_306_SWITCH_PROXY,
554 ACurl::ResponseCode::HTTP_307_TEMPORARY_REDIRECT,
555 ACurl::ResponseCode::HTTP_308_PERMANENT_REDIRECT,
556 ACurl::ResponseCode::HTTP_400_BAD_REQUEST,
557 ACurl::ResponseCode::HTTP_401_UNAUTHORIZED,
558 ACurl::ResponseCode::HTTP_402_PAYMENT_REQUIRED,
559 ACurl::ResponseCode::HTTP_403_FORBIDDEN,
560 ACurl::ResponseCode::HTTP_404_NOT_FOUND,
561 ACurl::ResponseCode::HTTP_405_METHOD_NOT_ALLOWED,
562 ACurl::ResponseCode::HTTP_406_NOT_ACCEPTABLE,
563 ACurl::ResponseCode::HTTP_407_PROXY_AUTHENTICATION_REQUIRED,
564 ACurl::ResponseCode::HTTP_408_REQUEST_TIMEOUT,
565 ACurl::ResponseCode::HTTP_409_CONFLICT,
566 ACurl::ResponseCode::HTTP_410_GONE,
567 ACurl::ResponseCode::HTTP_411_LENGTH_REQUIRED,
568 ACurl::ResponseCode::HTTP_412_PRECONDITION_FAILED,
569 ACurl::ResponseCode::HTTP_413_REQUEST_ENTITY_TOO_LARGE,
570 ACurl::ResponseCode::HTTP_414_REQUEST_URI_TOO_LONG,
571 ACurl::ResponseCode::HTTP_415_UNSUPPORTED_MEDIA_TYPE,
572 ACurl::ResponseCode::HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE,
573 ACurl::ResponseCode::HTTP_417_EXPECTATION_FAILED,
574 ACurl::ResponseCode::HTTP_500_INTERNAL_SERVER_ERROR,
575 ACurl::ResponseCode::HTTP_501_NOT_IMPLEMENTED,
576 ACurl::ResponseCode::HTTP_502_BAD_GATEWAY,
577 ACurl::ResponseCode::HTTP_503_SERVICE_UNAVAILABLE,
578 ACurl::ResponseCode::HTTP_504_GATEWAY_TIMEOUT,
579 ACurl::ResponseCode::HTTP_505_HTTP_VERSION_NOT_SUPPORTED)
Acts like std::string_view but for AByteBuffer.
Definition AByteBufferView.h:24
std::vector-like growing array for byte storage.
Definition AByteBuffer.h:31
Multi curl instance.
Definition ACurlMulti.h:44
Builder & withMultipart(const AFormMultipart &multipart)
Add multipart data.
Definition ACurl.h:213
Builder & withBody(std::string contents)
Like withBody with callback, but wrapped with string.
Definition ACurl.h:255
Builder & withWriteCallback(WriteCallback callback)
Called on server -> client data received (download).
Definition ACurl.h:201
Builder & withParams(AString params) noexcept
Sets HTTP params to the query.
Definition ACurl.h:396
Builder & withErrorCallback(ErrorCallback callback)
Definition ACurl.h:293
Builder & withHeaderCallback(HeaderCallback headerCallback)
Called on header received.
Definition ACurl.h:285
Builder & withRanges(size_t begin, size_t end)
Sets: Accept-Ranges: begin-end (download part of the file)
Definition ACurl.cpp:52
Builder & withInputStream(_< IInputStream > inputStream)
Called on client -> server data requested (upload).
Definition ACurl.h:235
Builder & withBody(ReadCallback callback)
Called on client -> server data requested (upload).
Definition ACurl.h:224
Builder & withMethod(Method method) noexcept
Sets HTTP method to the query.
Definition ACurl.h:373
Builder & withRanges(size_t begin)
Sets: Accept-Ranges: begin-end (download part of the file)
Definition ACurl.h:333
Easy curl instance.
Definition ACurl.h:41
std::function< size_t(AByteBufferView data)> WriteCallback
A read callback.
Definition ACurl.h:142
emits success
Emitted on success.
Definition ACurl.h:528
emits< ErrorDescription > fail
Emitted on network error.
Definition ACurl.h:521
std::function< std::size_t(char *dst, size_t maxLen)> ReadCallback
A read callback.
Definition ACurl.h:154
Thrown when stream has reached end (end of file).
Definition AEOFException.h:20
Represents a value that will be available at some point in the future.
Definition AFuture.h:620
Represents a Unicode character string.
Definition AString.h:37
A std::vector with AUI extensions.
Definition AVector.h:39
An std::weak_ptr with AUI extensions.
Definition SharedPtrTypes.h:178
Avoids copy of the wrapped value, pointing to a reference.
Definition values.h:383
ASignal< Args... > emits
A signal declaration.
Definition ASignal.h:348
#define emit
emits the specified signal in context of this object.
Definition AObject.h:310
#define AUI_ENUM_VALUES(enum_t,...)
Defines all enum values for AEnumerate.
Definition AEnumerate.h:208
#define AUI_ASSERTX(condition, what)
Asserts that the passed condition evaluates to true. Adds extra message string.
Definition Assert.h:74
Response struct for Builder::runBlocking() and Builder::runAsync()
Definition ACurl.h:118