2 * uhttpd - Tiny single-threaded httpd
4 * Copyright (C) 2015 Felix Fietkau <nbd@openwrt.org>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <libubox/blobmsg.h>
20 #include <libubox/blobmsg_json.h>
21 #include <libubox/json_script.h>
26 struct list_head list;
28 struct json_script_file *request;
29 struct json_script_file *fallback;
32 static LIST_HEAD(handlers);
33 static struct json_script_ctx handler_ctx;
34 static struct env_var *cur_vars;
35 static struct blob_buf b;
36 static int handler_ret;
37 static struct client *cur_client;
38 static char **cur_url;
41 handle_redirect(struct json_script_ctx *ctx, struct blob_attr *data)
43 struct client *cl = cur_client;
44 static struct blobmsg_policy policy = {
45 .type = BLOBMSG_TYPE_STRING,
49 blobmsg_parse_array(&policy, 1, &tb, blobmsg_data(data), blobmsg_data_len(data));
53 uh_http_header(cl, 302, "Found");
54 ustream_printf(cl->us, "Content-Length: 0\r\n");
55 ustream_printf(cl->us, "Location: %s\r\n\r\n",
56 blobmsg_get_string(tb));
61 json_script_abort(ctx);
65 handle_set_uri(struct json_script_ctx *ctx, struct blob_attr *data)
67 struct client *cl = cur_client;
68 static struct blobmsg_policy policy = {
69 .type = BLOBMSG_TYPE_STRING,
72 struct blob_attr *old_url = blob_data(cl->hdr.head);
74 blobmsg_parse_array(&policy, 1, &tb, blobmsg_data(data), blobmsg_data_len(data));
79 blob_put_raw(&b, blob_next(old_url), blob_len(cl->hdr.head) - blob_pad_len(old_url));
81 /* replace URL in client header cache */
82 blob_buf_init(&cl->hdr, 0);
83 blobmsg_add_string(&cl->hdr, "URL", blobmsg_get_string(tb));
84 blob_put_raw(&cl->hdr, blob_data(b.head), blob_len(b.head));
85 *cur_url = blobmsg_data(blob_data(cl->hdr.head));
91 json_script_abort(ctx);
95 handle_command(struct json_script_ctx *ctx, const char *name,
96 struct blob_attr *data, struct blob_attr *vars)
100 void (*func)(struct json_script_ctx *ctx, struct blob_attr *data);
102 { "redirect", handle_redirect },
103 { "set_uri", handle_set_uri }
107 for (i = 0; i < ARRAY_SIZE(cmds); i++) {
108 if (!strcmp(cmds[i].name, name)) {
109 cmds[i].func(ctx, data);
116 handle_var(struct json_script_ctx *ctx, const char *name,
117 struct blob_attr *vars)
119 struct client *cl = cur_client;
121 static struct path_info empty_path;
124 struct path_info *p = uh_path_lookup(cl, *cur_url);
129 cur_vars = uh_get_process_vars(cl, p);
132 for (cur = cur_vars; cur->name; cur++) {
133 if (!strcmp(cur->name, name))
142 if (handler_ctx.handle_command)
145 json_script_init(&handler_ctx);
146 handler_ctx.handle_command = handle_command;
147 handler_ctx.handle_var = handle_var;
150 static bool set_handler(struct json_script_file **dest, struct blob_attr *data)
155 *dest = json_script_file_from_blobmsg(NULL, blobmsg_data(data), blobmsg_data_len(data));
159 int uh_handler_add(const char *file)
166 struct blobmsg_policy policy[__H_MAX] = {
167 [H_REQUEST] = { "request", BLOBMSG_TYPE_ARRAY },
168 [H_FALLBACK] = { "fallback", BLOBMSG_TYPE_ARRAY },
170 struct blob_attr *tb[__H_MAX];
174 blob_buf_init(&b, 0);
176 if (!blobmsg_add_json_from_file(&b, file))
179 blobmsg_parse(policy, __H_MAX, tb, blob_data(b.head), blob_len(b.head));
180 if (!tb[H_REQUEST] && !tb[H_FALLBACK])
183 h = calloc(1, sizeof(*h));
184 if (!set_handler(&h->request, tb[H_REQUEST]) ||
185 !set_handler(&h->fallback, tb[H_FALLBACK])) {
192 list_add_tail(&h->list, &handlers);
196 int uh_handler_run(struct client *cl, char **url, bool fallback)
198 struct json_script_file *f;
207 list_for_each_entry(h, &handlers, list) {
208 f = fallback ? h->fallback : h->request;
212 blob_buf_init(&b, 0);
213 json_script_run_file(&handler_ctx, f, b.head);
214 if (handler_ctx.abort)