mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-08 08:48:39 +09:00
DevTools - network - security (improvements)
https://github.com/MoonchildProductions/moebius/pull/113 https://github.com/MoonchildProductions/moebius/pull/118 https://github.com/MoonchildProductions/moebius/pull/127
This commit is contained in:
parent
f92a4b1c8a
commit
38e95f9e35
13 changed files with 258 additions and 15 deletions
|
|
@ -617,6 +617,37 @@ netmonitor.security.protocolVersion=Protocol version:
|
|||
# in the security tab describing the cipher suite used to secure this connection.
|
||||
netmonitor.security.cipherSuite=Cipher suite:
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.security.keaGroup): This is the label displayed
|
||||
# in the security tab describing the key exchange group suite used to secure
|
||||
# this connection.
|
||||
netmonitor.security.keaGroup=Key Exchange Group:
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.security.keaGroup.none): This is the label
|
||||
# displayed in the security tab describing the case when no group was used.
|
||||
netmonitor.security.keaGroup.none=none
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.security.keaGroup.custom): This is the label
|
||||
# displayed in the security tab describing the case when a custom group was used.
|
||||
netmonitor.security.keaGroup.custom=custom
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.security.keaGroup.unknown): This is the value
|
||||
# displayed in the security tab describing an unknown group.
|
||||
netmonitor.security.keaGroup.unknown=unknown group
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.security.signatureScheme): This is the label
|
||||
# displayed in the security tab describing the signature scheme used by for
|
||||
# the server certificate in this connection.
|
||||
netmonitor.security.signatureScheme=Signature Scheme:
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.security.signatureScheme.none): This is the
|
||||
# label displayed in the security tab describing the case when no signature
|
||||
# was used.
|
||||
netmonitor.security.signatureScheme.none=none
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.security.signatureScheme.unknown): This is the
|
||||
# value displayed in the security tab describing an unknown signature scheme.
|
||||
netmonitor.security.signatureScheme.unknown=unknown signature scheme
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.security.hsts): This is the label displayed
|
||||
# in the security tab describing the usage of HTTP Strict Transport Security.
|
||||
netmonitor.security.hsts=HTTP Strict Transport Security:
|
||||
|
|
|
|||
|
|
@ -1124,6 +1124,8 @@ NetworkDetailsView.prototype = {
|
|||
setValue("#security-protocol-version-value",
|
||||
securityInfo.protocolVersion);
|
||||
setValue("#security-ciphersuite-value", securityInfo.cipherSuite);
|
||||
setValue("#security-keagroup-value", securityInfo.keaGroupName);
|
||||
setValue("#security-signaturescheme-value", securityInfo.signatureSchemeName);
|
||||
|
||||
// Host header
|
||||
let domain = getUriHostPort(url);
|
||||
|
|
|
|||
|
|
@ -550,6 +550,26 @@
|
|||
id="security-warning-cipher"
|
||||
data-localization="tooltiptext=netmonitor.security.warning.cipher" />
|
||||
</hbox>
|
||||
<hbox id="security-keagroup"
|
||||
class="tabpanel-summary-container"
|
||||
align="baseline">
|
||||
<label class="plain tabpanel-summary-label"
|
||||
data-localization="content=netmonitor.security.keaGroup"/>
|
||||
<textbox id="security-keagroup-value"
|
||||
class="plain tabpanel-summary-value devtools-monospace cropped-textbox"
|
||||
flex="1"
|
||||
readonly="true"/>
|
||||
</hbox>
|
||||
<hbox id="security-signaturescheme"
|
||||
class="tabpanel-summary-container"
|
||||
align="baseline">
|
||||
<label class="plain tabpanel-summary-label"
|
||||
data-localization="content=netmonitor.security.signatureScheme"/>
|
||||
<textbox id="security-signaturescheme-value"
|
||||
class="plain tabpanel-summary-value devtools-monospace cropped-textbox"
|
||||
flex="1"
|
||||
readonly="true"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
<vbox id="security-info-domain"
|
||||
|
|
|
|||
|
|
@ -66,6 +66,10 @@ add_task(function* () {
|
|||
checkLabel("#security-cert-issuer-o", "Mozilla Testing");
|
||||
checkLabel("#security-cert-issuer-ou", "<Not Available>");
|
||||
|
||||
// These two values can change. So only check they're not empty.
|
||||
checkLabelNotEmpty("#security-keagroup-value");
|
||||
checkLabelNotEmpty("#security-signaturescheme-value");
|
||||
|
||||
// Locale sensitive and varies between timezones. Cant't compare equality or
|
||||
// the test fails depending on which part of the world the test is executed.
|
||||
checkLabelNotEmpty("#security-cert-validity-begins");
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ const {components, Cc, Ci} = require("chrome");
|
|||
loader.lazyImporter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm");
|
||||
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
const Services = require("Services");
|
||||
const { LocalizationHelper } = require("devtools/shared/l10n");
|
||||
const L10N = new LocalizationHelper("devtools/client/locales/netmonitor.properties");
|
||||
|
||||
// The cache used in the `nsIURL` function.
|
||||
const gNSURLStore = new Map();
|
||||
|
|
@ -620,6 +622,31 @@ var NetworkHelper = {
|
|||
// Cipher suite.
|
||||
info.cipherSuite = SSLStatus.cipherName;
|
||||
|
||||
// Key exchange group name.
|
||||
info.keaGroupName = SSLStatus.keaGroupName;
|
||||
// Localise two special values.
|
||||
if (info.keaGroupName == "none") {
|
||||
info.keaGroupName = L10N.getStr("netmonitor.security.keaGroup.none");
|
||||
}
|
||||
if (info.keaGroupName == "custom") {
|
||||
info.keaGroupName = L10N.getStr("netmonitor.security.keaGroup.custom");
|
||||
}
|
||||
if (info.keaGroupName == "unknown group") {
|
||||
info.keaGroupName = L10N.getStr("netmonitor.security.keaGroup.unknown");
|
||||
}
|
||||
|
||||
// Certificate signature scheme.
|
||||
info.signatureSchemeName = SSLStatus.signatureSchemeName;
|
||||
// Localise two special values.
|
||||
if (info.signatureSchemeName == "none") {
|
||||
info.signatureSchemeName =
|
||||
L10N.getStr("netmonitor.security.signatureScheme.none");
|
||||
}
|
||||
if (info.signatureSchemeName == "unknown signature") {
|
||||
info.signatureSchemeName =
|
||||
L10N.getStr("netmonitor.security.signatureScheme.unknown");
|
||||
}
|
||||
|
||||
// Protocol version.
|
||||
info.protocolVersion =
|
||||
this.formatSecurityProtocol(SSLStatus.protocolVersion);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@ interface nsISSLStatus : nsISupports {
|
|||
readonly attribute ACString cipherName;
|
||||
readonly attribute unsigned long keyLength;
|
||||
readonly attribute unsigned long secretKeyLength;
|
||||
[must_use]
|
||||
readonly attribute ACString keaGroupName;
|
||||
[must_use]
|
||||
readonly attribute ACString signatureSchemeName;
|
||||
|
||||
const short SSL_VERSION_3 = 0;
|
||||
const short TLS_VERSION_1 = 1;
|
||||
|
|
|
|||
|
|
@ -848,6 +848,99 @@ PK11PasswordPrompt(PK11SlotInfo* slot, PRBool /*retry*/, void* arg)
|
|||
return runnable->mResult;
|
||||
}
|
||||
|
||||
static nsCString
|
||||
getKeaGroupName(uint32_t aKeaGroup)
|
||||
{
|
||||
nsCString groupName;
|
||||
switch (aKeaGroup) {
|
||||
case ssl_grp_ec_secp256r1:
|
||||
groupName = NS_LITERAL_CSTRING("P256");
|
||||
break;
|
||||
case ssl_grp_ec_secp384r1:
|
||||
groupName = NS_LITERAL_CSTRING("P384");
|
||||
break;
|
||||
case ssl_grp_ec_secp521r1:
|
||||
groupName = NS_LITERAL_CSTRING("P521");
|
||||
break;
|
||||
case ssl_grp_ec_curve25519:
|
||||
groupName = NS_LITERAL_CSTRING("x25519");
|
||||
break;
|
||||
case ssl_grp_ffdhe_2048:
|
||||
groupName = NS_LITERAL_CSTRING("FF 2048");
|
||||
break;
|
||||
case ssl_grp_ffdhe_3072:
|
||||
groupName = NS_LITERAL_CSTRING("FF 3072");
|
||||
break;
|
||||
case ssl_grp_none:
|
||||
groupName = NS_LITERAL_CSTRING("none");
|
||||
break;
|
||||
case ssl_grp_ffdhe_custom:
|
||||
groupName = NS_LITERAL_CSTRING("custom");
|
||||
break;
|
||||
// All other groups are not enabled in Firefox. See namedGroups in
|
||||
// nsNSSIOLayer.cpp.
|
||||
default:
|
||||
// This really shouldn't happen!
|
||||
MOZ_ASSERT_UNREACHABLE("Invalid key exchange group.");
|
||||
groupName = NS_LITERAL_CSTRING("unknown group");
|
||||
}
|
||||
return groupName;
|
||||
}
|
||||
|
||||
static nsCString
|
||||
getSignatureName(uint32_t aSignatureScheme)
|
||||
{
|
||||
nsCString signatureName;
|
||||
switch (aSignatureScheme) {
|
||||
case ssl_sig_none:
|
||||
signatureName = NS_LITERAL_CSTRING("none");
|
||||
break;
|
||||
case ssl_sig_rsa_pkcs1_sha1:
|
||||
signatureName = NS_LITERAL_CSTRING("RSA-PKCS1-SHA1");
|
||||
break;
|
||||
case ssl_sig_rsa_pkcs1_sha256:
|
||||
signatureName = NS_LITERAL_CSTRING("RSA-PKCS1-SHA256");
|
||||
break;
|
||||
case ssl_sig_rsa_pkcs1_sha384:
|
||||
signatureName = NS_LITERAL_CSTRING("RSA-PKCS1-SHA384");
|
||||
break;
|
||||
case ssl_sig_rsa_pkcs1_sha512:
|
||||
signatureName = NS_LITERAL_CSTRING("RSA-PKCS1-SHA512");
|
||||
break;
|
||||
case ssl_sig_ecdsa_secp256r1_sha256:
|
||||
signatureName = NS_LITERAL_CSTRING("ECDSA-P256-SHA256");
|
||||
break;
|
||||
case ssl_sig_ecdsa_secp384r1_sha384:
|
||||
signatureName = NS_LITERAL_CSTRING("ECDSA-P384-SHA384");
|
||||
break;
|
||||
case ssl_sig_ecdsa_secp521r1_sha512:
|
||||
signatureName = NS_LITERAL_CSTRING("ECDSA-P521-SHA512");
|
||||
break;
|
||||
case ssl_sig_rsa_pss_sha256:
|
||||
signatureName = NS_LITERAL_CSTRING("RSA-PSS-SHA256");
|
||||
break;
|
||||
case ssl_sig_rsa_pss_sha384:
|
||||
signatureName = NS_LITERAL_CSTRING("RSA-PSS-SHA384");
|
||||
break;
|
||||
case ssl_sig_rsa_pss_sha512:
|
||||
signatureName = NS_LITERAL_CSTRING("RSA-PSS-SHA512");
|
||||
break;
|
||||
case ssl_sig_ecdsa_sha1:
|
||||
signatureName = NS_LITERAL_CSTRING("ECDSA-SHA1");
|
||||
break;
|
||||
case ssl_sig_rsa_pkcs1_sha1md5:
|
||||
signatureName = NS_LITERAL_CSTRING("RSA-PKCS1-SHA1MD5");
|
||||
break;
|
||||
// All other groups are not enabled in Firefox. See sEnabledSignatureSchemes
|
||||
// in nsNSSIOLayer.cpp.
|
||||
default:
|
||||
// This really shouldn't happen!
|
||||
MOZ_ASSERT_UNREACHABLE("Invalid signature scheme.");
|
||||
signatureName = NS_LITERAL_CSTRING("unknown signature");
|
||||
}
|
||||
return signatureName;
|
||||
}
|
||||
|
||||
// call with shutdown prevention lock held
|
||||
static void
|
||||
PreliminaryHandshakeDone(PRFileDesc* fd)
|
||||
|
|
@ -874,6 +967,9 @@ PreliminaryHandshakeDone(PRFileDesc* fd)
|
|||
status->mHaveCipherSuiteAndProtocol = true;
|
||||
status->mCipherSuite = channelInfo.cipherSuite;
|
||||
status->mProtocolVersion = channelInfo.protocolVersion & 0xFF;
|
||||
status->mKeaGroup.Assign(getKeaGroupName(channelInfo.keaGroup));
|
||||
status->mSignatureSchemeName.Assign(
|
||||
getSignatureName(channelInfo.signatureScheme));
|
||||
infoObject->SetKEAUsed(channelInfo.keaType);
|
||||
infoObject->SetKEAKeyBits(channelInfo.keaKeyBits);
|
||||
infoObject->SetMACAlgorithmUsed(cipherInfo.macAlgorithm);
|
||||
|
|
|
|||
|
|
@ -2492,6 +2492,8 @@ loser:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Please change getSignatureName in nsNSSCallbacks.cpp when changing the list
|
||||
// here.
|
||||
static const SSLSignatureScheme sEnabledSignatureSchemes[] = {
|
||||
ssl_sig_ecdsa_secp256r1_sha256,
|
||||
ssl_sig_ecdsa_secp384r1_sha384,
|
||||
|
|
@ -2569,6 +2571,8 @@ nsSSLIOLayerSetOptions(PRFileDesc* fd, bool forSTARTTLS,
|
|||
}
|
||||
|
||||
// Include a modest set of named groups.
|
||||
// Please change getKeaGroupName in nsNSSCallbacks.cpp when changing the list
|
||||
// here.
|
||||
const SSLNamedGroup namedGroups[] = {
|
||||
ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
|
||||
ssl_grp_ec_secp521r1, ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072
|
||||
|
|
|
|||
|
|
@ -76,6 +76,28 @@ nsSSLStatus::GetCipherName(nsACString& aCipherName)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSSLStatus::GetKeaGroupName(nsACString& aKeaGroup)
|
||||
{
|
||||
if (!mHaveCipherSuiteAndProtocol) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
aKeaGroup.Assign(mKeaGroup);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSSLStatus::GetSignatureSchemeName(nsACString& aSignatureScheme)
|
||||
{
|
||||
if (!mHaveCipherSuiteAndProtocol) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
aSignatureScheme.Assign(mSignatureSchemeName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSSLStatus::GetProtocolVersion(uint16_t* aProtocolVersion)
|
||||
{
|
||||
|
|
@ -194,6 +216,15 @@ nsSSLStatus::Read(nsIObjectInputStream* aStream)
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Added in version 2 (see bug 1304923).
|
||||
if (streamFormatVersion >= 2) {
|
||||
rv = aStream->ReadCString(mKeaGroup);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aStream->ReadCString(mSignatureSchemeName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
@ -201,7 +232,7 @@ NS_IMETHODIMP
|
|||
nsSSLStatus::Write(nsIObjectOutputStream* aStream)
|
||||
{
|
||||
// The current version of the binary stream format.
|
||||
const uint8_t STREAM_FORMAT_VERSION = 1;
|
||||
const uint8_t STREAM_FORMAT_VERSION = 2;
|
||||
|
||||
nsresult rv = aStream->WriteCompoundObject(mServerCert,
|
||||
NS_GET_IID(nsIX509Cert),
|
||||
|
|
@ -237,6 +268,13 @@ nsSSLStatus::Write(nsIObjectOutputStream* aStream)
|
|||
rv = aStream->Write16(mCertificateTransparencyStatus);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Added in version 2.
|
||||
rv = aStream->WriteStringZ(mKeaGroup.get());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aStream->WriteStringZ(mSignatureSchemeName.get());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
@ -300,6 +338,8 @@ nsSSLStatus::nsSSLStatus()
|
|||
, mProtocolVersion(0)
|
||||
, mCertificateTransparencyStatus(nsISSLStatus::
|
||||
CERTIFICATE_TRANSPARENCY_NOT_APPLICABLE)
|
||||
, mKeaGroup()
|
||||
, mSignatureSchemeName()
|
||||
, mIsDomainMismatch(false)
|
||||
, mIsNotValidAtThisTime(false)
|
||||
, mIsUntrusted(false)
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ public:
|
|||
uint16_t mCipherSuite;
|
||||
uint16_t mProtocolVersion;
|
||||
uint16_t mCertificateTransparencyStatus;
|
||||
nsCString mKeaGroup;
|
||||
nsCString mSignatureSchemeName;
|
||||
|
||||
bool mIsDomainMismatch;
|
||||
bool mIsNotValidAtThisTime;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,5 @@
|
|||
[idlharness.html]
|
||||
type: testharness
|
||||
[PerformanceTiming interface: attribute secureConnectionStart]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceTiming interface: window.performance.timing must inherit property "secureConnectionStart" with the proper type (10)]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: existence and properties of interface object]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
|||
|
|
@ -1502,12 +1502,24 @@
|
|||
"n_buckets": 50,
|
||||
"description": "HTTP page: DNS lookup time (ms)"
|
||||
},
|
||||
"HTTP_PAGE_TCP_CONNECTION": {
|
||||
"HTTP_PAGE_TLS_HANDSHAKE": {
|
||||
"alert_emails": ["necko@mozilla.com", "pmcmanus@mozilla.com"],
|
||||
"bug_numbers": [772589],
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": 30000,
|
||||
"n_buckets": 50,
|
||||
"description": "HTTP page: TCP connection setup (ms)"
|
||||
"description": "HTTP page channel: After TCP SYN to Ready for HTTP (ms)"
|
||||
|
||||
},
|
||||
"HTTP_PAGE_TCP_CONNECTION_2": {
|
||||
"alert_emails": ["necko@mozilla.com", "pmcmanus@mozilla.com"],
|
||||
"bug_numbers": [772589],
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": 30000,
|
||||
"n_buckets": 50,
|
||||
"description": "HTTP page channel: TCP SYN to Ready for HTTP (ms)"
|
||||
},
|
||||
"HTTP_PAGE_OPEN_TO_FIRST_SENT": {
|
||||
"expires_in_version": "never",
|
||||
|
|
@ -1621,12 +1633,23 @@
|
|||
"n_buckets": 50,
|
||||
"description": "HTTP subitem: DNS lookup time (ms)"
|
||||
},
|
||||
"HTTP_SUB_TCP_CONNECTION": {
|
||||
"HTTP_SUB_TLS_HANDSHAKE": {
|
||||
"alert_emails": ["necko@mozilla.com", "pmcmanus@mozilla.com"],
|
||||
"bug_numbers": [772589],
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": 30000,
|
||||
"n_buckets": 50,
|
||||
"description": "HTTP subitem: TCP connection setup (ms)"
|
||||
"description": "HTTP subitem channel: After TCP SYN to Ready for HTTP (ms)"
|
||||
},
|
||||
"HTTP_SUB_TCP_CONNECTION_2": {
|
||||
"alert_emails": ["necko@mozilla.com", "pmcmanus@mozilla.com"],
|
||||
"bug_numbers": [772589],
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": 30000,
|
||||
"n_buckets": 50,
|
||||
"description": "HTTP subitem channel: TCP SYN to Ready for HTTP (ms)"
|
||||
},
|
||||
"HTTP_SUB_OPEN_TO_FIRST_SENT": {
|
||||
"expires_in_version": "never",
|
||||
|
|
|
|||
|
|
@ -333,7 +333,6 @@
|
|||
"HTTP_PAGE_OPEN_TO_FIRST_RECEIVED",
|
||||
"HTTP_PAGE_OPEN_TO_FIRST_SENT",
|
||||
"HTTP_PAGE_REVALIDATION",
|
||||
"HTTP_PAGE_TCP_CONNECTION",
|
||||
"HTTP_PROXY_TYPE",
|
||||
"HTTP_REQUEST_PER_CONN",
|
||||
"HTTP_REQUEST_PER_PAGE",
|
||||
|
|
@ -359,7 +358,6 @@
|
|||
"HTTP_SUB_OPEN_TO_FIRST_RECEIVED",
|
||||
"HTTP_SUB_OPEN_TO_FIRST_SENT",
|
||||
"HTTP_SUB_REVALIDATION",
|
||||
"HTTP_SUB_TCP_CONNECTION",
|
||||
"HTTP_TRANSACTION_IS_SSL",
|
||||
"HTTP_TRANSACTION_USE_ALTSVC",
|
||||
"HTTP_TRANSACTION_USE_ALTSVC_OE",
|
||||
|
|
@ -1167,7 +1165,6 @@
|
|||
"HTTP_PAGE_OPEN_TO_FIRST_RECEIVED",
|
||||
"HTTP_PAGE_OPEN_TO_FIRST_SENT",
|
||||
"HTTP_PAGE_REVALIDATION",
|
||||
"HTTP_PAGE_TCP_CONNECTION",
|
||||
"HTTP_PROXY_TYPE",
|
||||
"HTTP_REQUEST_PER_CONN",
|
||||
"HTTP_REQUEST_PER_PAGE",
|
||||
|
|
@ -1193,7 +1190,6 @@
|
|||
"HTTP_SUB_OPEN_TO_FIRST_RECEIVED",
|
||||
"HTTP_SUB_OPEN_TO_FIRST_SENT",
|
||||
"HTTP_SUB_REVALIDATION",
|
||||
"HTTP_SUB_TCP_CONNECTION",
|
||||
"HTTP_TRANSACTION_IS_SSL",
|
||||
"HTTP_TRANSACTION_USE_ALTSVC",
|
||||
"HTTP_TRANSACTION_USE_ALTSVC_OE",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue