7.6.5. HV-05 — Cookies and Form / File Upload

This tutorial covers cookie management and form/file upload — both on the client side (building requests) and on the server side (reading submitted data).

Prerequisites: HV-03 — HTTP Server Basics and HV-04 — Advanced HTTP Server Features.

7.6.5.1. Cookies

7.6.5.1.1. Setting Cookies on a Response

Inside a route handler, add_cookie(resp, name, value) appends a Set-Cookie header. An extended overload accepts domain, path, max-age, secure, and httponly flags:

GET("/set-cookies") <| @(var req : HttpRequest?; var resp : HttpResponse?) : http_status {
    // Simple cookie
    add_cookie(resp, "session", "abc123")
    // Extended: domain, path, max_age, secure, httponly
    add_cookie(resp, "prefs", "dark-mode", "", "/", 3600, false, true)
    return resp |> TEXT_PLAIN("cookies set")
}

7.6.5.1.2. Reading Cookies from a Request

On the server side, get_cookie reads a named cookie from the request pointer:

GET("/read-cookies") <| @(var req : HttpRequest?; var resp : HttpResponse?) : http_status {
    let session = get_cookie(req, "session")
    let prefs   = get_cookie(req, "prefs")
    // session and prefs are strings; empty if not found
    ...
}

7.6.5.1.3. Iterating All Cookies

each_cookie iterates every cookie on a message, returning parsed name/value pairs. each_header also yields cookies, but as serialized Set-Cookie (response) or Cookie (request) values. Use each_cookie when you need individual fields; use each_header for a complete view of all HTTP headers.

each_cookie(req) <| $(name, value) {
    print("{name} = {value}\n")
}

7.6.5.1.4. Sending Cookies from the Client

When building a request with with_http_request, add_cookie adds cookies that will be sent with the request. Inside the with_http_request block, req is already a pointer, so no addr() is needed:

with_http_request() <| $(var req) {
    req.method = http_method.GET
    req.url := "http://localhost:8080/read-cookies"
    add_cookie(req, "session", "abc123")
    add_cookie(req, "prefs", "dark-mode")
    request(req) <| $(resp) {
        print("{resp.body}\n")
    }
}

7.6.5.2. Multipart Form Data

7.6.5.2.1. Client Side — Building Form Requests

Use set_form_data for text fields and set_form_file for file attachments. These set Content-Type: multipart/form-data automatically:

with_http_request() <| $(var req) {
    req.method = http_method.POST
    req.url := "http://localhost:8080/upload"
    set_form_data(req, "title", "My Document")
    set_form_data(req, "description", "A test upload")
    set_form_file(req, "attachment", "/path/to/file.txt")
    request(req) <| $(resp) {
        print("{resp.body}\n")
    }
}

7.6.5.2.2. Server Side — Reading Form Fields

get_form_data reads a single text field. each_form_field iterates all fields (text and file):

POST("/upload") <| @(var req : HttpRequest?; var resp : HttpResponse?) : http_status {
    let title = get_form_data(req, "title")
    each_form_field(req) <| $(name, content, filename) {
        if (!empty(filename)) {
            print("file: {filename}\n")
        } else {
            print("{name}: {content}\n")
        }
    }
    return resp |> TEXT_PLAIN("ok")
}

7.6.5.2.3. Server Side — Saving Uploaded Files

save_form_file(req, field_name, directory) writes the uploaded file to disk. If the path is a directory, the original filename is preserved:

let status = save_form_file(req, "attachment", upload_dir)
// status == 200 on success, 400 on bad request, 500 on I/O error

7.6.5.3. URL-Encoded Form Data

For simple application/x-www-form-urlencoded submissions:

// Client side
with_http_request() <| $(var req) {
    req.method = http_method.POST
    req.url := "http://localhost:8080/login"
    set_url_encoded(req, "username", "admin")
    set_url_encoded(req, "password", "secret123")
    request(req) <| $(resp) { ... }
}

// Server side
POST("/login") <| @(var req : HttpRequest?; var resp : HttpResponse?) : http_status {
    let username = get_url_encoded(req, "username")
    let password = get_url_encoded(req, "password")
    ...
}

7.6.5.4. Quick Reference

Function

Description

add_cookie(resp, name, value)

Set simple cookie on response

add_cookie(resp, name, value, domain, path, max_age, secure, httponly)

Set cookie with extended attributes

add_cookie(req, name, value)

Add cookie to outgoing request

get_cookie(req_ptr, name)

Get cookie value (empty string if not found)

each_cookie(msg_ptr) <| $(name, value) { }

Iterate all cookies

set_form_data(req, name, value)

Set multipart form field (client)

set_form_file(req, name, filepath)

Set file upload field (client)

get_form_data(req_ptr, name)

Get form field value (server)

save_form_file(req_ptr, name, dir)

Save uploaded file to disk (server)

each_form_field(req_ptr) <| $(name, content, filename) { }

Iterate all form fields (server)

set_url_encoded(req, key, value)

Set URL-encoded form field (client)

get_url_encoded(req_ptr, key)

Get URL-encoded form field (server)

Source: tutorials/dasHV/05_cookies_and_forms.das

See also

Full source: tutorials/dasHV/05_cookies_and_forms.das

Next tutorial: HV-06 — WebSockets