45#define N_HTTP_RESPONSE_CHUNK 65536
57 return "Switching Protocols";
67 return "Partial Content";
69 return "Moved Permanently";
75 return "Not Modified";
77 return "Temporary Redirect";
79 return "Permanent Redirect";
83 return "Unauthorized";
89 return "Method Not Allowed";
91 return "Not Acceptable";
93 return "Request Timeout";
99 return "Length Required";
101 return "Precondition Failed";
103 return "Content Too Large";
105 return "URI Too Long";
107 return "Unsupported Media Type";
109 return "Range Not Satisfiable";
111 return "Expectation Failed";
113 return "Misdirected Request";
115 return "Unprocessable Content";
117 return "Upgrade Required";
119 return "Precondition Required";
121 return "Too Many Requests";
123 return "Request Header Fields Too Large";
125 return "Unavailable For Legal Reasons";
127 return "Internal Server Error";
129 return "Not Implemented";
131 return "Bad Gateway";
133 return "Service Unavailable";
135 return "Gateway Timeout";
137 return "HTTP Version Not Supported";
141 if (status >= 100 && status < 200)
142 return "Informational";
143 if (status >= 200 && status < 300)
145 if (status >= 300 && status < 400)
146 return "Redirection";
147 if (status >= 400 && status < 500)
148 return "Client Error";
149 if (status >= 500 && status < 600)
150 return "Server Error";
155 return (c >=
'A' && c <=
'Z') ? c -
'A' +
'a' : c;
172 unsigned char c = (
unsigned char)*s;
173 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') || (c >=
'0' && c <=
'9'))
175 if (!strchr(
"!#$%&'*+-.^_`|~", c))
183 return (status >= 100 && status < 200) || status == 204 || status == 304;
193 if (status < 100 || status > 599)
220 for (i = 0; i < (*r)->nb_headers; i++) {
235 if (!r || status < 100 || status > 599)
250 char *n = NULL, *v = NULL;
262 for (i = 0; i < ve; i++) {
263 unsigned char c = (
unsigned char)value[i];
264 if ((c < 0x20 && c !=
'\t') || c == 0x7f) {
265 n_log(
LOG_DEBUG,
"response: control byte 0x%02x in %s refused", c, name);
270 while (vs < ve && (value[vs] ==
' ' || value[vs] ==
'\t'))
272 while (ve > vs && (value[ve - 1] ==
' ' || value[ve - 1] ==
'\t'))
275 Malloc(v,
char, ve - vs + 1);
281 memcpy(v, value + vs, ve - vs);
296 size_t i, o = 0, removed = 0;
335 for (i = 0; i < before; i++) {
381 if (!r || (!data && len > 0))
404 if (!r || fd < 0 || offset < 0 || length < 0) {
425 if (!r || (version_minor != 0 && version_minor != 1))
451 size_t n = strlen(str);
453 return *
h != NULL || (*
h =
new_nstr(1)) != NULL;
491 if (!
_resp_cat(&
h,
"Connection: keep-alive\r\n"))
511 ssize_t w = fn(ctx, buf, len);
512 if (w <= 0 || (
size_t)w > len)
522static ssize_t
_resp_pread(
int fd,
char* buf,
size_t len,
long long offset) {
524 if (_lseeki64(fd, offset, SEEK_SET) < 0)
526 return (ssize_t)_read(fd, buf, (
unsigned)len);
528 return pread(fd, buf, len, (off_t)offset);
579static int _resp_num(
const char* s,
size_t n,
long long* v) {
582 if (n == 0 || n > 18)
584 for (i = 0; i < n; i++) {
585 if (s[i] <
'0' || s[i] >
'9')
587 *v = *v * 10 + (s[i] -
'0');
604 if (!value || !first || !
last || total < 0 || len < 7 || memcmp(value,
"bytes=", 6) != 0)
608 for (dash = 0; dash < len && value[dash] !=
'-'; dash++);
615 if (b == 0 || total == 0)
617 *first = b >= total ? 0 : total - b;
623 if (dash + 1 == len) {
625 }
else if (!
_resp_num(value + dash + 1, len - dash - 1, &b) || b < a) {
static N_GUI_MOUSE_EVENT last
the last event the widget was told of, and how many
static int h(void *ctx, const N_ROUTE_MATCH *m)
a handler that does nothing (the test only routes)
volatile sig_atomic_t done
void line(BITMAP *bmp, int x1, int y1, int x2, int y2, int color)
draw a line
#define FreeNoLog(__ptr)
Free Handler without log.
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
#define __n_assert(__ptr, __ret)
macro to assert things
#define Free(__ptr)
Free Handler to get errors.
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_DEBUG
debug-level messages
int version_minor
HTTP/1.x minor version of the request (0 or 1).
long long fd_length
file body length
int status
status code, 100..599
int fd
file body descriptor (owned, closed on free), or -1
size_t nb_headers
number of headers
char * names[64]
header names, nb_headers of them
long long fd_offset
file body start offset
int head_only
non-zero: send headers only (HEAD request)
char * values[64]
header values
N_STR * body
memory body, or NULL
int keep_alive
non-zero: the connection stays open after this response
N_HTTP_RANGE n_http_parse_range(const char *value, size_t len, long long total, long long *first, long long *last)
interpret a single-range Range header for a body of total bytes
#define N_HTTP_RESPONSE_VALUE_MAX
longest header value accepted, in bytes
#define N_HTTP_RESPONSE_HEADERS_MAX
most headers a response may carry
int n_http_response_append(N_HTTP_RESP *r, const void *data, size_t len)
append bytes to the memory body (drops a file body)
const char * n_http_status_reason(int status)
reason phrase of a status code, a class phrase for an unlisted one
int n_http_response_head(const N_HTTP_RESP *r, N_STR **out)
append the status line and headers, through the blank line
int n_http_response_set_header(N_HTTP_RESP *r, const char *name, const char *value)
set a header: remove every header of that name, then add it
ssize_t(* n_http_write_fn)(void *ctx, const void *buf, size_t len)
a write function: write up to len bytes, return how many were written (at least 1) or -1 on a fatal e...
int n_http_response_add_header(N_HTTP_RESP *r, const char *name, const char *value)
add a header line after validating name and value
int n_http_response_file(N_HTTP_RESP *r, int fd, long long offset, long long length)
use a file range as the body; the response owns fd from now on
int n_http_response_set_status(N_HTTP_RESP *r, int status)
change the status code
long long n_http_response_body_length(const N_HTTP_RESP *r)
body length the response declares, 0 for a bodiless status
size_t n_http_response_remove_header(N_HTTP_RESP *r, const char *name)
remove every header of that name (ASCII case-insensitive)
N_HTTP_RANGE
result of n_http_parse_range()
int n_http_response_write(const N_HTTP_RESP *r, n_http_write_fn fn, void *ctx)
write the whole response (head, then body unless HEAD or bodiless)
int n_http_response_set_connection(N_HTTP_RESP *r, int keep_alive, int version_minor, int head_only)
connection handling for this response
void n_http_response_free(N_HTTP_RESP **r)
free a response (closing its file body) and set *r to NULL
const char * n_http_response_get_header(const N_HTTP_RESP *r, const char *name)
value of the first header of that name (ASCII case-insensitive)
N_HTTP_RESP * n_http_response_new(int status)
new response with a status, keep-alive off, HTTP/1.1
@ N_HTTP_RANGE_NONE
no usable Range: send the whole body (200)
@ N_HTTP_RANGE_UNSATISFIABLE
send 416, with a Content-Range that gives only the total
@ N_HTTP_RANGE_OK
one satisfiable range: send 206
a response under construction (fields are private, use the functions)
size_t written
number of meaningful bytes in data, excluding the null terminator; the size including the null termin...
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
N_STR * nstrcat_ex(N_STR **dest, void *src, NSTRBYTE size, int resize_flag)
Append data into N_STR using internal N_STR size and cursor position.
N_STR * new_nstr(NSTRBYTE size)
create a new N_STR string
A box including a string and his lenght.
#define N_TIME_HTTP_DATE_LEN
buffer size for n_time_http_date(): "Thu, 01 Jan 1970 00:00:00 GMT" + NUL
int n_time_http_date(time_t t, char *out, size_t size)
format t as an HTTP date (RFC 9110 IMF-fixdate, always GMT)
Common headers and low-level functions & define.
static int _resp_write_all(n_http_write_fn fn, void *ctx, const char *buf, size_t len)
static int _resp_cat(N_STR **h, const char *str)
static int _resp_bodiless(int status)
static int _resp_token(const char *s)
#define N_HTTP_RESPONSE_CHUNK
static int _resp_ieq(const char *a, const char *b)
static ssize_t _resp_pread(int fd, char *buf, size_t len, long long offset)
static int _resp_num(const char *s, size_t n, long long *v)
static void _resp_drop_body(N_HTTP_RESP *r)
static int _resp_lc(int c)
HTTP/1.1 response: validated headers, memory or file body, framing.
N_STR and string function declaration.