FAQ | This is a LIVE service | Changelog

Skip to content
Snippets Groups Projects
Commit 31c3ec03 authored by Dave Hart's avatar Dave Hart :pizza:
Browse files

feat: add max HTTP request size setting and increase default

Default maximum size of an HTTP request to be proxied is now 100MiB (was
1MiB), and is a setting that can be viewed in the UI and set and run time
via the `GATEWAY_MAX_REQUEST_SIZE` environment variable.

Run linting via pre-commit hook (or manually).

Update version of Auto-DevOps used in CI.
parent a58c9355
No related branches found
No related tags found
1 merge request!1Add max HTTP request size setting and increase default
Pipeline #408025 passed
include: include:
- project: 'uis/devops/continuous-delivery/ci-templates' - project: 'uis/devops/continuous-delivery/ci-templates'
file: '/auto-devops/common-pipeline.yml' file: '/auto-devops/common-pipeline.yml'
ref: v2.4.0 ref: v3.0.0
variables: variables:
DAST_DISABLED: "1" DAST_DISABLED: "1"
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
This is an _experimental_ emulator for the API Gateway This is an _experimental_ emulator for the API Gateway
The docker packaging in this repo will spin up a proxy listening on port 9000 The docker packaging in this repo will spin up a proxy listening on port 9000
which forward requests to the URL pointed to by the which forwards requests to the URL pointed to by the
`GATEWAY_PROXY_DESTINATION_URL` environment variable. `GATEWAY_PROXY_DESTINATION_URL` environment variable.
A proxy configuration UI is at port 9001. A proxy configuration UI is at port 9001.
...@@ -37,6 +37,30 @@ of the incoming request as a JSON document. ...@@ -37,6 +37,30 @@ of the incoming request as a JSON document.
The issuer for the JWT is set such that you should be able to copy the JWT passed to the backend and The issuer for the JWT is set such that you should be able to copy the JWT passed to the backend and
paste it into the https://jwt.io/ debugger and be able to validate the signature. paste it into the https://jwt.io/ debugger and be able to validate the signature.
## Backend development
Install pipx following [the instructions on their site](https://pypa.github.io/pipx/), then
install the Python dependency manager and task runner:
```bash
$ pipx install poetry
$ pipx install poethepoet
```
The development environment can then be setup:
```bash
$ poetry install
$ poe setup
```
The pre-commit code checks (linting) should be performed automatically when committing to git
(assuming `poe setup` has previously been run). To run the checks manually:
```bash
$ poe fix
```
## Frontend development ## Frontend development
You can install and start a development server as usual by running `yarn install` and `yarn start` You can install and start a development server as usual by running `yarn install` and `yarn start`
......
...@@ -47,6 +47,9 @@ class Settings(pydantic.BaseSettings): ...@@ -47,6 +47,9 @@ class Settings(pydantic.BaseSettings):
jwt_key_id: str = pydantic.Field(default_factory=token_hex) jwt_key_id: str = pydantic.Field(default_factory=token_hex)
# Max size (in bytes) of an HTTP request that can be proxied
max_request_size = 100 * (2**20)
class Config: class Config:
env_prefix = "gateway_" env_prefix = "gateway_"
...@@ -73,6 +76,7 @@ reverse_proxy = ReverseProxy( ...@@ -73,6 +76,7 @@ reverse_proxy = ReverseProxy(
application_id=settings.application_id, application_id=settings.application_id,
application_class=settings.application_class, application_class=settings.application_class,
organisation_id=settings.organisation_id, organisation_id=settings.organisation_id,
max_request_size=settings.max_request_size,
) )
...@@ -110,6 +114,7 @@ class ProxyStatus(pydantic.BaseModel): ...@@ -110,6 +114,7 @@ class ProxyStatus(pydantic.BaseModel):
application_id: str application_id: str
application_class: str application_class: str
organisation_id: str organisation_id: str
max_request_size: int
class Config: class Config:
alias_generator = camelcase alias_generator = camelcase
......
...@@ -28,6 +28,7 @@ class ReverseProxy: ...@@ -28,6 +28,7 @@ class ReverseProxy:
application_id="", application_id="",
application_class="", application_class="",
organisation_id="", organisation_id="",
max_request_size=0,
): ):
self.destination_url = destination_url self.destination_url = destination_url
self.jwt_factory = jwt_factory self.jwt_factory = jwt_factory
...@@ -41,10 +42,11 @@ class ReverseProxy: ...@@ -41,10 +42,11 @@ class ReverseProxy:
self.application_id = application_id self.application_id = application_id
self.application_class = application_class self.application_class = application_class
self.organisation_id = organisation_id self.organisation_id = organisation_id
self.max_request_size = max_request_size
async def serve(self): async def serve(self):
# Configure the aiohttp web server application for the proxy. # Configure the aiohttp web server application for the proxy.
proxy_app = aiohttp.web.Application() proxy_app = aiohttp.web.Application(client_max_size=self.max_request_size)
proxy_app.router.add_route("*", "/{path:.*}", self._handle_request) proxy_app.router.add_route("*", "/{path:.*}", self._handle_request)
proxy_runner = aiohttp.web.AppRunner(proxy_app) proxy_runner = aiohttp.web.AppRunner(proxy_app)
await proxy_runner.setup() await proxy_runner.setup()
......
...@@ -2,7 +2,11 @@ import React from "react"; ...@@ -2,7 +2,11 @@ import React from "react";
import Box from "@mui/material/Box"; import Box from "@mui/material/Box";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import Card from '@mui/material/Card';
import Grid from "@mui/material/Grid"; import Grid from "@mui/material/Grid";
import List from "@mui/material/List";
import ListItem from "@mui/material/ListItem";
import ListItemText from "@mui/material/ListItemText";
import MenuItem from "@mui/material/MenuItem"; import MenuItem from "@mui/material/MenuItem";
import InputAdornment from "@mui/material/InputAdornment"; import InputAdornment from "@mui/material/InputAdornment";
import TextField from "@mui/material/TextField"; import TextField from "@mui/material/TextField";
...@@ -24,6 +28,7 @@ interface FormState { ...@@ -24,6 +28,7 @@ interface FormState {
applicationId: string; applicationId: string;
applicationClass: "public" | "confidential"; applicationClass: "public" | "confidential";
organisationId: string; organisationId: string;
maxRequestSize: number;
} }
const INITIAL_FORM_STATE: FormState = { const INITIAL_FORM_STATE: FormState = {
...@@ -38,6 +43,7 @@ const INITIAL_FORM_STATE: FormState = { ...@@ -38,6 +43,7 @@ const INITIAL_FORM_STATE: FormState = {
applicationId: "", applicationId: "",
applicationClass: "public", applicationClass: "public",
organisationId: "", organisationId: "",
maxRequestSize: 0,
}; };
const USER_SUFFICES = { const USER_SUFFICES = {
...@@ -309,6 +315,22 @@ const ProxyForm = () => { ...@@ -309,6 +315,22 @@ const ProxyForm = () => {
error={!!errors.organisationId} error={!!errors.organisationId}
helperText={errors.organisationId} helperText={errors.organisationId}
/> />
<Typography variant="subtitle1">Read-only settings</Typography>
<Card variant="outlined">
<List dense>
<ListItem
secondaryAction={
<Typography variant="body2">
{fetchedState ? fetchedState.maxRequestSize : ""}
</Typography>
}
>
<ListItemText
primary="Maximum HTTP request size (bytes)"
/>
</ListItem>
</List>
</Card>
<Grid container spacing={2} marginTop={1}> <Grid container spacing={2} marginTop={1}>
<Grid item xs={6}> <Grid item xs={6}>
<Button <Button
......
...@@ -19,6 +19,7 @@ export interface ProxyState { ...@@ -19,6 +19,7 @@ export interface ProxyState {
applicationId: string; applicationId: string;
applicationClass: string; applicationClass: string;
organisationId: string; organisationId: string;
maxRequestSize: number;
} }
export interface ProxyConfigurationPatch { export interface ProxyConfigurationPatch {
......
...@@ -22,6 +22,16 @@ case-converter = "^1.1.0" ...@@ -22,6 +22,16 @@ case-converter = "^1.1.0"
cryptography = "^41.0.4" cryptography = "^41.0.4"
jwcrypto = "^1.5.0" jwcrypto = "^1.5.0"
[tool.poetry.group.dev.dependencies]
pre-commit = "^3.4.0"
[tool.poe.tasks.setup]
help = "Setup the application for local development"
cmd = "pre-commit install"
[tool.poe.tasks.fix]
help = "Run pre-commit checks to fix formatting errors"
cmd = "pre-commit run --all-files"
[build-system] [build-system]
requires = ["poetry-core"] requires = ["poetry-core"]
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment