mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
feat(upload): increase document upload size limits to 50MB across the application
This commit is contained in:
86
docs/uploads.md
Normal file
86
docs/uploads.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# Upload size limits
|
||||
|
||||
A document upload passes through four independent ceilings. The **smallest one
|
||||
wins**, so raising a limit in application code changes nothing while a lower
|
||||
limit sits in front of it.
|
||||
|
||||
| # | Layer | Limit | Where it lives |
|
||||
| - | ----- | ----- | -------------- |
|
||||
| 1 | Reverse proxy (`client_max_body_size`) | **50m** | nginx config on the API host — **not in this repo** for deployed environments |
|
||||
| 2 | Express JSON/urlencoded body | `JSON_BODY_LIMIT` = 80mb | `apps/edr-freight-api/src/main.ts` |
|
||||
| 3 | Multer multipart (`fileSize`) | `DOCUMENT_UPLOAD_MAX_BYTES` = 50MB | `apps/edr-freight-api/src/common/document-upload.options.ts` |
|
||||
| 4 | Per-field portal gate (`max_size_mb`) | 50 | `freight.file_upload_fields`, seeded by `file-upload-settings.seeder.ts` |
|
||||
|
||||
Layer 4 is the only one the customer sees before uploading — `SmartFileInput`
|
||||
blocks the file client-side with "File size exceeds the limit of NMB". Layers
|
||||
1–3 produce a failed request after the fact.
|
||||
|
||||
## The nginx layer is the one that bites
|
||||
|
||||
nginx defaults `client_max_body_size` to **1m** and answers anything larger with
|
||||
its own HTML error page:
|
||||
|
||||
```
|
||||
HTTP/1.1 413 Request Entity Too Large
|
||||
Server: nginx
|
||||
Content-Type: text/html
|
||||
```
|
||||
|
||||
Two tells that a 413 came from the proxy rather than the API:
|
||||
|
||||
- the body is nginx's HTML page, not the API's JSON envelope, and
|
||||
- `curl -w '%{size_upload}'` reports **0** — nginx rejects on the `Content-Length`
|
||||
header, so the body is never transmitted.
|
||||
|
||||
This is also why the failure looks like a CORS error in the browser: nginx's
|
||||
error response carries no `Access-Control-Allow-Origin` header.
|
||||
|
||||
### Applying it
|
||||
|
||||
Add to the `server` (or `location`) block fronting the API and reload:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
server_name edrfreightapi-staging.edrsc.com;
|
||||
|
||||
client_max_body_size 50m;
|
||||
|
||||
location / {
|
||||
proxy_pass http://freight-api:3001;
|
||||
# Large uploads stream for a while; the default 60s read timeout can
|
||||
# cut off a slow client mid-body.
|
||||
proxy_read_timeout 300s;
|
||||
proxy_request_buffering off;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
nginx -t && nginx -s reload # -t first: a bad config that reloads takes the site down
|
||||
```
|
||||
|
||||
On Kubernetes ingress-nginx this is an annotation on the Ingress instead:
|
||||
|
||||
```yaml
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: 50m
|
||||
```
|
||||
|
||||
Note that `client_max_body_size 0` disables the check entirely — do not use it.
|
||||
An unbounded body is a denial-of-service vector, and layer 3 buffers uploads in
|
||||
memory.
|
||||
|
||||
## Verifying end to end
|
||||
|
||||
512KB should pass the proxy and reach the API; 50MB should too. A `401` here is
|
||||
a *success* for this purpose — it means the request got past nginx to the API's
|
||||
auth layer.
|
||||
|
||||
```bash
|
||||
head -c 52428800 /dev/urandom > big.bin
|
||||
curl -s -o /dev/null -w 'HTTP %{http_code} uploaded %{size_upload}\n' \
|
||||
-X POST "https://edrfreightapi-staging.edrsc.com/api/companies/<id>/documents" \
|
||||
-F "test=@big.bin"
|
||||
```
|
||||
|
||||
- `413` with `uploaded 0` → the proxy is still capped; layer 1 was not applied.
|
||||
- `401`/`200` with the full byte count → the body made it through.
|
||||
Reference in New Issue
Block a user