Metadata-Version: 2.4
Name: simplehttp-lite
Version: 0.1.3
Summary: A tiny and simple dependency-free HTTP server toolkit
Author-email: Reed Gabriel <reedy4687@gmail.com>
License: MIT
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# simplehttp-lite

A minimal, dependency-free HTTP server library built on Python's `socket` module. Define pages and files, then run a blocking server loop that serves them over plain HTTP.

## Installation
# Important!!
# Install via pip install simplehttp-lite but import via simplehttp
Copy the module into your project as `simplehttp-lite.py` via pip install simplehttp-lite, then import it directly:

```python
import simplehttp
```

No external dependencies — only the Python standard library (`socket`) is required.

## Quick Start

```python
import simplehttp

simplehttp.addpage("/dog.html", "<img src=\"/dog.png\">", "text/html")
simplehttp.addfile("/dog.png", "dog.png", "image/png")

simplehttp.runserver(host="0.0.0.0", port=8080)
```

Then visit `http://localhost:8080/dog.html` in a browser.

## API Reference

### `addpage(endpoint, content, contenttype)`

Registers an in-memory page to be served at a given endpoint.

| Argument | Type | Description |
|---|---|---|
| `endpoint` | `str` | The URL path to serve this content at, e.g. `"/index.html"`. |
| `content` | `str` or `bytes` | The body to return when this endpoint is requested. |
| `contenttype` | `str` | The `Content-Type` header value, e.g. `"text/html"`. |

**Returns:** `None`

```python
simplehttp.addpage("/hello", "<h1>Hi there</h1>", "text/html")
```

---

### `addfile(endpoint, filepath, contenttype)`

Reads a file from disk and registers it to be served at a given endpoint. The file is read once, at registration time, and kept in memory — changes to the file on disk afterward won't be reflected without re-registering.

| Argument | Type | Description |
|---|---|---|
| `endpoint` | `str` | The URL path to serve this file at. |
| `filepath` | `str` | Local path to the file to read. |
| `contenttype` | `str` | The `Content-Type` header value, e.g. `"image/png"`. |

**Returns:** `None`

```python
simplehttp.addfile("/dog.png", "assets/dog.png", "image/png")
```

---

### `response(status="OK", statuscode=200, contenttype="text/plain", length=None, content="Yo its gator G!")`

Builds a raw HTTP response as a list of byte chunks, ready to send over a socket. Used internally by `runserver`, but can be called directly if you're building a custom handler.

| Argument | Type | Default | Description |
|---|---|---|---|
| `status` | `str` | `"OK"` | The status text, e.g. `"OK"`, `"NOT FOUND"`. |
| `statuscode` | `int` | `200` | The HTTP status code. |
| `contenttype` | `str` | `"text/plain"` | The `Content-Type` header value. |
| `length` | `int` or `None` | `None` | Content length. If `None`, computed automatically from `content`. |
| `content` | `str` or `bytes` | `"Yo its gator G!"` | The response body. |

**Returns:** `list[bytes]` — a list of encoded chunks (status line, headers, blank line, body) meant to be sent in order.

```python
for chunk in simplehttp.response(content="Hello", contenttype="text/plain"):
    clientsocket.send(chunk)
```

> **Note:** `Content-Length` is computed with `len(content)`. This is byte-accurate for `bytes` content, but for `str` content with multi-byte UTF-8 characters, `len()` counts characters, not encoded bytes — this can produce an incorrect `Content-Length` for non-ASCII text.

---

### `runserver(host="127.0.0.1", port="8080")`

Starts the server: binds a socket, listens for connections, and serves registered pages/files. Blocks the calling thread — runs until interrupted with `Ctrl+C`.

| Argument | Type | Default | Description |
|---|---|---|---|
| `host` | `str` | `"127.0.0.1"` | Address to bind the server socket to. |
| `port` | `int` | `"8080"` | Port to bind the server socket to. |

**Returns:** `None`. Prints connection info and requested endpoints to stdout as it runs.

For any unregistered endpoint, responds with `404 NOT FOUND`.

```python
simplehttp.runserver(host="0.0.0.0", port=8080)
```

> **Note:** the `port` default is the string `"8080"`, but `socket.bind()` requires an integer port for `AF_INET`. Pass an explicit integer (e.g. `port=8080`) rather than relying on the string default, which may raise a `TypeError` depending on your Python/OS socket implementation.

---

### `between(text, start, end)` *(internal)*

Extracts the substring between two markers in `text`. Used internally to pull the requested path out of the raw HTTP request line (e.g. the endpoint between the two spaces in `GET /path HTTP/1.1`). Not intended for use outside the module.

| Argument | Type | Description |
|---|---|---|
| `text` | `bytes` | The text to search. |
| `start` | `bytes` | The marker after which extraction begins. |
| `end` | `bytes` | The marker before which extraction ends. |

**Returns:** `bytes` — the substring found between `start` and `end`.

## Cons

- **Single-threaded, one connection at a time.** `runserver` doesn't accept a new client until the current one disconnects. Not suitable for concurrent traffic without adding threading.
- **Plain HTTP only.** No TLS/HTTPS support.
- **Files are cached at registration time.** `addfile` reads the file once; it won't pick up later changes on disk.
- **No routing parameters, query strings, or HTTP methods.** Requests are matched purely on the literal path between the first two spaces in the request line — `GET` and `POST` to the same path are treated identically, and query strings (`?key=value`) will cause a lookup miss since they're part of the matched string.

## Pros

- **Educational** This project is meant for learning how servers work.
- **Simple** This project is extremely simple. You can make a website with three lines of code.
