Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ Detailed benchmark results, scalability measurements, and soak tests are
available in the [Dimensioning](./docs/dimensioning) and
[Soak testing](./docs/soak) documentation.

During a 5-minute performance test, the server handled **922 HTTP requests with
During a 5-minute performance test, the server handled **1118 HTTP requests with
zero errors** while heap usage remained stable throughout the test with no
observable memory growth.

Expand Down
2 changes: 1 addition & 1 deletion docs/application_development/concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[← Back](index.md)

This chapter introduces the architectural concepts and design principles that underpin PyRobusta.
This page introduces the architectural concepts and design principles that underpin PyRobusta.
Detailed information about configuration, routing, and request handling is covered in the corresponding chapters.

---
Expand Down
95 changes: 92 additions & 3 deletions docs/application_development/error_handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

[← Back](index.md)

This page is work in progress. Refer to the [main page](index.md) for available documentation.
This page describes how the server provides logging with different levels of verbosity
and handles HTTP status codes for client and server errors, including exceptions raised by applications.

---

Expand All @@ -13,19 +14,107 @@ This page is work in progress. Refer to the [main page](index.md) for available
+ [Client Errors (4xx)](#client-errors-4xx)
+ [Server Errors (5xx)](#server-errors-5xx)
+ [Exception Handling](#exception-handling)
+ [Custom Error Responses](#custom-error-responses)

---

## Logging

The server provides built-in logging constructs implemented by the `pyrobusta.utils.logging`
module. The logging module supports several log levels, controlled by the `log_level` server
configuration. `log_level` can be set to one of `error`, `warning`, `info`, or `debug`, listed in increasing
order of verbosity. Selecting a log level enables logging for that level and all less verbose levels.
For example, setting `log_level` to `info` enables `info`, `warning`, and `error` messages.

Logging methods expect a mandatory format string as the first positional argument,
followed by optional positional arguments substituted in the format string.

```python
import asyncio

from pyrobusta import application
from pyrobusta.utils import logging


async def main():
await application.run()
logging.info("%s: %s", __name__, "the application started")
while True:
await asyncio.sleep(1)

asyncio.run(main())
```

```log
29972 INFO pyrobusta.application: connected, ip=[192.168.1.101]
29983 INFO pyrobusta.server.http_server: 1 connection(s) allowed
30029 INFO pyrobusta.server.http_server: started
30041 INFO __main__: the application started
```

## Client Errors (4xx)

As described in the [Response Handling](./response.md#status-codes) guide, route
handlers can set the status codes directly with the `terminate` method of the HTTP
context. Invalid requests should be rejected by the application with a 4xx status
code. The specific status code is application-specific.

```python
@HttpEngine.route("/app/action", "POST")
def handler(http_ctx, _):
content_type = http_ctx.headers.get("content-type")
if content_type != "application/json":
http_ctx.terminate(415)
return "text/plain", "Unsupported media"
# <rest of the application route>
```

The application must use one of the following status codes supported by PyRobusta:

| Status Code | HTTP Status |
| --- | --- |
| 400 | Bad Request |
| 401 | Unauthorized |
| 403 | Forbidden |
| 404 | Not Found |
| 405 | Method Not Allowed |
| 408 | Request Timeout |
| 413 | Content Too Large |
| 415 | Unsupported Media Type |

## Server Errors (5xx)

5xx status codes indicate errors preventing the server from processing a valid request.
The following list of 5xx status codes are supported by PyRobusta:

| Status Code | HTTP Status |
| --- | --- |
| 500 | Internal Server Error |
| 503 | Service Unavailable |
| 505 | Version Not Supported |

## Exception Handling

## Custom Error Responses
Applications may raise exceptions to signal a failure. Uncaught exceptions are
automatically mapped to the 500 status code sent in the response.

Additionally, when the server catches an exception raised by the application,
it logs an error message.

```python
@HttpEngine.route("/app/action", "POST")
def handler(http_ctx, _):
# [...]
raise RuntimeError("failed to execute action")
# [...]
```

```log
2287169 INFO pyrobusta.application: already connected ip=[192.168.1.101]
2287179 INFO pyrobusta.server.http_server: 1 connection(s) allowed
2287222 INFO pyrobusta.server.http_server: started
[...]
2292844 ERROR pyrobusta.protocol.http.run: error=[failed to execute action]
```

---

Expand Down
1 change: 1 addition & 0 deletions docs/application_development/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Then continue with the remaining guides in the order listed below.
* [Static Content](static_content.md)
* [File Server API](file_server.md)
* [Authentication & Security](security.md)
* [Logging & Error Handling](error_handling.md)
* [Source Code](https://github.com/szeka9/PyRobusta)

---
Expand Down
10 changes: 4 additions & 6 deletions docs/application_development/request.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ incrementally rather than assuming the full payload is available at once.
```
from pyrobusta import application
from pyrobusta.protocol.http import HttpEngine
from pyrobusta.utils.lexpath import normalize_path

@HttpEngine.route("/app/chunks", "POST")
def upload_chunks(http_ctx, payload: bytes):
Expand All @@ -131,7 +130,7 @@ def upload_chunks(http_ctx, payload: bytes):

if payload:
# Wait for more chunks before setting response status
with open(normalize_path("/tmp/chunks.txt"), "ab") as f:
with open("/tmp/chunks.txt", "ab") as f:
f.write(payload)
return

Expand Down Expand Up @@ -173,7 +172,6 @@ from os import listdir, remove, rename, mkdir

from pyrobusta import application
from pyrobusta.protocol.http import HttpEngine
from pyrobusta.utils.lexpath import normalize_path

@HttpEngine.route("/app/parts", "POST")
def handle_parts(http_ctx, payload: tuple):
Expand All @@ -183,8 +181,8 @@ def handle_parts(http_ctx, payload: tuple):

_part_headers, part_body = payload

tmp_path = normalize_path(f"/tmp/parts.{http_ctx.id}.txt")
target_path = normalize_path(f"/www/user_data/parts.{http_ctx.id}.txt")
tmp_path = f"/tmp/parts.{http_ctx.id}.txt"
target_path = f"/www/user_data/parts.{http_ctx.id}.txt"

with open(tmp_path, "ab") as f:
f.write(part_body)
Expand All @@ -196,7 +194,7 @@ def handle_parts(http_ctx, payload: tuple):
return "text/plain", "OK"

async def main():
mkdir(normalize_path("/tmp"))
mkdir("/tmp")
await application.run()
while True:
await asyncio.sleep(1)
Expand Down
19 changes: 19 additions & 0 deletions docs/application_development/response.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,25 @@ def handler(http_ctx, _):
return "text/plain", "Resource not found"
```

The following list of status codes are supported by PyRobusta:

| Status Code | HTTP Status |
| --- | --- |
| 200 | OK |
| 201 | Created |
| 204 | No Content |
| 400 | Bad Request |
| 401 | Unauthorized |
| 403 | Forbidden |
| 404 | Not Found |
| 405 | Method Not Allowed |
| 408 | Request Timeout |
| 413 | Content Too Large |
| 415 | Unsupported Media Type |
| 500 | Internal Server Error |
| 503 | Service Unavailable |
| 505 | Version Not Supported |

## Response Headers

Response headers and response bodies can be configured through methods exposed by the HTTP context
Expand Down
2 changes: 1 addition & 1 deletion docs/application_development/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ flowchart TD

C -->|Public| Z[Process request]

C -->|Protected| D[Establish identity]
C -->|Protected| D[Read cookie data]

D --> E{Session cookie?}

Expand Down
Binary file added docs/dimensioning/esp32_c3/auth_001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/dimensioning/esp32_c3/auth_002.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/dimensioning/esp32_c3/auth_003.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/dimensioning/esp32_c3/base.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/dimensioning/esp32_c3/files_api_001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/dimensioning/esp32_c3/files_api_002.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/dimensioning/esp32_c3/files_api_003.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/dimensioning/esp32_c3/high_mem_cap_001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/dimensioning/esp32_c3/high_mem_cap_002.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/dimensioning/esp32_c3/high_mem_cap_003.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/dimensioning/esp32_c3/low_mem_cap_001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/dimensioning/esp32_c3/low_mem_cap_002.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/dimensioning/esp32_c3/low_mem_cap_003.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading