duckweb_head

scalar · LOAD duckweb

duckweb_head(INTEGER, VARCHAR, VARCHAR) -> VARCHAR

Opens a streamed response: status line, content type, framing, and any extra header lines.

SELECT duckweb_head(200, 'text/html', '')

emits the status line, Content-Type, Transfer-Encoding: chunked, Connection: close, the extra block, and the blank line that ends the head. What follows is duckweb_chunk rows and exactly one duckweb_end.

Connection: close is not optional politeness: HTTP/1.1 keeps a connection alive unless told otherwise and duckweb answers one request per connection, so without it a client is entitled to send its next request into a socket that is already closing.

status is clamped to 100–599. Codes duckweb knows get their reason phrase; the rest get Unknown, which is advisory — the code is what matters.

The extra block

extra is header lines already built by duckweb_header, duckweb_set_cookie or duckweb_speculate, concatenated:

duckweb_head(200, 'text/html',
  duckweb_header('Cache-Control', 'no-store')
  || duckweb_set_cookie('seen', '1', 'Path=/; SameSite=Lax'))

Every line in it is re-terminated, and anything that is not name: value with a token name is dropped. That is a backstop, not a sanitiser: it exists so a %0d%0a%0d%0a arriving through user input cannot end the head early and let that input write the response body itself. It cannot tell a header you meant from one smuggled into a value, so build lines with the helpers, which escape what goes into them.