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
)