Bug 1769332 - Generate XPCOM error code lists for Java, r=geckoview-reviewers,agi,calu

This allows us to replace a number of magic numbers in the
WebRequestError code with automatically generated constants which are
guaranteed to be kept up to date.

This build script is able to run early enough during the build step as
generated files which take a `.jinja` file as an argument are hard-coded
to be run during the pre-export phase for Android builds. As it is just
as simple python script with no other dependencies, this shouldn't
impact geckoview build performance even when using build artifacts.

Differential Revision: https://phabricator.services.mozilla.com/D146356
This commit is contained in:
Nika Layzell 2022-05-16 18:01:19 +00:00
Родитель c0ac0addf7
Коммит 7d84828a9c
7 изменённых файлов: 109 добавлений и 36 удалений

Просмотреть файл

@ -3879,10 +3879,10 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
} }
if (nsCOMPtr<nsILoadURIDelegate> loadURIDelegate = GetLoadURIDelegate()) { if (nsCOMPtr<nsILoadURIDelegate> loadURIDelegate = GetLoadURIDelegate()) {
nsresult code = isHttpsOnlyError ? NS_ERROR_HTTPS_ONLY : aError;
nsCOMPtr<nsIURI> errorPageURI; nsCOMPtr<nsIURI> errorPageURI;
rv = loadURIDelegate->HandleLoadError( rv = loadURIDelegate->HandleLoadError(aURI, code, NS_ERROR_GET_MODULE(code),
aURI, (isHttpsOnlyError ? NS_ERROR_HTTPS_ONLY : aError), getter_AddRefs(errorPageURI));
NS_ERROR_GET_MODULE(aError), getter_AddRefs(errorPageURI));
// If the docshell is going away there's no point in showing an error page. // If the docshell is going away there's no point in showing an error page.
if (NS_FAILED(rv) || mIsBeingDestroyed) { if (NS_FAILED(rv) || mIsBeingDestroyed) {
*aDisplayedErrorPage = false; *aDisplayedErrorPage = false;

Просмотреть файл

@ -354,7 +354,7 @@ class NavigationDelegateTest : BaseSessionTest() {
mainSession.forCallbacksDuringWait(object : NavigationDelegate { mainSession.forCallbacksDuringWait(object : NavigationDelegate {
@AssertCalled(count = 1) @AssertCalled(count = 1)
override fun onLoadError(session: GeckoSession, uri: String?, error: WebRequestError): GeckoResult<String>? { override fun onLoadError(session: GeckoSession, uri: String?, error: WebRequestError): GeckoResult<String>? {
assertThat("categories should match", error.category, equalTo(WebRequestError.ERROR_CATEGORY_SECURITY)) assertThat("categories should match", error.category, equalTo(WebRequestError.ERROR_CATEGORY_NETWORK))
assertThat("codes should match", error.code, equalTo(WebRequestError.ERROR_HTTPS_ONLY)) assertThat("codes should match", error.code, equalTo(WebRequestError.ERROR_HTTPS_ONLY))
return null return null
} }
@ -424,7 +424,7 @@ class NavigationDelegateTest : BaseSessionTest() {
privateSession.forCallbacksDuringWait(object : NavigationDelegate { privateSession.forCallbacksDuringWait(object : NavigationDelegate {
@AssertCalled(count = 1) @AssertCalled(count = 1)
override fun onLoadError(session: GeckoSession, uri: String?, error: WebRequestError): GeckoResult<String>? { override fun onLoadError(session: GeckoSession, uri: String?, error: WebRequestError): GeckoResult<String>? {
assertThat("categories should match", error.category, equalTo(WebRequestError.ERROR_CATEGORY_SECURITY)) assertThat("categories should match", error.category, equalTo(WebRequestError.ERROR_CATEGORY_NETWORK))
assertThat("codes should match", error.code, equalTo(WebRequestError.ERROR_HTTPS_ONLY)) assertThat("codes should match", error.code, equalTo(WebRequestError.ERROR_HTTPS_ONLY))
return null return null
} }

Просмотреть файл

@ -0,0 +1,38 @@
/* -*- Mode: Java; c-basic-offset: 2; tab-width: 4; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.util;
public final class XPCOMError {
/** Check if the error code corresponds to a failure */
public static boolean failed(long err) {
return (err & 0x80000000L) != 0;
}
/** Check if the error code corresponds to a failure */
public static boolean succeeded(long err) {
return !failed(err);
}
/** Extract the error code part of the error message */
public static int getErrorCode(long err) {
return (int)(err & 0xffffL);
}
/** Extract the error module part of the error message */
public static int getErrorModule(long err) {
return (int)(((err >> 16) - NS_ERROR_MODULE_BASE_OFFSET) & 0x1fffL);
}
public static final int NS_ERROR_MODULE_BASE_OFFSET = {{ MODULE_BASE_OFFSET }};
{% for mod, val in modules %}
public static final int NS_ERROR_MODULE_{{ mod }} = {{ val }};
{% endfor %}
{% for error, val in errors %}
public static final long {{ error }} = 0x{{ "%X" % val }}L;
{% endfor %}
}

Просмотреть файл

@ -18,6 +18,7 @@ import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.Arrays; import java.util.Arrays;
import org.mozilla.gecko.annotation.WrapForJNI; import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.util.XPCOMError;
/** /**
* WebRequestError is simply a container for error codes and categories used by {@link * WebRequestError is simply a container for error codes and categories used by {@link
@ -245,8 +246,10 @@ public class WebRequestError extends Exception {
final int geckoErrorModule, final int geckoErrorModule,
final int geckoErrorClass, final int geckoErrorClass,
final byte[] certificateBytes) { final byte[] certificateBytes) {
final int code = convertGeckoError(geckoError, geckoErrorModule, geckoErrorClass); // XXX: the geckoErrorModule argument is redundant
final int category = getErrorCategory(geckoErrorModule, code); assert geckoErrorModule == XPCOMError.getErrorModule(geckoError);
final int code = convertGeckoError(geckoError, geckoErrorClass);
final int category = getErrorCategory(XPCOMError.getErrorModule(geckoError), code);
X509Certificate certificate = null; X509Certificate certificate = null;
if (certificateBytes != null) { if (certificateBytes != null) {
try { try {
@ -266,8 +269,7 @@ public class WebRequestError extends Exception {
@WrapForJNI @WrapForJNI
/* package */ static @ErrorCategory int getErrorCategory( /* package */ static @ErrorCategory int getErrorCategory(
final long errorModule, final @Error int error) { final long errorModule, final @Error int error) {
// Match flags with XPCOM ErrorList.h. if (errorModule == XPCOMError.NS_ERROR_MODULE_SECURITY) {
if (errorModule == 21) {
return ERROR_CATEGORY_SECURITY; return ERROR_CATEGORY_SECURITY;
} }
return error & 0xF; return error & 0xF;
@ -275,87 +277,86 @@ public class WebRequestError extends Exception {
@WrapForJNI @WrapForJNI
/* package */ static @Error int convertGeckoError( /* package */ static @Error int convertGeckoError(
final long geckoError, final int geckoErrorModule, final int geckoErrorClass) { final long geckoError, final int geckoErrorClass) {
// Match flags with XPCOM ErrorList.h.
// safebrowsing // safebrowsing
if (geckoError == 0x805D001FL) { if (geckoError == XPCOMError.NS_ERROR_PHISHING_URI) {
return ERROR_SAFEBROWSING_PHISHING_URI; return ERROR_SAFEBROWSING_PHISHING_URI;
} }
if (geckoError == 0x805D001EL) { if (geckoError == XPCOMError.NS_ERROR_MALWARE_URI) {
return ERROR_SAFEBROWSING_MALWARE_URI; return ERROR_SAFEBROWSING_MALWARE_URI;
} }
if (geckoError == 0x805D0023L) { if (geckoError == XPCOMError.NS_ERROR_UNWANTED_URI) {
return ERROR_SAFEBROWSING_UNWANTED_URI; return ERROR_SAFEBROWSING_UNWANTED_URI;
} }
if (geckoError == 0x805D0026L) { if (geckoError == XPCOMError.NS_ERROR_HARMFUL_URI) {
return ERROR_SAFEBROWSING_HARMFUL_URI; return ERROR_SAFEBROWSING_HARMFUL_URI;
} }
// content // content
if (geckoError == 0x805E0010L) { if (geckoError == XPCOMError.NS_ERROR_CONTENT_CRASHED) {
return ERROR_CONTENT_CRASHED; return ERROR_CONTENT_CRASHED;
} }
if (geckoError == 0x804B001BL) { if (geckoError == XPCOMError.NS_ERROR_INVALID_CONTENT_ENCODING) {
return ERROR_INVALID_CONTENT_ENCODING; return ERROR_INVALID_CONTENT_ENCODING;
} }
if (geckoError == 0x804B004AL) { if (geckoError == XPCOMError.NS_ERROR_UNSAFE_CONTENT_TYPE) {
return ERROR_UNSAFE_CONTENT_TYPE; return ERROR_UNSAFE_CONTENT_TYPE;
} }
if (geckoError == 0x804B001DL) { if (geckoError == XPCOMError.NS_ERROR_CORRUPTED_CONTENT) {
return ERROR_CORRUPTED_CONTENT; return ERROR_CORRUPTED_CONTENT;
} }
// network // network
if (geckoError == 0x804B0014L) { if (geckoError == XPCOMError.NS_ERROR_NET_RESET) {
return ERROR_NET_RESET; return ERROR_NET_RESET;
} }
if (geckoError == 0x804B0047L) { if (geckoError == XPCOMError.NS_ERROR_NET_RESET) {
return ERROR_NET_INTERRUPT; return ERROR_NET_INTERRUPT;
} }
if (geckoError == 0x804B000EL) { if (geckoError == XPCOMError.NS_ERROR_NET_TIMEOUT) {
return ERROR_NET_TIMEOUT; return ERROR_NET_TIMEOUT;
} }
if (geckoError == 0x804B000DL) { if (geckoError == XPCOMError.NS_ERROR_CONNECTION_REFUSED) {
return ERROR_CONNECTION_REFUSED; return ERROR_CONNECTION_REFUSED;
} }
if (geckoError == 0x804B0033L) { if (geckoError == XPCOMError.NS_ERROR_UNKNOWN_SOCKET_TYPE) {
return ERROR_UNKNOWN_SOCKET_TYPE; return ERROR_UNKNOWN_SOCKET_TYPE;
} }
if (geckoError == 0x804B001FL) { if (geckoError == XPCOMError.NS_ERROR_REDIRECT_LOOP) {
return ERROR_REDIRECT_LOOP; return ERROR_REDIRECT_LOOP;
} }
if (geckoError == 0x804B0056L) { if (geckoError == XPCOMError.NS_ERROR_HTTPS_ONLY) {
return ERROR_HTTPS_ONLY; return ERROR_HTTPS_ONLY;
} }
if (geckoError == 0x804B0010L) { if (geckoError == XPCOMError.NS_ERROR_OFFLINE) {
return ERROR_OFFLINE; return ERROR_OFFLINE;
} }
if (geckoError == 0x804B0013L) { if (geckoError == XPCOMError.NS_ERROR_PORT_ACCESS_NOT_ALLOWED) {
return ERROR_PORT_BLOCKED; return ERROR_PORT_BLOCKED;
} }
// uri // uri
if (geckoError == 0x804B0012L) { if (geckoError == XPCOMError.NS_ERROR_UNKNOWN_PROTOCOL) {
return ERROR_UNKNOWN_PROTOCOL; return ERROR_UNKNOWN_PROTOCOL;
} }
if (geckoError == 0x804B001EL) { if (geckoError == XPCOMError.NS_ERROR_UNKNOWN_HOST) {
return ERROR_UNKNOWN_HOST; return ERROR_UNKNOWN_HOST;
} }
if (geckoError == 0x804B000AL) { if (geckoError == XPCOMError.NS_ERROR_MALFORMED_URI) {
return ERROR_MALFORMED_URI; return ERROR_MALFORMED_URI;
} }
if (geckoError == 0x80520012L) { if (geckoError == XPCOMError.NS_ERROR_FILE_NOT_FOUND) {
return ERROR_FILE_NOT_FOUND; return ERROR_FILE_NOT_FOUND;
} }
if (geckoError == 0x80520015L) { if (geckoError == XPCOMError.NS_ERROR_FILE_ACCESS_DENIED) {
return ERROR_FILE_ACCESS_DENIED; return ERROR_FILE_ACCESS_DENIED;
} }
// proxy // proxy
if (geckoError == 0x804B002AL) { if (geckoError == XPCOMError.NS_ERROR_UNKNOWN_PROXY_HOST) {
return ERROR_UNKNOWN_PROXY_HOST; return ERROR_UNKNOWN_PROXY_HOST;
} }
if (geckoError == 0x804B0048L) { if (geckoError == XPCOMError.NS_ERROR_PROXY_CONNECTION_REFUSED) {
return ERROR_PROXY_CONNECTION_REFUSED; return ERROR_PROXY_CONNECTION_REFUSED;
} }
if (geckoErrorModule == 21) { if (XPCOMError.getErrorModule(geckoError) == XPCOMError.NS_ERROR_MODULE_SECURITY) {
if (geckoErrorClass == 1) { if (geckoErrorClass == 1) {
return ERROR_SECURITY_SSL; return ERROR_SECURITY_SSL;
} }

Просмотреть файл

@ -18,12 +18,15 @@ exclude: true
([bug 1499635]({{bugzilla}}1499635)) ([bug 1499635]({{bugzilla}}1499635))
- Deprecated [`onLocationChange(2)`][102.3], please use [`onLocationChange(3)`][102.4]. - Deprecated [`onLocationChange(2)`][102.3], please use [`onLocationChange(3)`][102.4].
- Added [`GeckoSession.setPriorityHint`][102.5] function to set the session to either high priority or default. - Added [`GeckoSession.setPriorityHint`][102.5] function to set the session to either high priority or default.
- [`WebRequestError.ERROR_HTTPS_ONLY`][102.6] now has error category
`ERROR_CATEGORY_NETWORK` rather than `ERROR_CATEGORY_SECURITY`.
[102.1]: {{javadoc_uri}}/GeckoSession.PromptDelegate.DateTimePrompt.html#stepValue [102.1]: {{javadoc_uri}}/GeckoSession.PromptDelegate.DateTimePrompt.html#stepValue
[102.2]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date#step [102.2]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date#step
[102.3]: {{javadoc_uri}}/GeckoSession.NavigationDelegate.html#onLocationChange(org.mozilla.geckoview.GeckoSession,java.lang.String) [102.3]: {{javadoc_uri}}/GeckoSession.NavigationDelegate.html#onLocationChange(org.mozilla.geckoview.GeckoSession,java.lang.String)
[102.4]: {{javadoc_uri}}/GeckoSession.NavigationDelegate.html#onLocationChange(org.mozilla.geckoview.GeckoSession,java.lang.String,java.util.List) [102.4]: {{javadoc_uri}}/GeckoSession.NavigationDelegate.html#onLocationChange(org.mozilla.geckoview.GeckoSession,java.lang.String,java.util.List)
[102.5]: {{javadoc_uri}}/GeckoSession.html#setPriorityHint(int) [102.5]: {{javadoc_uri}}/GeckoSession.html#setPriorityHint(int)
[102.6]: {{javadoc_uri}}/WebRequestError.html#ERROR_HTTPS_ONLY
## v101 ## v101
- Added [`GeckoDisplay.surfaceChanged`][101.1] function taking new type [`GeckoDisplay.SurfaceInfo`][101.2]. - Added [`GeckoDisplay.surfaceChanged`][101.1] function taking new type [`GeckoDisplay.SurfaceInfo`][101.2].

Просмотреть файл

@ -46,6 +46,13 @@ GeneratedFile(
flags=flags, flags=flags,
) )
GeneratedFile(
("geckoview/src/main/java/org/mozilla/gecko/util/XPCOMError.java",),
script="/xpcom/base/ErrorList.py",
entry_point="gen_jinja",
inputs=["geckoview/src/main/java/org/mozilla/gecko/util/XPCOMError.jinja"],
)
CONFIGURE_SUBST_FILES += ["installer/Makefile"] CONFIGURE_SUBST_FILES += ["installer/Makefile"]
DIRS += [ DIRS += [

Просмотреть файл

@ -1372,3 +1372,27 @@ use super::nsresult;
for error, val in errors.items(): for error, val in errors.items():
output.write("pub const {}: nsresult = nsresult(0x{:X});\n".format(error, val)) output.write("pub const {}: nsresult = nsresult(0x{:X});\n".format(error, val))
def gen_jinja(output, input_filename):
# This is used to generate Java code for error lists, and can be expanded to
# other required contexts in the future if desired.
from jinja2 import Environment, FileSystemLoader, StrictUndefined
import os
# FileSystemLoader requires the path to the directory containing templates,
# not the file name of the template itself.
(path, leaf) = os.path.split(input_filename)
env = Environment(
loader=FileSystemLoader(path, encoding="utf-8"),
undefined=StrictUndefined,
)
tpl = env.get_template(leaf)
context = {
"MODULE_BASE_OFFSET": MODULE_BASE_OFFSET,
"modules": ((mod, val.num) for mod, val in modules.items()),
"errors": errors.items(),
}
tpl.stream(context).dump(output, encoding="utf-8")