1 /* 2 * uhttpd - Tiny single-threaded httpd 3 * 4 * Copyright (C) 2015 Felix Fietkau <nbd@openwrt.org> 5 * 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. 9 * 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. 17 */ 18 19 #include <libubox/blobmsg.h> 20 #include <libubox/blobmsg_json.h> 21 #include <libubox/json_script.h> 22 23 #include "uhttpd.h" 24 25 struct handler { 26 struct list_head list; 27 28 struct json_script_file *request; 29 struct json_script_file *fallback; 30 }; 31 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; 39 40 static void 41 handle_redirect(struct json_script_ctx *ctx, struct blob_attr *data) 42 { 43 struct client *cl = cur_client; 44 static struct blobmsg_policy policy[3] = { 45 { .type = BLOBMSG_TYPE_STRING }, 46 { .type = BLOBMSG_TYPE_INT32 }, 47 { .type = BLOBMSG_TYPE_STRING }, 48 }; 49 struct blob_attr *tb[3]; 50 const char *status = "Found"; 51 int code = 302; 52 53 blobmsg_parse_array(policy, ARRAY_SIZE(policy), tb, blobmsg_data(data), blobmsg_data_len(data)); 54 if (!tb[0]) 55 return; 56 57 if (tb[1]) { 58 code = blobmsg_get_u32(tb[1]); 59 if (tb[2]) 60 status = blobmsg_get_string(tb[2]); 61 } 62 63 uh_http_header(cl, code, status); 64 if (!uh_use_chunked(cl)) 65 ustream_printf(cl->us, "Content-Length: 0\r\n"); 66 ustream_printf(cl->us, "Location: %s\r\n\r\n", 67 blobmsg_get_string(tb[0])); 68 uh_request_done(cl); 69 *cur_url = NULL; 70 71 handler_ret = 1; 72 json_script_abort(ctx); 73 } 74 75 static void 76 handle_set_uri(struct json_script_ctx *ctx, struct blob_attr *data) 77 { 78 struct client *cl = cur_client; 79 static struct blobmsg_policy policy = { 80 .type = BLOBMSG_TYPE_STRING, 81 }; 82 struct blob_attr *tb; 83 struct blob_attr *old_url = blob_data(cl->hdr.head); 84 85 blobmsg_parse_array(&policy, 1, &tb, blobmsg_data(data), blobmsg_data_len(data)); 86 if (!tb) 87 return; 88 89 blob_buf_init(&b, 0); 90 blob_put_raw(&b, blob_next(old_url), blob_len(cl->hdr.head) - blob_pad_len(old_url)); 91 92 /* replace URL in client header cache */ 93 blob_buf_init(&cl->hdr, 0); 94 blobmsg_add_string(&cl->hdr, "URL", blobmsg_get_string(tb)); 95 blob_put_raw(&cl->hdr, blob_data(b.head), blob_len(b.head)); 96 *cur_url = blobmsg_data(blob_data(cl->hdr.head)); 97 cur_vars = NULL; 98 99 blob_buf_init(&b, 0); 100 101 handler_ret = 1; 102 json_script_abort(ctx); 103 } 104 105 static void 106 handle_add_header(struct json_script_ctx *ctx, struct blob_attr *data) 107 { 108 struct client *cl = cur_client; 109 static struct blobmsg_policy policy[2] = { 110 { .type = BLOBMSG_TYPE_STRING }, 111 { .type = BLOBMSG_TYPE_STRING }, 112 }; 113 struct blob_attr *tb[2]; 114 115 blobmsg_parse_array(policy, ARRAY_SIZE(tb), tb, blobmsg_data(data), blobmsg_data_len(data)); 116 if (!tb[0] || !tb[1]) 117 return; 118 119 blobmsg_add_string(&cl->hdr_response, blobmsg_get_string(tb[0]), 120 blobmsg_get_string(tb[1])); 121 } 122 123 static void 124 handle_no_cache(struct json_script_ctx *ctx, struct blob_attr *data) 125 { 126 struct client *cl = cur_client; 127 128 cl->dispatch.no_cache = true; 129 } 130 131 static void 132 handle_command(struct json_script_ctx *ctx, const char *name, 133 struct blob_attr *data, struct blob_attr *vars) 134 { 135 static const struct { 136 const char *name; 137 void (*func)(struct json_script_ctx *ctx, struct blob_attr *data); 138 } cmds[] = { 139 { "redirect", handle_redirect }, 140 { "rewrite", handle_set_uri }, 141 { "add-header", handle_add_header }, 142 { "no-cache", handle_no_cache }, 143 }; 144 int i; 145 146 for (i = 0; i < ARRAY_SIZE(cmds); i++) { 147 if (!strcmp(cmds[i].name, name)) { 148 cmds[i].func(ctx, data); 149 return; 150 } 151 } 152 } 153 154 static const char * 155 handle_var(struct json_script_ctx *ctx, const char *name, 156 struct blob_attr *vars) 157 { 158 struct client *cl = cur_client; 159 struct env_var *cur; 160 static struct path_info empty_path; 161 162 if (!cur_vars) { 163 struct path_info *p = uh_path_lookup(cl, *cur_url); 164 165 if (!p) 166 p = &empty_path; 167 168 cur_vars = uh_get_process_vars(cl, p); 169 } 170 171 for (cur = cur_vars; cur->name; cur++) { 172 if (!strcmp(cur->name, name)) 173 return cur->value; 174 } 175 return NULL; 176 } 177 178 static void 179 handler_init(void) 180 { 181 if (handler_ctx.handle_command) 182 return; 183 184 json_script_init(&handler_ctx); 185 handler_ctx.handle_command = handle_command; 186 handler_ctx.handle_var = handle_var; 187 } 188 189 static bool set_handler(struct json_script_file **dest, struct blob_attr *data) 190 { 191 if (!data) 192 return true; 193 194 *dest = json_script_file_from_blobmsg(NULL, blobmsg_data(data), blobmsg_data_len(data)); 195 return *dest; 196 } 197 198 int uh_handler_add(const char *file) 199 { 200 enum { 201 H_REQUEST, 202 H_FALLBACK, 203 __H_MAX, 204 }; 205 struct blobmsg_policy policy[__H_MAX] = { 206 [H_REQUEST] = { "request", BLOBMSG_TYPE_ARRAY }, 207 [H_FALLBACK] = { "fallback", BLOBMSG_TYPE_ARRAY }, 208 }; 209 struct blob_attr *tb[__H_MAX]; 210 struct handler *h; 211 212 handler_init(); 213 blob_buf_init(&b, 0); 214 215 if (!blobmsg_add_json_from_file(&b, file)) 216 return -1; 217 218 blobmsg_parse(policy, __H_MAX, tb, blob_data(b.head), blob_len(b.head)); 219 if (!tb[H_REQUEST] && !tb[H_FALLBACK]) 220 return -1; 221 222 h = calloc(1, sizeof(*h)); 223 if (!set_handler(&h->request, tb[H_REQUEST]) || 224 !set_handler(&h->fallback, tb[H_FALLBACK])) { 225 free(h->request); 226 free(h->fallback); 227 free(h); 228 return -1; 229 } 230 231 list_add_tail(&h->list, &handlers); 232 return 0; 233 } 234 235 int uh_handler_run(struct client *cl, char **url, bool fallback) 236 { 237 struct json_script_file *f; 238 struct handler *h; 239 240 cur_client = cl; 241 cur_url = url; 242 cur_vars = NULL; 243 244 handler_ret = 0; 245 246 list_for_each_entry(h, &handlers, list) { 247 f = fallback ? h->fallback : h->request; 248 if (!f) 249 continue; 250 251 blob_buf_init(&b, 0); 252 json_script_run_file(&handler_ctx, f, b.head); 253 if (handler_ctx.abort) 254 break; 255 } 256 257 return handler_ret; 258 } 259
This page was automatically generated by LXR 0.3.1. • OpenWrt