#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include union any; struct vec; struct str; struct circbuf; struct vstream; struct dirbase; struct list; struct key_value; struct node_kv; struct hashtable; struct opt; struct deq; struct thunk; struct err; struct error_handler; struct buffer; struct proc; struct timeout; struct io_epoll; struct scheduler; struct shuttle; struct sock; struct shuttle_buffer; struct shuttle_sock_p; struct type; struct cache_item; struct listener_try; struct reader_try; struct writer_try; struct httpd_launcher; struct httpd; typedef union any any; typedef struct vec vec; typedef struct str str; typedef struct circbuf circbuf; typedef struct vstream vstream; typedef struct dirbase dirbase; typedef struct list list; typedef struct key_value key_value; typedef struct node_kv node_kv; typedef struct hashtable hashtable; typedef struct opt opt; typedef struct deq deq; typedef struct thunk thunk; typedef struct err err; typedef struct error_handler error_handler; typedef struct buffer buffer; typedef struct proc proc; typedef struct timeout timeout; typedef struct io_epoll io_epoll; typedef struct scheduler scheduler; typedef struct shuttle shuttle; typedef struct sock sock; typedef struct shuttle_buffer shuttle_buffer; typedef struct shuttle_sock_p shuttle_sock_p; typedef struct type type; typedef struct cache_item cache_item; typedef struct listener_try listener_try; typedef struct reader_try reader_try; typedef struct writer_try writer_try; typedef struct httpd_launcher httpd_launcher; typedef struct httpd httpd; typedef double num; typedef unsigned char boolean; typedef char *cstr; typedef struct timeval timeval; typedef void *ptr; typedef void (*sighandler_t)(int); typedef struct passwd passwd; typedef struct spwd spwd; typedef struct epoll_event epoll_event; typedef void (*vs_putc_t)(int c, vstream *vs); typedef int (*vs_getc_t)(vstream *vs); typedef int (*vs_printf_t)(vstream *vs, const char *format, va_list ap); typedef char *(*vs_gets_t)(char *s, int size, vstream *vs); typedef void (*vs_write_t)(const void *ptr, size_t size, size_t nmemb, vstream *vs); typedef size_t (*vs_read_t)(void *ptr, size_t size, size_t nmemb, vstream *vs); typedef void (*vs_flush_t)(vstream *vs); typedef void (*vs_close_t)(vstream *vs); typedef void (*vs_shutdown_t)(vstream *vs, int how); typedef struct sockaddr sockaddr; typedef struct sockaddr_in sockaddr_in; typedef struct in_addr in_addr; typedef struct hostent hostent; typedef struct dirent dirent; typedef struct stat stats; typedef struct stat Stats; typedef int (*cmp_t)(const void *, const void *); typedef unsigned long hash_func(void *key); typedef boolean eq_func(void *k1, void *k2); typedef void *(*thunk_func)(void *obj, void *common_arg, void *specific_arg); typedef enum { OE_CONT, OE_ERRCODE, OE_ERROR, OE_WARN=1<<31 } opt_err; typedef vec priq; typedef int (*proc_func)(proc *p); typedef proc *proc_p; typedef priq timeouts; typedef timeout *timeout_p; typedef sock *sock_p; typedef listener_try listener_tcp; typedef enum { HTTP_GET, HTTP_HEAD, HTTP_POST, HTTP_PUT, HTTP_DELETE, HTTP_INVALID } http__method; typedef enum { TYPE_VOID, TYPE_INT, TYPE_FLOAT, TYPE_POINT, TYPE_ARRAY, TYPE_STRUCT, TYPE_UNION, TYPE_FUNC, TYPE_DEF } type_t; union any { void *p; char *cs; char c; short s; int i; long l; long long ll; float f; double d; long double ld; size_t z; off_t o; }; struct buffer { char *start; char *end; char *space_end; }; struct vec { buffer b; ssize_t element_size; ssize_t space; ssize_t size; }; struct str { char *start; char *end; }; struct circbuf { ssize_t size; ssize_t space; ssize_t start; char *data; }; struct vstream { vs_putc_t putc; vs_getc_t getc; vs_printf_t printf; vs_gets_t gets; vs_write_t write; vs_read_t read; vs_flush_t flush; vs_close_t close; vs_shutdown_t shutdown; void *data; }; struct dirbase { cstr dir; cstr base; }; struct list { list *next; }; struct key_value { void *k; void *v; }; struct node_kv { list l; key_value kv; }; struct hashtable { list *buckets; size_t size; hash_func *hash; eq_func *eq; }; struct opt { cstr name; cstr *arg; }; struct deq { circbuf b; ssize_t element_size; ssize_t space; ssize_t size; ssize_t start; }; struct thunk { thunk_func func; void *obj; void *common_arg; }; struct err { cstr msg; int no; void *data; }; struct error_handler { jmp_buf *jump; thunk handler; int err; }; struct proc { proc_func f; int pc; }; struct timeout { num time; thunk handler; int i; }; struct io_epoll { int epfd; int max_fd_plus_1; int count; vec *events; }; struct scheduler { int exit; deq q; io_epoll io; vec readers; vec writers; num now; timeouts tos; hashtable children; int step; int n_children; int got_sigchld; }; struct shuttle { proc *current; proc *other; enum { ACTIVE, WAITING, GONE } other_state; }; struct sock { int fd; sockaddr *sa; socklen_t len; }; struct shuttle_buffer { shuttle sh; buffer d; }; struct shuttle_sock_p { shuttle sh; sock_p d; }; struct type { type_t type; cstr name; long size; }; struct cache_item { time_t mtime; buffer body; }; struct listener_try { proc p; int listen_fd; socklen_t socklen; shuttle_sock_p *out; sock_p s; }; struct reader_try { proc p; int fd; size_t block_size; boolean sel_first; shuttle_buffer *out; boolean done; }; struct writer_try { proc p; int fd; boolean sel_first; shuttle_buffer *in; boolean done; }; struct httpd_launcher { proc p; shuttle_sock_p *in; sock_p sk; httpd *s; }; struct httpd { proc p; sock *sk; shuttle_buffer *in; shuttle_buffer *out; shuttle_buffer *fio; int fd; reader_try r; writer_try w; reader_try fr; writer_try fw; sockaddr_in sockname; socklen_t namelen; cstr scheme; in_addr server_addr; cstr server_addr_str; int server_port; in_addr remote_addr; cstr remote_addr_str; int remote_port; shuttle_buffer struct__my__5899_sh; shuttle_buffer *my__5899_sh; shuttle_buffer struct__my__5912_sh; shuttle_buffer *my__5912_sh; cstr s; char *c; size_t l; cstr method_str; http__method method; cstr url; cstr proto; cstr host; cstr path; cstr root; cstr fullpath; cstr query; cstr user; cstr pass; off_t reqlen; int file_fd; passwd *u; int code; cstr msg; cstr location; int private; int expire_already; cstr user_agent; boolean keep_alive; boolean statable; Stats struct__st; Stats *st; boolean http1_1; cstr body; time_t mtime; cstr mtype; int status; boolean range_req; long long int byte0; long long int byte1; boolean content_range_req; long long int cr_byte0; long long int cr_byte1; off_t fullsize; off_t size; off_t offset; ssize_t count; int line_start; vec struct__headers; vec *headers; buffer struct__base64; buffer *base64; buffer struct__o; buffer *o; cstr base; cstr ext; boolean is_php; shuttle_buffer struct__my__6171_sh; shuttle_buffer *my__6171_sh; buffer out_tmp; buffer bwrite_direct__saved_buffer; boolean in_cache; cache_item *citem; buffer struct__b0; buffer *b0; buffer struct__b1; buffer *b1; }; void vec_init_el_size(vec *v, ssize_t element_size, ssize_t space); void vec_clear(vec *v); void vec_free(vec *v); void vec_space(vec *v, ssize_t space); void vec_size(vec *v, ssize_t size); void vec_double(vec *v); void vec_squeeze(vec *v); void *vec_element(vec *v, ssize_t index); void *vec_top(vec *v, ssize_t index); void *vec_push(vec *v); void vec_pop(vec *v); void vec_ensure_size(vec *v, ssize_t size); void *vec_to_array(vec *v); void cstr_dos_to_unix(cstr s); boolean cstr_eq(void *s1, void *s2); boolean cstr_ends_with(cstr s, cstr substr); cstr cstr_begins_with(cstr s, cstr substr); cstr cstr_chop_start(cstr c, cstr start); void splitv(vec *v, cstr s, char c); void splitv1(vec *v, cstr s, char c); cstr *split(cstr s, char c); cstr *splitn(cstr s, char c, int n); void splitvn(vec *v, cstr s, char c, int n); void splitvn1(vec *v, cstr s, char c, int n); char *Strchr(const char *s, int c); size_t strlcpy(char *dst, char *src, size_t size); pid_t Fork(void); pid_t Waitpid(pid_t pid, int *status, int options); pid_t Child_done(void); int auth(passwd *pw, cstr pass); hashtable *load_passwd(void); passwd *passwd_dup(passwd *_p); struct passwd *Getpwent(void); struct spwd *Getspent(void); void Setuid(uid_t uid); void Setgid(gid_t gid); void Seteuid(uid_t euid); void Setegid(gid_t egid); sighandler_t sigact(int signum, sighandler_t handler, int sa_flags); void Sigprocmask(int how, const sigset_t *set, sigset_t *oldset); sigset_t Sig_defer(int signum); sigset_t Sig_pass(int signum); sigset_t Sig_mask(int signum, int defer); sigset_t Sig_setmask(sigset_t *set); void Nice(int inc); void exit_exec_failed(void); void Exit(int status); void Execv(const char *path, char *const argv[]); void Execvp(const char *file, char *const argv[]); static void exec_argv_do_init(void); void Execl(const char *path, ...); void Vexecl(const char *path, va_list ap); void Execlp(const char *file, ...); void Vexeclp(const char *file, va_list ap); void sh_quote(const char *from, buffer *to); sighandler_t Sigact(int signum, sighandler_t handler, int sa_flags); void Raise(int sig); int fix_exit_status(int status); void q_init(void); cstr q(const char *s); cstr x(cstr command); void cork(int fd, int cork); int Epoll_create(int size); int Epoll_pwait(int epfd, struct epoll_event *events, int maxevents, num timeout, const sigset_t *sigmask); void circbuf_init(circbuf *b, ssize_t space); void circbuf_set_space(circbuf *b, ssize_t space); void circbuf_clear(circbuf *b); void vstream_init_stdio(vstream *vs, FILE *s); void vs_putc_stdio(int c, vstream *vs); int vs_getc_stdio(vstream *vs); int vs_printf_stdio(vstream *vs, const char *format, va_list ap); char *vs_gets_stdio(char *s, int size, vstream *vs); void vs_write_stdio(const void *ptr, size_t size, size_t nmemb, vstream *vs); size_t vs_read_stdio(void *ptr, size_t size, size_t nmemb, vstream *vs); void vs_flush_stdio(vstream *vs); void vs_close_stdio(vstream *vs); void vs_shutdown_stdio(vstream *vs, int how); void vstreams_init(void); void vstream_init_buffer(vstream *vs, buffer *b); void vs_putc_buffer(int c, vstream *vs); int vs_getc_buffer(vstream *vs); int vs_printf_buffer(vstream *vs, const char *format, va_list ap); char *vs_gets_buffer(char *s, int size, vstream *vs); void vs_write_buffer(const void *ptr, size_t size, size_t nmemb, vstream *vs); size_t vs_read_buffer(void *ptr, size_t size, size_t nmemb, vstream *vs); void vs_flush_buffer(vstream *vs); void vs_close_buffer(vstream *vs); void vs_shutdown_buffer(vstream *vs, int how); void vs_putc(int c); int vs_getc(void); char *vs_gets(char *s, int size); int rl(buffer *b); dirbase dirbasename(cstr path); cstr dir_name(cstr path); cstr base_name(cstr path); cstr path_relative_to(cstr path, cstr origin); cstr path_tidy(cstr path); cstr path_under(cstr parent, cstr child); cstr path_under_maybe(cstr parent, cstr child); cstr which(cstr file); cstr Which(cstr file); char *Getenv(const char *name, char *_default); void Putenv(char *string); void Setenv(const char *name, const char *value, int overwrite); void Clearenv(void); num rtime(void); void Gettimeofday(struct timeval *tv); void rtime_to_timeval(num rtime, struct timeval *tv); num timeval_to_rtime(const struct timeval *tv); int rtime_to_ms(num rtime); int delay_to_ms(num delay); void date_rfc1123_init(void); char *date_rfc1123(time_t t); void nonblock(int fd, int nb); void Fcntl_setfd(int fd, long arg); void cloexec(int fd); int Socket(int domain, int type, int protocol); void Bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen); void Listen(int sockfd, int backlog); void Sockaddr_in(struct sockaddr_in *sa, char *addr, int port); hostent *Gethostbyname(const char *name); cstr name_to_ip(const char *name); int Server_tcp(char *addr, int port); void Setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen); void Shutdown(int s, int how); void keepalive(int fd, int keepalive); void nodelay(int fd, int nodelay); void reuseaddr(int fd, int reuseaddr); void Getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen); int Getsockerr(int fd); void Close(int fd); ssize_t Read_some(int fd, void *buf, size_t count); ssize_t Read(int fd, void *buf, size_t count); void fslurp_2(FILE *s, buffer *b); buffer *fslurp_1(FILE *s); FILE *Fopen(const char *path, const char *mode); void Fclose(FILE *fp); char *Fgets(char *s, int size, FILE *stream); int Vfprintf(FILE *stream, const char *format, va_list ap); void Fflush(FILE *stream); vec *ls(const char *name, boolean all); vec *ls_(const char *name, boolean all, vec *v); int exists(const char *file_name); int Stat(const char *file_name, struct stat *buf); void Fstat(int filedes, struct stat *buf); void Stats_init(stats *s, const char *file_name); int Lstat(const char *file_name, struct stat *buf); FILE *Popen(const char *command, const char *type); int Pclose(FILE *stream); int Fgetc(FILE *stream); void Fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); size_t Fread(void *ptr, size_t size, size_t nmemb, FILE *stream); void Fputc(int c, FILE *stream); off_t Lseek(int fd, off_t offset, int whence); void Ftruncate(int fd, off_t length); void _Readlink(const char *path, buffer *b); cstr Readlink(const char *path); cstr readlinks(cstr path, opt_err if_dead); void _Getcwd(buffer *b); cstr Getcwd(void); int Dup2(int oldfd, int newfd); mode_t mode(const char *file_name); void fd_set_init(fd_set *o); int can_read(int fd, num timeout); int can_write(int fd, num timeout); int has_error(int fd, num timeout); ssize_t Writev(int fd, const struct iovec *iov, int iovcnt); int Fileno(FILE *stream); void list_init(list *l); size_t arylen(void *_p); vec *sort_vec(vec *v, cmp_t cmp); int cstr_cmp(const void *_a, const void *_b); int imax(int x, int y); void seed(void); num rmod(num r, num base); void hashtable_init(hashtable *ht, hash_func *hash, eq_func *eq, size_t size); list *alloc_buckets(size_t size); list *hashtable_lookup_ref(hashtable *ht, void *key); key_value *hashtable_lookup(hashtable *ht, void *key); key_value *hashtable_ref_lookup(list *l); void *hashtable_value(hashtable *ht, void *key); void *hashtable_value_or_null(hashtable *ht, void *key); void *hashtable_value_or(hashtable *ht, void *key, void *def); key_value *hashtable_add(hashtable *ht, void *key, void *value); void hashtable_ref_add(list *l, void *key, void *value); boolean hashtable_ref_add_maybe(list *l, void *key, void *value); key_value hashtable_delete(hashtable *ht, void *key); key_value hashtable_ref_delete(list *l); node_kv *hashtable_ref_node(list *l); boolean hashtable_ref_exists(list *l); key_value *hashtable_ref_key_value(list *l); list *which_bucket(hashtable *ht, void *key); size_t hashtable_sensible_size(size_t size); unsigned long cstr_hash(void *s); key_value *hashtable_lookup_or_add_key(hashtable *ht, void *key, void *value_init); unsigned long int_hash(void *i_ptr); boolean int_eq(void *a, void *b); void sym_init(void); cstr sym(cstr s); void main__init(int _argc, char *_argv[]); void _deq_init(deq *q, ssize_t element_size, ssize_t space); void deq_space(deq *q, ssize_t space); void deq_clear(deq *q); void deq_double(deq *q); void *deq_element(deq *q, ssize_t index); void *deq_push(deq *q); void deq_shift(deq *q); void error(const char *format, ...); void verror(const char *format, va_list ap); void serror(const char *format, ...); void vserror(const char *format, va_list ap); void warn(const char *format, ...); void vwarn(const char *format, va_list ap); void failed(const char *funcname); void failed2(const char *funcname, const char *errmsg); void failed3(const char *funcname, const char *msg1, const char *msg2); void warn_failed(const char *funcname); void swarning(const char *format, ...); void vswarning(const char *format, va_list ap); void error_init(void); err *error_add(cstr msg, int no, void *data); void Throw(cstr msg, int no, void *data); void throw_(err *e); void die_errors(int status); void clear_errors(void); void warn_errors(void); void warn_errors_keep(void); void fault_(char *file, int line, const char *format, ...); void vfault_(char *file, int line, const char *format, va_list ap); cstr Strerror(int errnum); void Perror(const char *s); any opt_err_do(opt_err opt, any value, any errcode, char *format, ...); any vopt_err_do(opt_err opt, any value, any errcode, char *format, va_list ap); void *normal_Malloc(size_t size); void *normal_Realloc(void *ptr, size_t size); void *normal_Calloc(size_t nmemb, size_t size); cstr normal_Strdup(const char *s); char *normal_Strndup(const char *s, size_t n); void buffer_init(buffer *b, size_t space); void buffer_free(buffer *b); void buffer_set_space(buffer *b, size_t space); void buffer_set_size(buffer *b, size_t size); void buffer_double(buffer *b); void buffer_squeeze(buffer *b); void buffer_cat_char(buffer *b, char c); void buffer_cat_cstr(buffer *b, const char *s); void buffer_cat_range(buffer *b, const char *start, const char *end); void buffer_grow(buffer *b, size_t delta_size); void buffer_clear(buffer *b); char buffer_first_char(buffer *b); int Sprintf(buffer *b, const char *format, ...); cstr format(const char *format, ...); cstr vformat(const char *format, va_list ap); int Vsnprintf(char *buf, size_t size, const char *format, va_list ap); int Vsprintf(buffer *b, const char *format, va_list ap); char *buffer_add_nul(buffer *b); char *buffer_nul_terminate(buffer *b); cstr buffer_to_cstr(buffer *b); void buffer_from_cstr(buffer *b, cstr s, size_t len); void buffer_shift(buffer *b, size_t shift); void buffer_ensure_space(buffer *b, size_t space); void buffer_ensure_free(buffer *b, ssize_t free); boolean sched_sig_child_exited(sigset_t *oldsigmask); boolean sched_sig_child_exited_2(sigset_t *oldsigmask); void proc_init(proc *p, proc_func f); int resume(proc *p); timeout *timeouts_next(timeouts *q); void timeouts_shift(timeouts *q); void timeouts_call(timeouts *timeouts, num time); num timeouts_delay(timeouts *timeouts, num time); void io_epoll_init(io_epoll *io); int io_epoll_wait(io_epoll *io, num delay, sigset_t *sigmask); int io_epoll_add(io_epoll *io, int fd, boolean et); void io_epoll_rm(io_epoll *io, int fd); void scheduler_init(scheduler *sched); void start_f(proc *p); void run(void); void step(void); int scheduler_add_fd(scheduler *sched, int fd, int et); void set_reader(int fd, proc *p); void set_writer(int fd, proc *p); void clr_reader(int fd); void clr_writer(int fd); void set_waitchild(pid_t pid, proc *p); void clr_waitchild(pid_t pid); void sigchld_handler(int signum); num sched_get_time(void); void sched_forget_time(void); void sched_set_time(void); void shuttle_init(shuttle *sh, proc *p1, proc *p2); boolean pull_f(shuttle *s, proc *p); void push_f(shuttle *s, proc *p); void sock_init(sock *s, socklen_t socklen); void sock_free(sock *s); in_addr sock_in_addr(sock *s); u_int16_t sock_in_port(sock *s); void listener_tcp_init(listener_try *p, cstr listen_addr, int listen_port); void listener_try_init(listener_try *d, int listen_fd, socklen_t socklen); int listener_try_f(proc *b__p); void reader_try_init(reader_try *d, int fd, size_t block_size, boolean sel_first); int reader_try_f(proc *b__p); void writer_try_init(writer_try *d, int fd, boolean sel_first); int writer_try_f(proc *b__p); void url_decode(cstr q); cstr get_host_from_url(cstr url); cstr get_path_from_url(cstr url); void base64_decode_buffers(buffer *i, buffer *o); void base64_decode(void); http__method http_which_method(cstr method); void mimetypes_init(void); void load_mimetypes_vio(void); cstr mimetype(cstr ext); int main(int main__argc, char *main__argv[]); void term_handler(int sig); void usr1_handler(int sig); void httpd_launcher_init(httpd_launcher *d); int httpd_launcher_f(proc *b__p); void httpd_init(httpd *d, sock *sk); int httpd_f(proc *b__p); void text_mimetypes(void); extern int sig_execfailed; extern int passwd_n_buckets; extern int exit__execfailed; extern int status__execfailed; extern boolean process__forked; extern boolean process__fork_fflush; extern boolean process__exit_fflush; extern boolean exec__warn_fail; static int exec_argv_init; extern vec *q_vec; extern char *env__required; extern int listen_backlog; extern size_t block_size; extern fd_set *tmp_fd_set; extern const num e; extern key_value kv_null; extern size_t syms_n_buckets; extern hashtable *syms; extern const boolean mingw; extern int exit__error; extern int exit__fault; extern int throw_faults; extern int io_epoll_size; extern int io_epoll_maxevents; extern epoll_event io_epoll_rm__event; extern num sched_delay; extern int sched_busy; extern int sched__children_n_buckets; extern scheduler struct__sched, *sched; extern int max_line_length; extern const char *base64_encode_map; extern char *base64_decode_map; extern cstr mimetypes_file; extern size_t mimetypes_n_buckets; extern hashtable struct__mimetypes, *mimetypes; extern cstr version; extern cstr listen_addr; extern int listen_port; extern cstr listen_addr_stunnel; extern int listen_port_stunnel; extern int listen_port_ssl; extern cstr www_root; extern cstr default_user; extern cstr default_host; extern cstr server_admin; extern cstr index_files[]; extern int n_servers; extern hashtable _cache, *cache; extern int cache_n_buckets; extern off_t cache_max_entry_size; static vec exec_argv; int wait__status; vec struct__q_vec; vstream struct__in, *in; vstream struct__out, *out; vstream struct__er, *er; hashtable syms__struct; int argc; int args; char **argv; char *program_full; char *program_real; char *program; char *program_dir; char **arg; char *main_dir; vec *error_handlers; vec *errors; hashtable *extra_error_messages; pid_t waitchild__pid; int waitchild__status; int server_i; hashtable *users; passwd *defu; int sig_execfailed = SIGUSR2; int passwd_n_buckets = 1009; int exit__execfailed = 127; int status__execfailed = 512 + 127; boolean process__forked = 0; boolean process__fork_fflush = 1; boolean process__exit_fflush = 1; boolean exec__warn_fail = 1; static int exec_argv_init = 0; vec *q_vec = NULL; char *env__required = (char *)-1; int listen_backlog = SOMAXCONN; size_t block_size = 1024; fd_set *tmp_fd_set = NULL; const num e = M_E; key_value kv_null = { ((void*)(intptr_t)(-1)), ((void*)(intptr_t)(-1)) }; size_t syms_n_buckets = 1021; hashtable *syms = NULL; const boolean mingw = 0; int exit__error = 125; int exit__fault = 124; int throw_faults = 0; int io_epoll_size = 1024; int io_epoll_maxevents = 1024; epoll_event io_epoll_rm__event = { 0, { .u64 = 0 } }; num sched_delay = 0; int sched_busy = 16; int sched__children_n_buckets = 1009; scheduler struct__sched, *sched = &struct__sched; int max_line_length = 0; const char *base64_encode_map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; char *base64_decode_map = NULL; cstr mimetypes_file = "/etc/mime.types"; size_t mimetypes_n_buckets = 1009; hashtable struct__mimetypes, *mimetypes = NULL; cstr version = "0"; cstr listen_addr = "0.0.0.0"; int listen_port = 80; cstr listen_addr_stunnel = "127.0.0.1"; int listen_port_stunnel = 81; int listen_port_ssl = 443; cstr www_root = "/www"; cstr default_user = "www-data"; cstr default_host = "default"; cstr server_admin = "sam@nipl.net"; cstr index_files[] = { "index.html", "index.cgi", "index.php", NULL }; int n_servers = 2; hashtable _cache, *cache = &_cache; int cache_n_buckets = 1009; off_t cache_max_entry_size = 4096; void vec_init_el_size(vec *v, ssize_t element_size, ssize_t space) { v->space = space ? space : 1; buffer_init(&v->b, v->space * element_size); v->element_size = element_size; v->size = 0; } void vec_clear(vec *v) { buffer_clear(&v->b); v->size = 0; } void vec_free(vec *v) { buffer_free(&v->b); } void vec_space(vec *v, ssize_t space) { v->space = space ? space : 1; buffer_set_space(&v->b, v->space * v->element_size); } void vec_size(vec *v, ssize_t size) { ssize_t cap = v->space; if(size > cap) { do { cap *= 2; } while(size > cap); vec_space(v, cap); } v->size = size; buffer_set_size(&v->b, size * v->element_size); } void vec_double(vec *v) { vec_space(v, v->space * 2); } void vec_squeeze(vec *v) { vec_space(v, v->size); } void *vec_element(vec *v, ssize_t index) { return v->b.start + index * v->element_size; } void *vec_top(vec *v, ssize_t index) { return vec_element(v, v->size - 1 - index); } void *vec_push(vec *v) { if(v->size == v->space) { vec_double(v); } ++v->size; buffer_grow(&v->b, v->element_size); return vec_element(v, v->size-1); } void vec_pop(vec *v) { --v->size; buffer_grow(&v->b, - v->element_size); } void vec_ensure_size(vec *v, ssize_t size) { if((v->size) < size) { vec_size(v, size); } } void *vec_to_array(vec *v) { *(typeof(NULL) *)vec_push(v) = NULL; vec_squeeze(v); vec_pop(v); return (vec_element(v, 0)); } void cstr_dos_to_unix(cstr s) { cstr p1, p2; for(p1=p2=s; *p1 != '\0'; ++p1) { if(*p1 != '\r') { *p2 = *p1; ++p2; } } *p2 = '\0'; } boolean cstr_eq(void *s1, void *s2) { return strcmp(s1, s2) == 0; } boolean cstr_ends_with(cstr s, cstr substr) { size_t s_len = strlen(s); size_t substr_len = strlen(substr); if(substr_len > s_len) { return 0; } cstr expect = s + s_len - substr_len; return cstr_eq(expect, substr); } cstr cstr_begins_with(cstr s, cstr substr) { while(1) { if(*substr == '\0') { return (cstr)s; } if(*substr != *s) { return NULL; } ++s; ++substr; } } cstr cstr_chop_start(cstr c, cstr start) { int len = strlen(start); memmove(c, start, len); c[len] = '\0'; return c; } void splitv(vec *v, cstr s, char c) { if(*s) { splitv1(v, s, c); } } void splitv1(vec *v, cstr s, char c) { *(typeof(s) *)vec_push(v) = s; char *i; for(i=s; *i != '\0'; ++i) { if(*i == c) { *i = '\0'; *(typeof((i+1)) *)vec_push(v) = (i+1); } } } cstr *split(cstr s, char c) { vec struct__v; vec *v = &struct__v; vec_init_el_size(v, sizeof(cstr), (16)); splitv(v, s, c); return vec_to_array(v); } cstr *splitn(cstr s, char c, int n) { vec struct__v; vec *v = &struct__v; vec_init_el_size(v, sizeof(cstr), (16)); splitvn(v, s, c, n); return vec_to_array(v); } void splitvn(vec *v, cstr s, char c, int n) { if(*s) { splitvn1(v, s, c, n); } } void splitvn1(vec *v, cstr s, char c, int n) { *(typeof(s) *)vec_push(v) = s; if(--n) { char *i; for(i=s; *i != '\0'; ++i) { if(*i == c) { *i = '\0'; *(typeof((i+1)) *)vec_push(v) = (i+1); if(--n == 0) { break; } } } } } char *Strchr(const char *s, int c) { char *rv = strchr(s, c); if(!rv) { error("%s failed", "strchr"); } return rv; } size_t strlcpy(char *dst, char *src, size_t size) { if(size == 0) { return strlen(src); } char *src0 = src; do { if((*dst++ = *src++) == 0) { break; } } while(--size); if(src[-1]) { dst[-1] = '\0'; while(*src++) { } } return src - src0 - 1; } pid_t Fork(void) { if(process__fork_fflush) { Fflush(NULL); } pid_t pid = fork(); if(pid == -1) { failed("fork"); } else if(pid == 0) { process__forked = 1; } return pid; } pid_t Waitpid(pid_t pid, int *status, int options) { pid_t r_pid; while(1) { r_pid = waitpid(pid, status, options); if(r_pid == -1) { if(errno != EINTR) { failed("waitpid"); } } else { return r_pid; } } } pid_t Child_done(void) { pid_t pid = Waitpid(-1, &wait__status, WNOHANG); if(pid) { wait__status = fix_exit_status(wait__status); } return pid; } int auth(passwd *pw, cstr pass) { char *x = pw->pw_passwd; char salt[64]; char *dollar = strrchr(x, '$'); if(!dollar) { return 0; } int l = dollar - x; if(1 && !(l < (int)sizeof(salt))) { fault_(__FILE__, __LINE__, "auth: salt too long"); } strlcpy(salt, x, l+1); salt[l] = '\0'; return cstr_eq(x, crypt(pass, salt)) && !cstr_eq(pw->pw_shell, "/bin/false"); } hashtable *load_passwd(void) { hashtable *ht; ht = ((hashtable *)(normal_Malloc((sizeof(hashtable))))); hashtable_init(ht, cstr_hash, cstr_eq, passwd_n_buckets); passwd *p; while((p = Getpwent())) { p = passwd_dup(p); (hashtable_add(ht, ((void*)(intptr_t)(p->pw_name)), ((void*)(intptr_t)p))); } endpwent(); spwd *s; while((s = Getspent())) { passwd *p = (hashtable_value_or_null(ht, ((void*)(intptr_t)(s->sp_namp)))); ((free((p->pw_passwd))), (p->pw_passwd) = NULL); p->pw_passwd = (normal_Strdup((s->sp_pwdp))); } endspent(); return ht; } passwd *passwd_dup(passwd *_p) { passwd *p = ((passwd *)(normal_Malloc((sizeof(passwd))))); *p = *_p; p->pw_name = (normal_Strdup((p->pw_name))); p->pw_passwd = (normal_Strdup((p->pw_passwd))); p->pw_gecos = (normal_Strdup((p->pw_gecos))); p->pw_dir = (normal_Strdup((p->pw_dir))); p->pw_shell = (normal_Strdup((p->pw_shell))); return p; } struct passwd *Getpwent(void) { struct passwd *rv; errno = 0; rv = getpwent(); if(!rv && errno) { failed("getpwent"); } return rv; } struct spwd *Getspent(void) { struct spwd *rv; errno = 0; rv = getspent(); if(!rv && errno) { failed("getspent"); } return rv; } void Setuid(uid_t uid) { if(setuid(uid)) { failed("setuid"); } } void Setgid(gid_t gid) { if(setgid(gid)) { failed("setgid"); } } void Seteuid(uid_t euid) { if(seteuid(euid)) { failed("seteuid"); } } void Setegid(gid_t egid) { if(setegid(egid)) { failed("setegid"); } } sighandler_t sigact(int signum, sighandler_t handler, int sa_flags) { struct sigaction act, oldact; act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = sa_flags; if(sigaction(signum, &act, &oldact) < 0) { return SIG_ERR; } return oldact.sa_handler; } void Sigprocmask(int how, const sigset_t *set, sigset_t *oldset) { if(sigprocmask(how, set, oldset)) { failed("sigprocmask"); } } sigset_t Sig_defer(int signum) { return Sig_mask(signum, 1); } sigset_t Sig_pass(int signum) { return Sig_mask(signum, 0); } sigset_t Sig_mask(int signum, int defer) { sigset_t set; sigset_t oldset; sigemptyset(&set); sigaddset(&set, signum); Sigprocmask(defer ? SIG_BLOCK : SIG_UNBLOCK, &set, &oldset); return oldset; } sigset_t Sig_setmask(sigset_t *set) { sigset_t oldset; Sigprocmask(SIG_SETMASK, set, &oldset); return oldset; } void Nice(int inc) { errno = 0; if(nice(inc) == -1 && errno) { failed("nice"); } } void exit_exec_failed(void) { if(sig_execfailed) { (Sigact(sig_execfailed, SIG_DFL, 0)); Sig_pass(sig_execfailed); Raise(sig_execfailed); } Exit(exit__execfailed); } void Exit(int status) { if(process__forked) { if(process__exit_fflush) { Fflush(NULL); } _Exit(status); } exit(status); } void Execv(const char *path, char *const argv[]) { execv(path, argv); if(exec__warn_fail) { warn_failed("execv"); } exit_exec_failed(); } void Execvp(const char *file, char *const argv[]) { execvp(file, argv); if(exec__warn_fail) { warn_failed("execvp"); } exit_exec_failed(); } static void exec_argv_do_init(void) { vec_init_el_size(&exec_argv, sizeof(cstr), (10)); exec_argv_init = 1; } void Execl(const char *path, ...) { va_list ap; va_start(ap, path); Vexecl(path, ap); va_end(ap); } void Vexecl(const char *path, va_list ap) { if(!exec_argv_init) { exec_argv_do_init(); } vec_clear(&exec_argv); while(1) { char *arg = va_arg(ap, char *); if(arg == NULL) { break; } *(char **)vec_push(&exec_argv) = arg; } Execv(path, (char *const *)vec_to_array(&exec_argv)); } void Execlp(const char *file, ...) { va_list ap; va_start(ap, file); Vexeclp(file, ap); va_end(ap); } void Vexeclp(const char *file, va_list ap) { if(!exec_argv_init) { exec_argv_do_init(); } vec_clear(&exec_argv); while(1) { char *arg = va_arg(ap, char *); if(arg == NULL) { break; } *(char **)vec_push(&exec_argv) = arg; } Execvp(file, (char *const *)vec_to_array(&exec_argv)); } void sh_quote(const char *from, buffer *to) { char c; int i = ((ssize_t)((to->end)-(to->start))); while(1) { c = *from; if(c == '\0') { break; } if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || strchr("-_./", c) != NULL) { buffer_set_size(to, i+1); to->start[i] = c; ++i; } else if(c == '\n') { buffer_set_size(to, i+3); to->start[i] = '"'; to->start[i+1] = c; to->start[i+2] = '"'; i += 3; } else { buffer_set_size(to, i+2); to->start[i] = '\\'; to->start[i+1] = c; i += 2; } ++from; } buffer_nul_terminate(to); } sighandler_t Sigact(int signum, sighandler_t handler, int sa_flags) { sighandler_t rv = sigact(signum, handler, sa_flags); if(rv == SIG_ERR) { failed("sigact"); } return rv; } void Raise(int sig) { if(raise(sig)) { failed("raise"); } } int fix_exit_status(int status) { if(WIFEXITED(status)) { status = WEXITSTATUS(status); if(!sig_execfailed && status == exit__execfailed) { status = status__execfailed; } } else if(WIFSIGNALED(status)) { status = 256 + 128 + WTERMSIG(status); if(sig_execfailed && status == 256 + 128 + sig_execfailed) { status = status__execfailed; } } else { fault_(__FILE__, __LINE__, "unknown exit status %d - perhaps child stop/cont.\nSet your SIGCHLD handler with Sigact or Sigintr to avoid this.", status); } return status; } void q_init(void) { q_vec = &struct__q_vec; vec_init_el_size(q_vec, sizeof(cstr), (16)); } cstr q(const char *s) { if(!q_vec) { q_init(); } buffer struct__b; buffer *b = &struct__b; buffer_init(b, 128); sh_quote(s, b); cstr q = buffer_to_cstr(b); *(typeof(q) *)vec_push(q_vec) = q; return q; } cstr x(cstr command) { FILE *s = Popen(command, "r"); cstr rv = buffer_to_cstr(fslurp_1(s)); Pclose(s); return rv; } void cork(int fd, int cork) { Setsockopt(fd, IPPROTO_TCP, TCP_CORK, &cork, sizeof(cork)); } int Epoll_create(int size) { int rv = epoll_create(size); if(rv < 0) { failed("epoll_create"); } return rv; } int Epoll_pwait(int epfd, struct epoll_event *events, int maxevents, num timeout, const sigset_t *sigmask) { int rv = epoll_pwait(epfd, events, maxevents, delay_to_ms(timeout), sigmask); if(rv < 0 && errno != EINTR) { failed("epoll_pwait"); } return rv; } void circbuf_init(circbuf *b, ssize_t space) { b->space = space ? space : 1; b->data = (normal_Malloc((b->space))); b->size = 0; b->start = 0; } void circbuf_set_space(circbuf *b, ssize_t space) { space = space ? space : 1; char *new_data = (normal_Malloc(space)); ssize_t max_first_part = b->space - b->start; ssize_t second_part = b->size - max_first_part; if(second_part <= 0) { memcpy(new_data, b->data+b->start, b->size); } else { memcpy(new_data, b->data+b->start, max_first_part); memcpy(new_data+max_first_part, b->data, second_part); } ((free((b->data))), (b->data) = NULL); b->data = new_data; b->space = space; b->start = 0; } void circbuf_clear(circbuf *b) { b->size = 0; b->start = 0; } void vstream_init_stdio(vstream *vs, FILE *s) { vs->putc = vs_putc_stdio; vs->getc = vs_getc_stdio; vs->printf = vs_printf_stdio; vs->gets = vs_gets_stdio; vs->write = vs_write_stdio; vs->read = vs_read_stdio; vs->flush = vs_flush_stdio; vs->close = vs_close_stdio; vs->shutdown = vs_shutdown_stdio; vs->data = s; } void vs_putc_stdio(int c, vstream *vs) { Fputc(c, vs->data); } int vs_getc_stdio(vstream *vs) { return Fgetc(vs->data); } int vs_printf_stdio(vstream *vs, const char *format, va_list ap) { return Vfprintf(vs->data, format, ap); } char *vs_gets_stdio(char *s, int size, vstream *vs) { return Fgets(s, size, vs->data); } void vs_write_stdio(const void *ptr, size_t size, size_t nmemb, vstream *vs) { Fwrite(ptr, size, nmemb, vs->data); } size_t vs_read_stdio(void *ptr, size_t size, size_t nmemb, vstream *vs) { return Fread(ptr, size, nmemb, vs->data); } void vs_flush_stdio(vstream *vs) { Fflush(vs->data); } void vs_close_stdio(vstream *vs) { Fclose(vs->data); } void vs_shutdown_stdio(vstream *vs, int how) { Shutdown(fileno((FILE*)vs->data), how); } void vstreams_init(void) { in = &struct__in; out = &struct__out; er = &struct__er; vstream_init_stdio(in, stdin); vstream_init_stdio(out, stdout); vstream_init_stdio(er, stderr); } void vstream_init_buffer(vstream *vs, buffer *b) { vs->putc = vs_putc_buffer; vs->getc = vs_getc_buffer; vs->printf = vs_printf_buffer; vs->gets = vs_gets_buffer; vs->write = vs_write_buffer; vs->read = vs_read_buffer; vs->flush = vs_flush_buffer; vs->close = vs_close_buffer; vs->shutdown = vs_shutdown_buffer; vs->data = b; } void vs_putc_buffer(int c, vstream *vs) { buffer *b = vs->data; buffer_cat_char(b, c); } int vs_getc_buffer(vstream *vs) { buffer *b = vs->data; if(((ssize_t)((b->end)-(b->start)))) { int c = buffer_first_char(b); buffer_shift(b, 1); return c; } else { return EOF; } } int vs_printf_buffer(vstream *vs, const char *format, va_list ap) { buffer *b = vs->data; return Vsprintf(b, format, ap); } char *vs_gets_buffer(char *s, int size, vstream *vs) { buffer *b = vs->data; char *c = (b->start); char *e = (b->end); if(c == e || *c == 0) { return NULL; } char *o = s; if(e > c+size-1) { e = c+size-1; } while(c < e) { if(((*c) == '\0' || (*c) == '\n')) { c++; break; } *o++ = *c++; } *o++ = '\0'; buffer_shift(b, c-(b->start)); return s; } void vs_write_buffer(const void *ptr, size_t size, size_t nmemb, vstream *vs) { buffer *b = vs->data; size_t l = size * nmemb; buffer_cat_range(b, ptr, ((const char *)ptr)+l); } size_t vs_read_buffer(void *ptr, size_t size, size_t nmemb, vstream *vs) { buffer *b = vs->data; ssize_t l = size * nmemb; if(l > ((ssize_t)((b->end)-(b->start)))) { l = ((ssize_t)((b->end)-(b->start))); } memmove(ptr, (b->start), l); buffer_shift(b, l); return nmemb; } void vs_flush_buffer(vstream *vs) { buffer *b = vs->data; buffer_nul_terminate(b); } void vs_close_buffer(vstream *vs) { buffer *b = vs->data; buffer_to_cstr(b); } void vs_shutdown_buffer(vstream *vs, int how) { if((how == SHUT_WR || how == SHUT_RDWR)) { vs_close_buffer(vs); } } void vs_putc(int c) { (*out->putc)(c, out); } int vs_getc(void) { return (*in->getc)(in); } char *vs_gets(char *s, int size) { return (*in->gets)(s, size, in); } int rl(buffer *b) { ssize_t len = ((ssize_t)((b->end)-(b->start))); while(1) { char *rv = vs_gets(b->start+len, ((ssize_t)(b->space_end - b->start))-len); if(rv == NULL) { return EOF; } len += strlen(b->start+len); if(b->start[len-1] == '\n') { b->start[len-1] = '\0'; --len; break; } if(len < ((ssize_t)(b->space_end - b->start)) - 1) { break; } buffer_double(b); } buffer_set_size(b, len); return 0; } dirbase dirbasename(cstr path) { dirbase rv; typeof(strlen(path)) len = strlen(path); if(len == 0) { rv.dir = "."; rv.base = "."; return rv; } if(((path[len-1]) == '/')) { while(len && ((path[len-1]) == '/')) { path[len-1] = '\0'; --len; } if(path[0] == '\0') { rv.dir = "/"; } else { rv.dir = path; } rv.base = "."; return rv; } typeof(path+len-2) slash = path+len-2; while(1) { if(slash < path) { slash = NULL; break; } if(((*slash) == '/')) { break; } --slash; } if(slash) { *slash = '\0'; if(slash == path) { rv.dir = "/"; } else { rv.dir = path; } rv.base = slash+1; } else { rv.dir = "."; rv.base = path; } return rv; } cstr dir_name(cstr path) { typeof(dirbasename(path)) rv = dirbasename(path); return rv.dir; } cstr base_name(cstr path) { typeof(dirbasename(path)) rv = dirbasename(path); return rv.base; } cstr path_relative_to(cstr path, cstr origin) { if(cstr_begins_with(path, "/")) { return path; } origin = (normal_Strdup(origin)); typeof(dir_name(origin)) dir = dir_name(origin); typeof(format("%s" "/" "%s", dir, path)) _path = format("%s" "/" "%s", dir, path); ((free(origin)), origin = NULL); ((free(path)), path = NULL); return _path; } cstr path_tidy(cstr path) { typeof(path) i = path; typeof(path) o = path; boolean o_uppable = 0; boolean abs = 0; if(*i == '\0') { error("path_tidy: empty path not valid"); } if(((*i) == '/')) { *o++ = '/'; i++; abs = 1; } while(1) { if(1 && !((i == path || ((i[-1]) == '/')) && (o == path || ((o[-1]) == '/')))) { fault_(__FILE__, __LINE__, "borked in path_tidy"); } if(((*i) == '/')) { ++i; } else if(i[0] == '.' && (((i[1]) == '/') || (i[1]) == '\0')) { i += 2; } else { boolean dotdot = i[0] == '.' && i[1] == '.' && (((i[2]) == '/') || (i[2]) == '\0'); if(dotdot && o_uppable) { i += 3; --o_uppable; do { --o; } while(!(o == path || ((o[-1]) == '/'))); } else if(dotdot && abs) { i += 3; } else { if(1 && !(!dotdot || (dotdot && !abs && !o_uppable))) { fault_(__FILE__, __LINE__, "borked in path_tidy 2"); } if(!dotdot) { ++o_uppable; } do { *o++ = *i++; } while(!(((i[-1]) == '/') || (i[-1]) == '\0')); } } if(i[-1] == '\0') { break; } else if(o != path) { o[-1] = '/'; } } if((o-path > 1 && ((o[-1]) == '/')) || (o-path > 0 && o[-1] == '\0')) { --o; } if(o == path) { *o++ = '.'; } *o = '\0'; (path = normal_Realloc(path, (o - path + 1))); return path; } cstr path_under(cstr parent, cstr child) { cstr e = cstr_begins_with(child, parent); if(e) { if(((*e) == '/')) { cstr_chop_start(child, e+1); (child = normal_Realloc(child, ((strlen(child))+1))); return child; } else if(*e == '\0') { ((free(child)), child = NULL); return (normal_Strdup(".")); } } return NULL; } cstr path_under_maybe(cstr parent, cstr child) { cstr rv = path_under(parent, child); if(rv == NULL) { rv = child; } return rv; } cstr which(cstr file) { cstr PATH = (normal_Strdup((Getenv("PATH", "")))); vec struct__v; vec *v = &struct__v; vec_init_el_size(v, sizeof(cstr), (32)); splitv(v, PATH, ':'); cstr path = NULL; vec *my__1008_v1 = v; cstr *my__1008_end = (vec_element(my__1008_v1, my__1008_v1->size)); cstr *my__1008_i1 = (vec_element(my__1008_v1, 0)); for(; my__1008_i1!=my__1008_end ; ++my__1008_i1) { typeof(my__1008_i1) dir = my__1008_i1; path = (format("%s%s%s", (cstr_eq((*dir), "/") ? "" : (*dir)), "/", file)); if(exists(path)) { break; } ((free(path)), path = NULL); } vec_free(v); ((free(PATH)), PATH = NULL); return path; } cstr Which(cstr file) { cstr path = which(file); if(!path) { failed2("which", file); } return path; } char *Getenv(const char *name, char *_default) { char *value = getenv(name); if(value == NULL) { if(_default == env__required) { error("missing required env arg: %s\n", name); } value = _default; } return value; } void Putenv(char *string) { if(putenv(string) != 0) { failed("putenv"); } } void Setenv(const char *name, const char *value, int overwrite) { if(setenv(name, value, overwrite)) { failed("setenv"); } } void Clearenv(void) { if(clearenv() != 0) { failed("clearenv"); } } num rtime(void) { struct timeval tv; Gettimeofday(&tv); return timeval_to_rtime(&tv); } void Gettimeofday(struct timeval *tv) { if((gettimeofday(tv, NULL)) != 0) { failed("gettimeofday"); } } void rtime_to_timeval(num rtime, struct timeval *tv) { tv->tv_sec = (long)rtime; tv->tv_usec = (long)((rtime - tv->tv_sec) * 1e6); } num timeval_to_rtime(const struct timeval *tv) { return (num)tv->tv_sec + tv->tv_usec / 1e6; } int rtime_to_ms(num rtime) { return (int)(rtime * 1000); } int delay_to_ms(num delay) { if(delay == (-1)) { return -1; } else { return rtime_to_ms(delay); } } void date_rfc1123_init(void) { setlocale(LC_TIME, "POSIX"); Putenv("TZ=GMT"); tzset(); } char *date_rfc1123(time_t t) { static char date[32]; static char maxdate[32]; static time_t maxtime = -1; if(t == maxtime) { return maxdate; } char *d = date; if(t > maxtime) { maxtime = t; d = maxdate; } strftime(d, sizeof(date), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t)); return d; } void nonblock(int fd, int nb) { if(ioctl(fd, FIONBIO, &nb) == -1) { failed("ioctl"); } } void Fcntl_setfd(int fd, long arg) { int rv = fcntl(fd, F_SETFD, arg); if(rv == -1) { error("fcntl_setfd"); } } void cloexec(int fd) { Fcntl_setfd(fd, FD_CLOEXEC); } int Socket(int domain, int type, int protocol) { int fd = socket(domain, type, protocol); if(fd == -1) { failed("socket"); } return fd; } void Bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) { if(bind(sockfd, my_addr, addrlen) != 0) { failed("bind"); } } void Listen(int sockfd, int backlog) { if(listen(sockfd, backlog) != 0) { failed("listen"); } } void Sockaddr_in(struct sockaddr_in *sa, char *addr, int port) { sa->sin_family = AF_INET; sa->sin_port = htons(port); if(inet_aton(addr, &sa->sin_addr) == 0) { error("Invalid IP address `%s'.\n", addr); } memset(&sa->sin_zero, 0, 8); } hostent *Gethostbyname(const char *name) { typeof(gethostbyname(name)) rv = gethostbyname(name); if(rv == NULL) { errno = h_errno; failed("gethostbyname"); } return rv; } cstr name_to_ip(const char *name) { struct in_addr addr; if(inet_aton(name, &addr)) { return (char*)name; } typeof(Gethostbyname(name)) he = Gethostbyname(name); if(he->h_addrtype != AF_INET) { error("name_to_ip: does not support ip6 yet"); } return inet_ntoa(*(struct in_addr *)(he->h_addr_list[0])); } int Server_tcp(char *addr, int port) { addr = name_to_ip(addr); int ear = Socket(PF_INET, SOCK_STREAM, 0); (reuseaddr(ear, 1)); struct sockaddr_in sa; Sockaddr_in(&sa, addr, port); Bind(ear, (sockaddr *)&sa, sizeof(sockaddr_in)); (Listen(ear, listen_backlog)); return ear; } void Setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) { if(setsockopt(s, level, optname, optval, optlen)) { failed("setsockopt"); } } void Shutdown(int s, int how) { int rv = shutdown(s, how); if(rv == -1) { failed("shutdown"); } } void keepalive(int fd, int keepalive) { Setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive)); } void nodelay(int fd, int nodelay) { Setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay)); } void reuseaddr(int fd, int reuseaddr) { Setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)); } void Getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) { if(getsockopt(s, level, optname, optval, optlen)) { failed("getsockopt"); } } int Getsockerr(int fd) { int err; socklen_t size = sizeof(err); Getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &size); return err; } void Close(int fd) { if(close(fd) != 0) { failed("close"); } } ssize_t Read_some(int fd, void *buf, size_t count) { errno = 0; ssize_t bytes_read = read(fd, buf, count); if(bytes_read == -1) { if(errno == EAGAIN) { bytes_read = 0; } else { failed("read"); } } return bytes_read; } ssize_t Read(int fd, void *buf, size_t count) { ssize_t bytes_read_tot = 0; while(1) { ssize_t bytes_read = Read_some(fd, buf, count); bytes_read_tot += bytes_read; count -= bytes_read; if(count == 0 || bytes_read == 0) { break; } buf = (char *)buf + bytes_read; } return bytes_read_tot; } void fslurp_2(FILE *s, buffer *b) { int space = ((ssize_t)(b->space_end - b->start)); int size = ((ssize_t)((b->end)-(b->start))); char *start = (b->start); while(1) { int to_read = space - size; ssize_t bytes_read = Fread(start + size, 1, to_read, s); buffer_grow(b, bytes_read); size += bytes_read; if(bytes_read < to_read) { break; } if(size == space) { buffer_double(b); space = ((ssize_t)(b->space_end - b->start)); size = ((ssize_t)((b->end)-(b->start))); start = (b->start); } } } buffer *fslurp_1(FILE *s) { Stats struct__st; Stats *st = &struct__st; Fstat(Fileno(s), st); int size = st->st_size; if(size == 0) { size = 1024; } else { ++size; } buffer *b; b = ((buffer *)(normal_Malloc((sizeof(buffer))))); buffer_init(b, size); fslurp_2(s, b); return b; } FILE *Fopen(const char *path, const char *mode) { FILE *f = fopen(path, mode); if(f == NULL) { failed3("fopen", mode, path); } return f; } void Fclose(FILE *fp) { if(fclose(fp) == EOF) { failed("fclose"); } } char *Fgets(char *s, int size, FILE *stream) { errno = 0; char *rv = fgets(s, size, stream); if(errno) { failed("fgets"); } return rv; } int Vfprintf(FILE *stream, const char *format, va_list ap) { int len = vfprintf(stream, format, ap); if(len < 0) { failed("vfprintf"); } return len; } void Fflush(FILE *stream) { if(fflush(stream) != 0) { failed("fflush"); } } vec *ls(const char *name, boolean all) { vec *v; v = ((vec *)(normal_Malloc((sizeof(vec))))); vec_init_el_size(v, sizeof(cstr), (64)); return ls_(name, all, v); } vec *ls_(const char *name, boolean all, vec *v) { struct dirent *e; DIR *dir = opendir(name); if(dir == NULL) { return NULL; } while(1) { errno = 0; e = readdir(dir); if(errno) { ((free(v)), v = NULL); v = NULL; break; } if(!e) { break; } if(e->d_name[0] == '.' && (!all || e->d_name[1] == '\0' || (e->d_name[1] == '.' && e->d_name[2] == '\0'))) { { continue; } } *(cstr*)vec_push(v) = (normal_Strdup((e->d_name))); } closedir(dir); return v; } int exists(const char *file_name) { struct stat buf; return !stat(file_name, &buf); } int Stat(const char *file_name, struct stat *buf) { errno = 0; int rv = stat(file_name, buf); if(rv == 0) { return 1; } if(errno == ENOENT || errno == ENOTDIR) { return 0; } failed2("stat", file_name); return 0; } void Fstat(int filedes, struct stat *buf) { if(fstat(filedes, buf) == -1) { failed("fstat"); } } void Stats_init(stats *s, const char *file_name) { if(!Stat(file_name, s)) { (bzero(s, sizeof(*s))); } } int Lstat(const char *file_name, struct stat *buf) { errno = 0; int rv = lstat(file_name, buf); if(rv == 0) { return 1; } if(errno == ENOENT || errno == ENOTDIR) { return 0; } failed2("lstat", file_name); return 0; } FILE *Popen(const char *command, const char *type) { FILE *rv = popen(command, type); if(rv == NULL) { failed("popen"); } return rv; } int Pclose(FILE *stream) { int rv = pclose(stream); if(rv == -1) { failed("pclose"); } return -1; } int Fgetc(FILE *stream) { int c = fgetc(stream); if(c == EOF && ferror(stream)) { failed("fgetc"); } return c; } void Fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { size_t count = fwrite(ptr, size, nmemb, stream); if(count != nmemb) { failed("fwrite"); } } size_t Fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { size_t count = fread(ptr, size, nmemb, stream); if(count < nmemb && ferror(stream)) { failed("fread"); } return count; } void Fputc(int c, FILE *stream) { if(0) {} else if(fputc(c, stream) == EOF) { { failed("fputc"); } } } off_t Lseek(int fd, off_t offset, int whence) { off_t ret = lseek(fd, offset, whence); if(ret == -1) { failed("lseek"); } return ret; } void Ftruncate(int fd, off_t length) { int ret = ftruncate(fd, length); if(ret) { failed("ftruncate"); } } void _Readlink(const char *path, buffer *b) { while(1) { typeof(readlink(path, (b->end), ((ssize_t)(b->space_end - b->end)))) len = readlink(path, (b->end), ((ssize_t)(b->space_end - b->end))); if(len == -1) { if(errno == ENAMETOOLONG) { buffer_double(b); } else { failed("readlink"); } } else { buffer_grow(b, len); return; } } } cstr Readlink(const char *path) { buffer struct__b; buffer *b = &struct__b; buffer_init(b, 256); return (_Readlink(path, b), buffer_to_cstr(b)); } cstr readlinks(cstr path, opt_err if_dead) { Stats struct__stat_b; Stats *stat_b = &struct__stat_b; while(1) { if(!Lstat(path, stat_b)) { return opt_err_do(if_dead, (any){.cs=path}, (any){.cs=NULL}, "file does not exist: %s", path).cs; } if(!S_ISLNK(stat_b->st_mode)) { break; } typeof(Readlink(path)) path1 = Readlink(path); path1 = path_relative_to(path1, path); ((free(path)), path = NULL); path = path1; } return path; } void _Getcwd(buffer *b) { while(1) { if(getcwd((b->end), ((ssize_t)(b->space_end - b->end))) == NULL) { if(errno == ERANGE) { buffer_double(b); } else { failed("getcwd"); } } else { buffer_grow(b, strlen(b->end)); return; } } } cstr Getcwd(void) { buffer struct__b; buffer *b = &struct__b; buffer_init(b, 256); _Getcwd(b); return buffer_to_cstr(b); } int Dup2(int oldfd, int newfd) { int fd = dup2(oldfd, newfd); if(fd == -1) { failed("dup2"); } return fd; } mode_t mode(const char *file_name) { Stats struct__s; Stats *s = &struct__s; Stats_init(s, file_name); return s->st_mode; } void fd_set_init(fd_set *o) { FD_ZERO(o); } int can_read(int fd, num timeout) { if(!tmp_fd_set) { tmp_fd_set = ((fd_set *)(normal_Malloc((sizeof(fd_set))))); fd_set_init(tmp_fd_set); } timeval tv; rtime_to_timeval(timeout, &tv); FD_SET(fd, tmp_fd_set); int n_ready = select(fd+1, tmp_fd_set, NULL, NULL, &tv); FD_CLR(fd, tmp_fd_set); if(n_ready == -1) { failed("select"); } return n_ready; } int can_write(int fd, num timeout) { if(!tmp_fd_set) { tmp_fd_set = ((fd_set *)(normal_Malloc((sizeof(fd_set))))); fd_set_init(tmp_fd_set); } timeval tv; rtime_to_timeval(timeout, &tv); FD_SET(fd, tmp_fd_set); int n_ready = select(fd+1, NULL, tmp_fd_set, NULL, &tv); FD_CLR(fd, tmp_fd_set); if(n_ready == -1) { failed("select"); } return n_ready; } int has_error(int fd, num timeout) { if(!tmp_fd_set) { tmp_fd_set = ((fd_set *)(normal_Malloc((sizeof(fd_set))))); fd_set_init(tmp_fd_set); } timeval tv; rtime_to_timeval(timeout, &tv); FD_SET(fd, tmp_fd_set); int n_ready = select(fd+1, NULL, NULL, tmp_fd_set, &tv); FD_CLR(fd, tmp_fd_set); if(n_ready == -1) { failed("select"); } return n_ready; } ssize_t Writev(int fd, const struct iovec *iov, int iovcnt) { ssize_t rv = writev(fd, iov, iovcnt); if(rv < 0) { failed("writev"); } return rv; } int Fileno(FILE *stream) { int rv = fileno(stream); if(rv < 0) { failed("fileno"); } return rv; } void list_init(list *l) { l->next = NULL; } size_t arylen(void *_p) { void **p = _p; int count = 0; while((*p++)) { ++count; } return count; } vec *sort_vec(vec *v, cmp_t cmp) { qsort((vec_element(v, 0)), (v->size), (v->element_size), cmp); return v; } int cstr_cmp(const void *_a, const void *_b) { char * const *a = _a; char * const *b = _b; return strcmp(*a, *b); } int imax(int x, int y) { if(x > y) { return x; } return y; } void seed(void) { int s = (int)((rmod(rtime()*1000, pow(2, 32)))) ^ (getpid()<<16); (srandom(s)); } num rmod(num r, num base) { int d = (floor(r / base)); return r - d * base; } void hashtable_init(hashtable *ht, hash_func *hash, eq_func *eq, size_t size) { ht->size = hashtable_sensible_size(size); ht->buckets = alloc_buckets(ht->size); ht->hash = hash; ht->eq = eq; } list *alloc_buckets(size_t size) { list *buckets = ((list *)(normal_Malloc((size * sizeof(list))))); list *end = buckets + size; list *i; for(i = buckets ; i != end ; ++i) { list_init(i); } return buckets; } list *hashtable_lookup_ref(hashtable *ht, void *key) { list *bucket = which_bucket(ht, key); eq_func *eq = ht->eq; while(1) { node_kv *node = (node_kv *)bucket->next; if(node == NULL || (*eq)(key, node->kv.k)) { return bucket; } bucket = (list *)node; } } key_value *hashtable_lookup(hashtable *ht, void *key) { list *l = hashtable_lookup_ref(ht, key); if(l->next == NULL) { return NULL; } else { return hashtable_ref_lookup(l); } } key_value *hashtable_ref_lookup(list *l) { node_kv *node = (node_kv *)l->next; return (key_value *)&node->kv; } void *hashtable_value(hashtable *ht, void *key) { key_value *kv = hashtable_lookup(ht, key); if(kv == NULL) { error("hashtable_value: key does not exist"); return NULL; } else { return kv->v; } } void *hashtable_value_or_null(hashtable *ht, void *key) { return hashtable_value_or(ht, key, NULL); } void *hashtable_value_or(hashtable *ht, void *key, void *def) { key_value *kv = hashtable_lookup(ht, key); if(kv == NULL) { return def; } else { return kv->v; } } key_value *hashtable_add(hashtable *ht, void *key, void *value) { list *l = hashtable_lookup_ref(ht, key); hashtable_ref_add(l, key, value); return hashtable_ref_key_value(l); } void hashtable_ref_add(list *l, void *key, void *value) { if(!hashtable_ref_add_maybe(l, key, value)) { error("hashtable_ref_add: key already exists"); } } boolean hashtable_ref_add_maybe(list *l, void *key, void *value) { if(l->next != NULL) { return 0; } node_kv *node = ((node_kv *)(normal_Malloc((sizeof(node_kv))))); node->kv.k = key; node->kv.v = value; typeof(*(&l->next)) next = *(&l->next); *(&l->next) = ((list *)node); *(&((list *)node)->next) = next; return 1; } key_value hashtable_delete(hashtable *ht, void *key) { list *l = hashtable_lookup_ref(ht, key); return hashtable_ref_delete(l); } key_value hashtable_ref_delete(list *l) { key_value ret; if(hashtable_ref_exists(l)) { node_kv *node = hashtable_ref_node(l); *(&l->next) = (*(&l->next))->next; ret = node->kv; ((free(node)), node = NULL); } else { ret = kv_null; } return ret; } node_kv *hashtable_ref_node(list *l) { node_kv *node = (node_kv *)l->next; if(1 && !(node != NULL)) { fault_(__FILE__, __LINE__, "hashtable_ref_node: node not found"); } return node; } boolean hashtable_ref_exists(list *l) { return l->next != NULL; } key_value *hashtable_ref_key_value(list *l) { node_kv *node = hashtable_ref_node(l); return &node->kv; } list *which_bucket(hashtable *ht, void *key) { unsigned int hash = (*ht->hash)(key); unsigned int i = hash % ht->size; return ht->buckets + i; } size_t hashtable_sensible_size(size_t size) { if(size == 0) { size = 1; } return size; } unsigned long cstr_hash(void *s) { unsigned long rv = 0; typeof(((char *)s)+strlen(((char *)s))) my__2512_end = ((char *)s)+strlen(((char *)s)); typeof((char *)s) my__2512_v1 = (char *)s; for(; my__2512_v1next == NULL) { hashtable_ref_add(ref, key, value_init); } return hashtable_ref_lookup(ref); } unsigned long int_hash(void *i_ptr) { long i = ((intptr_t)i_ptr); char s[64]; size_t size = snprintf(s, sizeof(s), "%ld", i); if(size >= sizeof(s)) { failed("int_hash"); } return cstr_hash(s); } boolean int_eq(void *a, void *b) { return ((intptr_t)a) == ((intptr_t)b); } void sym_init(void) { if(!syms) { syms = &syms__struct; hashtable_init(syms, cstr_hash, cstr_eq, syms_n_buckets); } } cstr sym(cstr s) { if(!syms) { sym_init(); } list *ref = hashtable_lookup_ref(syms, s); if(hashtable_ref_exists(ref)) { key_value *kv = hashtable_ref_key_value(ref); return (cstr)kv->k; } cstr s1 = (normal_Strdup(s)); hashtable_add(syms, s1, NULL); return s1; } void main__init(int _argc, char *_argv[]) { argc = _argc; argv = _argv; vstreams_init(); error_init(); main_dir = Getcwd(); program_full = argv[0]; if(!exists(program_full)) { program_full = Which(program_full); } program_real = (readlinks((normal_Strdup(program_full)), OE_ERROR)); typeof(dirbasename((normal_Strdup(program_real)))) my__2750_rv = dirbasename((normal_Strdup(program_real))); typeof(my__2750_rv.dir) d = my__2750_rv.dir; typeof(my__2750_rv.base) b = my__2750_rv.base; program_dir = d; program = b; if(mingw && cstr_ends_with(program, ".exe")) { program[strlen(program)-4] = '\0'; } if(program[0] == '.') { ++program; } arg = argv+1; args = argc - 1; seed(); } void _deq_init(deq *q, ssize_t element_size, ssize_t space) { q->space = space ? space : 1; circbuf_init(&q->b, q->space * element_size); q->element_size = element_size; q->size = 0; q->start = 0; } void deq_space(deq *q, ssize_t space) { q->space = space ? space : 1; circbuf_set_space(&q->b, q->space * q->element_size); if(q->b.start == 0) { q->start = 0; } } void deq_clear(deq *q) { circbuf_clear(&q->b); q->start = q->size = 0; } void deq_double(deq *q) { deq_space(q, q->space * 2); } void *deq_element(deq *q, ssize_t index) { index += q->start; if(index >= q->space) { index -= q->space; } return q->b.data + index * q->element_size; } void *deq_push(deq *q) { if(q->size == q->space) { deq_double(q); } ++q->size; q->b.size += q->element_size; return deq_element(q, q->size-1); } void deq_shift(deq *q) { --q->size; if(q->size == 0) { deq_clear(q); return; } q->b.size -= q->element_size; ++q->start; q->b.start += q->element_size; if(q->start >= q->space) { q->start -= q->space; q->b.start -= q->b.space; } } void error(const char *format, ...) { va_list ap; va_start(ap, format); verror(format, ap); va_end(ap); } void verror(const char *format, va_list ap) { buffer struct__b; buffer *b = &struct__b; (buffer_init(b, 128)); Vsprintf(b, format, ap); buffer_add_nul(b); buffer_squeeze(b); Throw((b->start), 0, NULL); } void serror(const char *format, ...) { va_list ap; va_start(ap, format); vserror(format, ap); va_end(ap); } void vserror(const char *format, va_list ap) { int no = errno; buffer struct__b; buffer *b = &struct__b; (buffer_init(b, 128)); Vsprintf(b, format, ap); Sprintf(b, ": %s", Strerror(no)); buffer_add_nul(b); buffer_squeeze(b); Throw((b->start), no, NULL); } void warn(const char *format, ...) { va_list ap; va_start(ap, format); vwarn(format, ap); va_end(ap); } void vwarn(const char *format, va_list ap) { size_t my__3004_len = strlen(format); char format1[my__3004_len+2]; char *my__3004_e = format1 + my__3004_len; strcpy(format1, format); *my__3004_e = '\n'; my__3004_e[1] = '\0'; fflush(stdout); vfprintf(stderr, format1, ap); if(mingw) { fflush(stderr); } } void failed(const char *funcname) { serror("%s failed", funcname); } void failed2(const char *funcname, const char *errmsg) { serror("%s failed: %s", funcname, errmsg); } void failed3(const char *funcname, const char *msg1, const char *msg2) { serror("%s failed: %s, %s", funcname, msg1, msg2); } void warn_failed(const char *funcname) { swarning("%s failed", funcname); } void swarning(const char *format, ...) { va_list ap; va_start(ap, format); vswarning(format, ap); va_end(ap); } void vswarning(const char *format, va_list ap) { fflush(stdout); Vfprintf(stderr, format, ap); fprintf(stderr, ": "); Perror(NULL); if(mingw) { fflush(stderr); } } void error_init(void) { error_handlers = ((vec *)(normal_Malloc((sizeof(vec))))); vec_init_el_size(error_handlers, sizeof(error_handler), (16)); errors = ((vec *)(normal_Malloc((sizeof(vec))))); vec_init_el_size(errors, sizeof(err), (16)); extra_error_messages = ((hashtable *)(normal_Malloc((sizeof(hashtable))))); hashtable_init(extra_error_messages, int_hash, int_eq, 101); } err *error_add(cstr msg, int no, void *data) { err *e = vec_push(errors); e->msg = msg; e->no = no; e->data = data; return e; } void Throw(cstr msg, int no, void *data) { throw_(error_add(msg, no, data)); } void throw_(err *e) { if((!error_handlers->size)) { die_errors(exit__error); } error_handler *h = (vec_top(error_handlers, 0)); if(((&h->handler)->func != NULL)) { if(((*(&h->handler)->func)((&h->handler)->obj, (&h->handler)->common_arg, e))) { h->jump = NULL; } } if(h->jump) { vec_pop(error_handlers); longjmp(*h->jump, 1); } } void die_errors(int status) { warn_errors(); if(*(Getenv("DEBUG", ""))) { abort(); } Exit(status); } void clear_errors(void) { vec *my__3065_v1 = errors; err *my__3065_end = (vec_element(my__3065_v1, my__3065_v1->size)); err *my__3065_i1 = (vec_element(my__3065_v1, 0)); for(; my__3065_i1!=my__3065_end ; ++my__3065_i1) { typeof(my__3065_i1) e = my__3065_i1; ((free((e->msg))), (e->msg) = NULL); ((free((e->data))), (e->data) = NULL); } vec_size(errors, 0); } void warn_errors(void) { warn_errors_keep(); clear_errors(); } void warn_errors_keep(void) { vec *my__3107_v1 = errors; err *my__3107_end = (vec_element(my__3107_v1, my__3107_v1->size)); err *my__3107_i1 = (vec_element(my__3107_v1, 0)); for(; my__3107_i1!=my__3107_end ; ++my__3107_i1) { typeof(my__3107_i1) e = my__3107_i1; warn("%s", e->msg); } } void fault_(char *file, int line, const char *format, ...) { va_list ap; va_start(ap, format); vfault_(file, line, format, ap); va_end(ap); } void vfault_(char *file, int line, const char *format, va_list ap) { file = (path_under_maybe(main_dir, path_tidy((normal_Strdup(file))))); buffer struct__b; buffer *b = &struct__b; (buffer_init(b, 128)); Sprintf(b, "%s:%d: ", file, line); Vsprintf(b, format, ap); buffer_add_nul(b); buffer_squeeze(b); if(throw_faults) { Throw((b->start), 0, NULL); } else { error_add((b->start), 0, NULL); die_errors(exit__fault); } } cstr Strerror(int errnum) { key_value *kv = hashtable_lookup(extra_error_messages, ((void*)(intptr_t)errnum)); if(kv == NULL) { return strerror(errnum); } else { return kv->v; } } void Perror(const char *s) { cstr msg = Strerror(errno); if(s) { warn("%s: %s", s, msg); } else { warn("%s", msg); } } any opt_err_do(opt_err opt, any value, any errcode, char *format, ...) { va_list ap; va_start(ap, format); typeof(vopt_err_do(opt, value, errcode, format, ap)) rv = vopt_err_do(opt, value, errcode, format, ap); va_end(ap); return rv; } any vopt_err_do(opt_err opt, any value, any errcode, char *format, va_list ap) { if(opt & OE_WARN || opt == OE_ERROR) { opt &= ~OE_WARN; if(opt == OE_ERROR) { verror(format, ap); } else { vwarn(format, ap); } } switch(opt) { case OE_CONT: return value; break; case OE_ERRCODE: return errcode; break; default: failed2("vopt_err_do", "unknown opt_err option"); } return errcode; } void *normal_Malloc(size_t size) { void *ptr = malloc(size); if(ptr == NULL) { failed("malloc"); } return ptr; } void *normal_Realloc(void *ptr, size_t size) { if(size == 0) { size = 1; } ptr = realloc(ptr, size); if((ptr == NULL)) { failed("realloc"); } return ptr; } void *normal_Calloc(size_t nmemb, size_t size) { void *ptr = calloc(nmemb, size); if((ptr == NULL)) { failed("calloc"); } return ptr; } cstr normal_Strdup(const char *s) { cstr rv = strdup(s); if(rv == NULL) { failed("strdup"); } return rv; } char *normal_Strndup(const char *s, size_t n) { char *rv = strndup(s, n); if(!rv) { failed("strndup"); } return rv; } void buffer_init(buffer *b, size_t space) { if(space == 0) { space = 1; } b->start = (char *)(normal_Malloc(space)); b->end = b->start; b->space_end = b->start + space; } void buffer_free(buffer *b) { ((free((b->start))), (b->start) = NULL); } void buffer_set_space(buffer *b, size_t space) { size_t size = ((ssize_t)((b->end)-(b->start))); if(1 && !(size <= space)) { fault_(__FILE__, __LINE__, "cannot set buffer space less than buffer size"); } if(space == 0) { space = 1; } ((b->start) = normal_Realloc((b->start), space)); b->end = b->start + size; b->space_end = b->start + space; } void buffer_set_size(buffer *b, size_t size) { buffer_ensure_space(b, size); b->end = b->start + size; } void buffer_double(buffer *b) { buffer_set_space(b, 2 * ((ssize_t)(b->space_end - b->start))); } void buffer_squeeze(buffer *b) { buffer_set_space(b, ((ssize_t)((b->end)-(b->start)))); } void buffer_cat_char(buffer *b, char c) { buffer_grow(b, 1); *(b->end - 1) = c; } void buffer_cat_cstr(buffer *b, const char *s) { int l = strlen(s); buffer_grow(b, l); memcpy(b->end - l, s, l); } void buffer_cat_range(buffer *b, const char *start, const char *end) { int l = end - start; buffer_grow(b, l); memmove(b->end - l, start, l); } void buffer_grow(buffer *b, size_t delta_size) { buffer_set_size(b, ((ssize_t)((b->end)-(b->start))) + delta_size); } void buffer_clear(buffer *b) { b->end = b->start; } char buffer_first_char(buffer *b) { return b->start[0]; } int Sprintf(buffer *b, const char *format, ...) { va_list ap; va_start(ap, format); typeof(Vsprintf(b, format, ap)) rv = Vsprintf(b, format, ap); va_end(ap); return rv; } cstr format(const char *format, ...) { va_list ap; va_start(ap, format); typeof(vformat(format, ap)) rv = vformat(format, ap); va_end(ap); return rv; } cstr vformat(const char *format, va_list ap) { buffer struct__b; buffer *b = &struct__b; buffer_init(b, 4096); Vsprintf(b, format, ap); buffer_add_nul(b); buffer_squeeze(b); return (b->start); } int Vsnprintf(char *buf, size_t size, const char *format, va_list ap) { typeof(vsnprintf(buf, size, format, ap)) rv = vsnprintf(buf, size, format, ap); if(rv < 0) { failed("vsnprintf"); } return rv; } int Vsprintf(buffer *b, const char *format, va_list ap) { va_list ap1; va_copy(ap1, ap); ssize_t old_size = ((ssize_t)((b->end)-(b->start))); char *start = b->start + old_size; ssize_t space = ((ssize_t)(b->space_end - b->start)) - old_size; if(space == 0) { buffer_ensure_space(b, old_size+1); start = b->start + old_size; space = ((ssize_t)(b->space_end - b->start)) - old_size; } ssize_t len = Vsnprintf(start, space, format, ap); if(len < space) { buffer_grow(b, len); } else { buffer_set_size(b, old_size+len+1); start = b->start + old_size; space = ((ssize_t)(b->space_end - b->start)) - old_size; len = Vsnprintf(start, space, format, ap1); if(1 && !(old_size+len == ((ssize_t)((b->end)-(b->start)))-1)) { fault_(__FILE__, __LINE__, "vsnprintf returned different sizes on same input!!"); } buffer_set_size(b, old_size+len); } va_end(ap1); return len; } char *buffer_add_nul(buffer *b) { buffer_cat_char(b, '\0'); return (b->start); } char *buffer_nul_terminate(buffer *b) { buffer_cat_char(b, '\0'); buffer_grow(b, -1); return (b->start); } cstr buffer_to_cstr(buffer *b) { buffer_add_nul(b); buffer_squeeze(b); return (b->start); } void buffer_from_cstr(buffer *b, cstr s, size_t len) { b->start = s; b->end = s + len; b->space_end = b->end + 1; } void buffer_shift(buffer *b, size_t shift) { char *start = (b->start); size_t size = ((ssize_t)((b->end)-(b->start))); memmove(start, start+shift, size-shift); buffer_grow(b, -shift); } void buffer_ensure_space(buffer *b, size_t space) { size_t ospace = ((ssize_t)(b->space_end - b->start)); if(space > ospace) { do { ospace *= 2; } while(space > ospace); buffer_set_space(b, ospace); } } void buffer_ensure_free(buffer *b, ssize_t free) { while(((ssize_t)(b->space_end - b->end)) < free) { buffer_double(b); } } boolean sched_sig_child_exited(sigset_t *oldsigmask) { *oldsigmask = Sig_defer(SIGCHLD); return sched->got_sigchld; } boolean sched_sig_child_exited_2(sigset_t *oldsigmask) { boolean got_sigchld = 0; if(sched->got_sigchld) { got_sigchld = 1; sched->got_sigchld = 0; } Sig_setmask(oldsigmask); return got_sigchld; } void proc_init(proc *p, proc_func f) { p->f = f; p->pc = 1; } int resume(proc *p) { int rv = (*p->f)(p); if(rv) { p->pc = rv; } return rv; } timeout *timeouts_next(timeouts *q) { return *(timeout_p*)(vec_element(q, 0)); } void timeouts_shift(timeouts *q) { int my__4329_last_i = (q->size) - 1; int my__4338_j = 0; int my__4338_size = (q->size); int my__4338_c1, my__4338_c2; void *my__4338_last = (vec_element(q, (my__4338_size-1))); while(1) { my__4338_c1 = (my__4338_j*2+1); my__4338_c2 = my__4338_c1+1; if(my__4338_c2 >= my__4338_size) { break; } if(((*(timeout_p*)(vec_element(q, my__4338_c2)))->time - (*(timeout_p*)(vec_element(q, my__4338_c1)))->time) < 0) { my__4338_c1 = my__4338_c2; } if(((*(timeout_p*)(vec_element(q, my__4338_c1)))->time - (*(timeout_p*)my__4338_last)->time) >= 0) { break; } int my__4364_old_i = my__4338_c1; *(timeout_p *)vec_element(q, my__4338_j) = *(timeout_p *)vec_element(q, my__4338_c1); if(my__4338_j != my__4364_old_i) {} my__4338_j = my__4338_c1; } if(my__4338_j != my__4338_size-1) { *(timeout_p *)vec_element(q, my__4338_j) = *(timeout_p *)vec_element(q, (my__4338_size-1)); if(my__4338_j != my__4329_last_i) {} } vec_pop(q); } void timeouts_call(timeouts *timeouts, num time) { while(!((timeouts->size) == 0)) { timeout *timeout_next = timeouts_next(timeouts); if(timeout_next->time > time) { break; } timeout *my__4383_next = timeouts_next(timeouts); ((*(&my__4383_next->handler)->func)((&my__4383_next->handler)->obj, (&my__4383_next->handler)->common_arg, NULL)); if(!((timeouts->size) == 0) && timeouts_next(timeouts) == my__4383_next) { timeouts_shift(timeouts); } } } num timeouts_delay(timeouts *timeouts, num time) { if(((timeouts->size) == 0)) { return -1; } else { timeout *next = timeouts_next(timeouts); num delay = next->time - time; if(delay < 0) { delay = 0; } return delay; } } void io_epoll_init(io_epoll *io) { io->epfd = Epoll_create(io_epoll_size); io->max_fd_plus_1 = 0; io->count = 0; io->events = ((vec *)(normal_Malloc((sizeof(vec))))); vec_init_el_size(io->events, sizeof(epoll_event), (io_epoll_maxevents)); } int io_epoll_wait(io_epoll *io, num delay, sigset_t *sigmask) { int n_ready = Epoll_pwait(io->epfd, (vec_element((io->events), 0)), ((io->events)->space), delay, sigmask); vec_size(io->events, imax(n_ready, 0)); return n_ready; } int io_epoll_add(io_epoll *io, int fd, boolean et) { epoll_event ev; ev.events = (et ? EPOLLET : 0) | EPOLLIN | EPOLLOUT; ev.data.fd = fd; if(epoll_ctl(io->epfd, EPOLL_CTL_ADD, fd, &ev) < 0) { swarning("failed epoll_ctl ADD %d", fd); return -1; } io->count += 2; if(fd >= io->max_fd_plus_1) { io->max_fd_plus_1 = fd + 1; return 1; } return 0; } void io_epoll_rm(io_epoll *io, int fd) { if(epoll_ctl(io->epfd, EPOLL_CTL_DEL, fd, &io_epoll_rm__event)) { swarning("failed epoll_ctl DEL %d", fd); } io->count -= 2; } void scheduler_init(scheduler *sched) { sched->exit = 0; _deq_init(&sched->q, sizeof(proc_p), (8)); io_epoll_init(&sched->io); vec_init_el_size(&sched->readers, sizeof(proc_p), (8)); vec_init_el_size(&sched->writers, sizeof(proc_p), (8)); sched->now = -1; vec_init_el_size(&sched->tos, sizeof(timeout_p), (64)); hashtable_init(&sched->children, int_hash, int_eq, sched__children_n_buckets); sched->step = 0; sched->n_children = 0; sched->got_sigchld = 0; (Sigact(SIGCHLD, sigchld_handler, SA_RESTART|(SIGCHLD == SIGCHLD ? SA_NOCLDSTOP : 0))); } void start_f(proc *p) { *(proc **)deq_push(&sched->q) = p; } void run(void) { sched->exit = 0; while(!sched->exit) { step(); } } void step(void) { int need_select; num delay; int n_ready = 0; io_epoll *io = &sched->io; timeouts *tos = &sched->tos; if(!((tos->size) == 0)) { delay = timeouts_delay(tos, sched_get_time()); } else if(sched->q.size) { delay = (io->count) ? sched_delay : 0; } else { delay = (-1); } if(delay == (-1) && (io->count) == 0 && sched->n_children == 0) { sched->exit = 1; return; } need_select = delay || (sched_busy && (io->count) && sched->step % sched_busy == 0); sigset_t oldsigmask, *oldsigmaskp = NULL; int got_sigchld = 0; if(need_select) { if(sched->n_children) { oldsigmaskp = &oldsigmask; if(sched_sig_child_exited(oldsigmaskp)) { delay = 0; } } n_ready = io_epoll_wait(io, delay, oldsigmaskp); sched_forget_time(); if(sched->n_children) { if(sched_sig_child_exited_2(oldsigmaskp)) { got_sigchld = 1; } } } if(got_sigchld) { pid_t pid; while(sched->n_children && (pid = Child_done())) { proc *p = (hashtable_value_or_null((&sched->children), ((void*)(intptr_t)pid))); if(p) { clr_waitchild(pid); waitchild__pid = pid; waitchild__status = wait__status; if(resume(p)) { start_f(p); } else {} } else { warn("no waiter for child %d", pid); } } } if(!((tos->size) == 0)) { timeouts_call(tos, sched_get_time()); } if(n_ready > 0) { int fd; vec *my__4487_v1 = io->events; epoll_event *my__4487_end = (vec_element(my__4487_v1, my__4487_v1->size)); epoll_event *my__4487_i1 = (vec_element(my__4487_v1, 0)); for(; my__4487_i1!=my__4487_end ; ++my__4487_i1) { typeof(my__4487_i1) my__4483_e = my__4487_i1; fd = my__4483_e->data.fd; boolean can_read = my__4483_e->events & (EPOLLIN|EPOLLHUP); boolean can_write = my__4483_e->events & (EPOLLOUT|EPOLLHUP); boolean has_error = my__4483_e->events & EPOLLERR; if(!(can_read || can_write || has_error)) { continue; } if(has_error) { errno = Getsockerr(fd); if(!(errno == ECONNRESET || errno == EPIPE)) { swarning("sched: fd %d has an error", fd); } } if(can_read) { proc *p = *(proc **)vec_element(&sched->readers, fd); clr_reader(fd); if(p) { if(resume(p)) { start_f(p); } else {} } } if(can_write) { proc *p = *(proc **)vec_element(&sched->writers, fd); clr_writer(fd); if(p) { if(resume(p)) { start_f(p); } else {} } } } } if(sched->q.size) { proc *p = *(proc **)deq_element(&sched->q, 0); deq_shift(&sched->q); if(resume(p)) { start_f(p); } else {} } ++sched->step; } int scheduler_add_fd(scheduler *sched, int fd, int et) { int rv = io_epoll_add(&sched->io, fd, et); if(rv == 1) { vec_ensure_size(&sched->readers, fd+1); vec_ensure_size(&sched->writers, fd+1); rv = 0; } if(rv == 0) { *(proc **)vec_element(&sched->readers, fd) = NULL; *(proc **)vec_element(&sched->writers, fd) = NULL; } return rv; } void set_reader(int fd, proc *p) { *(proc**)vec_element(&sched->readers, fd) = p; } void set_writer(int fd, proc *p) { *(proc**)vec_element(&sched->writers, fd) = p; } void clr_reader(int fd) { *(proc**)vec_element(&sched->readers, fd) = NULL; } void clr_writer(int fd) { *(proc**)vec_element(&sched->writers, fd) = NULL; } void set_waitchild(pid_t pid, proc *p) { if(1 && !((hashtable_value_or_null((&sched->children), ((void*)(intptr_t)pid))) == NULL)) { fault_(__FILE__, __LINE__, "set_waitchild: waiter already set"); } (hashtable_add((&sched->children), ((void*)(intptr_t)pid), ((void*)(intptr_t)p))); ++sched->n_children; } void clr_waitchild(pid_t pid) { (hashtable_delete((&sched->children), ((void*)(intptr_t)pid))); --sched->n_children; } void sigchld_handler(int signum) { ((void)signum); sched->got_sigchld = 1; } num sched_get_time(void) { if(sched->now < 0) { sched_set_time(); } return sched->now; } void sched_forget_time(void) { sched->now = -1; } void sched_set_time(void) { sched->now = rtime(); } void shuttle_init(shuttle *sh, proc *p1, proc *p2) { sh->current = p1; sh->other = p2; sh->other_state = ACTIVE; } boolean pull_f(shuttle *s, proc *p) { boolean must_wait = s->current != p; if(must_wait) { s->other_state = WAITING; } return must_wait; } void push_f(shuttle *s, proc *p) { if(s->current == p) { proc *other = s->other; s->current = other; s->other = p; int other_state = s->other_state; s->other_state = ACTIVE; if(other_state == WAITING) { start_f(other); } } } void sock_init(sock *s, socklen_t socklen) { s->fd = -1; s->sa = (normal_Malloc(socklen)); s->len = socklen; bzero(s->sa, socklen); } void sock_free(sock *s) { if(s->fd != -1) { close(s->fd); } s->fd = -1; ((free((s->sa))), (s->sa) = NULL); } in_addr sock_in_addr(sock *s) { return ((sockaddr_in*)s->sa)->sin_addr; } u_int16_t sock_in_port(sock *s) { return ntohs(((sockaddr_in*)s->sa)->sin_port); } void listener_tcp_init(listener_try *p, cstr listen_addr, int listen_port) { int listen_fd = (Server_tcp(listen_addr, listen_port)); listener_try_init(p, listen_fd, sizeof(sockaddr_in)); } void listener_try_init(listener_try *d, int listen_fd, socklen_t socklen) { d->listen_fd = listen_fd; d->socklen = socklen; proc_init(&d->p, listener_try_f); } int listener_try_f(proc *b__p) { listener_try *This = (listener_try *)b__p; switch(b__p->pc) { case 1: ; if((scheduler_add_fd(sched, (This->listen_fd), 1))) { Close((This->listen_fd)); error("listener: can't create listener, too many sockets"); } cloexec((This->listen_fd)); (nonblock((This->listen_fd), 1)); while(1) { (This->s) = ((sock *)(normal_Malloc((sizeof(sock))))); sock_init((This->s), (This->socklen)); (This->s)->fd = accept((This->listen_fd), (struct sockaddr *)(This->s)->sa, &(This->s)->len); if((This->s)->fd < 0) { sock_free((This->s)); if(errno == EAGAIN) { } else if(errno == EMFILE || errno == ENFILE) { warn("listener: maximum number of file descriptors exceeded, rejecting %d", (This->s)->fd); } else { failed("accept"); } set_reader((This->listen_fd), b__p); b__p->pc = 2; return 0; case 2: ; } else if((scheduler_add_fd(sched, ((This->s)->fd), 1))) { warn("listener: maximum number of sockets exceeded, rejecting %d", (This->s)->fd); sock_free((This->s)); } else { cloexec((This->s)->fd); (nonblock(((This->s)->fd), 1)); (keepalive(((This->s)->fd), 1)); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 3; return 0; case 3: ; } (This->out->d) = (This->s); push_f(&This->out->sh, b__p); } } } return 0; } void reader_try_init(reader_try *d, int fd, size_t block_size, boolean sel_first) { d->fd = fd; d->block_size = block_size; d->sel_first = sel_first; proc_init(&d->p, reader_try_f); } int reader_try_f(proc *b__p) { reader_try *This = (reader_try *)b__p; switch(b__p->pc) { case 1: ; (This->done) = 0; if((This->sel_first)) { set_reader((This->fd), b__p); b__p->pc = 2; return 0; case 2: ; } while(!(This->done)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 3; return 0; case 3: ; } buffer_ensure_free(&(This->out->d), (This->block_size)); ssize_t want = ((ssize_t)((&(This->out->d))->space_end - (&(This->out->d))->end)); ssize_t n = read((This->fd), ((&(This->out->d))->end), want); if(n < 0 && errno != EAGAIN) { n = 0; if(errno != ECONNRESET) { swarning("reader %010p: error", b__p); } } if(n >= 0) { if(n == 0) { buffer_clear(&(This->out->d)); (This->done) = 1; } else { buffer_grow(&(This->out->d), n); } push_f(&This->out->sh, b__p); } if(n < want) { set_reader((This->fd), b__p); b__p->pc = 4; return 0; case 4: ; } } } return 0; } void writer_try_init(writer_try *d, int fd, boolean sel_first) { d->fd = fd; d->sel_first = sel_first; proc_init(&d->p, writer_try_f); } int writer_try_f(proc *b__p) { writer_try *This = (writer_try *)b__p; switch(b__p->pc) { case 1: ; (This->done) = 0; if((This->sel_first)) { set_writer((This->fd), b__p); b__p->pc = 2; return 0; case 2: ; } while(!(This->done)) { if(pull_f(&This->in->sh, b__p)) { b__p->pc = 3; return 0; case 3: ; } if(!((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start)))) { shutdown((This->fd), SHUT_WR); (This->done) = 1; } while(((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start)))) { ssize_t want = ((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start))); ssize_t n = write((This->fd), ((&(This->in->d))->start), want); if(n < 0 && errno != EAGAIN) { swarning("writer %010p: error", b__p); (This->done) = 1; break; } if(n >= 0) { buffer_shift(&(This->in->d), n); } if(n < want) { set_writer((This->fd), b__p); b__p->pc = 4; return 0; case 4: ; } } push_f(&This->in->sh, b__p); } } return 0; } void url_decode(cstr q) { cstr o = q; while(*q) { if(*q == '%' && q[1] && q[2]) { char c[3] = { q[1], q[2], '\0' }; *o = (char)strtol(c, NULL, 16); q+=2; } else { *o = *q; } ++q; ++o; } *o = '\0'; } cstr get_host_from_url(cstr url) { cstr host = strstr(url, "://"); if(host) { host += 3; char *e = strchr(host, '/'); if(e) { host = (normal_Strndup(host, (e-host))); } else { host = NULL; } } return host; } cstr get_path_from_url(cstr url) { cstr path = url; cstr host = strstr(url, "://"); if(host) { host += 3; path = strchr(host, '/'); if(!path) { path = "/"; } } return path; } void base64_decode_buffers(buffer *i, buffer *o) { vstream struct__my__5149_vsi; vstream *my__5149_vsi = &struct__my__5149_vsi; vstream_init_buffer(my__5149_vsi, i); vstream struct__my__5149_vso; vstream *my__5149_vso = &struct__my__5149_vso; vstream_init_buffer(my__5149_vso, o); vstream *my__5170_old_in = in, *my__5170_old_out = out; int my__5177_x = 0; my__5177_x: if(my__5177_x == 1) { ++my__5177_x; in = my__5170_old_in; out = my__5170_old_out; } for(; my__5177_x < 2 ; ++my__5177_x) { if(my__5177_x == 1) { goto my__5177_x; } my__5170_old_in = in; my__5170_old_out = out; in = my__5149_vsi; out = my__5149_vso; base64_decode(); } } void base64_decode(void) { if(!base64_decode_map) { base64_decode_map = (normal_Calloc(128, 1)); typeof(64) my__5189_end = 64; typeof(0) my__5189_v1 = 0; for(; my__5189_v1sh, &l->p, &w->p); l->out = my__5821_sh; w->in = my__5821_sh; listener_tcp struct__l_https; listener_tcp *l_https = &struct__l_https; listener_tcp_init(l_https, listen_addr_stunnel, listen_port_stunnel); httpd_launcher struct__w_https; httpd_launcher *w_https = &struct__w_https; httpd_launcher_init(w_https); shuttle_sock_p struct__my__5840_sh; shuttle_sock_p *my__5840_sh = &struct__my__5840_sh; shuttle_init(&my__5840_sh->sh, &l_https->p, &w_https->p); l_https->out = my__5840_sh; w_https->in = my__5840_sh; Setegid((defu->pw_gid)); Seteuid((defu->pw_uid)); for(server_i=0; server_i < n_servers-1 ; ++server_i) { if(Fork() == 0) { break; } } scheduler_init(sched); start_f(&l->p); start_f(&w->p); start_f(&l_https->p); start_f(&w_https->p); run(); Seteuid(0); Setegid(0); return 0; } void term_handler(int sig) { kill(0, sig); exit(0); } void usr1_handler(int sig) { ((void)sig); sched->exit = 1; } void httpd_launcher_init(httpd_launcher *d) { proc_init(&d->p, httpd_launcher_f); } int httpd_launcher_f(proc *b__p) { httpd_launcher *This = (httpd_launcher *)b__p; switch(b__p->pc) { case 1: ; while(1) { if(pull_f(&This->in->sh, b__p)) { b__p->pc = 2; return 0; case 2: ; } (This->sk) = (This->in->d); push_f(&This->in->sh, b__p); (This->s) = ((httpd *)(normal_Malloc((sizeof(httpd))))); httpd_init((This->s), (This->sk)); start_f(&(This->s)->p); } } return 0; } void httpd_init(httpd *d, sock *sk) { d->sk = sk; proc_init(&d->p, httpd_f); } int httpd_f(proc *b__p) { httpd *This = (httpd *)b__p; switch(b__p->pc) { case 1: ; (This->fd) = (This->sk)->fd; (This->namelen) = sizeof(sockaddr_in); (This->scheme) = "http"; if(getsockname((This->fd), &(This->sockname), &(This->namelen)) == 0) { if((This->sockname).sin_family == AF_INET) { (This->server_addr) = (This->sockname).sin_addr; (This->server_addr_str) = (normal_Strdup((inet_ntoa((This->server_addr))))); int port = ntohs((This->sockname).sin_port); if(listen_addr_stunnel && port == listen_port_stunnel) { (This->scheme) = "https"; (This->server_port) = listen_port_ssl; } else { (This->server_port) = port; } } } (This->remote_addr) = sock_in_addr((This->sk)); (This->remote_addr_str) = (normal_Strdup((inet_ntoa((This->remote_addr))))); (This->remote_port) = sock_in_port((This->sk)); (nodelay((This->fd), 1)); reader_try_init((&(This->r)), (This->fd), block_size, 0); writer_try_init((&(This->w)), (This->fd), 0); (This->my__5899_sh) = &(This->struct__my__5899_sh); shuttle_init(&(This->my__5899_sh)->sh, &(&(This->r))->p, &This->p); (&(This->r))->out = (This->my__5899_sh); This->in = (This->my__5899_sh); (This->my__5912_sh) = &(This->struct__my__5912_sh); shuttle_init(&(This->my__5912_sh)->sh, &This->p, &(&(This->w))->p); This->out = (This->my__5912_sh); (&(This->w))->in = (This->my__5912_sh); buffer_init(&(This->in->d), block_size); buffer_init(&(This->out->d), block_size); start_f(&(&(This->r))->p); start_f(&(&(This->w))->p); req: (This->url) = NULL; (This->proto) = NULL; (This->host) = NULL; (This->path) = NULL; (This->root) = NULL; (This->fullpath) = NULL; (This->query) = NULL; (This->user) = default_user; (This->pass) = NULL; (This->reqlen) = -1; (This->file_fd) = -1; (This->private) = 0; (This->expire_already) = 0; (This->user_agent) = NULL; (This->keep_alive) = 1; (This->statable) = 0; (This->st) = &(This->struct__st); (This->http1_1) = 1; (This->body) = NULL; (This->mtime) = -1; (This->mtype) = "text/plain"; (This->range_req) = 0; (This->byte0) = 0; (This->content_range_req) = 0; (This->cr_byte0) = 0; (This->line_start) = 0; (This->headers) = &(This->struct__headers); vec_init_el_size((This->headers), sizeof(key_value), (32)); while(1) { if((This->in->sh.current == b__p) && ((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start))) <= 0) { push_f(&This->in->sh, b__p); } while(1) { if(pull_f(&This->in->sh, b__p)) { b__p->pc = 2; return 0; case 2: ; } if(((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start))) <= 0) { break; } (This->c) = memchr(((&(This->in->d))->start+0), '\n', ((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start)))-0); if((This->c)) { *(This->c) = '\0'; } if(max_line_length && (((This->c) && (This->c)-((&(This->in->d))->start+0) >= max_line_length) || (!(This->c) && ((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start)))-0 >= max_line_length))) { warn("received line longer than max_line_length %d - closing", max_line_length); (buffer_clear((&(This->in->d)))); break; } if((This->c)) { break; } push_f(&This->in->sh, b__p); } if(!((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start)))) { goto quit; } (This->s) = ((&(This->in->d))->start); (This->l) = (This->c) - (This->s) + 1; cstr_dos_to_unix((This->s)); if(*(This->s)) { break; } buffer_shift(&(This->in->d), (This->l)); } sched_set_time(); cstr *words = split((This->s), ' '); if(arylen(words) != 3) { buffer_shift(&(This->in->d), (This->l)); ((free(words)), words = NULL); goto bad; } (This->method_str) = (normal_Strdup((words[0]))); (This->method) = http_which_method((This->method_str)); (This->url) = (normal_Strdup((words[1]))); (This->proto) = (normal_Strdup((words[2]))); url_decode((This->url)); ((free(words)), words = NULL); (This->line_start) = (This->l); if(!strncmp((This->proto), "HTTP/", 5)) { if(!strcmp((This->proto)+5, "1.0") || (This->proto)[5] == '0') { (This->http1_1) = 0; (This->keep_alive) = 0; } } while(1) { if((This->in->sh.current == b__p) && ((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start))) <= (This->line_start)) { push_f(&This->in->sh, b__p); } while(1) { if(pull_f(&This->in->sh, b__p)) { b__p->pc = 3; return 0; case 3: ; } if(((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start))) <= (This->line_start)) { break; } (This->c) = memchr(((&(This->in->d))->start+(This->line_start)), '\n', ((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start)))-(This->line_start)); if((This->c)) { *(This->c) = '\0'; } if(max_line_length && (((This->c) && (This->c)-((&(This->in->d))->start+(This->line_start)) >= max_line_length) || (!(This->c) && ((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start)))-(This->line_start) >= max_line_length))) { warn("received line longer than max_line_length %d - closing", max_line_length); (buffer_clear((&(This->in->d)))); break; } if((This->c)) { break; } push_f(&This->in->sh, b__p); } if(((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start))) <= (This->line_start)) { goto quit; } (This->s) = ((&(This->in->d))->start+(This->line_start)); (This->l) = (This->c) - (This->s) + 1; cstr_dos_to_unix((This->s)); (This->line_start) += (This->l); if(!*(This->s)) { break; } cstr *words = (splitn((This->s), ':', 2)); if(arylen(words) != 2) { ((free(words)), words = NULL); goto bad; } cstr key = words[0], val = words[1]; ((free(words)), words = NULL); while(isspace(val[0])) { ++val; } for(char *i=key; *i; ++i) { if(((*i) >= 'A' && (*i) <= 'Z')) { *i += 'a' - 'A'; } } key_value *kv = vec_push((This->headers)); kv->k = (normal_Strdup(key)); kv->v = (normal_Strdup(val)); if(!strcmp(key, "host")) { (This->host) = (normal_Strdup(val)); } else if(!strcmp(key, "authorization")) { if(!strncasecmp(val, "Basic ", 6)) { (This->base64) = &(This->struct__base64); buffer_from_cstr((This->base64), (val+6), strlen((val+6))); (This->o) = &(This->struct__o); buffer_init((This->o), 32); base64_decode_buffers((This->base64), (This->o)); (This->user) = buffer_to_cstr((This->o)); cstr *user_pass = (splitn((This->user), ':', 2)); if(arylen(user_pass) != 2) { ((free(user_pass)), user_pass = NULL); goto bad; } (This->pass) = user_pass[1]; ((free(user_pass)), user_pass = NULL); } } else if(!strcmp(key, "user-agent")) { (This->user_agent) = (normal_Strdup(val)); } else if(!strcmp(key, "content-Length")) { (This->reqlen) = atoll(val); } else if(!strcmp(key, "connection")) { if(!strcasecmp(val, "close")) { (This->keep_alive) = 0; } else if(!strcasecmp(val, "Keep-Alive")) { (This->keep_alive) = 1; } } else if(!strcmp(key, "range")) { int n = sscanf(val, "bytes=%lld-%lld", &(This->byte0), &(This->byte1)); if(n) { (This->range_req) = 1; if(n == 1) { (This->byte1) = -1; } } } else if(!strcmp(key, "content-range")) { int n = sscanf(val, "bytes=%lld-%lld", &(This->cr_byte0), &(This->cr_byte1)); if(n) { (This->content_range_req) = 1; if(n == 1) { (This->cr_byte1) = -1; } } } } if((This->host) == NULL) { (This->host) = get_host_from_url((This->url)); } if((This->host) == NULL) { (This->host) = (normal_Strdup(default_host)); } (This->path) = get_path_from_url((This->url)); (This->root) = (format("%s%s%s", (cstr_eq(www_root, "/") ? "" : www_root), "/", (This->host))); Stats str; if(!lstat((This->root), &str)) { if(S_ISLNK(str.st_mode)) { cstr realhost = readlinks((normal_Strdup((This->root))), OE_CONT); cstr free_me = realhost; size_t www_root_len = strlen(www_root); if(cstr_begins_with(realhost, www_root) && realhost[www_root_len] == '/') { realhost += www_root_len + 1; } if(!strchr(realhost, '/')) { (This->location) = format("%s://%s%s", (This->scheme), base_name(realhost), (This->path)); ((free(free_me)), free_me = NULL); goto loc; } ((free(free_me)), free_me = NULL); } } else { goto notf; } (This->fullpath) = (format("%s%s%s", (cstr_eq((This->root), "/") ? "" : (This->root)), "/", (*(This->path) == '/' ? (This->path)+1 : (This->path)))); (This->query) = strchr((This->fullpath), '?'); if((This->query)) { *(This->query)++ = '\0'; cstr q2 = strchr((This->path), '?'); if(q2) { *q2 = '\0'; } (This->query) = (normal_Strdup((This->query))); } (This->fullpath) = path_tidy((This->fullpath)); if(!(cstr_begins_with((This->fullpath), (This->root)) && (This->fullpath)[strlen((This->root))] == '/')) { goto bad; } for(char *i=(This->fullpath); *i; ++i) { if(*i == '/' && i[1] == '.') { goto forbid; } } if(cstr_ends_with((This->url), "/index.html")) { (This->location) = (normal_Strdup((This->url))); strrchr((This->location), '/')[1] = '\0'; goto loc; } (This->u) = (hashtable_value_or_null(users, ((void*)(intptr_t)(This->user)))); if((This->user) != default_user && !((This->u) && (This->pass) && auth((This->u), (This->pass)))) { goto reqauth; } if((This->pass)) { bzero((This->pass), strlen((This->pass))); } if((This->user) != default_user) { Seteuid(0); Setegid(0); Setegid(((This->u)->pw_gid)); Seteuid(((This->u)->pw_uid)); } if((This->fullpath)[strlen((This->fullpath))-1] == '/') { cstr *index; for(index = index_files; *index; ++index) { cstr fullpath_index = (format("%s%s", (This->fullpath), (*index))); (This->statable) = !stat(fullpath_index, (This->st)); if((This->statable) && S_ISREG((This->st)->st_mode)) { ((free((This->fullpath))), (This->fullpath) = NULL); (This->fullpath) = fullpath_index; if((This->method) == HTTP_GET && !(This->query) && !strstr(*index, ".htm")) { (This->query) = (normal_Strdup("?")); } } else { ((free(fullpath_index)), fullpath_index = NULL); } } } if(!(This->statable)) { (This->statable) = !stat((This->fullpath), (This->st)); } if((This->statable)) { (This->mtime) = (This->st)->st_mtime; (This->fullsize) = (This->st)->st_size; } else if(((This->method) == HTTP_GET || (This->method) == HTTP_HEAD || (This->method) == HTTP_DELETE)) { if((This->user) != default_user) { Seteuid(0); Setegid(0); Setegid((defu->pw_gid)); Seteuid((defu->pw_uid)); } goto accerr; } else { (This->fullsize) = 0; } if(!((This->st)->st_mode & S_IROTH)) { (This->private) = 1; (This->expire_already) = 1; } (This->base) = strrchr((This->fullpath), '/'); (This->ext) = strrchr((This->base), '.'); if((This->ext)) { ++(This->ext); } else { (This->ext) = ""; } (This->is_php) = cstr_eq((This->ext), "php"); if(S_ISREG((This->st)->st_mode) && ((This->st)->st_mode & S_IXUSR || (This->is_php)) && ((This->method) == HTTP_POST || ((This->method) == HTTP_GET && (This->query)))) { pid_t child = Fork(); if(child == 0) { Seteuid(0); Setegid(0); Setgid(((This->u)->pw_gid)); Setuid(((This->u)->pw_uid)); buffer_nul_terminate(&(This->in->d)); Setenv("REQUEST_BODY_1", ((&(This->in->d))->start+(This->line_start)), 1); if((This->query)) { Setenv("QUERY_STRING", (This->query), 1); } char tmp[1024]; Setenv("SERVER_NAME", (This->host), 1); Setenv("SERVER_PROTOCOL", (This->proto), 1); Setenv("REQUEST_METHOD", (This->method_str), 1); Setenv("SCRIPT_NAME", (This->path), 1); Setenv("REMOTE_ADDR", (This->remote_addr_str), 1); if ((This->method) == HTTP_POST) { { sprintf(tmp, "%lld", (long long int)(This->reqlen)); Setenv("CONTENT_LENGTH", tmp, 1); } } snprintf(tmp, sizeof(tmp), "
%s/%s at %s Port %d
", program, version, (This->host), (This->server_port)); Setenv("SERVER_SIGNATURE", tmp, 1); Setenv("SERVER_ADDR", (This->server_addr_str), 1); sprintf(tmp, "%d", (This->server_port)); Setenv("SERVER_PORT", tmp, 1); Setenv("DOCUMENT_ROOT", (This->root), 1); Setenv("SCRIPT_FILENAME", (This->fullpath), 1); sprintf(tmp, "%d", (This->remote_port)); Setenv("REMOTE_PORT", tmp, 1); Setenv("REQUEST_URI", (This->path), 1); key_value *i = (vec_element((This->headers), 0)); key_value *e = (vec_element((This->headers), (This->headers)->size)); for(; i!=e; ++i) { char tmp[64]; strcpy(tmp, "HTTP_"); strncpy(tmp+5, i->k, sizeof(tmp)-5-1); tmp[63] = '\0'; char *j = tmp+5; for(; *j; ++j) { if(*j == '-') { *j = '_'; } else if(islower(*j)) { *j -= 'a' - 'A'; } } Setenv(tmp, (i->v), 1); } Dup2((This->fd), STDIN_FILENO); Dup2((This->fd), STDOUT_FILENO); (Sigact(SIGPIPE, SIG_DFL, 0)); exec__warn_fail = 0; dirbase d_b = dirbasename(normal_Strdup((This->fullpath))); if(chdir(d_b.dir)) { exit_exec_failed(); } if((This->is_php)) { Execlp("php", "php", (This->fullpath), NULL); } Execl((This->fullpath), (This->fullpath), NULL); } buffer_set_size(&(This->in->d), (This->line_start)); if((This->user) != default_user) { Seteuid(0); Setegid(0); Setegid((defu->pw_gid)); Seteuid((defu->pw_uid)); } { set_waitchild(child, b__p); b__p->pc = 4; return 0; case 4: ; (This->status) = waitchild__status; } if(((This->status) == status__execfailed)) { goto reqauth; } else if((This->status) != 0) { (This->keep_alive) = 0; goto srverr; } else { (This->keep_alive) = 0; } } else if(((This->method) == HTTP_PUT || (This->method) == HTTP_POST)) { int open_opt = O_WRONLY|O_CREAT|O_NONBLOCK; if((This->content_range_req)) { if((This->range_req)) { if((This->cr_byte0) < 0) { (This->cr_byte0) += (This->fullsize); if((This->cr_byte0) < 0) { (This->cr_byte0) = 0; } } if((This->cr_byte1) < 0) { (This->cr_byte1) += (This->fullsize); if((This->cr_byte1) < 0) { (This->cr_byte1) = 0; } } if((This->cr_byte1) <= (This->cr_byte0)) { goto bad; } } } else { if((This->method) == HTTP_PUT) { open_opt |= O_TRUNC; } else { open_opt |= O_APPEND; } } (This->file_fd) = open((This->fullpath), open_opt, 0666); if((This->user) != default_user) { Seteuid(0); Setegid(0); Setegid((defu->pw_gid)); Seteuid((defu->pw_uid)); } if((This->content_range_req)) { (Lseek((This->file_fd), (This->cr_byte0), SEEK_SET)); } if((This->file_fd) == -1) { goto accerr; } if((scheduler_add_fd(sched, (This->file_fd), 1))) { Close((This->file_fd)); (This->file_fd) = -1; goto srverr; } cloexec((This->file_fd)); writer_try_init((&(This->fw)), (This->file_fd), 0); (This->my__6171_sh) = &(This->struct__my__6171_sh); shuttle_init(&(This->my__6171_sh)->sh, &This->p, &(&(This->fw))->p); This->fio = (This->my__6171_sh); (&(This->fw))->in = (This->my__6171_sh); buffer_init(&(This->fio->d), block_size); start_f(&(&(This->fw))->p); (This->out_tmp) = (This->out->d); (This->offset) = 0; if(((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start))) <= (This->line_start)) { push_f(&This->in->sh, b__p); } if((This->reqlen) != 0) { while(1) { if(pull_f(&This->in->sh, b__p)) { b__p->pc = 5; return 0; case 5: ; } if(((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start))) <= (This->line_start)) { break; } (This->count) = ((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start))); if((This->reqlen) > 0 && (off_t)((This->offset) + (This->count)) > (This->reqlen)) { (This->count) = (This->reqlen) - (This->offset); } (This->offset) += (This->count); (This->bwrite_direct__saved_buffer) = (This->fio->d); if(pull_f(&This->fio->sh, b__p)) { b__p->pc = 6; return 0; case 6: ; } (This->fio->d).start = ((&(This->in->d))->start+(This->line_start)); (This->fio->d).end = ((&(This->in->d))->start+((This->line_start)+(This->count))); (This->fio->d).space_end = ((&(This->in->d))->start+((This->line_start)+(This->count))); if(pull_f(&This->fio->sh, b__p)) { b__p->pc = 7; return 0; case 7: ; } if(!((ssize_t)(((&(This->fio->d))->end)-((&(This->fio->d))->start)))) { } else { push_f(&This->fio->sh, b__p); if(pull_f(&This->fio->sh, b__p)) { b__p->pc = 8; return 0; case 8: ; } } (This->fio->d) = (This->bwrite_direct__saved_buffer); if(((ssize_t)(((&(This->fio->d))->end)-((&(This->fio->d))->start)))) { break; } buffer_set_size(&(This->in->d), (This->line_start)); if((This->offset) == (This->reqlen)) { break; } push_f(&This->in->sh, b__p); } } (This->out->d) = (This->out_tmp); if((This->content_range_req) && (This->method) == HTTP_PUT && (This->cr_byte1) >= (This->fullsize)-1) { Ftruncate((This->file_fd), (This->cr_byte0) + (This->offset)); } if((This->file_fd) != -1) { io_epoll_rm(&sched->io, (This->file_fd)); *(proc **)vec_element(&sched->readers, (This->file_fd)) = NULL; *(proc **)vec_element(&sched->writers, (This->file_fd)) = NULL; if(close((This->file_fd))) { swarning("close failed for file: %s", (This->fullpath)); } (This->file_fd) = -1; } if((This->reqlen) == -1) { (This->keep_alive) = 0; } else if((This->offset) < (This->reqlen)) { (This->reqlen) = 0; goto bad; } (This->reqlen) = 0; if((This->statable)) { goto ok; } else { goto created; } } else if((This->method) == HTTP_DELETE) { int failed = remove((This->fullpath)); if((This->user) != default_user) { Seteuid(0); Setegid(0); Setegid((defu->pw_gid)); Seteuid((defu->pw_uid)); } if(failed) { goto accerr; } goto ok; } else if(!((This->method) == HTTP_GET || (This->method) == HTTP_HEAD) || (This->reqlen) > 0) { if((This->user) != default_user) { Seteuid(0); Setegid(0); Setegid((defu->pw_gid)); Seteuid((defu->pw_uid)); } goto bad; } else if(S_ISREG((This->st)->st_mode)) { if(*(This->ext)) { cstr _mtype = mimetype((This->ext)); if(_mtype) { (This->mtype) = _mtype; } } (This->in_cache) = 0; (This->citem) = NULL; if((This->method) == HTTP_GET) { if((This->fullsize) < cache_max_entry_size && (This->mtime) < (time_t)sched_get_time() && (This->user) == default_user) { key_value *kv = (hashtable_lookup_or_add_key(cache, ((void*)(intptr_t)(This->fullpath)), ((void*)(intptr_t)NULL))); if(kv->v == NULL) { kv->k = strdup((This->fullpath)); (This->citem) = kv->v = ((cache_item *)(normal_Malloc((sizeof(cache_item))))); buffer_init(&(This->citem)->body, (This->st)->st_size); } else { (This->citem) = kv->v; if((This->mtime) == (This->citem)->mtime) { (This->in_cache) = 1; if((This->user) != default_user) { Seteuid(0); Setegid(0); Setegid((defu->pw_gid)); Seteuid((defu->pw_uid)); } } } if(!(This->in_cache)) { (This->citem)->mtime = (This->mtime); buffer_set_size(&(This->citem)->body, (This->fullsize)); buffer_squeeze(&(This->citem)->body); (This->file_fd) = open((This->fullpath), O_RDONLY); if((This->user) != default_user) { Seteuid(0); Setegid(0); Setegid((defu->pw_gid)); Seteuid((defu->pw_uid)); } if((This->file_fd) == -1) { (hashtable_delete(cache, ((void*)(intptr_t)(This->fullpath)))); ((free((kv->k))), (kv->k) = NULL); ((free((kv->v))), (kv->v) = NULL); goto accerr; } Read((This->file_fd), ((&(This->citem)->body)->start), (This->fullsize)); close((This->file_fd)); (This->file_fd) = -1; (This->in_cache) = 1; } } else { (This->file_fd) = open((This->fullpath), O_RDONLY); if((This->user) != default_user) { Seteuid(0); Setegid(0); Setegid((defu->pw_gid)); Seteuid((defu->pw_uid)); } if((This->file_fd) == -1) { goto accerr; } cloexec((This->file_fd)); } } else { if((This->user) != default_user) { Seteuid(0); Setegid(0); Setegid((defu->pw_gid)); Seteuid((defu->pw_uid)); } } if((This->range_req)) { if((This->byte0) < 0) { (This->byte0) += (This->fullsize); if((This->byte0) < 0) { (This->byte0) = 0; } } if((This->byte1) < 0) { (This->byte1) += (This->fullsize); if((This->byte1) < 0) { (This->byte1) = 0; } } if((This->byte1) >= (This->fullsize)) { (This->byte1) = (This->fullsize) - 1; } (This->size) = (This->byte1) - (This->byte0) + 1; if((This->byte1) <= (This->byte0)) { goto badrng; } } else { (This->size) = (This->fullsize); } if((This->range_req)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 9; return 0; case 9: ; } Sprintf(&(This->out->d), "HTTP/1.1 %d %s\r", 206, "Partial Content"); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 10; return 0; case 10: ; } Sprintf(&(This->out->d), "Date: %s\r", (date_rfc1123((time_t)sched_get_time()))); buffer_cat_char(&(This->out->d), '\n'); if((This->mtime) != -1) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 11; return 0; case 11: ; } Sprintf(&(This->out->d), "Last-Modified: %s\r", (date_rfc1123((This->mtime)))); buffer_cat_char(&(This->out->d), '\n'); } if((This->range_req)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 12; return 0; case 12: ; } Sprintf(&(This->out->d), "Content-Range: %lld-%lld/%lld\r", ((long long int)(This->byte0)), ((long long int)(This->byte1)), ((long long int)(This->fullsize))); buffer_cat_char(&(This->out->d), '\n'); } if(pull_f(&This->out->sh, b__p)) { b__p->pc = 13; return 0; case 13: ; } Sprintf(&(This->out->d), "Content-Length: %lld\r", ((long long int)(This->size))); buffer_cat_char(&(This->out->d), '\n'); if(206 == 200 && (This->expire_already)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 14; return 0; case 14: ; } buffer_cat_cstr(&(This->out->d), "Cache-Control: private, no-cache, no-store\r"); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 15; return 0; case 15: ; } buffer_cat_cstr(&(This->out->d), "Expires: 0\r"); buffer_cat_char(&(This->out->d), '\n'); } if(pull_f(&This->out->sh, b__p)) { b__p->pc = 16; return 0; case 16: ; } Sprintf(&(This->out->d), "Content-Type: %s\r", (This->mtype)); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 17; return 0; case 17: ; } Sprintf(&(This->out->d), "Server: %s\r", program); buffer_cat_char(&(This->out->d), '\n'); if(!(This->http1_1)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 18; return 0; case 18: ; } Sprintf(&(This->out->d), "Connection: %s\r", ((This->keep_alive) ? "Keep-Alive" : "close")); buffer_cat_char(&(This->out->d), '\n'); } } else { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 19; return 0; case 19: ; } Sprintf(&(This->out->d), "HTTP/1.1 %d %s\r", 200, "OK"); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 20; return 0; case 20: ; } Sprintf(&(This->out->d), "Date: %s\r", (date_rfc1123((time_t)sched_get_time()))); buffer_cat_char(&(This->out->d), '\n'); if((This->mtime) != -1) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 21; return 0; case 21: ; } Sprintf(&(This->out->d), "Last-Modified: %s\r", (date_rfc1123((This->mtime)))); buffer_cat_char(&(This->out->d), '\n'); } if((This->range_req)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 22; return 0; case 22: ; } Sprintf(&(This->out->d), "Content-Range: %lld-%lld/%lld\r", ((long long int)(This->byte0)), ((long long int)(This->byte1)), ((long long int)(This->fullsize))); buffer_cat_char(&(This->out->d), '\n'); } if(pull_f(&This->out->sh, b__p)) { b__p->pc = 23; return 0; case 23: ; } Sprintf(&(This->out->d), "Content-Length: %lld\r", ((long long int)(This->size))); buffer_cat_char(&(This->out->d), '\n'); if(200 == 200 && (This->expire_already)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 24; return 0; case 24: ; } buffer_cat_cstr(&(This->out->d), "Cache-Control: private, no-cache, no-store\r"); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 25; return 0; case 25: ; } buffer_cat_cstr(&(This->out->d), "Expires: 0\r"); buffer_cat_char(&(This->out->d), '\n'); } if(pull_f(&This->out->sh, b__p)) { b__p->pc = 26; return 0; case 26: ; } Sprintf(&(This->out->d), "Content-Type: %s\r", (This->mtype)); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 27; return 0; case 27: ; } Sprintf(&(This->out->d), "Server: %s\r", program); buffer_cat_char(&(This->out->d), '\n'); if(!(This->http1_1)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 28; return 0; case 28: ; } Sprintf(&(This->out->d), "Connection: %s\r", ((This->keep_alive) ? "Keep-Alive" : "close")); buffer_cat_char(&(This->out->d), '\n'); } } if(pull_f(&This->out->sh, b__p)) { b__p->pc = 29; return 0; case 29: ; } buffer_cat_cstr(&(This->out->d), "\r\n"); if((This->method) == HTTP_GET) { if((This->in_cache)) { struct iovec iov[2]; iov[0].iov_base = ((&(This->out->d))->start); iov[0].iov_len = ((ssize_t)(((&(This->out->d))->end)-((&(This->out->d))->start))); iov[1].iov_base = ((&(This->citem)->body)->start+(This->byte0)); iov[1].iov_len = (This->size); nonblock((This->fd), 0); Writev((This->fd), iov, 2); nonblock((This->fd), 1); (buffer_clear((&(This->out->d)))); } else { (cork((This->fd), 1)); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 30; return 0; case 30: ; } if(!((ssize_t)(((&(This->out->d))->end)-((&(This->out->d))->start)))) { } else { push_f(&This->out->sh, b__p); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 31; return 0; case 31: ; } } (This->offset) = (This->byte0); while((This->size)) { (This->count) = sendfile((This->fd), (This->file_fd), &(This->offset), (This->size)); if((This->count) == -1) { if((errno == ECONNRESET || errno == EPIPE)) { (This->keep_alive) = 0; break; } else if(errno != EAGAIN) { swarning("sendfile %d %d %d %d", (This->fd), (This->file_fd), (int)(This->offset), (int)(This->size)); break; } (This->count) = 0; } if((This->count) < (This->size)) { set_writer((This->fd), b__p); b__p->pc = 32; return 0; case 32: ; } (This->size) -= (This->count); } cork((This->fd), 0); close((This->file_fd)); (This->file_fd) = -1; } } else { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 33; return 0; case 33: ; } if(!((ssize_t)(((&(This->out->d))->end)-((&(This->out->d))->start)))) { } else { push_f(&This->out->sh, b__p); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 34; return 0; case 34: ; } } } } else if(S_ISDIR((This->st)->st_mode)) { if((This->fullpath)[strlen((This->fullpath))-1] != '/') { if((This->user) != default_user) { Seteuid(0); Setegid(0); Setegid((defu->pw_gid)); Seteuid((defu->pw_uid)); } (This->location) = format("%s/", (This->url)); goto loc; } vec *v = (ls((This->fullpath), 0)); if(!v) { if((This->user) != default_user) { Seteuid(0); Setegid(0); Setegid((defu->pw_gid)); Seteuid((defu->pw_uid)); } goto accerr; } sort_vec(v, cstr_cmp); (This->b0) = &(This->struct__b0); buffer_init((This->b0), 256); (This->b1) = &(This->struct__b1); buffer_init((This->b1), 256); cstr *j = (vec_element(v, 0)); cstr *e = (vec_element(v, v->size)); for(; j!=e; ++j) { if((*j)[0] == '.') { continue; } cstr entpath = (format("%s%s%s", (cstr_eq((This->fullpath), "/") ? "" : (This->fullpath)), "/", (*j))); int dir = 0; Stats ste; if(!stat(entpath, &ste) && S_ISDIR(ste.st_mode)) { dir = 1; } cstr line; if(dir) { line = format("%s
\n", *j, *j); buffer_cat_cstr((This->b0), line); } else { line = format("%s
\n", *j, *j); buffer_cat_cstr((This->b1), line); } ((free(line)), line = NULL); ((free(entpath)), entpath = NULL); ((free((*j))), (*j) = NULL); } vec_free(v); if((This->user) != default_user) { Seteuid(0); Setegid(0); Setegid((defu->pw_gid)); Seteuid((defu->pw_uid)); } buffer_cat_cstr((This->b0), "\n

\n\n"); buffer_cat_cstr((This->b1), "\n

\n\n"); buffer_cat_range((This->b0), ((This->b1)->start), ((This->b1)->end)); buffer_free((This->b1)); (This->mtype) = "text/html"; (This->fullsize) = ((ssize_t)(((This->b0)->end)-((This->b0)->start))); if((This->range_req)) { if((This->byte0) < 0) { (This->byte0) += (This->fullsize); if((This->byte0) < 0) { (This->byte0) = 0; } } if((This->byte1) < 0) { (This->byte1) += (This->fullsize); if((This->byte1) < 0) { (This->byte1) = 0; } } if((This->byte1) >= (This->fullsize)) { (This->byte1) = (This->fullsize) - 1; } (This->size) = (This->byte1) - (This->byte0) + 1; if((This->byte1) <= (This->byte0)) { goto badrng; } } else { (This->size) = (This->fullsize); } if((This->range_req)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 35; return 0; case 35: ; } Sprintf(&(This->out->d), "HTTP/1.1 %d %s\r", 206, "Partial Content"); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 36; return 0; case 36: ; } Sprintf(&(This->out->d), "Date: %s\r", (date_rfc1123((time_t)sched_get_time()))); buffer_cat_char(&(This->out->d), '\n'); if((This->mtime) != -1) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 37; return 0; case 37: ; } Sprintf(&(This->out->d), "Last-Modified: %s\r", (date_rfc1123((This->mtime)))); buffer_cat_char(&(This->out->d), '\n'); } if((This->range_req)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 38; return 0; case 38: ; } Sprintf(&(This->out->d), "Content-Range: %lld-%lld/%lld\r", ((long long int)(This->byte0)), ((long long int)(This->byte1)), ((long long int)(This->fullsize))); buffer_cat_char(&(This->out->d), '\n'); } if(pull_f(&This->out->sh, b__p)) { b__p->pc = 39; return 0; case 39: ; } Sprintf(&(This->out->d), "Content-Length: %lld\r", ((long long int)(This->size))); buffer_cat_char(&(This->out->d), '\n'); if(206 == 200 && (This->expire_already)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 40; return 0; case 40: ; } buffer_cat_cstr(&(This->out->d), "Cache-Control: private, no-cache, no-store\r"); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 41; return 0; case 41: ; } buffer_cat_cstr(&(This->out->d), "Expires: 0\r"); buffer_cat_char(&(This->out->d), '\n'); } if(pull_f(&This->out->sh, b__p)) { b__p->pc = 42; return 0; case 42: ; } Sprintf(&(This->out->d), "Content-Type: %s\r", (This->mtype)); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 43; return 0; case 43: ; } Sprintf(&(This->out->d), "Server: %s\r", program); buffer_cat_char(&(This->out->d), '\n'); if(!(This->http1_1)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 44; return 0; case 44: ; } Sprintf(&(This->out->d), "Connection: %s\r", ((This->keep_alive) ? "Keep-Alive" : "close")); buffer_cat_char(&(This->out->d), '\n'); } } else { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 45; return 0; case 45: ; } Sprintf(&(This->out->d), "HTTP/1.1 %d %s\r", 200, "OK"); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 46; return 0; case 46: ; } Sprintf(&(This->out->d), "Date: %s\r", (date_rfc1123((time_t)sched_get_time()))); buffer_cat_char(&(This->out->d), '\n'); if((This->mtime) != -1) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 47; return 0; case 47: ; } Sprintf(&(This->out->d), "Last-Modified: %s\r", (date_rfc1123((This->mtime)))); buffer_cat_char(&(This->out->d), '\n'); } if((This->range_req)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 48; return 0; case 48: ; } Sprintf(&(This->out->d), "Content-Range: %lld-%lld/%lld\r", ((long long int)(This->byte0)), ((long long int)(This->byte1)), ((long long int)(This->fullsize))); buffer_cat_char(&(This->out->d), '\n'); } if(pull_f(&This->out->sh, b__p)) { b__p->pc = 49; return 0; case 49: ; } Sprintf(&(This->out->d), "Content-Length: %lld\r", ((long long int)(This->size))); buffer_cat_char(&(This->out->d), '\n'); if(200 == 200 && (This->expire_already)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 50; return 0; case 50: ; } buffer_cat_cstr(&(This->out->d), "Cache-Control: private, no-cache, no-store\r"); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 51; return 0; case 51: ; } buffer_cat_cstr(&(This->out->d), "Expires: 0\r"); buffer_cat_char(&(This->out->d), '\n'); } if(pull_f(&This->out->sh, b__p)) { b__p->pc = 52; return 0; case 52: ; } Sprintf(&(This->out->d), "Content-Type: %s\r", (This->mtype)); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 53; return 0; case 53: ; } Sprintf(&(This->out->d), "Server: %s\r", program); buffer_cat_char(&(This->out->d), '\n'); if(!(This->http1_1)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 54; return 0; case 54: ; } Sprintf(&(This->out->d), "Connection: %s\r", ((This->keep_alive) ? "Keep-Alive" : "close")); buffer_cat_char(&(This->out->d), '\n'); } } if(pull_f(&This->out->sh, b__p)) { b__p->pc = 55; return 0; case 55: ; } buffer_cat_cstr(&(This->out->d), "\r\n"); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 56; return 0; case 56: ; } if(!((ssize_t)(((&(This->out->d))->end)-((&(This->out->d))->start)))) { } else { push_f(&This->out->sh, b__p); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 57; return 0; case 57: ; } } if((This->method) == HTTP_GET) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 58; return 0; case 58: ; } buffer_cat_range(&(This->out->d), ((This->b0)->start+(This->byte0)), ((This->b0)->start+(This->size))); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 59; return 0; case 59: ; } if(!((ssize_t)(((&(This->out->d))->end)-((&(This->out->d))->start)))) { } else { push_f(&This->out->sh, b__p); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 60; return 0; case 60: ; } } } buffer_free((This->b0)); if(((ssize_t)(((&(This->out->d))->end)-((&(This->out->d))->start)))) { (This->keep_alive) = 0; } } else { if((This->user) != default_user) { Seteuid(0); Setegid(0); Setegid((defu->pw_gid)); Seteuid((defu->pw_uid)); } goto notf; } done: ((free((This->url))), (This->url) = NULL); ((free((This->proto))), (This->proto) = NULL); ((free((This->host))), (This->host) = NULL); ((free((This->method_str))), (This->method_str) = NULL); ((free((This->root))), (This->root) = NULL); ((free((This->fullpath))), (This->fullpath) = NULL); ((free((This->body))), (This->body) = NULL); ((free((This->query))), (This->query) = NULL); if((This->file_fd) != -1) { close((This->file_fd)); (This->file_fd) = -1; } key_value *i = (vec_element((This->headers), 0)); key_value *e = (vec_element((This->headers), (This->headers)->size)); for(; i!=e; ++i) { ((free((i->k))), (i->k) = NULL); ((free((i->v))), (i->v) = NULL); } vec_free((This->headers)); if((This->user) != default_user) { ((free((This->user))), (This->user) = NULL); } if((This->keep_alive)) { buffer_shift(&(This->in->d), (This->line_start)); goto req; } ((free((This->server_addr_str))), (This->server_addr_str) = NULL); ((free((This->remote_addr_str))), (This->remote_addr_str) = NULL); goto shut; shut: (buffer_clear((&(This->out->d)))); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 61; return 0; case 61: ; } push_f(&This->out->sh, b__p); while(1) { if((This->in->sh.current == b__p) && !((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start)))) { buffer_ensure_space(&(This->in->d), block_size); push_f(&This->in->sh, b__p); } while(1) { if(pull_f(&This->in->sh, b__p)) { b__p->pc = 62; return 0; case 62: ; } if((size_t)((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start))) >= (size_t)block_size || !((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start)))) { break; } buffer_ensure_space(&(This->in->d), block_size-((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start)))); push_f(&This->in->sh, b__p); } if(!((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start)))) { break; } } goto quit; quit: ; io_epoll_rm(&sched->io, (This->fd)); *(proc **)vec_element(&sched->readers, (This->fd)) = NULL; *(proc **)vec_element(&sched->writers, (This->fd)) = NULL; sock_free((This->sk)); ((free((This->sk))), (This->sk) = NULL); buffer_free(&(This->in->d)); buffer_free(&(This->out->d)); ((free(This)), This = NULL); return 0; mesg: (This->body) = format("%s: %d %s\r\n", program, (This->code), (This->msg)); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 63; return 0; case 63: ; } Sprintf(&(This->out->d), "HTTP/1.1 %d %s\r", (This->code), (This->msg)); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 64; return 0; case 64: ; } Sprintf(&(This->out->d), "Date: %s\r", (date_rfc1123((time_t)sched_get_time()))); buffer_cat_char(&(This->out->d), '\n'); if((This->mtime) != -1) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 65; return 0; case 65: ; } Sprintf(&(This->out->d), "Last-Modified: %s\r", (date_rfc1123((This->mtime)))); buffer_cat_char(&(This->out->d), '\n'); } if((This->range_req)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 66; return 0; case 66: ; } Sprintf(&(This->out->d), "Content-Range: %lld-%lld/%lld\r", ((long long int)(This->byte0)), ((long long int)(This->byte1)), ((long long int)(This->fullsize))); buffer_cat_char(&(This->out->d), '\n'); } if(pull_f(&This->out->sh, b__p)) { b__p->pc = 67; return 0; case 67: ; } Sprintf(&(This->out->d), "Content-Length: %lld\r", ((long long int)(strlen((This->body))))); buffer_cat_char(&(This->out->d), '\n'); if((This->code) == 200 && (This->expire_already)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 68; return 0; case 68: ; } buffer_cat_cstr(&(This->out->d), "Cache-Control: private, no-cache, no-store\r"); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 69; return 0; case 69: ; } buffer_cat_cstr(&(This->out->d), "Expires: 0\r"); buffer_cat_char(&(This->out->d), '\n'); } if(pull_f(&This->out->sh, b__p)) { b__p->pc = 70; return 0; case 70: ; } Sprintf(&(This->out->d), "Content-Type: %s\r", (This->mtype)); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 71; return 0; case 71: ; } Sprintf(&(This->out->d), "Server: %s\r", program); buffer_cat_char(&(This->out->d), '\n'); if(!(This->http1_1)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 72; return 0; case 72: ; } Sprintf(&(This->out->d), "Connection: %s\r", ((This->keep_alive) ? "Keep-Alive" : "close")); buffer_cat_char(&(This->out->d), '\n'); } goto bodymsg; bodymsg: if((This->reqlen) > 0) { if((This->in->sh.current == b__p) && !((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start)))) { buffer_ensure_space(&(This->in->d), (This->reqlen)); push_f(&This->in->sh, b__p); } while(1) { if(pull_f(&This->in->sh, b__p)) { b__p->pc = 73; return 0; case 73: ; } if((size_t)((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start))) >= (size_t)(This->reqlen) || !((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start)))) { break; } buffer_ensure_space(&(This->in->d), (This->reqlen)-((ssize_t)(((&(This->in->d))->end)-((&(This->in->d))->start)))); push_f(&This->in->sh, b__p); } buffer_set_size(&(This->in->d), (This->line_start)); } if(pull_f(&This->out->sh, b__p)) { b__p->pc = 74; return 0; case 74: ; } buffer_cat_cstr(&(This->out->d), "\r\n"); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 75; return 0; case 75: ; } if(!((ssize_t)(((&(This->out->d))->end)-((&(This->out->d))->start)))) { } else { push_f(&This->out->sh, b__p); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 76; return 0; case 76: ; } } if((This->method) != HTTP_HEAD) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 77; return 0; case 77: ; } buffer_cat_cstr(&(This->out->d), (This->body)); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 78; return 0; case 78: ; } if(!((ssize_t)(((&(This->out->d))->end)-((&(This->out->d))->start)))) { } else { push_f(&This->out->sh, b__p); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 79; return 0; case 79: ; } } } if(((ssize_t)(((&(This->out->d))->end)-((&(This->out->d))->start)))) { (This->keep_alive) = 0; } goto done; ok: (This->code) = 200; (This->msg) = "OK"; goto mesg; created: (This->code) = 201; (This->msg) = "Created"; goto mesg; bad: (This->code) = 400; (This->msg) = "Bad Request"; goto mesg; forbid: (This->code) = 403; (This->msg) = "Forbidden"; goto mesg; notf: (This->code) = 404; (This->msg) = "Not Found"; goto mesg; badrng: (This->code) = 416; (This->msg) = "Requested Range Not Satisfiable"; goto mesg; srverr: (This->code) = 500; (This->msg) = "Internal Server Error"; goto mesg; reqauth: if(!cstr_eq((This->scheme), "https")) { goto https; } (This->body) = format("%s: 401 Unauthorized\r\n", program); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 80; return 0; case 80: ; } Sprintf(&(This->out->d), "HTTP/1.1 %d %s\r", 401, "Unauthorized"); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 81; return 0; case 81: ; } Sprintf(&(This->out->d), "Date: %s\r", (date_rfc1123((time_t)sched_get_time()))); buffer_cat_char(&(This->out->d), '\n'); if((This->mtime) != -1) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 82; return 0; case 82: ; } Sprintf(&(This->out->d), "Last-Modified: %s\r", (date_rfc1123((This->mtime)))); buffer_cat_char(&(This->out->d), '\n'); } if((This->range_req)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 83; return 0; case 83: ; } Sprintf(&(This->out->d), "Content-Range: %lld-%lld/%lld\r", ((long long int)(This->byte0)), ((long long int)(This->byte1)), ((long long int)(This->fullsize))); buffer_cat_char(&(This->out->d), '\n'); } if(pull_f(&This->out->sh, b__p)) { b__p->pc = 84; return 0; case 84: ; } Sprintf(&(This->out->d), "Content-Length: %lld\r", ((long long int)(strlen((This->body))))); buffer_cat_char(&(This->out->d), '\n'); if(401 == 200 && (This->expire_already)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 85; return 0; case 85: ; } buffer_cat_cstr(&(This->out->d), "Cache-Control: private, no-cache, no-store\r"); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 86; return 0; case 86: ; } buffer_cat_cstr(&(This->out->d), "Expires: 0\r"); buffer_cat_char(&(This->out->d), '\n'); } if(pull_f(&This->out->sh, b__p)) { b__p->pc = 87; return 0; case 87: ; } Sprintf(&(This->out->d), "Content-Type: %s\r", (This->mtype)); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 88; return 0; case 88: ; } Sprintf(&(This->out->d), "Server: %s\r", program); buffer_cat_char(&(This->out->d), '\n'); if(!(This->http1_1)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 89; return 0; case 89: ; } Sprintf(&(This->out->d), "Connection: %s\r", ((This->keep_alive) ? "Keep-Alive" : "close")); buffer_cat_char(&(This->out->d), '\n'); } if(pull_f(&This->out->sh, b__p)) { b__p->pc = 90; return 0; case 90: ; } Sprintf(&(This->out->d), "WWW-Authenticate: Basic realm=\"%s\"\r", (This->host)); buffer_cat_char(&(This->out->d), '\n'); goto bodymsg; loc: (This->body) = format("%s: redirected to %s\r\n", program, (This->location)); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 91; return 0; case 91: ; } Sprintf(&(This->out->d), "HTTP/1.1 %d %s\r", 301, "Moved Permanently"); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 92; return 0; case 92: ; } Sprintf(&(This->out->d), "Date: %s\r", (date_rfc1123((time_t)sched_get_time()))); buffer_cat_char(&(This->out->d), '\n'); if((This->mtime) != -1) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 93; return 0; case 93: ; } Sprintf(&(This->out->d), "Last-Modified: %s\r", (date_rfc1123((This->mtime)))); buffer_cat_char(&(This->out->d), '\n'); } if((This->range_req)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 94; return 0; case 94: ; } Sprintf(&(This->out->d), "Content-Range: %lld-%lld/%lld\r", ((long long int)(This->byte0)), ((long long int)(This->byte1)), ((long long int)(This->fullsize))); buffer_cat_char(&(This->out->d), '\n'); } if(pull_f(&This->out->sh, b__p)) { b__p->pc = 95; return 0; case 95: ; } Sprintf(&(This->out->d), "Content-Length: %lld\r", ((long long int)(strlen((This->body))))); buffer_cat_char(&(This->out->d), '\n'); if(301 == 200 && (This->expire_already)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 96; return 0; case 96: ; } buffer_cat_cstr(&(This->out->d), "Cache-Control: private, no-cache, no-store\r"); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 97; return 0; case 97: ; } buffer_cat_cstr(&(This->out->d), "Expires: 0\r"); buffer_cat_char(&(This->out->d), '\n'); } if(pull_f(&This->out->sh, b__p)) { b__p->pc = 98; return 0; case 98: ; } Sprintf(&(This->out->d), "Content-Type: %s\r", (This->mtype)); buffer_cat_char(&(This->out->d), '\n'); if(pull_f(&This->out->sh, b__p)) { b__p->pc = 99; return 0; case 99: ; } Sprintf(&(This->out->d), "Server: %s\r", program); buffer_cat_char(&(This->out->d), '\n'); if(!(This->http1_1)) { if(pull_f(&This->out->sh, b__p)) { b__p->pc = 100; return 0; case 100: ; } Sprintf(&(This->out->d), "Connection: %s\r", ((This->keep_alive) ? "Keep-Alive" : "close")); buffer_cat_char(&(This->out->d), '\n'); } if(pull_f(&This->out->sh, b__p)) { b__p->pc = 101; return 0; case 101: ; } Sprintf(&(This->out->d), "Location: %s\r", (This->location)); buffer_cat_char(&(This->out->d), '\n'); ((free((This->location))), (This->location) = NULL); goto bodymsg; https: (This->location) = format("https://%s%s", (This->host), (This->path)); goto loc; accerr: switch(errno) { case EACCES: goto reqauth; break; case EPERM: goto reqauth; break; case ENOENT: goto notf; break; case ENOTDIR: goto notf; break; case ENAMETOOLONG: goto bad; break; default: goto srverr; } } return 0; } void text_mimetypes(void) { mimetypes_init(); sym_init(); cstr type = sym("text/plain"); typeof((char *)"b") my__6958_ary[13]; my__6958_ary[0] = ((char *)"b"); my__6958_ary[1] = "bb"; my__6958_ary[2] = "c"; my__6958_ary[3] = "cc"; my__6958_ary[4] = "h"; my__6958_ary[5] = "pl"; my__6958_ary[6] = "pm"; my__6958_ary[7] = "py"; my__6958_ary[8] = "rb"; my__6958_ary[9] = "java"; my__6958_ary[10] = "sh"; my__6958_ary[11] = "diff"; my__6958_ary[12] = "patch"; typeof(&my__6958_ary[sizeof(my__6958_ary)/sizeof(my__6958_ary[0])]) my__6972_end = &my__6958_ary[sizeof(my__6958_ary)/sizeof(my__6958_ary[0])]; typeof(&my__6958_ary[0]) my__6972_i1 = &my__6958_ary[0]; for(; my__6972_i1