Files

303 lines
15 KiB
Zig

const sys = @import("sys");
const errors = @import("error");
// ---------------------------------------------------------------------------
// http_parser (third-party parser bundled with ESP-IDF)
// ---------------------------------------------------------------------------
pub const Parser = struct {
pub const version = sys.http_parser_version;
pub const init = sys.http_parser_init;
pub const settingsInit = sys.http_parser_settings_init;
pub const execute = sys.http_parser_execute;
pub const urlInit = sys.http_parser_url_init;
pub const parseUrl = sys.http_parser_parse_url;
pub const pause = sys.http_parser_pause;
};
pub const shouldKeepAlive = sys.http_should_keep_alive;
pub const methodStr = sys.http_method_str;
pub const errnoName = sys.http_errno_name;
pub const errnoDescription = sys.http_errno_description;
pub const bodyIsFinal = sys.http_body_is_final;
// ---------------------------------------------------------------------------
// HTTP server (httpd)
// ---------------------------------------------------------------------------
pub const Server = struct {
/// Start the HTTP server. Returns a handle on success.
pub fn start(config: *const sys.httpd_config_t) !sys.httpd_handle_t {
var handle: sys.httpd_handle_t = null;
try errors.espCheckError(sys.httpd_start(&handle, config));
return handle;
}
/// Stop and clean up the HTTP server.
pub fn stop(handle: sys.httpd_handle_t) !void {
return errors.espCheckError(sys.httpd_stop(handle));
}
/// Register a URI handler.
pub fn registerUri(handle: sys.httpd_handle_t, uri_handler: *const sys.httpd_uri_t) !void {
return errors.espCheckError(sys.httpd_register_uri_handler(handle, uri_handler));
}
/// Unregister a URI handler by URI string and method.
pub fn unregisterUri(handle: sys.httpd_handle_t, uri: [*:0]const u8, method: sys.httpd_method_t) !void {
return errors.espCheckError(sys.httpd_unregister_uri_handler(handle, uri, method));
}
/// Unregister all URI handlers for a given URI string.
pub fn unregisterAllUris(handle: sys.httpd_handle_t, uri: [*:0]const u8) !void {
return errors.espCheckError(sys.httpd_unregister_uri(handle, uri));
}
pub const Session = struct {
pub fn setReceiveOverride(hd: sys.httpd_handle_t, sockfd: c_int, recv_func: sys.httpd_recv_func_t) !void {
return errors.espCheckError(sys.httpd_sess_set_recv_override(hd, sockfd, recv_func));
}
pub fn setSendOverride(hd: sys.httpd_handle_t, sockfd: c_int, send_func: sys.httpd_send_func_t) !void {
return errors.espCheckError(sys.httpd_sess_set_send_override(hd, sockfd, send_func));
}
pub fn setPendingOverride(hd: sys.httpd_handle_t, sockfd: c_int, pending_func: sys.httpd_pending_func_t) !void {
return errors.espCheckError(sys.httpd_sess_set_pending_override(hd, sockfd, pending_func));
}
pub fn triggerClose(handle: sys.httpd_handle_t, sockfd: c_int) !void {
return errors.espCheckError(sys.httpd_sess_trigger_close(handle, sockfd));
}
pub fn updateLRUCounter(handle: sys.httpd_handle_t, sockfd: c_int) !void {
return errors.espCheckError(sys.httpd_sess_update_lru_counter(handle, sockfd));
}
pub const getContext = sys.httpd_sess_get_ctx;
pub const setContext = sys.httpd_sess_set_ctx;
pub const getTransportContext = sys.httpd_sess_get_transport_ctx;
pub const setTransportContext = sys.httpd_sess_set_transport_ctx;
};
pub const Request = struct {
pub fn asyncHandlerBegin(r: [*c]sys.httpd_req_t, out: [*c][*c]sys.httpd_req_t) !void {
return errors.espCheckError(sys.httpd_req_async_handler_begin(r, out));
}
pub fn asyncHandlerComplete(r: [*c]sys.httpd_req_t) !void {
return errors.espCheckError(sys.httpd_req_async_handler_complete(r));
}
pub const toSockfd = sys.httpd_req_to_sockfd;
pub const receiver = sys.httpd_req_recv;
pub const getHDRValueLen = sys.httpd_req_get_hdr_value_len;
pub fn getHDRValueStr(r: [*c]sys.httpd_req_t, field: [*:0]const u8, val: [*:0]u8, val_size: usize) !void {
return errors.espCheckError(sys.httpd_req_get_hdr_value_str(r, field, val, val_size));
}
pub const getUrlQueryLen = sys.httpd_req_get_url_query_len;
pub fn getUrlQueryStr(r: [*c]sys.httpd_req_t, buf: [*:0]u8, buf_len: usize) !void {
return errors.espCheckError(sys.httpd_req_get_url_query_str(r, buf, buf_len));
}
pub fn getCookieValue(req: [*c]sys.httpd_req_t, cookie_name: [*:0]const u8, val: [*:0]u8, val_size: [*c]usize) !void {
return errors.espCheckError(sys.httpd_req_get_cookie_val(req, cookie_name, val, val_size));
}
};
pub fn queryKeyValue(qry: [*:0]const u8, key: [*:0]const u8, val: [*:0]u8, val_size: usize) !void {
return errors.espCheckError(sys.httpd_query_key_value(qry, key, val, val_size));
}
pub const uri_MatchWildcard = sys.httpd_uri_match_wildcard;
pub const Response = struct {
/// Send a complete response with a byte-slice body.
pub fn send(r: [*c]sys.httpd_req_t, buf: []const u8) !void {
return errors.espCheckError(sys.httpd_resp_send(r, buf.ptr, @intCast(buf.len)));
}
/// Send a response chunk with a byte-slice body.
pub fn sendChunk(r: [*c]sys.httpd_req_t, buf: []const u8) !void {
return errors.espCheckError(sys.httpd_resp_send_chunk(r, buf.ptr, @intCast(buf.len)));
}
/// Send a null-terminated string as the complete response.
/// Passes -1 (HTTPD_RESP_USE_STRLEN) so ESP-IDF calls strlen.
pub fn sendStr(r: [*c]sys.httpd_req_t, str: [*:0]const u8) !void {
return errors.espCheckError(sys.httpd_resp_send(r, str, -1));
}
/// Send a null-terminated string as a response chunk.
pub fn sendStrChunk(r: [*c]sys.httpd_req_t, str: [*:0]const u8) !void {
return errors.espCheckError(sys.httpd_resp_send_chunk(r, str, -1));
}
pub fn setStatus(r: [*c]sys.httpd_req_t, status: [*:0]const u8) !void {
return errors.espCheckError(sys.httpd_resp_set_status(r, status));
}
pub fn setType(r: [*c]sys.httpd_req_t, @"type": [*:0]const u8) !void {
return errors.espCheckError(sys.httpd_resp_set_type(r, @"type"));
}
pub fn setHDR(r: [*c]sys.httpd_req_t, field: [*:0]const u8, value: [*:0]const u8) !void {
return errors.espCheckError(sys.httpd_resp_set_hdr(r, field, value));
}
pub fn sendError(req: [*c]sys.httpd_req_t, @"error": sys.httpd_err_code_t, msg: [*:0]const u8) !void {
return errors.espCheckError(sys.httpd_resp_send_err(req, @"error", msg));
}
pub fn send404(r: [*c]sys.httpd_req_t) !void {
return errors.espCheckError(sys.httpd_resp_send_err(r, .HTTPD_404_NOT_FOUND, null));
}
pub fn send408(r: [*c]sys.httpd_req_t) !void {
return errors.espCheckError(sys.httpd_resp_send_err(r, .HTTPD_408_REQ_TIMEOUT, null));
}
pub fn send500(r: [*c]sys.httpd_req_t) !void {
return errors.espCheckError(sys.httpd_resp_send_err(r, .HTTPD_500_INTERNAL_SERVER_ERROR, null));
}
};
pub const rawSend = sys.httpd_send;
pub const Socket = struct {
pub const send = sys.httpd_socket_send;
pub const receive = sys.httpd_socket_recv;
};
pub const getGlobalUserContext = sys.httpd_get_global_user_ctx;
pub const getGlobalTransportContext = sys.httpd_get_global_transport_ctx;
pub fn getClientList(handle: sys.httpd_handle_t, fds: [*c]usize, client_fds: [*c]c_int) !void {
return errors.espCheckError(sys.httpd_get_client_list(handle, fds, client_fds));
}
pub const httpd_work_fn_t = sys.httpd_work_fn_t;
pub fn queueWork(handle: sys.httpd_handle_t, work: httpd_work_fn_t, arg: ?*anyopaque) !void {
return errors.espCheckError(sys.httpd_queue_work(handle, work, arg));
}
};
// ---------------------------------------------------------------------------
// HTTP client (esp_http_client)
// ---------------------------------------------------------------------------
pub const Client = struct {
handle: sys.esp_http_client_handle_t = null,
/// Initialise the HTTP client from a config struct. Call `deinit()` when done.
pub fn init(config: *const sys.esp_http_client_config_t) Client {
return .{ .handle = sys.esp_http_client_init(config) };
}
/// Clean up the client handle. Must be called after use.
pub fn deinit(self: Client) !void {
return errors.espCheckError(sys.esp_http_client_cleanup(self.handle));
}
/// Perform a complete blocking request/response cycle.
pub fn perform(self: Client) !void {
return errors.espCheckError(sys.esp_http_client_perform(self.handle));
}
/// Open the connection (for streaming writes).
/// `write_len` is Content-Length; pass 0 for requests without a body.
pub fn open(self: Client, write_len: c_int) !void {
return errors.espCheckError(sys.esp_http_client_open(self.handle, write_len));
}
/// Close the connection (without cleaning up the handle).
pub fn close(self: Client) !void {
return errors.espCheckError(sys.esp_http_client_close(self.handle));
}
/// Write request body data (call after `open()`).
pub fn write(self: Client, data: []const u8) !c_int {
const n = sys.esp_http_client_write(self.handle, data.ptr, @intCast(data.len));
if (n < 0) return error.HttpWriteFailed;
return n;
}
/// Fetch (read) response headers after `open()`.
/// Returns Content-Length, or negative on error / chunked encoding.
pub fn fetchHeaders(self: Client) i64 {
return sys.esp_http_client_fetch_headers(self.handle);
}
/// Read response body into `buf`. Returns number of bytes read (0 = done).
pub fn read(self: Client, buf: []u8) !c_int {
const n = sys.esp_http_client_read(self.handle, buf.ptr, @intCast(buf.len));
if (n < 0) return error.HttpReadFailed;
return n;
}
/// Read the entire response into `buf` (convenience wrapper).
pub fn readResponse(self: Client, buf: []u8) !c_int {
const n = sys.esp_http_client_read_response(self.handle, buf.ptr, @intCast(buf.len));
if (n < 0) return error.HttpReadFailed;
return n;
}
/// HTTP status code of the last response.
pub fn getStatusCode(self: Client) c_int {
return sys.esp_http_client_get_status_code(self.handle);
}
/// Content-Length of the last response (-1 if unknown / chunked).
pub fn getContentLength(self: Client) i64 {
return sys.esp_http_client_get_content_length(self.handle);
}
/// Cancel the current in-progress request.
pub fn cancelRequest(self: Client) !void {
return errors.espCheckError(sys.esp_http_client_cancel_request(self.handle));
}
/// Setters — configure the client before calling `perform()` or `open()`.
pub const Set = struct {
pub fn url(client: sys.esp_http_client_handle_t, _url: [*:0]const u8) !void {
return errors.espCheckError(sys.esp_http_client_set_url(client, _url));
}
pub fn postField(client: sys.esp_http_client_handle_t, data: []const u8) !void {
return errors.espCheckError(sys.esp_http_client_set_post_field(client, data.ptr, @intCast(data.len)));
}
pub fn header(client: sys.esp_http_client_handle_t, field: [*:0]const u8, value: [*:0]const u8) !void {
return errors.espCheckError(sys.esp_http_client_set_header(client, field, value));
}
pub fn username(client: sys.esp_http_client_handle_t, _username: [*:0]const u8) !void {
return errors.espCheckError(sys.esp_http_client_set_username(client, _username));
}
pub fn password(client: sys.esp_http_client_handle_t, _password: [*:0]const u8) !void {
return errors.espCheckError(sys.esp_http_client_set_password(client, _password));
}
pub fn method(client: sys.esp_http_client_handle_t, _method: sys.esp_http_client_method_t) !void {
return errors.espCheckError(sys.esp_http_client_set_method(client, _method));
}
pub fn timeout(client: sys.esp_http_client_handle_t, timeout_ms: u32) !void {
return errors.espCheckError(sys.esp_http_client_set_timeout_ms(client, timeout_ms));
}
pub fn userData(client: sys.esp_http_client_handle_t, user_data: ?*anyopaque) !void {
return errors.espCheckError(sys.esp_http_client_set_user_data(client, user_data));
}
pub fn authData(client: sys.esp_http_client_handle_t, auth_data: []const u8) !void {
return errors.espCheckError(sys.esp_http_client_set_auth_data(client, auth_data.ptr, @intCast(auth_data.len)));
}
pub fn authType(client: sys.esp_http_client_handle_t, auth_type: sys.esp_http_client_auth_type_t) !void {
return errors.espCheckError(sys.esp_http_client_set_authtype(client, auth_type));
}
pub fn redirection(client: sys.esp_http_client_handle_t) !void {
return errors.espCheckError(sys.esp_http_client_set_redirection(client));
}
};
/// Getters — retrieve configuration or response state.
pub const Get = struct {
/// Copy the current URL into a buffer.
pub fn url(client: sys.esp_http_client_handle_t, buf: []u8) !void {
return errors.espCheckError(sys.esp_http_client_get_url(client, buf.ptr, @intCast(buf.len)));
}
/// Get a pointer to the POST field data (no copy).
pub fn postField(client: sys.esp_http_client_handle_t, data: *[*c]const u8, len: *c_int) !void {
return errors.espCheckError(sys.esp_http_client_get_post_field(client, data, len));
}
/// Get the value of a request header by key (returns pointer via `value`).
pub fn header(client: sys.esp_http_client_handle_t, key: [*:0]const u8, value: *[*c]const u8) !void {
return errors.espCheckError(sys.esp_http_client_get_header(client, key, value));
}
/// Get the configured username (returns pointer via `value`).
pub fn username(client: sys.esp_http_client_handle_t, value: *[*c]const u8) !void {
return errors.espCheckError(sys.esp_http_client_get_username(client, value));
}
/// Get the configured password (returns pointer via `value`).
pub fn password(client: sys.esp_http_client_handle_t, value: *[*c]const u8) !void {
return errors.espCheckError(sys.esp_http_client_get_password(client, value));
}
pub fn userData(client: sys.esp_http_client_handle_t, user_data: *?*anyopaque) !void {
return errors.espCheckError(sys.esp_http_client_get_user_data(client, user_data));
}
};
};