mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-07 13:39:55 +00:00
Merge pull request #14303 from voidlakhan/feat/nkwebkit-url-helpers
feat(libSceNKWebKit): implement WTF::protocolHostAndPortAreEqual
This commit is contained in:
6 files changed
+145
-7
No files matched your search
@@ -19454,10 +19454,6 @@ int APS5_VABI _ZN3WTF26normalizeLineEndingsToCRLFEONS_6VectorIhLm0ENS_15CrashOnO
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3WTF27protocolHostAndPortAreEqualERKNS_3URLES2_() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3WTF28encodeWithURLEscapeSequencesERKNS_6StringE() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
@@ -1834,7 +1834,6 @@ int APS5_VABI _ZN3WTF24normalizeLineEndingsToLFEONS_6VectorIhLm0ENS_15CrashOnOve
|
||||
int APS5_VABI _ZN3WTF25activateSignalHandlersForENS_6SignalE();
|
||||
int APS5_VABI _ZN3WTF26getAndResetAccumulatedLogsEv();
|
||||
int APS5_VABI _ZN3WTF26normalizeLineEndingsToCRLFEONS_6VectorIhLm0ENS_15CrashOnOverflowELm16ENS_10FastMallocEEE();
|
||||
int APS5_VABI _ZN3WTF27protocolHostAndPortAreEqualERKNS_3URLES2_();
|
||||
int APS5_VABI _ZN3WTF28encodeWithURLEscapeSequencesERKNS_6StringE();
|
||||
int APS5_VABI _ZN3WTF28normalizeLineEndingsToNativeEONS_6VectorIhLm0ENS_15CrashOnOverflowELm16ENS_10FastMallocEEE();
|
||||
int APS5_VABI _ZN3WTF30numCodeUnitsInGraphemeClustersENS_10StringViewEj();
|
||||
|
||||
@@ -136,6 +136,7 @@ WTF::LocalTimeOffset APS5_VABI _ZN3WTF24calculateLocalTimeOffsetEdNS_8TimeTypeE(
|
||||
void APS5_VABI _ZN3WTF25addLanguageChangeObserverEPvPFvS0_E(void* context, void (APS5_VABI *observer)(void*));
|
||||
void APS5_VABI _ZN3WTF25fastDecommitAlignedMemoryEPvm(void*, std::size_t);
|
||||
void APS5_VABI _ZN3WTF25fastMallocDumpMallocStatsEv();
|
||||
bool APS5_VABI _ZN3WTF27protocolHostAndPortAreEqualERKNS_3URLES2_(const NKWebKit::WtfAbi::URL* a, const NKWebKit::WtfAbi::URL* b);
|
||||
void APS5_VABI _ZN3WTF27releaseFastMallocFreeMemoryEv();
|
||||
NKWebKit::WtfAbi::String APS5_VABI _ZN3WTF28displayNameForLanguageLocaleERKNS_6StringE(const NKWebKit::WtfAbi::String* localeName);
|
||||
void APS5_VABI _ZN3WTF28removeLanguageChangeObserverEPv(void* context);
|
||||
|
||||
@@ -1116,6 +1116,27 @@ bool APS5_VABI _ZN3WTF31equalIgnoringFragmentIdentifierERKNS_3URLES2_(const URL*
|
||||
return EqualViews(ViewWithoutFragment(first), ViewWithoutFragment(second));
|
||||
}
|
||||
|
||||
bool APS5_VABI _ZN3WTF27protocolHostAndPortAreEqualERKNS_3URLES2_(const URL* a, const URL* b) {
|
||||
const auto& first = Checked(a);
|
||||
const auto& second = Checked(b);
|
||||
unsigned schemeEndA = first.bits >> 6;
|
||||
unsigned schemeEndB = second.bits >> 6;
|
||||
if (schemeEndA != schemeEndB) return false;
|
||||
unsigned hostStartA = HostStart(first);
|
||||
unsigned hostStartB = HostStart(second);
|
||||
if (first.hostEnd < hostStartA || second.hostEnd < hostStartB) return false;
|
||||
unsigned hostLengthA = first.hostEnd - hostStartA;
|
||||
unsigned hostLengthB = second.hostEnd - hostStartB;
|
||||
if (hostLengthA != hostLengthB) return false;
|
||||
auto viewA = View(first.impl);
|
||||
auto viewB = View(second.impl);
|
||||
if (schemeEndA > viewA.length || schemeEndB > viewB.length) return false;
|
||||
if (hostStartA + hostLengthA > viewA.length || hostStartB + hostLengthB > viewB.length) return false;
|
||||
if (!EqualViews(Slice(viewA, 0, schemeEndA), Slice(viewB, 0, schemeEndB), true)) return false;
|
||||
if (!EqualViews(Slice(viewA, hostStartA, hostLengthA), Slice(viewB, hostStartB, hostLengthB), true)) return false;
|
||||
return URLPort(first) == URLPort(second);
|
||||
}
|
||||
|
||||
void APS5_VABI _ZN3WTF3URL10invalidateEv(URL* self) {
|
||||
auto& url = Checked(self);
|
||||
url.bits = 0;
|
||||
|
||||
@@ -804,6 +804,7 @@ const auto URLJavaScript = &_ZNK3WTF3URL20protocolIsJavaScriptEv;
|
||||
const auto URLInvalidate = &_ZN3WTF3URL10invalidateEv;
|
||||
const auto URLEqualIgnoringFragment = &_ZN3WTF31equalIgnoringFragmentIdentifierERKNS_3URLES2_;
|
||||
const auto URLPortAllowed = &_ZN3WTF11portAllowedERKNS_3URLE;
|
||||
const auto URLProtocolHostAndPortAreEqual = &_ZN3WTF27protocolHostAndPortAreEqualERKNS_3URLES2_;
|
||||
const auto IsJavaScript = &_ZN3WTF20protocolIsJavaScriptENS_10StringViewE;
|
||||
const auto IsHTTP = &_ZN3WTF22protocolIsInHTTPFamilyENS_10StringViewE;
|
||||
const auto JSRealloc = &_ZN3WTF14jsValueReallocEPvm;
|
||||
@@ -1386,6 +1387,127 @@ void TestURLsAndReallocation() {
|
||||
Check(URLPortAllowed(&urlWraparoundPort));
|
||||
Check(URLPortAllowed(&absent));
|
||||
Throws([&] { URLPortAllowed(nullptr); });
|
||||
{
|
||||
Check(URLProtocolHostAndPortAreEqual(&url, &url));
|
||||
Check(URLProtocolHostAndPortAreEqual(&url, &urlNoFrag));
|
||||
Check(URLProtocolHostAndPortAreEqual(&url, &urlDiffQuery));
|
||||
Check(URLProtocolHostAndPortAreEqual(&url, &urlDiffPath));
|
||||
auto urlUpperSchemeStr = FromUTF8Z(U8("HTTPS://u%20:p%[email protected]:8443/a/b?q=1#frag"));
|
||||
URL urlUpperScheme = url;
|
||||
urlUpperScheme.impl = urlUpperSchemeStr.impl;
|
||||
Check(URLProtocolHostAndPortAreEqual(&url, &urlUpperScheme));
|
||||
auto urlUpperHostStr = FromUTF8Z(U8("https://u%20:p%[email protected]:8443/a/b?q=1#frag"));
|
||||
URL urlUpperHost = url;
|
||||
urlUpperHost.impl = urlUpperHostStr.impl;
|
||||
Check(URLProtocolHostAndPortAreEqual(&url, &urlUpperHost));
|
||||
auto urlHttpStr = FromUTF8Z(U8("http://u%20:p%[email protected]:8443/a/b?q=1#frag"));
|
||||
URL urlHttp = url;
|
||||
urlHttp.impl = urlHttpStr.impl;
|
||||
urlHttp.bits = 1U | 2U | (5U << 3) | (4U << 6);
|
||||
Check(!URLProtocolHostAndPortAreEqual(&url, &urlHttp));
|
||||
Check(!URLProtocolHostAndPortAreEqual(&url, &urlDiffHost));
|
||||
auto urlShortHostStr = FromUTF8Z(U8("https://u%20:p%[email protected]:8443/a/b?q=1#frag"));
|
||||
URL urlShortHost = url;
|
||||
urlShortHost.impl = urlShortHostStr.impl;
|
||||
urlShortHost.hostEnd = 25;
|
||||
Check(!URLProtocolHostAndPortAreEqual(&url, &urlShortHost));
|
||||
auto urlDiffPortStr = FromUTF8Z(U8("https://u%20:p%[email protected]:9443/a/b?q=1#frag"));
|
||||
URL urlDiffPort = url;
|
||||
urlDiffPort.impl = urlDiffPortStr.impl;
|
||||
Check(!URLProtocolHostAndPortAreEqual(&url, &urlDiffPort));
|
||||
auto urlPort80Str = FromUTF8Z(U8("http://example.test:80/path"));
|
||||
URL urlPort80{urlPort80Str.impl, 1U | 2U | (3U << 3) | (4U << 6), 7, 7, 7, 19, 23, 27, 27};
|
||||
auto urlNoPortStr = FromUTF8Z(U8("http://example.test/path"));
|
||||
URL urlNoPort{urlNoPortStr.impl, 1U | 2U | (0U << 3) | (4U << 6), 7, 7, 7, 19, 20, 24, 24};
|
||||
Check(!URLProtocolHostAndPortAreEqual(&urlPort80, &urlNoPort));
|
||||
auto urlNoPort2Str = FromUTF8Z(U8("http://example.test/other"));
|
||||
URL urlNoPort2{urlNoPort2Str.impl, 1U | 2U | (0U << 3) | (4U << 6), 7, 7, 7, 19, 20, 25, 25};
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlNoPort, &urlNoPort2));
|
||||
auto widePort = Create16(u"http://wide.test:8080/path", 26);
|
||||
URL urlWidePort{widePort.impl, 1U | 2U | (5U << 3) | (4U << 6), 7, 7, 7, 16, 22, 26, 26};
|
||||
auto widePortMatch = Create16(u"HTTP://WIDE.TEST:8080/other", 27);
|
||||
URL urlWideMatch{widePortMatch.impl, 1U | 2U | (5U << 3) | (4U << 6), 7, 7, 7, 16, 22, 27, 27};
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlWidePort, &urlWideMatch));
|
||||
auto narrowPortStr = FromUTF8Z(U8("http://wide.test:8080/narrow"));
|
||||
URL urlNarrowPort{narrowPortStr.impl, 1U | 2U | (5U << 3) | (4U << 6), 7, 7, 7, 16, 22, 28, 28};
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlWidePort, &urlNarrowPort));
|
||||
auto urlPort0Str = FromUTF8Z(U8("http://example.test:0/path"));
|
||||
URL urlPort0{urlPort0Str.impl, 1U | 2U | (2U << 3) | (4U << 6), 7, 7, 7, 19, 22, 26, 26};
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlPort0, &urlPort0));
|
||||
Check(!URLProtocolHostAndPortAreEqual(&urlPort0, &urlNoPort));
|
||||
Check(!URLProtocolHostAndPortAreEqual(&urlPort0, &urlPort80));
|
||||
auto urlPortMaxStr = FromUTF8Z(U8("http://example.test:65535/path"));
|
||||
URL urlPortMax{urlPortMaxStr.impl, 1U | 2U | (6U << 3) | (4U << 6), 7, 7, 7, 19, 26, 30, 30};
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlPortMax, &urlPortMax));
|
||||
Check(!URLProtocolHostAndPortAreEqual(&urlPortMax, &urlPort80));
|
||||
auto urlEmptyPortStr = FromUTF8Z(U8("http://example.test:/path"));
|
||||
URL urlEmptyPort{urlEmptyPortStr.impl, 1U | 2U | (1U << 3) | (4U << 6), 7, 7, 7, 19, 21, 25, 25};
|
||||
Check(!URLProtocolHostAndPortAreEqual(&urlEmptyPort, &urlPort80));
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlEmptyPort, &urlNoPort));
|
||||
auto urlMalformedPortStr = FromUTF8Z(U8("http://example.test:8x/path"));
|
||||
URL urlMalformedPort{urlMalformedPortStr.impl, 1U | 2U | (3U << 3) | (4U << 6), 7, 7, 7, 19, 23, 27, 27};
|
||||
Check(!URLProtocolHostAndPortAreEqual(&urlMalformedPort, &urlPort80));
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlMalformedPort, &urlNoPort));
|
||||
auto urlOutOfRangePortStr = FromUTF8Z(U8("http://example.test:70000/path"));
|
||||
URL urlOutOfRangePort{urlOutOfRangePortStr.impl, 1U | 2U | (6U << 3) | (4U << 6), 7, 7, 7, 19, 26, 30, 30};
|
||||
Check(!URLProtocolHostAndPortAreEqual(&urlOutOfRangePort, &urlPort80));
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlOutOfRangePort, &urlNoPort));
|
||||
auto urlPlusPort80Str = FromUTF8Z(U8("http://example.test:+80/path"));
|
||||
URL urlPlusPort80{urlPlusPort80Str.impl, 1U | 2U | (4U << 3) | (4U << 6), 7, 7, 7, 19, 24, 28, 28};
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlPlusPort80, &urlPort80));
|
||||
Check(!URLProtocolHostAndPortAreEqual(&urlPlusPort80, &urlNoPort));
|
||||
auto urlSpacePort80Str = FromUTF8Z(U8("http://example.test: 80 /path"));
|
||||
URL urlSpacePort80{urlSpacePort80Str.impl, 1U | 2U | (5U << 3) | (4U << 6), 7, 7, 7, 19, 25, 29, 29};
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlSpacePort80, &urlPort80));
|
||||
Check(!URLProtocolHostAndPortAreEqual(&urlSpacePort80, &urlNoPort));
|
||||
auto urlTabPort80Str = FromUTF8Z(U8("http://example.test:\t80/path"));
|
||||
URL urlTabPort80{urlTabPort80Str.impl, 1U | 2U | (4U << 3) | (4U << 6), 7, 7, 7, 19, 24, 28, 28};
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlTabPort80, &urlPort80));
|
||||
auto urlNewlinePort80Str = FromUTF8Z(U8("http://example.test:\n80/path"));
|
||||
URL urlNewlinePort80{urlNewlinePort80Str.impl, 1U | 2U | (4U << 3) | (4U << 6), 7, 7, 7, 19, 24, 28, 28};
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlNewlinePort80, &urlPort80));
|
||||
auto urlReturnPort80Str = FromUTF8Z(U8("http://example.test:\r80/path"));
|
||||
URL urlReturnPort80{urlReturnPort80Str.impl, 1U | 2U | (4U << 3) | (4U << 6), 7, 7, 7, 19, 24, 28, 28};
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlReturnPort80, &urlPort80));
|
||||
auto urlFormFeedPort80Str = FromUTF8Z(U8("http://example.test:\f80/path"));
|
||||
URL urlFormFeedPort80{urlFormFeedPort80Str.impl, 1U | 2U | (4U << 3) | (4U << 6), 7, 7, 7, 19, 24, 28, 28};
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlFormFeedPort80, &urlPort80));
|
||||
auto widePlusPort = Create16(u"http://wide.test:+8080/path", 27);
|
||||
URL urlWidePlusPort{widePlusPort.impl, 1U | 2U | (6U << 3) | (4U << 6), 7, 7, 7, 16, 23, 27, 27};
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlWidePlusPort, &urlWidePort));
|
||||
auto wideSpacePort = Create16(u"http://wide.test: 8080 /path", 28);
|
||||
URL urlWideSpacePort{wideSpacePort.impl, 1U | 2U | (7U << 3) | (4U << 6), 7, 7, 7, 16, 24, 28, 28};
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlWideSpacePort, &urlWidePort));
|
||||
auto wideTabPort = Create16(u"http://wide.test:\t8080/path", 27);
|
||||
URL urlWideTabPort{wideTabPort.impl, 1U | 2U | (6U << 3) | (4U << 6), 7, 7, 7, 16, 23, 27, 27};
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlWideTabPort, &urlWidePort));
|
||||
auto wideNewlinePort = Create16(u"http://wide.test:\n8080/path", 27);
|
||||
URL urlWideNewlinePort{wideNewlinePort.impl, 1U | 2U | (6U << 3) | (4U << 6), 7, 7, 7, 16, 23, 27, 27};
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlWideNewlinePort, &urlWidePort));
|
||||
auto wideReturnPort = Create16(u"http://wide.test:\r8080/path", 27);
|
||||
URL urlWideReturnPort{wideReturnPort.impl, 1U | 2U | (6U << 3) | (4U << 6), 7, 7, 7, 16, 23, 27, 27};
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlWideReturnPort, &urlWidePort));
|
||||
auto wideFormFeedPort = Create16(u"http://wide.test:\f8080/path", 27);
|
||||
URL urlWideFormFeedPort{wideFormFeedPort.impl, 1U | 2U | (6U << 3) | (4U << 6), 7, 7, 7, 16, 23, 27, 27};
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlWideFormFeedPort, &urlWidePort));
|
||||
auto urlMinusPortStr = FromUTF8Z(U8("http://example.test:-80/path"));
|
||||
URL urlMinusPort{urlMinusPortStr.impl, 1U | 2U | (4U << 3) | (4U << 6), 7, 7, 7, 19, 24, 28, 28};
|
||||
Check(!URLProtocolHostAndPortAreEqual(&urlMinusPort, &urlPort80));
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlMinusPort, &urlNoPort));
|
||||
auto urlBarePlusPortStr = FromUTF8Z(U8("http://example.test:+/path"));
|
||||
URL urlBarePlusPort{urlBarePlusPortStr.impl, 1U | 2U | (2U << 3) | (4U << 6), 7, 7, 7, 19, 22, 26, 26};
|
||||
Check(!URLProtocolHostAndPortAreEqual(&urlBarePlusPort, &urlPort80));
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlBarePlusPort, &urlNoPort));
|
||||
auto urlPortOutOfBoundsStr = FromUTF8Z(U8("http://example.test:80"));
|
||||
URL urlPortOutOfBounds{urlPortOutOfBoundsStr.impl, 1U | 2U | (5U << 3) | (4U << 6), 7, 7, 7, 19, 24, 22, 22};
|
||||
Check(URLProtocolHostAndPortAreEqual(&urlPortOutOfBounds, &urlNoPort));
|
||||
Check(!URLProtocolHostAndPortAreEqual(&urlPortOutOfBounds, &urlPort80));
|
||||
Check(URLProtocolHostAndPortAreEqual(&absent, &absent));
|
||||
Check(!URLProtocolHostAndPortAreEqual(&url, &absent));
|
||||
Check(!URLProtocolHostAndPortAreEqual(&absent, &url));
|
||||
Throws([&] { URLProtocolHostAndPortAreEqual(nullptr, &url); });
|
||||
Throws([&] { URLProtocolHostAndPortAreEqual(&url, nullptr); });
|
||||
}
|
||||
URLInvalidate(&url);
|
||||
Check(url.impl == string.impl && url.bits == 0 && url.userStart == 0 && url.userEnd == 0);
|
||||
Check(url.passwordEnd == 0 && url.hostEnd == 0 && url.pathEnd == 0 && url.pathAfterLastSlash == 0 && url.queryEnd == 0);
|
||||
|
||||
@@ -43,7 +43,7 @@ Inventory prose retains historical counts; use the [generated progress report](h
|
||||
|
||||
- The [revision-pinned identity inventory](https://gist.github.com/kyon-eth/d44995f181e1818977bd38f0e6fc0f34/8afcb14b0707a09b6274ff7f7bcf33ef46cfe2e7) records the module, library, symbol type and NIDs for the declarations in [Export.cpp](../../../core/libs/prx/libSceNKWebKit/Export.cpp); it is a metadata summary rather than independent verification. For the 255 absent from the public catalogue, [per-image ELF records](https://gist.github.com/kyon-eth/147be8dd556e9cced2577ccbed548972/1a659ecfe819e724675991a574a1aebb5fbb48e5) include the raw qualified names, module and library identities, symbol type, values and sizes; the record file SHA-256 is `44bdc4d6073192a8f41b7be359b75364b3d41dbbd11ce649924b8cebdd4ffe51`. Image labels are not authenticated.
|
||||
|
||||
- [Additional callable exports](../../../core/libs/prx/libSceNKWebKit/Export.cpp) - 7366 of the 8703 inventory declarations listed below throw through `NotImplemented_nid_no_patch`; signatures and behavior are unverified. The later 13.60-labelled image contains all 8703; 8448 match the public 3.20 catalogue, while 255 are absent and their presence in retail 3.20 is unverified. Per-image records show the latter in a separate 3.20-labelled image, but neither image label is authenticated. Identified names match NIDs in the [public symbol database](https://github.com/zecoxao/sce_symbols/blob/2883963a0a514ba6e77407a08ef4730a65e88254/aerolib.csv) or [supplemental catalog](https://github.com/claimore22/ps5rs/blob/2304be5131221bae0dac24b9767cabffda33f747/data/nids.csv). Data exports need separate analysis.
|
||||
- [Additional callable exports](../../../core/libs/prx/libSceNKWebKit/Export.cpp) - 7365 of the 8703 inventory declarations listed below throw through `NotImplemented_nid_no_patch`; signatures and behavior are unverified. The later 13.60-labelled image contains all 8703; 8448 match the public 3.20 catalogue, while 255 are absent and their presence in retail 3.20 is unverified. Per-image records show the latter in a separate 3.20-labelled image, but neither image label is authenticated. Identified names match NIDs in the [public symbol database](https://github.com/zecoxao/sce_symbols/blob/2883963a0a514ba6e77407a08ef4730a65e88254/aerolib.csv) or [supplemental catalog](https://github.com/claimore22/ps5rs/blob/2304be5131221bae0dac24b9767cabffda33f747/data/nids.csv). Data exports need separate analysis.
|
||||
|
||||
| Name | NID |
|
||||
| --- | --- |
|
||||
@@ -1789,7 +1789,6 @@ Inventory prose retains historical counts; use the [generated progress report](h
|
||||
| `_ZN3WTF25activateSignalHandlersForENS_6SignalE` | `Pyu7Zyt6XUE` |
|
||||
| `_ZN3WTF26getAndResetAccumulatedLogsEv` | `bD3nxh6Om44` |
|
||||
| `_ZN3WTF26normalizeLineEndingsToCRLFEONS_6VectorIhLm0ENS_15CrashOnOverflowELm16ENS_10FastMallocEEE` | `oUjgPUMQcao` |
|
||||
| `_ZN3WTF27protocolHostAndPortAreEqualERKNS_3URLES2_` | `tDDzvLlQ7CE` |
|
||||
| `_ZN3WTF28encodeWithURLEscapeSequencesERKNS_6StringE` | `3DqiPW3mayI` |
|
||||
| `_ZN3WTF28normalizeLineEndingsToNativeEONS_6VectorIhLm0ENS_15CrashOnOverflowELm16ENS_10FastMallocEEE` | `KWwKlT9hDkc` |
|
||||
| `_ZN3WTF30numCodeUnitsInGraphemeClustersENS_10StringViewEj` | `3PZOiy2oZ9w` |
|
||||
|
||||
Reference in new issue
Block a user