# luan:http/Http.luan

- `Http.request`, `Http.response`: the current request and response. Local only.
- `Http.response.text_writer()`: a UTF-8 writer on the response body. Errors if a writer was already taken. A page function that writes a template sets `Io.stdout = Http.response.text_writer()` first.
- `Http.response.binary_writer()`: the same for bytes, as in `Http.response.binary_writer().write( file.read_binary() )`.
- `Http.response.headers`: a table of response headers whose keys ignore case, as in `Http.response.headers["Content-Type"] = "text/html; charset=utf-8"`.
- `Http.format_date(time)`: formats a time in milliseconds the way HTTP headers such as `Last-Modified` want it, in GMT: `Fri, 06 Nov 2026 09:44:42 GMT`. `Http.parse_date(string)` goes the other way.
- `Http.not_found_handler`: a function called for paths with no file; it returns true if it handled the request. Local cloned, so set it once in init code and request interpreters inherit it.
- `Http.domain`: the site's domain, or nil when not hosted. Set by `Http.set_domain(domain)`, which the hosting init calls for each site.
- `Http.request.parameters`: query and form parameters. Each value is a string, but a name that appears more than once becomes a table (list) of strings, so code expecting a string gets a table (`?name=a&name=b`). An uploaded file (multipart form) is a table `{filename, content_type, content}`, where `content` is a string or binary. A JSON request body arrives as the string `parameters.json`.
- `Http.request.url()`: scheme, host and raw path (including the query string).
- `Http.response.write_chunked_text(fn)`: runs `fn(writer)` in a new thread (`Thread.run`) with a chunked UTF-8 writer, closed when `fn` returns. Use `writer.flush()` to send what's written so far. Takes the response's writer, like `text_writer()`.
- `Http.push(url, message)`: sends a server-sent event to every connection subscribed to exactly `url`. The webserver itself intercepts any request with `Accept: text/event-stream` (before Luan), keeps the connection open and registers it under its `request.url()`; a timer pings connections and drops dead ones. A message with newlines becomes several `data:` lines, which the browser joins back. When hosted, pushing to another domain is an error.
- `Http.request.method`: `"GET"`, `"POST"` and so on.
- `Http.request.headers`: a table of request headers whose keys ignore case (`headers["Referer"]`, `headers["Host"]`).
- `Http.response.send_redirect(location)`: sets status 302 and the `Location` header.
- `Http.request.path`: the path, without the query string (`/get_chat.js`).
- `Http.request.cookies`: a table of the request's cookies.
- `Http.response.set_cookie(name, value [, attributes])`: `attributes` is a table of strings, and `Path` defaults to `/`. Every attribute is written as `name=value`, so a flag like `HttpOnly` is written `{HttpOnly=""}`, which comes out as `HttpOnly=`. Browsers accept that (tested in Chromium).
- `Http.response.set_persistent_cookie(name, value [, attributes])`: the same, with `Max-Age` set to 10,000,000 seconds (about 4 months).
- `Http.response.remove_cookie(name [, attributes])`: sets the cookie to expire now. It works on `HttpOnly` cookies too, which JavaScript can't remove.
