bbwebservice


Namebbwebservice JSON
Version 2.2.0 PyPI version JSON
download
home_pageNone
SummaryA bare bone webserver
upload_time2025-10-16 10:49:31
maintainerNone
docs_urlNone
authorLukas
requires_python>=3.10
licenseNone
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # bbwebservice

`bbwebservice` is a lightweight Python library for building small webservers. It keeps the original simplicity but now ships with multi-endpoint support, chunked request handling, scoped routing and a bounded worker pool.

## Installation

```bash
pip install bbwebservice
```

## Usage

- import helpers:

```python
from bbwebservice.webserver import *
from bbwebservice import core
```

### 1. Register pages for HTTP `GET`
   - `@register(route=..., type=...)` registers a handler for a GET route.
   - `route` accepts either a plain string or the selector syntax `ip:port::domain:/path`. Examples:
     * `'::/status'` – matches every endpoint
     * `'127.0.0.1::/debug'` – IPv4 127.0.0.1 on any port and any domain
     * `':::example.com:/info'` – any IP/port, only domain `example.com`
     * `UrlTemplate('[::1]:8000::/v1/{slug:str}')` – IPv6 with typed placeholders
   - `type` specifies the MIME type of the response.

```python
@register(route='::/hello', type=MIME_TYPE.TEXT)
def hello():
    return 'Hello World'
```

### 2. Register pages for HTTP `POST`
   - `@post_handler` works like `@register` but the decorated function must accept an `args` parameter.

```python
@post_handler(route='::/login', type=MIME_TYPE.JSON)
def login(args):
    payload = args[STORE_VARS.POST].decode('utf-8')
    return {'status': 'ok', 'raw': payload}
```

### 3. Register handlers for other HTTP verbs
   - Additional decorators mirror `@post_handler`:
     * `@put_handler(...)`
     * `@patch_handler(...)`
     * `@delete_handler(...)`
     * `@options_handler(...)`
   - They share the same selector syntax and MIME type handling. `OPTIONS` handlers may omit the `args` parameter if you only need static responses; `HEAD` automatically reuses the corresponding `GET` handler and suppresses the body.

```python
@put_handler(route='::/items/{slug:str}', type=MIME_TYPE.JSON)
def update_item(args):
    data = json.loads(args[STORE_VARS.POST].decode('utf-8'))
    return {'slug': args[STORE_VARS.TEMPLATE_VARS]['slug'], 'data': data}

@options_handler(route='::/items/*', type=MIME_TYPE.TEXT)
def describe_items():
    return 'Allowed: GET, POST, PUT, DELETE, PATCH'
```

### 4. Redirects
   - Return a `Redirect` object to send 303/307 style responses.

```python
@register(route='::/old', type=MIME_TYPE.HTML)
def legacy():
    return Redirect('/new')
```

### 5. Partial content / streaming
   - Use `PartialContent` for ranged responses (video, downloads, etc.).

```python
@register(route='::/video', type=MIME_TYPE.MP4)
def video(_):
    return PartialContent('/content/movie.mp4', default_size=80_000)
```

### 6. Error handler
   - `@error_handler(error_code=..., type=...)` provides fallback pages.

```python
@error_handler(error_code=404, type=MIME_TYPE.HTML)
def not_found():
    return load_file('/content/404.html')
```

### 7. Handler arguments
   - Handlers that accept args can read or modify cookies, headers, query strings, etc.

```python
@register(route='::/inspect', type=MIME_TYPE.JSON)
def inspect(args):
    args['response'].header.add_header_line(
        Header_Line(Response_Header_Tag.SERVER, 'bbwebservice')
    )
    return args
```

### 8. Start the server
   - Use `core.start()` to launch all configured listeners.

```python
@register(route='::/index', type=MIME_TYPE.HTML)
def index():
    return load_file('/content/index.html')

core.start()
```

### 9. URL templates
   - Dynamic routes use `UrlTemplate` with typed placeholders.

| Supported Types | Example             |
|-----------------|--------------------|
| `str`           | `{name:str}`       |
| `int`           | `{id:int}`         |
| `float`         | `{value:float}`    |
| `bool`          | `{flag:bool}`      |
| `path`          | `{path:path}`      |

```python
@register(route=UrlTemplate('::/user/{name:str}/{age:int}'), type=MIME_TYPE.JSON)
def user(args):
    return args[STORE_VARS.TEMPLATE_VARS]
```

### 10. Selector hierarchy
   - The most specific selector wins automatically (IP > port > domain > global). Register routes knowing that concrete bindings take precedence over generic ones.

### 11. Response helpers
   - In addition to returning bytes/strings, you can respond with:
     * `Dynamic(content, mime_type)` – content with a custom MIME type
     * `PartialContent` / `Redirect`
     * `Response(...)` – convenience for setting status, headers, body in one object

### 12. Background tasks
   - `server_task(func, interval)` schedules functions (receives global state if `data` parameter present). Tasks shut down gracefully with the server.

### 13. CORS
   - Enable or disable at runtime:

```python
webserver.enable_cors(
    allow_origin="*",
    allow_methods=["GET", "POST"],
    allow_headers=["Content-Type"],
    expose_headers=["X-Total-Count"],
    allow_credentials=False,
    max_age=600,
)
```

`disable_cors()` and `get_cors_settings()` are provided as well. OPTIONS requests are answered automatically when CORS is active.

### 14. Worker pool and backpressure
   - All listeners share a bounded worker pool. If the queue is full, new connections get `503 Service Unavailable`. Per-listener `max_threads` throttle accept loops, while the global `max_threads` (see config) bounds total concurrency.

### 15. Request parsing
   - Headers are read incrementally up to `max_header_size`, bodies honour `Content-Length` or `Transfer-Encoding: chunked` (trailers are skipped). Chunked data is decoded into the `args[STORE_VARS.POST]` buffer. Oversized requests trigger 413/431 responses.

### 16. Logging
   - Logging honours scopes (`ip:port::domain`) and only formats messages when a sink is active.

```python
set_logging(LOGGING_OPTIONS.INFO, True)
log_to_file('/logs/server.log', [LOGGING_OPTIONS.ERROR, LOGGING_OPTIONS.INFO])
set_logging_callback(lambda msg, ts, lvl: print('[callback]', lvl, msg))
```

There is also `webserver.response()` for building structured responses and `log()` for manual logging with scopes.

## Server Configuration

`config/config.json` controls listeners and limits:

```json
{
  "max_threads": 100,
  "max_header_size": 16384,
  "max_body_size": 10485760,
  "server": [
    {
      "ip": "default",
      "port": 5000,
      "queue_size": 50,
      "max_threads": 25,
      "SSL": false,
      "host": "",
      "cert_path": "",
      "key_path": "",
      "https-redirect": false,
      "https-redirect-escape-paths": [],
      "update-cert-state": false
    }
  ]
}
```

* `ip`: `default` resolves at runtime, otherwise explicit IPv4/IPv6 (use `[::1]` style).
* Multiple entries in `server` bind additional sockets.
* `SSL` with `host` as list enables SNI (each entry supplies `host`, `cert_path`, `key_path`). Failed certificates are logged with full paths.
* `https-redirect` forces 301 to HTTPS except for paths listed in `https-redirect-escape-paths` (supports wildcard suffix `*`).
* `update-cert-state` watches certificate files and reloads them automatically.

Recommended ports: 5000 (local), 80 (HTTP), 443/8443 (HTTPS).

## Logging recap

```python
set_logging(LOGGING_OPTIONS.DEBUG, True)
set_logging(LOGGING_OPTIONS.TIME, True)
log_to_file()
```

Use `set_logging(scope='127.0.0.1:5000::example.com', ...)` to target specific endpoints.

## Testing

Run the integration script:

```bash
python testing/test_bbwebservice_example.py
```

It covers chunked uploads, CORS preflights, domain/IP selectors and redirects.

## License

MIT License © Lukas Walker (see `LICENSE` for details).



            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "bbwebservice",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": null,
    "author": "Lukas",
    "author_email": "lukasogwalker@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/63/a7/a21f2f7727383113af25bcbe011b6efa31b0d03cf775f9450ad980714ee2/bbwebservice-2.2.0.tar.gz",
    "platform": null,
    "description": "# bbwebservice\n\n`bbwebservice` is a lightweight Python library for building small webservers. It keeps the original simplicity but now ships with multi-endpoint support, chunked request handling, scoped routing and a bounded worker pool.\n\n## Installation\n\n```bash\npip install bbwebservice\n```\n\n## Usage\n\n- import helpers:\n\n```python\nfrom bbwebservice.webserver import *\nfrom bbwebservice import core\n```\n\n### 1. Register pages for HTTP `GET`\n   - `@register(route=..., type=...)` registers a handler for a GET route.\n   - `route` accepts either a plain string or the selector syntax `ip:port::domain:/path`. Examples:\n     * `'::/status'` \u2013 matches every endpoint\n     * `'127.0.0.1::/debug'` \u2013 IPv4 127.0.0.1 on any port and any domain\n     * `':::example.com:/info'` \u2013 any IP/port, only domain `example.com`\n     * `UrlTemplate('[::1]:8000::/v1/{slug:str}')` \u2013 IPv6 with typed placeholders\n   - `type` specifies the MIME type of the response.\n\n```python\n@register(route='::/hello', type=MIME_TYPE.TEXT)\ndef hello():\n    return 'Hello World'\n```\n\n### 2. Register pages for HTTP `POST`\n   - `@post_handler` works like `@register` but the decorated function must accept an `args` parameter.\n\n```python\n@post_handler(route='::/login', type=MIME_TYPE.JSON)\ndef login(args):\n    payload = args[STORE_VARS.POST].decode('utf-8')\n    return {'status': 'ok', 'raw': payload}\n```\n\n### 3. Register handlers for other HTTP verbs\n   - Additional decorators mirror `@post_handler`:\n     * `@put_handler(...)`\n     * `@patch_handler(...)`\n     * `@delete_handler(...)`\n     * `@options_handler(...)`\n   - They share the same selector syntax and MIME type handling. `OPTIONS` handlers may omit the `args` parameter if you only need static responses; `HEAD` automatically reuses the corresponding `GET` handler and suppresses the body.\n\n```python\n@put_handler(route='::/items/{slug:str}', type=MIME_TYPE.JSON)\ndef update_item(args):\n    data = json.loads(args[STORE_VARS.POST].decode('utf-8'))\n    return {'slug': args[STORE_VARS.TEMPLATE_VARS]['slug'], 'data': data}\n\n@options_handler(route='::/items/*', type=MIME_TYPE.TEXT)\ndef describe_items():\n    return 'Allowed: GET, POST, PUT, DELETE, PATCH'\n```\n\n### 4. Redirects\n   - Return a `Redirect` object to send 303/307 style responses.\n\n```python\n@register(route='::/old', type=MIME_TYPE.HTML)\ndef legacy():\n    return Redirect('/new')\n```\n\n### 5. Partial content / streaming\n   - Use `PartialContent` for ranged responses (video, downloads, etc.).\n\n```python\n@register(route='::/video', type=MIME_TYPE.MP4)\ndef video(_):\n    return PartialContent('/content/movie.mp4', default_size=80_000)\n```\n\n### 6. Error handler\n   - `@error_handler(error_code=..., type=...)` provides fallback pages.\n\n```python\n@error_handler(error_code=404, type=MIME_TYPE.HTML)\ndef not_found():\n    return load_file('/content/404.html')\n```\n\n### 7. Handler arguments\n   - Handlers that accept args can read or modify cookies, headers, query strings, etc.\n\n```python\n@register(route='::/inspect', type=MIME_TYPE.JSON)\ndef inspect(args):\n    args['response'].header.add_header_line(\n        Header_Line(Response_Header_Tag.SERVER, 'bbwebservice')\n    )\n    return args\n```\n\n### 8. Start the server\n   - Use `core.start()` to launch all configured listeners.\n\n```python\n@register(route='::/index', type=MIME_TYPE.HTML)\ndef index():\n    return load_file('/content/index.html')\n\ncore.start()\n```\n\n### 9. URL templates\n   - Dynamic routes use `UrlTemplate` with typed placeholders.\n\n| Supported Types | Example             |\n|-----------------|--------------------|\n| `str`           | `{name:str}`       |\n| `int`           | `{id:int}`         |\n| `float`         | `{value:float}`    |\n| `bool`          | `{flag:bool}`      |\n| `path`          | `{path:path}`      |\n\n```python\n@register(route=UrlTemplate('::/user/{name:str}/{age:int}'), type=MIME_TYPE.JSON)\ndef user(args):\n    return args[STORE_VARS.TEMPLATE_VARS]\n```\n\n### 10. Selector hierarchy\n   - The most specific selector wins automatically (IP > port > domain > global). Register routes knowing that concrete bindings take precedence over generic ones.\n\n### 11. Response helpers\n   - In addition to returning bytes/strings, you can respond with:\n     * `Dynamic(content, mime_type)` \u2013 content with a custom MIME type\n     * `PartialContent` / `Redirect`\n     * `Response(...)` \u2013 convenience for setting status, headers, body in one object\n\n### 12. Background tasks\n   - `server_task(func, interval)` schedules functions (receives global state if `data` parameter present). Tasks shut down gracefully with the server.\n\n### 13. CORS\n   - Enable or disable at runtime:\n\n```python\nwebserver.enable_cors(\n    allow_origin=\"*\",\n    allow_methods=[\"GET\", \"POST\"],\n    allow_headers=[\"Content-Type\"],\n    expose_headers=[\"X-Total-Count\"],\n    allow_credentials=False,\n    max_age=600,\n)\n```\n\n`disable_cors()` and `get_cors_settings()` are provided as well. OPTIONS requests are answered automatically when CORS is active.\n\n### 14. Worker pool and backpressure\n   - All listeners share a bounded worker pool. If the queue is full, new connections get `503 Service Unavailable`. Per-listener `max_threads` throttle accept loops, while the global `max_threads` (see config) bounds total concurrency.\n\n### 15. Request parsing\n   - Headers are read incrementally up to `max_header_size`, bodies honour `Content-Length` or `Transfer-Encoding: chunked` (trailers are skipped). Chunked data is decoded into the `args[STORE_VARS.POST]` buffer. Oversized requests trigger 413/431 responses.\n\n### 16. Logging\n   - Logging honours scopes (`ip:port::domain`) and only formats messages when a sink is active.\n\n```python\nset_logging(LOGGING_OPTIONS.INFO, True)\nlog_to_file('/logs/server.log', [LOGGING_OPTIONS.ERROR, LOGGING_OPTIONS.INFO])\nset_logging_callback(lambda msg, ts, lvl: print('[callback]', lvl, msg))\n```\n\nThere is also `webserver.response()` for building structured responses and `log()` for manual logging with scopes.\n\n## Server Configuration\n\n`config/config.json` controls listeners and limits:\n\n```json\n{\n  \"max_threads\": 100,\n  \"max_header_size\": 16384,\n  \"max_body_size\": 10485760,\n  \"server\": [\n    {\n      \"ip\": \"default\",\n      \"port\": 5000,\n      \"queue_size\": 50,\n      \"max_threads\": 25,\n      \"SSL\": false,\n      \"host\": \"\",\n      \"cert_path\": \"\",\n      \"key_path\": \"\",\n      \"https-redirect\": false,\n      \"https-redirect-escape-paths\": [],\n      \"update-cert-state\": false\n    }\n  ]\n}\n```\n\n* `ip`: `default` resolves at runtime, otherwise explicit IPv4/IPv6 (use `[::1]` style).\n* Multiple entries in `server` bind additional sockets.\n* `SSL` with `host` as list enables SNI (each entry supplies `host`, `cert_path`, `key_path`). Failed certificates are logged with full paths.\n* `https-redirect` forces 301 to HTTPS except for paths listed in `https-redirect-escape-paths` (supports wildcard suffix `*`).\n* `update-cert-state` watches certificate files and reloads them automatically.\n\nRecommended ports: 5000 (local), 80 (HTTP), 443/8443 (HTTPS).\n\n## Logging recap\n\n```python\nset_logging(LOGGING_OPTIONS.DEBUG, True)\nset_logging(LOGGING_OPTIONS.TIME, True)\nlog_to_file()\n```\n\nUse `set_logging(scope='127.0.0.1:5000::example.com', ...)` to target specific endpoints.\n\n## Testing\n\nRun the integration script:\n\n```bash\npython testing/test_bbwebservice_example.py\n```\n\nIt covers chunked uploads, CORS preflights, domain/IP selectors and redirects.\n\n## License\n\nMIT License \u00a9 Lukas Walker (see `LICENSE` for details).\n\n\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "A bare bone webserver",
    "version": "2.2.0",
    "project_urls": null,
    "split_keywords": [],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "0e02ba5a745bce05edf19541dce009b84db82967d02ad711ae829c897be17640",
                "md5": "dddc76dc5d87cf97379237230dfb8cc1",
                "sha256": "083ab3c9e13c69c5bf02e5bcad12a56d60d422536da1cf09752f751429fe1b3c"
            },
            "downloads": -1,
            "filename": "bbwebservice-2.2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "dddc76dc5d87cf97379237230dfb8cc1",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 38950,
            "upload_time": "2025-10-16T10:49:30",
            "upload_time_iso_8601": "2025-10-16T10:49:30.319731Z",
            "url": "https://files.pythonhosted.org/packages/0e/02/ba5a745bce05edf19541dce009b84db82967d02ad711ae829c897be17640/bbwebservice-2.2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "63a7a21f2f7727383113af25bcbe011b6efa31b0d03cf775f9450ad980714ee2",
                "md5": "072603eb63d0cf1ec43b11ffade22bf9",
                "sha256": "7b4b050ffce76b8a9e1a83182c757e24eff610f31385f5b2ab384570a0973da8"
            },
            "downloads": -1,
            "filename": "bbwebservice-2.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "072603eb63d0cf1ec43b11ffade22bf9",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 39179,
            "upload_time": "2025-10-16T10:49:31",
            "upload_time_iso_8601": "2025-10-16T10:49:31.762014Z",
            "url": "https://files.pythonhosted.org/packages/63/a7/a21f2f7727383113af25bcbe011b6efa31b0d03cf775f9450ad980714ee2/bbwebservice-2.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-16 10:49:31",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "bbwebservice"
}
        
Elapsed time: 0.95583s