UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
TransactionOne.inl
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5namespace UE::IoStore::HTTP
6{
7
15
16static int32 ParseMessage(FAnsiStringView Message, FMessageOffsets& Out)
17{
18 const FAnsiStringView Protocol("HTTP/1.1 ");
19
20 // Check there's enough data
21 if (Message.Len() < Protocol.Len() + 1) // "+1" accounts for at least one digit
22 {
23 return -1;
24 }
25
26 const char* Cursor = Message.GetData();
27
28 // Check for the expected protocol
29 if (FAnsiStringView(Cursor, 9) != Protocol)
30 {
31 return -1;
32 }
33 int32 i = Protocol.Len();
34
35 // Trim left and tightly reject anything adventurous
36 for (int n = 32; i < n && Cursor[i] == ' '; ++i);
37 Out.StatusCode = uint8(i);
38
39 // At least one status line digit. (Note to self; expect exactly three)
40 for (int n = 32; i < n && uint32(Cursor[i] - 0x30) <= 9; ++i);
41 if (uint32(i - Out.StatusCode - 1) > 32)
42 {
43 return -1;
44 }
45
46 // Trim left
47 for (int n = 32; i < n && Cursor[i] == ' '; ++i);
48 Out.Message = uint8(i);
49
50 // Extra conservative length allowance
51 if (i > 32)
52 {
53 return -1;
54 }
55
56 // Find \r\n
57 for (; Cursor[i] != '\r'; ++i)
58 {
59 if (i >= 2048)
60 {
61 return -1;
62 }
63 }
64 if (Cursor[i + 1] != '\n')
65 {
66 return -1;
67 }
68 Out.Headers = uint16(i + 2);
69
70 return 1;
71}
72
73
74
76template <typename LambdaType>
77static void EnumerateHeaders(FAnsiStringView Headers, LambdaType&& Lambda)
78{
79 // NB. here we are assuming that we will be dealing with servers that will
80 // not be returning headers with "obsolete line folding".
81
82 auto IsOws = [] (int32 c) { return (c == ' ') | (c == '\t'); };
83
84 const char* Cursor = Headers.GetData();
85 const char* End = Cursor + Headers.Len();
86 do
87 {
88 int32 ColonIndex = 0;
89 for (; Cursor + ColonIndex < End; ++ColonIndex)
90 {
91 if (Cursor[ColonIndex] == ':')
92 {
93 break;
94 }
95 }
96
97 Cursor += ColonIndex;
98
99 const char* Right = Cursor + 1;
100 while (Right + 1 < End)
101 {
102 if (Right[0] != '\r' || Right[1] != '\n')
103 {
104 Right += 1 + (Right[1] != '\r');
105 continue;
106 }
107
109
110 const char* Left = Cursor + 1;
111 for (; IsOws(Left[0]); ++Left);
112
113 Cursor = Right;
114 for (; Cursor > Left + 1 && IsOws(Cursor[-1]); --Cursor);
115
117
118 if (!Lambda(Name, Value))
119 {
120 Right = End;
121 }
122
123 break;
124 }
125
126 Cursor = Right + 2;
127 } while (Cursor < End);
128}
129
130
131
132namespace DetailOne
133{
134
136class FBase
137{
138public:
140
141protected:
143
144 const char* GetData() const;
145 uint32 GetSize() const;
148
149private:
150 FBuffer Buffer;
151 char Data[256];
152};
153
156: Buffer(Data, sizeof(Data)) // -V670
157{
158}
159
161const char* FBase::GetData() const
162{
163 return Buffer.GetData();
164}
165
168{
169 return Buffer.GetSize();
170}
171
174{
175 return Buffer.GetMutableFree(MinSize, PageSize);
176}
177
180{
181 return Buffer.AdvanceUsed(Delta);
182}
183
184
185
188 : public FBase
189{
190public:
191 using FBase::FBase;
192
193 void Begin(FAnsiStringView Host, FAnsiStringView Method, FAnsiStringView Path);
195 FTransactId End(bool bKeepAlive);
197
198private:
199 FRequest& operator << (FAnsiStringView Value);
200 uint16 HeaderLeft;
201 uint16 AlreadySent = 0;
202 int16 HeaderRight = -1;
203 int8 MethodLength = -1;
204 uint8 _Unnused;
205};
206
209{
210 check(MethodLength < 0);
211 AlreadySent = uint16(GetSize());
212 *this << Method << " " << Path << " HTTP/1.1" "\r\n";
213 MethodLength = int8(Method.Len());
214 HeaderLeft = uint16(GetSize());
215
216 AddHeader("Host", Host);
217}
218
221{
222 check(HeaderRight < 0);
223 *this << Key << ":" << Value << "\r\n";
224}
225
228{
229 // HTTP/1.1 is persistent by default thus "Connection" header isn't required
230 // unless we want to opt in to a single transaction.
231 if (!bKeepAlive)
232 {
233 AddHeader("Connection", "close");
234 }
235
236 *this << "\r\n";
237 HeaderRight = int16(GetSize());
238 return 1;
239}
240
242FRequest& FRequest::operator << (FAnsiStringView Value)
243{
244 uint32 Length = uint32(Value.Len());
246 ::memcpy(Section.Data, Value.GetData(), Length);
248 return *this;
249}
250
253{
254 const char* SendData = GetData();
256
257 SendData += AlreadySent;
258 SendSize -= AlreadySent;
259 check(SendSize > 0);
260
262 if (!Outcome.IsOk())
263 {
264 return Outcome;
265 }
266
267 int32 Result = Outcome.GetResult();
268 AlreadySent += uint16(Result);
269 if (AlreadySent == GetSize())
270 {
271 return FOutcome::Ok();
272 }
273
274 check(AlreadySent < GetSize());
275 return FOutcome::Waiting();
276}
277
278
279
282 : public FRequest
283{
284public:
285 using FRequest::FRequest;
286
288 bool IsKeepAlive() const;
289 uint32 GetStatusCode() const;
291 int64 GetContentLength() const;
292 bool IsChunked() const;
293 void ReadHeaders(FResponse::FHeaderSink Sink) const;
294
295protected:
296 const char* GetMessageRight() const;
297
298private:
299 FOutcome Parse();
300 int64 ContentLength = -1;
301 FMessageOffsets Offsets = {};
302 int16 MessageLeft = -1;
303 int16 MessageRight = -1;
304 uint16 StatusCode = 0;
305 uint8 bKeepAlive : 1;
306 uint8 bChunked : 1;
307 uint8 _Unused : 7;
308};
309
312{
313 return (MessageRight > 0) ? bKeepAlive : true;
314}
315
318{
319 check(StatusCode >= 100);
320 return StatusCode;
321}
322
325{
326 check(Offsets.Message > 0);
327 const char* Cursor = GetData() + MessageLeft;
328 return FAnsiStringView(Cursor + Offsets.Message, Offsets.Headers - Offsets.Message);
329}
330
333{
334 check(Offsets.Headers > 0);
335 return ContentLength;
336}
337
340{
341 check(MessageRight > 0);
342 return bChunked;
343}
344
347{
348 uint32 Offset = MessageLeft + Offsets.Headers;
349 uint32 Length = MessageRight - Offset - 2; // "-2" trims off '\r\n' that signals end of headers
350 const char* Cursor = GetData() + Offset;
351 FAnsiStringView Headers(Cursor, Length);
352 UE::IoStore::HTTP::EnumerateHeaders(Headers, Sink);
353}
354
357{
358 return GetData() + MessageRight;
359}
360
363{
364 auto FindMessageTerminal = [] (const char* Cursor, int32 Length)
365 {
366 for (int32 i = 4; i <= Length; ++i)
367 {
368 uint32 Candidate;
369 ::memcpy(&Candidate, Cursor + i - 4, sizeof(Candidate));
370 if (Candidate == 0x0a0d0a0d)
371 {
372 return i;
373 }
374
375 i += (Cursor[i - 1] > 0x0d) ? 3 : 0;
376 }
377
378 return -1;
379 };
380
381 if (MessageLeft < 0)
382 {
383 MessageLeft = int16(GetSize());
384 bKeepAlive = true;
385 bChunked = false;
386 }
387
388 while (true)
389 {
390 static const uint32 PageSize = 256;
391 static const uint32 MaxHeaderSize = 8 << 10;
392
393 auto [Dest, DestSize] = GetMutableFree(0, PageSize);
394 FOutcome Outcome = Peer.Recv(Dest, DestSize);
395 if (!Outcome.IsOk())
396 {
397 return Outcome;
398 }
399
400 int32 Result = Outcome.GetResult();
401 AdvanceUsed(Result);
402
403 // Rewind a little to cover cases where the terminal is fragmented across
404 // recv() calls
405 uint32 DestBias = 0;
406 if (Dest - 3 >= GetData() + MessageLeft)
407 {
408 Dest -= (DestBias = 3);
409 }
410
412 if (MessageEnd < 0)
413 {
414 if (GetSize() - MessageLeft > MaxHeaderSize)
415 {
416 return FOutcome::Error("Headers have grown larger than expected");
417 }
418
419 continue;
420 }
421
422 MessageRight = int16(ptrdiff_t(Dest + MessageEnd - GetData()));
423 return Parse();
424 }
425}
426
428FOutcome FStatusHeaders::Parse()
429{
430 const char* Cursor = GetData() + MessageLeft;
431 FAnsiStringView MessageView(Cursor, MessageRight - MessageLeft);
432
433 if (ParseMessage(MessageView, Offsets) < 0)
434 {
435 return FOutcome::Error("Failed to parse message status");
436 }
437
439 Cursor + Offsets.StatusCode,
440 Offsets.Message - Offsets.StatusCode
441 );
442 StatusCode = uint16(CrudeToInt(StatusCodeView));
443 if (!IsStatusCodeOk(StatusCode))
444 {
445 return FOutcome::Error("Invalid status code", StatusCode);
446 }
447
448 static const uint32 Flag_Length = 1 << 0;
449 static const uint32 Flag_XferEnc = 1 << 1;
450 static const uint32 Flag_Connection = 1 << 2;
451 static const uint32 Flag_All = 0x07;
452 uint32 Flags = 0;
453
455 [this, &Flags] (FAnsiStringView Name, FAnsiStringView Value) mutable
456 {
457 // todo; may need smarter value handling; ;/, separated options & key-value pairs (ex. in rfc2068)
458
459 if (Name.Equals("Content-Length", ESearchCase::IgnoreCase))
460 {
461 ContentLength = int32(CrudeToInt(Value));
462 Flags |= Flag_Length;
463 }
464
465 else if (Name.Equals("Transfer-Encoding", ESearchCase::IgnoreCase))
466 {
467 bChunked = Value.Equals("chunked", ESearchCase::IgnoreCase);
468 Flags |= Flag_XferEnc;
469 }
470
471 else if (Name.Equals("Connection", ESearchCase::IgnoreCase))
472 {
473 bKeepAlive = !Value.Equals("close", ESearchCase::IgnoreCase);
474 Flags |= Flag_Connection;
475 }
476
477 return Flags != Flag_All;
478 }
479 );
480
481 if (Flags & Flag_XferEnc)
482 {
483 if (!bChunked) return FOutcome::Error("Unsupported Transfer-Encoding");
484 if (Flags & Flag_Length) return FOutcome::Error("Chunked yet with length");
485 ContentLength = -1;
486 }
487 else if (uint32 Overshoot = GetSize() - MessageRight; Flags & Flag_Length)
488 {
489 if (ContentLength < 0) return FOutcome::Error("Invalid Content-Length field", uint32(ContentLength));
490 if (Overshoot > ContentLength) return FOutcome::Error("More data received that expected");
491 }
492 else if (Overshoot)
493 {
494 return FOutcome::Error("Received content when none was expected");
495 }
496 else
497 {
498 ContentLength = 0;
499 }
500
501 if (IsContentless(StatusCode))
502 {
503 ContentLength = 0;
504 bChunked = false;
505 }
506
507 return FOutcome::Ok();
508}
509
510
511
513class FBody
514 : public FStatusHeaders
515{
516public:
517 using FStatusHeaders::FStatusHeaders;
518
519 int64 GetRemaining() const;
521
522private:
523 enum class EState : uint8 { Init, Recv, Prologue, Chunk, Epilogue, Done };
524
525 FOutcome Gather(FMutableMemoryView Dest, FTlsPeer& Peer);
526 FOutcome Init(FMutableMemoryView Dest, FTlsPeer& Peer);
527 FOutcome Recv(FMutableMemoryView Dest, FTlsPeer& Peer);
528 FOutcome Prologue(FMutableMemoryView Dest, FTlsPeer& Peer);
529 FOutcome Chunk(FMutableMemoryView Dest, FTlsPeer& Peer);
530 FOutcome Epilogue(FMutableMemoryView Dest, FTlsPeer& Peer);
531 FMemoryView Overspill;
532 FMutableMemoryView Scratch;
533 int64 Remaining = 0;
534 EState State = EState::Init;
535
536 enum
537 {
538 HeaderBufSize = 32,
539 CrLfLength = 2,
540 EndOfXfer = -1,
541 };
542};
543
546{
547 return (State == EState::Recv) ? Remaining : -1;
548}
549
552{
553 if (Dest.GetSize() == 0)
554 {
555 return FOutcome::Error("Empty destination");
556 }
557
559
560 switch (State)
561 {
562 case EState::Init: Outcome = Init(Dest, Peer); break;
563 case EState::Recv: Outcome = Recv(Dest, Peer); break;
564 default: Outcome = Gather(Dest, Peer); break;
565 case EState::Done: Outcome = FOutcome::Error("Transaction is complete"); break;
566 }
567
568 if (Outcome.IsOk())
569 {
570 State = EState::Done;
571 }
572
573 return Outcome;
574}
575
577FOutcome FBody::Gather(FMutableMemoryView Dest, FTlsPeer& Peer)
578{
580
581 bool bDone = false;
582 int32 Size = 0;
583 do
584 {
585 switch (State)
586 {
587 case EState::Prologue: Outcome = Prologue(Dest, Peer); break;
588 case EState::Chunk: Outcome = Chunk(Dest, Peer); break;
589 case EState::Epilogue: Outcome = Epilogue(Dest, Peer); break;
590 default: Outcome = FOutcome::Error("Unexpected try-chunked state"); break;
591 }
592
593 if (Outcome.IsError())
594 {
595 return Outcome;
596 }
597
598 bDone = Outcome.IsOk();
599 int32 Result = Outcome.GetResult();
600 if (Result == 0)
601 {
602 break;
603 }
604
605 Size += Result;
606 Dest = Dest.Mid(Result);
607 }
608 while (!Dest.IsEmpty());
609
610 return bDone ? FOutcome::Ok(Size) : FOutcome::Waiting(Size);
611}
612
614FOutcome FBody::Init(FMutableMemoryView Dest, FTlsPeer& Peer)
615{
616 const char* DataEnd = GetData() + GetSize();
617 const char* MessageEnd = GetMessageRight();
619 if (AlreadyReceived < HeaderBufSize)
620 {
621 GetMutableFree(HeaderBufSize, HeaderBufSize);
623 }
624
625 if (AlreadyReceived)
626 {
627 Overspill = { (const uint8*)MessageEnd, AlreadyReceived };
628 }
629
630 Scratch = { (uint8*)MessageEnd, HeaderBufSize };
631
632 if (IsChunked())
633 {
634 check(Remaining == 0);
635 State = EState::Prologue;
636 }
637 else
638 {
639 Remaining = GetContentLength();
640 check(Remaining > 0);
641 State = EState::Recv;
642 }
643
644 return TryRecv(Dest, Peer);
645}
646
648FOutcome FBody::Recv(FMutableMemoryView Dest, FTlsPeer& Peer)
649{
650 int64 OverspillSize = Overspill.GetSize();
651 if (OverspillSize != 0)
652 {
653 int64 Size = FMath::Min<int64>(Dest.GetSize(), OverspillSize);
654 ::memcpy(Dest.GetData(), Overspill.GetData(), Size);
655 Dest = Dest.Mid(Size);
656 Overspill = Overspill.Mid(Size);
657 Remaining -= Size;
658 if (Remaining == 0 || Dest.IsEmpty())
659 {
661 return Remaining ? FOutcome::WaitBuffer(Result) : FOutcome::Ok(Result);
662 }
663 }
664
665 auto* Cursor = (char*)(Dest.GetData());
666 uint32 Size = uint32(FMath::Min<int64>(Dest.GetSize(), Remaining));
667 FOutcome Outcome = Peer.Recv(Cursor, Size);
668 if (Outcome.IsError())
669 {
670 return Outcome;
671 }
672
673 if (Outcome.IsWaiting())
674 {
675 check(Outcome.GetResult() == 0);
677 }
678
679 int32 Result = Outcome.GetResult();
680 Remaining -= Result;
681 if (Remaining < 0)
682 {
683 return FOutcome::Error("Unexpectedly received too much", int32(Remaining));
684 }
685
687
688 if (Remaining == 0)
689 {
690 return FOutcome::Ok(Result);
691 }
692
693 if (Result == Dest.GetSize())
694 {
695 return FOutcome::WaitBuffer(Result);
696 }
697
698 return FOutcome::Waiting(Result);
699}
700
702FOutcome FBody::Prologue(FMutableMemoryView Dest, FTlsPeer& Peer)
703{
704 auto FindHeader = [] (const char* Cursor, int32 Size)
705 {
706 // Base-16 size
707 int32 HexDigLen = 0;
708 for (; HexDigLen < Size; ++HexDigLen)
709 {
710 uint32 c = Cursor[HexDigLen];
711 if ((c - '0' >= 10) & (c - 'a' >= 6) & (c - 'A' >= 6))
712 {
713 break;
714 }
715 continue;
716 }
717
719
720 if (HexDigLen >= HeaderBufSize - 2) return FOutcome::Error("Chunk size too large");
721 if (HexDigLen == 0) return FOutcome::Error("Invalid chunk header");
722 if (Delta < 1) return FOutcome::Waiting();
723 if (Cursor[HexDigLen] != '\r') return FOutcome::Error("Chunk extensions are not supported (ERREXT)");
724 if (Delta < 2) return FOutcome::Waiting();
725 if (Cursor[HexDigLen + 1] != '\n') return FOutcome::Error("Invalid chunk CRLF");
726
727 return FOutcome::Ok(HexDigLen + 2);
728 };
729
730 const char* Header = nullptr;
731 FOutcome Outcome = FOutcome::None();
732 int32 HeaderLength = 0;
733
734 uint32 OverspillSize = uint32(Overspill.GetSize());
735 if (OverspillSize != 0)
736 {
737 // We try all the overspill first - we don't know how much we're expecting
738 // and overspill could contain both header and all data (thus further recvs
739 // could falsely hang us up).
740 Header = (char*)Overspill.GetData();
741
743 if (Outcome.IsError())
744 {
745 return Outcome;
746 }
747
748 HeaderLength = Outcome.GetResult();
749 Overspill = Overspill.Mid(HeaderLength);
750 }
751
752 if (HeaderLength == 0)
753 {
754 FMutableMemoryView View = Scratch;
755
756 if (OverspillSize != 0)
757 {
758 if (OverspillSize > uint32(View.GetSize()))
759 {
760 return FOutcome::Error("Unexpectedly large overspill");
761 }
762 std::memmove(View.GetData(), Overspill.GetData(), OverspillSize);
763 View = View.Mid(OverspillSize);
764 }
765
766 if (!View.IsEmpty())
767 {
768 char* Cursor = (char*)View.GetData();
769 Outcome = Peer.Recv(Cursor, uint32(View.GetSize()));
770 if (!Outcome.IsOk())
771 {
772 return Outcome;
773 }
774 View = Scratch.Left(OverspillSize + Outcome.GetResult());
775 }
776
777 char* Cursor = (char*)View.GetData();
778 Outcome = FindHeader(Cursor, uint32(View.GetSize()));
779 if (!Outcome.IsOk())
780 {
781 return Outcome;
782 }
783
784 check(View.GetData() == Scratch.GetData());
785 Header = (char*)Scratch.GetData();
786 HeaderLength = Outcome.GetResult();
787 Overspill = View.Mid(HeaderLength);
788 }
789
790 // Read chunk size
791 Header += Remaining;
792 int64 ChunkSize = CrudeToInt<16>(FAnsiStringView(Header, HeaderLength));
793 if (ChunkSize < 0) return FOutcome::Error("Unparsable chunk size");
794 if (ChunkSize > 16 << 20) return FOutcome::Error("Unacceptable chunk size");
795
796 if (ChunkSize == 0)
797 {
798 Remaining = EndOfXfer;
799 ::memset(Scratch.GetData(), 0, CrLfLength);
800 State = EState::Epilogue;
801 return Epilogue(Dest, Peer);
802 }
803
804 Remaining = ChunkSize;
805 State = EState::Chunk;
806 return Chunk(Dest, Peer);
807}
808
810FOutcome FBody::Chunk(FMutableMemoryView Dest, FTlsPeer& Peer)
811{
812 check(Remaining != 0);
813
814 Dest = Dest.Left(Remaining);
815 FOutcome Outcome = Recv(Dest, Peer);
816 if (!Outcome.IsOk())
817 {
818 return Outcome;
819 }
820
821 check(Remaining == 0);
822 ::memset(Scratch.GetData(), 0, CrLfLength);
823 State = EState::Epilogue;
824
825 int32 Result = Outcome.GetResult();
826 return FOutcome::WaitBuffer(Result);
827}
828
830FOutcome FBody::Epilogue(FMutableMemoryView Dest, FTlsPeer& Peer)
831{
832 auto* Cursor = (uint8*)(Scratch.GetData());
833
834 FMutableMemoryView CrLfBuffer(Cursor, CrLfLength);
835 if (Cursor[0] != 0)
836 {
837 CrLfBuffer = { Cursor + 1, 1 };
838 }
839
840 check(Remaining <= 0);
841
842 int64 RemainingCache = Remaining;
843 Remaining = CrLfBuffer.GetSize();
844 FOutcome Outcome = Recv(CrLfBuffer, Peer);
845 if (!Outcome.IsOk())
846 {
847 Remaining = RemainingCache;
848 return Outcome;
849 }
850
851 if (Cursor[0] != '\r' || Cursor[1] != '\n')
852 {
853 return FOutcome::Error("Trailing headers are not supported (ERRTRAIL)");
854 }
855
856 if (RemainingCache > EndOfXfer)
857 {
858 State = EState::Prologue;
859 return Prologue(Dest, Peer);
860 }
861
862 return FOutcome::Ok();
863}
864
865} // namespace DetailOne
866
867
868
871 : public DetailOne::FBody
872{
873public:
874 using DetailOne::FBody::FBody;
875};
876
877
878
881{
882 return FOutcome::Ok();
883}
884
887{
888 return FOutcome::Ok(1);
889}
890
892void GoAwayOne(FTlsPeer&, void*)
893{
894}
895
896
897
900{
901public:
902#define TR_METHOD(x, ...) \
903 template <typename... Arg> auto x(Arg&&... Args) __VA_ARGS__ { \
904 if (auto Self = UPTRINT(this); Self & 1) \
905 return ((FTransactionTwo*)(Self ^ 1))->x(Forward<Arg>(Args)...); \
906 return ((FTransactionOne*)this)->x(Forward<Arg>(Args)...); \
907 }
909 TR_METHOD(AddHeader)
911 TR_METHOD(TrySendRequest)
912 TR_METHOD(TryRecvResponse)
913 TR_METHOD(IsKeepAlive, const)
914 TR_METHOD(GetStatusCode, const)
915 TR_METHOD(GetStatusMessage, const)
916 TR_METHOD(GetContentLength, const)
917 TR_METHOD(IsChunked, const)
918 TR_METHOD(ReadHeaders, const)
919 TR_METHOD(GetRemaining, const)
920 TR_METHOD(TryRecv)
921#undef TR_METHOD
922
923private:
924 friend class FTransactRef;
925
926 void Destruct()
927 {
928 if (auto Self = UPTRINT(this); Self & 1)
929 {
930 void* Addr = (void*)(Self ^ 1);
931 ((FTransactionTwo*)Addr)->~FTransactionTwo();
932 FMemory::Free(Addr);
933 return;
934 }
935
936 ((FTransactionOne*)this)->~FTransactionOne();
937 FMemory::Free(this);
938 }
939};
940
941
942
945{
946public:
947 FTransactRef() = default;
951 FTransactRef(const FTransactRef&) = delete;
952 void operator = (const FTransactRef& Rhs) = delete;
953 void operator = (FTransactRef&& Rhs);
954 const FTransaction* operator -> () const;
956 bool IsValid() const;
957
958private:
959 const FTransaction* Get() const;
960 FTransaction* Get();
961 UPTRINT Self = 0;
962};
963
966: Self(Ptr | (Ver == 2))
967{
968 check((Ptr & 1) == 0);
969}
970
973{
974 Swap(Self, Rhs.Self);
975}
976
979{
980 return Get();
981}
982
985{
986 return Get();
987}
988
991{
992 return Get() != nullptr;
993}
994
996const FTransaction* FTransactRef::Get() const
997{
998 return (FTransaction*)Self;
999}
1000
1002FTransaction* FTransactRef::Get()
1003{
1004 return (FTransaction*)Self;
1005}
1006
1009{
1010 if (Self == 0)
1011 {
1012 return;
1013 }
1014
1015 Get()->Destruct();
1016}
1017
1018
1019
1022{
1023 void* Ptr = FMemory::Malloc(sizeof(FTransactionOne), alignof(FTransactionOne));
1024 new (Ptr) FTransactionOne();
1025 return FTransactRef(UPTRINT(Ptr), 1);
1026}
1027
1030{
1031#if IAS_HTTP_WITH_TWO
1032 using namespace DetailTwo;
1033
1034 auto* Driver = (FDriverNg*)PeerData;
1035
1036 void* Ptr = FMemory::Malloc(sizeof(FTransactionTwo), alignof(FTransactionTwo));
1037 new (Ptr) FTransactionTwo(*Driver);
1038
1039 return FTransactRef(UPTRINT(Ptr), 2);
1040#else
1041 return FTransactRef();
1042#endif
1043}
1044
1045} // namespace UE::IoStore::HTTP
#define check(expr)
Definition AssertionMacros.h:314
return Self
Definition CocoaThread.cpp:337
FPlatformTypes::int16 int16
A 16-bit signed integer.
Definition Platform.h:1123
FPlatformTypes::int8 int8
An 8-bit signed integer.
Definition Platform.h:1121
FPlatformTypes::int64 int64
A 64-bit signed integer.
Definition Platform.h:1127
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
FPlatformTypes::UPTRINT UPTRINT
An unsigned integer the same size as a pointer.
Definition Platform.h:1146
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
TStringView< ANSICHAR > FAnsiStringView
Definition StringFwd.h:46
#define TR_METHOD(x,...)
Definition TransactionOne.inl:902
uint32 Offset
Definition VulkanMemory.cpp:4033
uint32 Size
Definition VulkanMemory.cpp:4034
if(Failed) console_printf("Failed.\n")
memcpy(InputBufferBase, BinkBlocksData, BinkBlocksSize)
uint8_t uint8
Definition binka_ue_file_header.h:8
uint16_t uint16
Definition binka_ue_file_header.h:7
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition AndroidPlatformMisc.h:14
constexpr DataType * GetData() const
Definition MemoryView.h:68
constexpr TMemoryView Left(uint64 InSize) const
Definition MemoryView.h:83
constexpr bool IsEmpty() const
Definition MemoryView.h:77
TMemoryView Mid(uint64 InOffset, uint64 InSize=TNumericLimits< uint64 >::Max()) const
Definition MemoryView.h:115
constexpr uint64 GetSize() const
Definition MemoryView.h:74
constexpr int32 Len() const
Definition StringView.h:174
constexpr const CharType * GetData() const
Definition StringView.h:160
Definition TransactionOne.inl:137
void AdvanceUsed(uint32 Delta)
Definition TransactionOne.inl:179
const char * GetData() const
Definition TransactionOne.inl:161
uint32 GetSize() const
Definition TransactionOne.inl:167
FMutableSection GetMutableFree(uint32 MinSize, uint32 PageSize=256)
Definition TransactionOne.inl:173
FBase()
Definition TransactionOne.inl:155
Definition TransactionOne.inl:515
FOutcome TryRecv(FMutableMemoryView Dest, FTlsPeer &Peer)
Definition TransactionOne.inl:551
int64 GetRemaining() const
Definition TransactionOne.inl:545
Definition TransactionOne.inl:189
void Begin(FAnsiStringView Host, FAnsiStringView Method, FAnsiStringView Path)
Definition TransactionOne.inl:208
FOutcome TrySendRequest(FTlsPeer &Peer)
Definition TransactionOne.inl:252
FTransactId End(bool bKeepAlive)
Definition TransactionOne.inl:227
void AddHeader(FAnsiStringView Key, FAnsiStringView Value)
Definition TransactionOne.inl:220
Definition TransactionOne.inl:283
int64 GetContentLength() const
Definition TransactionOne.inl:332
const char * GetMessageRight() const
Definition TransactionOne.inl:356
FOutcome TryRecvResponse(FTlsPeer &Peer)
Definition TransactionOne.inl:362
void ReadHeaders(FResponse::FHeaderSink Sink) const
Definition TransactionOne.inl:346
FAnsiStringView GetStatusMessage() const
Definition TransactionOne.inl:324
uint32 GetStatusCode() const
Definition TransactionOne.inl:317
bool IsChunked() const
Definition TransactionOne.inl:339
bool IsKeepAlive() const
Definition TransactionOne.inl:311
Definition Misc.inl:342
void AdvanceUsed(uint32 Delta)
Definition Misc.inl:467
FMutableSection GetMutableFree(uint32 MinSize, uint32 PageSize=256)
Definition Misc.inl:453
uint32 GetSize() const
Definition Misc.inl:420
const char * GetData() const
Definition Misc.inl:414
Definition Misc.inl:73
static FOutcome Ok(int32 Result=0)
Definition Misc.inl:113
static FOutcome Error(const char *Message, int32 Code=-1)
Definition Misc.inl:151
static FOutcome WaitBuffer(int32 Result=0)
Definition Misc.inl:131
static FOutcome None()
Definition Misc.inl:80
static FOutcome Waiting(int32 Result=0)
Definition Misc.inl:122
Definition Peer.inl:423
FOutcome Send(const char *Data, int32 Size)
Definition Peer.inl:492
FOutcome Recv(char *Out, int32 MaxSize)
Definition Peer.inl:503
Definition TransactionOne.inl:945
bool IsValid() const
Definition TransactionOne.inl:990
FTransactRef(const FTransactRef &)=delete
const FTransaction * operator->() const
Definition TransactionOne.inl:978
FTransactRef(FTransactRef &&)=delete
~FTransactRef()
Definition TransactionOne.inl:1008
void operator=(const FTransactRef &Rhs)=delete
Definition TransactionOne.inl:872
Definition TransactionTwo.inl:897
Definition TransactionOne.inl:900
@ IgnoreCase
Definition CString.h:26
const TCHAR * Name
Definition OodleDataCompression.cpp:30
Definition Client.h:20
FOutcome HandshakeOne(FTlsPeer &, void *)
Definition TransactionOne.inl:880
bool IsStatusCodeOk(uint32 StatusCode)
Definition TransactionTwo.inl:18
FTransactRef CreateTransactOne(void *&)
Definition TransactionOne.inl:1021
FOutcome TickOne(FTlsPeer &, void *)
Definition TransactionOne.inl:886
bool IsContentless(uint32 StatusCode)
Definition TransactionTwo.inl:12
void GoAwayOne(FTlsPeer &, void *)
Definition TransactionOne.inl:892
uint32 FTransactId
Definition TransactionTwo.inl:9
FTransactRef CreateTransactTwo(void *PeerData)
Definition TransactionOne.inl:1029
UE_STRING_CLASS Result(Forward< LhsType >(Lhs), RhsLen)
Definition String.cpp.inl:732
static FORCENOINLINE CORE_API void Free(void *Original)
Definition UnrealMemory.cpp:685
char * Data
Definition Misc.inl:346
Definition TransactionOne.inl:10
uint8 Message
Definition TransactionOne.inl:12
uint16 Headers
Definition TransactionOne.inl:13
uint8 StatusCode
Definition TransactionOne.inl:11