• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/uhttpd/handler.c

  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