int n_clients = 0;
struct config conf = {};
-static const char *http_versions[] = {
+const char * const http_versions[] = {
[UH_HTTP_VER_0_9] = "HTTP/0.9",
[UH_HTTP_VER_1_0] = "HTTP/1.0",
[UH_HTTP_VER_1_1] = "HTTP/1.1",
};
+const char * const http_methods[] = {
+ [UH_HTTP_MSG_GET] = "GET",
+ [UH_HTTP_MSG_POST] = "POST",
+ [UH_HTTP_MSG_HEAD] = "HEAD",
+};
+
void uh_http_header(struct client *cl, int code, const char *summary)
{
const char *enc = "Transfer-Encoding: chunked\r\n";
code, summary, conn, enc);
}
-static void uh_client_error_header(struct client *cl, int code, const char *summary)
-{
- uh_http_header(cl, code, summary);
- ustream_printf(cl->us, "Content-Type: text/plain\r\n\r\n");
-}
-
static void uh_connection_close(struct client *cl)
{
cl->state = CLIENT_STATE_DONE;
static void uh_dispatch_done(struct client *cl)
{
- if (cl->dispatch_free)
- cl->dispatch_free(cl);
- cl->dispatch_free = NULL;
+ if (cl->dispatch.free)
+ cl->dispatch.free(cl);
}
void uh_request_done(struct client *cl)
uh_chunk_eof(cl);
uh_dispatch_done(cl);
cl->us->notify_write = NULL;
- memset(&cl->data, 0, sizeof(cl->data));
+ memset(&cl->dispatch, 0, sizeof(cl->dispatch));
if (cl->request.version != UH_HTTP_VER_1_1 || !conf.http_keepalive) {
uh_connection_close(cl);
{
va_list arg;
- uh_client_error_header(cl, code, summary);
+ uh_http_header(cl, code, summary);
+ ustream_printf(cl->us, "Content-Type: text/html\r\n\r\n");
+
+ uh_chunk_printf(cl, "<h1>%s</h1>", summary);
- va_start(arg, fmt);
- uh_chunk_vprintf(cl, fmt, arg);
- va_end(arg);
+ if (fmt) {
+ va_start(arg, fmt);
+ uh_chunk_vprintf(cl, fmt, arg);
+ va_end(arg);
+ }
uh_request_done(cl);
}
static void uh_header_error(struct client *cl, int code, const char *summary)
{
- uh_client_error(cl, code, summary, "%s", summary);
+ uh_client_error(cl, code, summary, NULL);
uh_connection_close(cl);
}
uh_connection_close(cl);
}
+static int find_idx(const char * const *list, int max, const char *str)
+{
+ int i;
+
+ for (i = 0; i < max; i++)
+ if (!strcmp(list[i], str))
+ return i;
+
+ return -1;
+}
+
static int client_parse_request(struct client *cl, char *data)
{
struct http_request *req = &cl->request;
char *type, *path, *version;
- int i;
type = strtok(data, " ");
path = strtok(NULL, " ");
return CLIENT_STATE_DONE;
req->url = path;
- if (!strcmp(type, "GET"))
- req->method = UH_HTTP_MSG_GET;
- else if (!strcmp(type, "POST"))
- req->method = UH_HTTP_MSG_POST;
- else if (!strcmp(type, "HEAD"))
- req->method = UH_HTTP_MSG_HEAD;
- else
+ req->method = find_idx(http_methods, ARRAY_SIZE(http_methods), type);
+ if (req->method < 0)
return CLIENT_STATE_DONE;
- cl->request.version = -1;
- i = array_size(http_versions);
- while (i--) {
- if (!strcmp(version, http_versions[i])) {
- cl->request.version = i;
- break;
- }
- }
+ req->version = find_idx(http_versions, ARRAY_SIZE(http_versions), version);
if (cl->request.version < 0)
return CLIENT_STATE_DONE;
static void client_header_complete(struct client *cl)
{
- uh_handle_file_request(cl);
+ uh_handle_request(cl);
}
static int client_parse_header(struct client *cl, char *data)
return CLIENT_STATE_DATA;
}
- val = strchr(data, ':');
+ val = uh_split_header(data);
if (!val)
return CLIENT_STATE_DONE;
- *val = 0;
- val++;
-
- while (isspace(*val))
- val++;
-
for (name = data; *name; name++)
if (isupper(*name))
*name = tolower(*name);
ustream_free(&cl->sfd.stream);
close(cl->sfd.fd.fd);
list_del(&cl->list);
+ blob_buf_free(&cl->hdr);
free(cl);
uh_unblock_listeners();
{
struct client *cl = container_of(s, struct client, sfd);
- if (cl->dispatch_write_cb)
- cl->dispatch_write_cb(cl);
+ if (cl->dispatch.write_cb)
+ cl->dispatch.write_cb(cl);
}
static void client_notify_state(struct ustream *s)
n_clients++;
cl->id = client_id++;
}
+
+void uh_close_fds(void)
+{
+ struct client *cl;
+
+ uloop_done();
+ uh_close_listen_fds();
+ list_for_each_entry(cl, &clients, list) {
+ close(cl->sfd.fd.fd);
+ if (cl->dispatch.close_fds)
+ cl->dispatch.close_fds(cl);
+ }
+}