1 /* 2 * uhttpd - Tiny single-threaded httpd 3 * 4 * Copyright (C) 2010-2013 Jo-Philipp Wich <xm@subsignal.org> 5 * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org> 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #ifndef __UHTTPD_H 21 #define __UHTTPD_H 22 23 #include <netinet/in.h> 24 #include <limits.h> 25 #include <dirent.h> 26 27 #include <libubox/list.h> 28 #include <libubox/uloop.h> 29 #include <libubox/ustream.h> 30 #include <libubox/blob.h> 31 #include <libubox/utils.h> 32 #ifdef HAVE_UBUS 33 #include <libubus.h> 34 #include <json-c/json.h> 35 #endif 36 #ifdef HAVE_UCODE 37 #include <ucode/vm.h> 38 #endif 39 #ifdef HAVE_TLS 40 #include <libubox/ustream-ssl.h> 41 #endif 42 43 #include "utils.h" 44 45 #define UH_LIMIT_CLIENTS 64 46 47 /* per-request cumulative header limits, aligned with common HTTP server 48 * defaults (Apache LimitRequestFields=100, Node.js max-header-size=16 KiB) */ 49 #define UH_LIMIT_HEADER_COUNT 100 50 #define UH_LIMIT_HEADER_BYTES 16384 51 52 #define __enum_header(_name, _val) HDR_##_name, 53 #define __blobmsg_header(_name, _val) [HDR_##_name] = { .name = #_val, .type = BLOBMSG_TYPE_STRING }, 54 55 struct client; 56 57 struct alias { 58 struct list_head list; 59 char *alias; 60 char *path; 61 }; 62 63 struct lua_prefix { 64 struct list_head list; 65 const char *handler; 66 const char *prefix; 67 void *ctx; 68 }; 69 70 #ifdef HAVE_UCODE 71 struct ucode_prefix { 72 struct list_head list; 73 const char *handler; 74 const char *prefix; 75 uc_vm_t ctx; 76 }; 77 #endif 78 79 struct config { 80 const char *docroot; 81 const char *realm; 82 const char *file; 83 const char *error_handler; 84 const char *cgi_prefix; 85 const char *cgi_docroot_path; 86 const char *cgi_path; 87 const char *ubus_prefix; 88 const char *ubus_socket; 89 const char *dirlist_charset; 90 int no_symlinks; 91 int no_dirlists; 92 int network_timeout; 93 int rfc1918_filter; 94 int tls_redirect; 95 int tcp_keepalive; 96 int max_script_requests; 97 int max_connections; 98 int http_keepalive; 99 int script_timeout; 100 int ubus_noauth; 101 int ubus_cors; 102 int cgi_prefix_len; 103 int events_retry; 104 struct list_head cgi_alias; 105 struct list_head lua_prefix; 106 #ifdef HAVE_UCODE 107 struct list_head ucode_prefix; 108 #endif 109 struct list_head sni_redirect; 110 }; 111 112 struct sni_redirect { 113 struct list_head list; 114 const char *host; 115 const char *url; 116 }; 117 118 struct auth_realm { 119 struct list_head list; 120 const char *path; 121 const char *user; 122 const char *pass; 123 }; 124 125 enum http_method { 126 UH_HTTP_MSG_GET, 127 UH_HTTP_MSG_POST, 128 UH_HTTP_MSG_HEAD, 129 UH_HTTP_MSG_OPTIONS, 130 UH_HTTP_MSG_PUT, 131 UH_HTTP_MSG_PATCH, 132 UH_HTTP_MSG_DELETE, 133 }; 134 135 enum http_version { 136 UH_HTTP_VER_0_9, 137 UH_HTTP_VER_1_0, 138 UH_HTTP_VER_1_1, 139 }; 140 141 enum http_user_agent { 142 UH_UA_UNKNOWN, 143 UH_UA_GECKO, 144 UH_UA_CHROME, 145 UH_UA_SAFARI, 146 UH_UA_MSIE, 147 UH_UA_KONQUEROR, 148 UH_UA_OPERA, 149 UH_UA_MSIE_OLD, 150 UH_UA_MSIE_NEW, 151 }; 152 153 enum chunked_state { 154 CHUNKED_OFF, /* not a chunked request */ 155 CHUNKED_FIRST, /* awaiting the first chunk-size line */ 156 CHUNKED_NEXT, /* awaiting a CRLF-prefixed chunk-size line for a subsequent chunk */ 157 CHUNKED_TRAILER, /* draining the optional trailer section after the terminal chunk */ 158 }; 159 160 struct http_request { 161 enum http_method method; 162 enum http_version version; 163 enum http_user_agent ua; 164 int redirect_status; 165 int content_length; 166 bool expect_cont; 167 bool connection_close; 168 bool disable_chunked; 169 enum chunked_state transfer_chunked; 170 const struct auth_realm *realm; 171 size_t header_count; 172 size_t header_bytes; 173 }; 174 175 enum client_state { 176 CLIENT_STATE_INIT, 177 CLIENT_STATE_HEADER, 178 CLIENT_STATE_DATA, 179 CLIENT_STATE_DONE, 180 CLIENT_STATE_CLOSE, 181 CLIENT_STATE_CLEANUP, 182 }; 183 184 struct interpreter { 185 struct list_head list; 186 const char *path; 187 const char *ext; 188 }; 189 190 struct path_info { 191 const char *root; 192 const char *phys; 193 const char *name; 194 const char *info; 195 const char *query; 196 bool redirected; 197 struct stat stat; 198 const struct interpreter *ip; 199 }; 200 201 struct env_var { 202 const char *name; 203 const char *value; 204 }; 205 206 struct relay { 207 struct ustream_fd sfd; 208 struct uloop_process proc; 209 struct uloop_timeout timeout; 210 struct client *cl; 211 212 bool process_done; 213 bool error; 214 bool skip_data; 215 216 int ret; 217 int header_ofs; 218 219 void (*header_cb)(struct relay *r, const char *name, const char *value); 220 void (*header_end)(struct relay *r); 221 void (*close)(struct relay *r, int ret); 222 }; 223 224 struct dispatch_proc { 225 struct uloop_timeout timeout; 226 struct blob_buf hdr; 227 struct uloop_fd wrfd; 228 struct relay r; 229 int status_code; 230 char status_msg[64]; 231 }; 232 233 struct dispatch_handler { 234 struct list_head list; 235 bool script; 236 237 bool (*check_url)(const char *url); 238 bool (*check_path)(struct path_info *pi, const char *url); 239 void (*handle_request)(struct client *cl, char *url, struct path_info *pi); 240 }; 241 242 #ifdef HAVE_UBUS 243 struct dispatch_ubus { 244 struct ubus_request req; 245 246 struct uloop_timeout timeout; 247 struct json_tokener *jstok; 248 struct json_object *jsobj; 249 struct json_object *jsobj_cur; 250 char *url_path; 251 int post_len; 252 253 uint32_t obj; 254 const char *func; 255 256 struct blob_buf buf; 257 bool req_pending; 258 bool array; 259 int array_idx; 260 bool legacy; /* Got legacy request => use legacy reply */ 261 262 struct ubus_subscriber sub; 263 }; 264 #endif 265 266 struct dispatch { 267 int (*data_send)(struct client *cl, const char *data, int len); 268 void (*data_done)(struct client *cl); 269 void (*write_cb)(struct client *cl); 270 void (*close_fds)(struct client *cl); 271 void (*free)(struct client *cl); 272 273 void *req_data; 274 void (*req_free)(struct client *cl); 275 276 bool data_blocked; 277 bool no_cache; 278 279 union { 280 struct { 281 struct blob_attr **hdr; 282 int fd; 283 } file; 284 struct dispatch_proc proc; 285 #ifdef HAVE_UBUS 286 struct dispatch_ubus ubus; 287 #endif 288 }; 289 }; 290 291 struct client { 292 struct list_head list; 293 int refcount; 294 int id; 295 296 struct ustream *us; 297 struct ustream_fd sfd; 298 #ifdef HAVE_TLS 299 struct ustream_ssl ssl; 300 #endif 301 struct uloop_timeout timeout; 302 int requests; 303 304 enum client_state state; 305 bool tls; 306 307 int http_code; 308 struct http_request request; 309 struct uh_addr srv_addr, peer_addr; 310 311 struct blob_buf hdr; 312 struct blob_buf hdr_response; 313 struct dispatch dispatch; 314 }; 315 316 extern char uh_buf[4096]; 317 extern int n_clients; 318 extern struct config conf; 319 extern const char * const http_versions[]; 320 extern const char * const http_methods[]; 321 extern struct dispatch_handler cgi_dispatch; 322 323 void uh_index_add(const char *filename); 324 325 bool uh_accept_client(int fd, bool tls); 326 327 void uh_unblock_listeners(void); 328 void uh_setup_listeners(void); 329 int uh_socket_bind(const char *host, const char *port, bool tls); 330 331 int uh_first_tls_port(int family); 332 333 bool uh_use_chunked(struct client *cl); 334 void uh_chunk_write(struct client *cl, const void *data, int len); 335 void uh_chunk_vprintf(struct client *cl, const char *format, va_list arg); 336 337 void __printf(2, 3) 338 uh_chunk_printf(struct client *cl, const char *format, ...); 339 340 void uh_chunk_eof(struct client *cl); 341 void uh_request_done(struct client *cl); 342 343 void uh_http_header(struct client *cl, int code, const char *summary); 344 void __printf(4, 5) 345 uh_client_error(struct client *cl, int code, const char *summary, const char *fmt, ...); 346 347 void uh_handle_request(struct client *cl); 348 void client_poll_post_data(struct client *cl); 349 void uh_client_read_cb(struct client *cl); 350 void uh_client_notify_state(struct client *cl); 351 352 void uh_auth_add(const char *path, const char *user, const char *pass); 353 bool uh_auth_check(struct client *cl, const char *path, const char *auth, 354 char **uptr, char **pptr); 355 356 void uh_close_listen_fds(void); 357 void uh_close_fds(void); 358 359 void uh_interpreter_add(const char *ext, const char *path); 360 void uh_dispatch_add(struct dispatch_handler *d); 361 362 void uh_relay_open(struct client *cl, struct relay *r, int fd, int pid); 363 void uh_relay_close(struct relay *r, int ret); 364 void uh_relay_free(struct relay *r); 365 void uh_relay_kill(struct client *cl, struct relay *r); 366 367 struct env_var *uh_get_process_vars(struct client *cl, struct path_info *pi); 368 bool uh_create_process(struct client *cl, struct path_info *pi, char *url, 369 void (*cb)(struct client *cl, struct path_info *pi, char *url)); 370 371 int uh_plugin_init(const char *name); 372 void uh_plugin_post_init(void); 373 374 int uh_handler_add(const char *file); 375 int uh_handler_run(struct client *cl, char **url, bool fallback); 376 377 struct path_info *uh_path_lookup(struct client *cl, const char *url); 378 379 static inline void uh_client_ref(struct client *cl) 380 { 381 cl->refcount++; 382 } 383 384 static inline void uh_client_unref(struct client *cl) 385 { 386 if (--cl->refcount) 387 return; 388 389 if (cl->state == CLIENT_STATE_CLEANUP) 390 ustream_state_change(cl->us); 391 } 392 393 #endif 394
This page was automatically generated by LXR 0.3.1. • OpenWrt