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
[3] = {
45 { .type
= BLOBMSG_TYPE_STRING
},
46 { .type
= BLOBMSG_TYPE_INT32
},
47 { .type
= BLOBMSG_TYPE_STRING
},
49 struct blob_attr
*tb
[3];
50 const char *status
= "Found";
53 blobmsg_parse_array(policy
, ARRAY_SIZE(policy
), tb
, blobmsg_data(data
), blobmsg_data_len(data
));
58 code
= blobmsg_get_u32(tb
[1]);
60 status
= blobmsg_get_string(tb
[2]);
63 uh_http_header(cl
, code
, status
);
64 ustream_printf(cl
->us
, "Content-Length: 0\r\n");
65 ustream_printf(cl
->us
, "Location: %s\r\n\r\n",
66 blobmsg_get_string(tb
[0]));
71 json_script_abort(ctx
);
75 handle_set_uri(struct json_script_ctx
*ctx
, struct blob_attr
*data
)
77 struct client
*cl
= cur_client
;
78 static struct blobmsg_policy policy
= {
79 .type
= BLOBMSG_TYPE_STRING
,
82 struct blob_attr
*old_url
= blob_data(cl
->hdr
.head
);
84 blobmsg_parse_array(&policy
, 1, &tb
, blobmsg_data(data
), blobmsg_data_len(data
));
89 blob_put_raw(&b
, blob_next(old_url
), blob_len(cl
->hdr
.head
) - blob_pad_len(old_url
));
91 /* replace URL in client header cache */
92 blob_buf_init(&cl
->hdr
, 0);
93 blobmsg_add_string(&cl
->hdr
, "URL", blobmsg_get_string(tb
));
94 blob_put_raw(&cl
->hdr
, blob_data(b
.head
), blob_len(b
.head
));
95 *cur_url
= blobmsg_data(blob_data(cl
->hdr
.head
));
101 json_script_abort(ctx
);
105 handle_command(struct json_script_ctx
*ctx
, const char *name
,
106 struct blob_attr
*data
, struct blob_attr
*vars
)
108 static const struct {
110 void (*func
)(struct json_script_ctx
*ctx
, struct blob_attr
*data
);
112 { "redirect", handle_redirect
},
113 { "rewrite", handle_set_uri
}
117 for (i
= 0; i
< ARRAY_SIZE(cmds
); i
++) {
118 if (!strcmp(cmds
[i
].name
, name
)) {
119 cmds
[i
].func(ctx
, data
);
126 handle_var(struct json_script_ctx
*ctx
, const char *name
,
127 struct blob_attr
*vars
)
129 struct client
*cl
= cur_client
;
131 static struct path_info empty_path
;
134 struct path_info
*p
= uh_path_lookup(cl
, *cur_url
);
139 cur_vars
= uh_get_process_vars(cl
, p
);
142 for (cur
= cur_vars
; cur
->name
; cur
++) {
143 if (!strcmp(cur
->name
, name
))
152 if (handler_ctx
.handle_command
)
155 json_script_init(&handler_ctx
);
156 handler_ctx
.handle_command
= handle_command
;
157 handler_ctx
.handle_var
= handle_var
;
160 static bool set_handler(struct json_script_file
**dest
, struct blob_attr
*data
)
165 *dest
= json_script_file_from_blobmsg(NULL
, blobmsg_data(data
), blobmsg_data_len(data
));
169 int uh_handler_add(const char *file
)
176 struct blobmsg_policy policy
[__H_MAX
] = {
177 [H_REQUEST
] = { "request", BLOBMSG_TYPE_ARRAY
},
178 [H_FALLBACK
] = { "fallback", BLOBMSG_TYPE_ARRAY
},
180 struct blob_attr
*tb
[__H_MAX
];
184 blob_buf_init(&b
, 0);
186 if (!blobmsg_add_json_from_file(&b
, file
))
189 blobmsg_parse(policy
, __H_MAX
, tb
, blob_data(b
.head
), blob_len(b
.head
));
190 if (!tb
[H_REQUEST
] && !tb
[H_FALLBACK
])
193 h
= calloc(1, sizeof(*h
));
194 if (!set_handler(&h
->request
, tb
[H_REQUEST
]) ||
195 !set_handler(&h
->fallback
, tb
[H_FALLBACK
])) {
202 list_add_tail(&h
->list
, &handlers
);
206 int uh_handler_run(struct client
*cl
, char **url
, bool fallback
)
208 struct json_script_file
*f
;
217 list_for_each_entry(h
, &handlers
, list
) {
218 f
= fallback
? h
->fallback
: h
->request
;
222 blob_buf_init(&b
, 0);
223 json_script_run_file(&handler_ctx
, f
, b
.head
);
224 if (handler_ctx
.abort
)