Middleware
The Middleware API allows developers to execute code before a request is processed. Based on the incoming request, you can run custom logic, return custom streams and files, modify responses, rewrite, redirect, add headers, and more. All that before returning a response.
Using Middleware in a plain Java Application
Since 1.3.0 you can also use Middleware in plain Java applications, to obtain a reference to the API use IMiddlewareService.findServiceReference()
.
API
Resource handlers for custom schemes must be added before any browser is initialized. Schemes http and https support the addition of handlers at any moment of the program execution.
Here’s an example of how you could set up a resource handler using a bundle activator and OSGi:
import com.equo.middleware.api.IMiddlewareService;
public class ContributionComponent {
private IMiddlewareService middlewareService = IMiddlewareService.findServiceReference();
public void configureSchemes() {
middlewareService.addResourceHandler("customscheme", "", (request, headers) -> {
// Modify response headers if needed
// Build response for the given request
// Return readable InputStream containing the response data
});
...
}
...
}
In the example above we can see all that’s needed to add a resource handler to your application. A resource handler is used by the middleware implementation to know which requests to intercept, it’s defined by the parameters of the addResourceHandler method. The first parameter of the API is the scheme of the URL you’ll be intercepting requests from. The second parameter is the domain of that URL, if empty or NULL your resource handler will be used for all domains in the scheme. The third parameter is an instance of an IResponseHandler, it will be used for every request done to the resource handler.
The handler gets called for every resource that matches the scheme and domain and the InputStream is used directly. Concurrent requests that match the handler need to return different InputStream instances or the data might get corrupted. |
Scheme
You can use existing schemes such as http
and https
and you can also pass arbitrary schemes like customscheme
used in the examples in this documentation page.
Domain
You can also intercept requests to arbitrary domains, if you wish to intercept requests to all domains in the defined scheme you can pass an empty string or a null reference in this parameter.
IResponseHandler
The IResponseHandler that you pass to the resource handler will be called in every request intercepted by the middleware. It can be defined with a lambda, but it has two methods: shouldProcessRequest(Request request) : boolean
and getResponseData(Request request, Map<String, String> headers) : InputStream
. The middleware first asks the response handler if it should handle the request (by default it handles all requests), and only if it returns true we try to get the response data for the request.
Custom Streams and Files
You can read your responses directly from the filesystem or use resources that you bundled directly in your jars.
import com.equo.middleware.api.IMiddlewareService;
public class ContributionComponent {
private IMiddlewareService middlewareService = IMiddlewareService.findServiceReference();
public void configureSchemes() {
middlewareService.addResourceHandler("customscheme", "", (request, headers) -> {
File htmlResource = new File("path/to/a/resource.html");
if (htmlResource.exists()) {
return new FileInputStream(htmlResource);
}
// If the file doesn't exist fall back to a default resource contained in our classpath.
return getClass().getClassLoader().getResourceAsStream("default.html");
});
...
}
...
}
Dynamic Content
You can also create your responses on demand depending on the Request.
import com.equo.middleware.api.IMiddlewareService;
import com.equo.middleware.api.handler.IResponseConstants;
public class ContributionComponent {
private IMiddlewareService middlewareService = IMiddlewareService.findServiceReference();
public void configureSchemes() {
middlewareService.addResourceHandler("customscheme", "", (request, headers) -> {
headers.put(IResponseConstants.CONTENT_TYPE_HEADER, "text/html");
StringBuilder sb = new StringBuilder("<!doctype html><html><body>");
if (request.getUrl().endsWith("welcome")) {
sb.append("<div> An awesome welcome page! </div>");
} else {
sb.append("This page is not implemented yet.");
}
sb.append("</body></html>");
return new ByteArrayInputStream(sb.toString().getBytes());
});
...
}
...
}
Blocking requests
You can block requests by default if you want complete control over the requests done in the browser.
import com.equo.middleware.api.IMiddlewareService;
public class ContributionComponent {
private IMiddlewareService middlewareService = IMiddlewareService.findServiceReference();
public void setupMiddleware() {
middlewareService.blockByDefault(true);
middlewareService.addAllowed("domain.com", "www.domain.com", "sub.domain.com");
...
}
...
}
Request filtering
You can define request filters to pre-process outgoing requests.
import com.equo.middleware.api.IMiddlewareService;
public class ContributionComponent {
private IMiddlewareService middlewareService = IMiddlewareService.findServiceReference();
public void setupMiddlewareFilters() {
middlewareService.addRequestFilter("http", "domain.com", (mutableRequest) -> {
mutableRequest.setUrl("http://another-domain.com");
mutableRequest.setMethod("POST");
mutableRequest.getHeaderMap().put("Some-Header", "some-value");
});
...
}
...
}
Only available in version >= 1.4.0 |
Only supported in Chromium version >= 116.0.14. |
Shemes and domains
The scheme and domain need to match exactly with the requests' that will be filtered. You may also use custom schemes that were added by the Middleware.
Custom Status Code
You can set a custom status code in the response to the browser, by setting IResponseConstants.STATUS_CODE
in the headers map.
By default the response status code is 200
for valid input stream, 404
for null input stream, and 500
in case of any exception thrown.
import com.equo.middleware.api.IMiddlewareService;
import com.equo.middleware.api.handler.IResponseConstants;
public class ContributionComponent {
private IMiddlewareService middlewareService = IMiddlewareService.findServiceReference();
public void configureSchemes() {
middlewareService.addResourceHandler("customscheme", "", (request, headers) -> {
headers.put(IResponseConstants.CONTENT_TYPE_HEADER, "text/html");
StringBuilder sb = new StringBuilder("<!doctype html><html><body>");
if (request.getUrl().endsWith("welcome")) {
sb.append("<div> Your user was created succesfully! </div>");
headers.put(IResponseConstants.STATUS_CODE, "201");
} else {
sb.append("This page is not implemented yet.");
headers.put(IResponseConstants.STATUS_CODE, "404");
}
sb.append("</body></html>");
return new ByteArrayInputStream(sb.toString().getBytes());
});
...
}
...
}
Custom Charset Encoding
You have the flexibility to define the character set that will be used in the HTTP response using the following approach:
import com.equo.middleware.api.IMiddlewareService;
import com.equo.middleware.api.handler.IResponseConstants;
public class ContributionComponent {
private IMiddlewareService middlewareService = IMiddlewareService.findServiceReference();
public void configureSchemes() {
middlewareService.addResourceHandler(resourceURL.getProtocol(), resourceURL.getHost(),
(request, responseHeaders) -> {
responseHeaders.put(IResponseConstants.CONTENT_TYPE_HEADER,
"text/html; charset=UTF-8");
try {
return new FileInputStream(Paths.get(path).toFile());
} catch (Exception e) {
fail();
}
return null;
});
...
}
...
}
This allows you to customize the character encoding to suit your specific requirements. This feature enhances the versatility of the framework, empowering you to tailor the response content as per your needs.
By default the charset is the default character encoding of the JVM (can be set with the file.encoding
system property). You can use Chromium’s default by setting the property middleware.default_encoding=CHROMIUM
.
Only available in version >= 1.3.4 |
Only supported in Chromium version >= 106.0.16. |