|
cwist
Modern C web framework with libttak runtime
|
HTML page and fragment responses for HTML-over-the-wire handlers. More...
#include <cwist/net/http/http.h>#include <cwist/core/html/builder.h>#include <cwist/core/html/component.h>#include <stdbool.h>

Go to the source code of this file.
Macros | |
| #define | CWIST_HTML_FRAGMENT_VARY "HX-Request, HX-History-Restore-Request, HX-Target, Turbo-Frame" |
| Request headers that select between a page and a fragment. | |
HTML page and fragment responses for HTML-over-the-wire handlers.
A handler builds the content it owns (usually with cwist_html_component_t) and lets these helpers decide how to answer: a full document on a normal navigation, only the fragment when the client asked for one. Out-of-band elements and redirects follow the same request-driven switch, so the same route works with and without client-side script (progressive enhancement).
Fragment requests are recognised by the request headers that fragment- swapping clients already send: HX-Request: true (htmx) and Turbo-Frame (Hotwire Turbo frames). Nothing here requires either library.
Definition in file html_response.h.
Request headers that select between a page and a fragment.
cwist_http_response_set_view() sends this as Vary so shared caches keep the two representations of one URL apart.
Definition at line 34 of file html_response.h.
| const char * cwist_http_request_fragment_target | ( | const cwist_http_request * | req | ) |
The element id the client will swap the fragment into, if it said.
Turbo-Frame first, then HX-Target. Only meaningful when cwist_http_request_wants_fragment() is true.
The element id the client will swap the fragment into, if it said.
| req | Request to inspect; may be NULL. |
Turbo-Frame id when present, otherwise the HX-Target header when present, or NULL when the client did not request a fragment or no target was given. The pointer is owned by the request. Definition at line 57 of file html_response.c.
References cap, and cwist_http_request_wants_fragment().
| bool cwist_http_request_wants_fragment | ( | const cwist_http_request * | req | ) |
Whether the client asked for a fragment instead of a full page.
True for HX-Request: true (unless HX-History-Restore-Request: true, which asks for the whole page again) and for any non-empty Turbo-Frame header.
| req | Parsed request. NULL gives false. |
Whether the client asked for a fragment instead of a full page.
A fragment is requested when the htmx HX-Request header is "true" (and it is not a history restore) or when a non-empty Turbo-Frame header is set.
| req | Request to inspect; may be NULL. |
Definition at line 43 of file html_response.c.
References cap.
Referenced by cwist_http_request_fragment_target(), cwist_http_response_add_oob(), and cwist_http_response_set_view().
| int cwist_http_response_add_oob | ( | const cwist_http_request * | req, |
| cwist_http_response * | res, | ||
| cwist_html_element_t * | el | ||
| ) |
Append an out-of-band element to a fragment response.
For a fragment request the element is rendered after the current body with hx-swap-oob="true" (unless the caller already set hx-swap-oob), so the client replaces the element with the same id elsewhere on the page. For a full-page request it is dropped: the page being sent already contains that region. Clients that do not implement out-of-band swaps ignore the extra element.
Call it after the main content has been set.
| req | Request being answered. |
| res | Response whose body receives the element. |
| el | Element to append; must carry a non-empty id attribute. Always consumed, including on failure. |
Append an out-of-band element to a fragment response.
The element must have an "id" attribute. When the client requested a full page the element is dropped (a full page already contains the region) and success is reported. Otherwise an hx-swap-oob="true" attribute is added if missing and the element is rendered and appended to the body. Takes ownership of el in all cases.
| req | Request used to decide whether an OOB update applies. |
| res | Response whose body the rendered element is appended to. |
| el | Element to append; consumed regardless of the result. |
Definition at line 226 of file html_response.c.
References cwist_http_response::body, cap, cwist_error_dispose(), cwist_html_element_add_attr(), cwist_html_element_destroy(), cwist_http_request_wants_fragment(), cwist_sstring_append(), cwist_sstring_destroy(), and cwist_sstring::data.
| int cwist_http_response_html_redirect | ( | const cwist_http_request * | req, |
| cwist_http_response * | res, | ||
| const char * | location | ||
| ) |
Redirect in a way both plain navigation and fragment clients follow.
An htmx request (HX-Request: true) gets 200 with HX-Redirect: <location>, because a script-driven request follows a 3xx itself and would swap the target page into the fragment slot. Every other request, Turbo frames included, gets 303 See Other with Location, which also turns a form POST into a GET. The body is emptied in both cases.
| req | Request being answered. |
| res | Response to fill. |
| location | Target URL; must be non-empty and free of control characters (CR/LF would split the response). |
Redirect in a way both plain navigation and fragment clients follow.
For htmx requests (HX-Request: true) the status stays 200 and the target is sent via the HX-Redirect header; otherwise a 303 See Other response with a Location header is produced. Any previous Location and HX-Redirect headers are removed and the body is cleared.
| req | Request used to decide between htmx and regular redirects. |
| res | Response to modify. |
| location | Redirect target; must be non-empty and free of control bytes. |
Definition at line 282 of file html_response.c.
References cwist_http_response::body, cap, cwist_error_dispose(), cwist_http_header_remove(), CWIST_HTTP_OK, CWIST_HTTP_SEE_OTHER, cwist_sstring_assign(), cwist_http_response::headers, and cwist_http_response::status_code.
| int cwist_http_response_set_html | ( | cwist_http_response * | res, |
| cwist_html_element_t * | root, | ||
| bool | document | ||
| ) |
Render an element tree into the response body as HTML.
Replaces the body, sets Content-Type: text/html; charset=utf-8 (replacing any earlier Content-Type) and leaves the status code alone. With document set, the body starts with <!DOCTYPE html>.
| res | Response to fill. |
| root | Element tree to render; always consumed (destroyed), including on failure. |
| document | True for a full document, false for a fragment. |
Render an element tree into the response body as HTML.
Always takes ownership of root and destroys it. On success the Content-Type header is set to text/html; charset=utf-8.
| res | Response whose body is replaced. |
| root | Element tree to render; consumed regardless of the result. |
| document | When true, render as a full document with a doctype. |
Definition at line 141 of file html_response.c.
References cwist_http_response::body, cap, cwist_error_dispose(), cwist_html_element_destroy(), cwist_sstring_assign_len(), and cwist_sstring_destroy().
Referenced by cwist_http_response_set_view().
| int cwist_http_response_set_view | ( | const cwist_http_request * | req, |
| cwist_http_response * | res, | ||
| cwist_html_element_t * | content, | ||
| cwist_html_component_t * | layout, | ||
| const void * | layout_props | ||
| ) |
Answer with a fragment or a full page, depending on the request.
A fragment request gets content alone. Any other request gets a document: content wrapped by layout when one is given (the layout component receives content as its single child, see cwist_html_component_instantiate()), or content itself as the document root otherwise. Both answers carry Vary: CWIST_HTML_FRAGMENT_VARY.
| req | Request being answered. |
| res | Response to fill. |
| content | Page content; always consumed, including on failure. |
| layout | Optional layout component for full-page answers (not consumed). |
| layout_props | Props passed to layout (may be NULL). |
Answer with a fragment or a full page, depending on the request.
When the client requested a fragment, content is rendered alone; otherwise it is embedded into the layout component (or rendered as a full document when no layout is given). Takes ownership of content in all cases. On success a Vary header for fragment-negotiation is appended.
| req | Request used to decide between fragment and full-page rendering. |
| res | Response whose body is replaced. |
| content | Element tree for the page content; consumed regardless of the result. |
| layout | Optional layout component that wraps content; may be NULL. |
| layout_props | Props passed to the layout component. |
content is NULL, or rendering fails. Definition at line 178 of file html_response.c.
References cap, cwist_html_component_instantiate(), cwist_html_element_destroy(), CWIST_HTML_FRAGMENT_VARY, cwist_http_request_wants_fragment(), and cwist_http_response_set_html().