123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- /*
- * uhttpd - Tiny single-threaded httpd
- *
- * Copyright (C) 2010-2013 Jo-Philipp Wich <xm@subsignal.org>
- * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include <signal.h>
- #include "uhttpd.h"
- void uh_relay_free(struct relay *r)
- {
- if (!r->cl)
- return;
- if (r->proc.pending)
- kill(r->proc.pid, SIGKILL);
- uloop_timeout_cancel(&r->timeout);
- uloop_process_delete(&r->proc);
- ustream_free(&r->sfd.stream);
- close(r->sfd.fd.fd);
- r->cl = NULL;
- }
- void uh_relay_close(struct relay *r, int ret)
- {
- struct ustream *us = &r->sfd.stream;
- if (!us->notify_read)
- return;
- us->notify_read = NULL;
- us->notify_write = NULL;
- us->notify_state = NULL;
- if (r->close)
- r->close(r, ret);
- }
- static void relay_error(struct relay *r)
- {
- struct ustream *s = &r->sfd.stream;
- int len;
- r->error = true;
- s->eof = true;
- ustream_get_read_buf(s, &len);
- if (len)
- ustream_consume(s, len);
- ustream_state_change(s);
- }
- static void relay_process_headers(struct relay *r)
- {
- struct ustream *s = &r->sfd.stream;
- char *buf, *newline;
- int len;
- if (!r->header_cb)
- return;
- while (r->header_cb) {
- int line_len;
- char *val;
- buf = ustream_get_read_buf(s, &len);
- if (!buf || !len)
- break;
- newline = strchr(buf, '\n');
- if (!newline)
- break;
- line_len = newline + 1 - buf;
- if (newline > buf && newline[-1] == '\r')
- newline--;
- *newline = 0;
- if (newline == buf) {
- r->header_cb = NULL;
- if (r->header_end)
- r->header_end(r);
- ustream_consume(s, line_len);
- break;
- }
- val = uh_split_header(buf);
- if (!val) {
- relay_error(r);
- return;
- }
- r->header_cb(r, buf, val);
- ustream_consume(s, line_len);
- }
- }
- static void relay_read_cb(struct ustream *s, int bytes)
- {
- struct relay *r = container_of(s, struct relay, sfd.stream);
- struct client *cl = r->cl;
- struct ustream *us = cl->us;
- char *buf;
- int len;
- if (r->process_done)
- uloop_timeout_set(&r->timeout, 1);
- if (!r->error)
- relay_process_headers(r);
- if (r->header_cb) {
- /*
- * if eof, ensure that remaining data is discarded, so the
- * state change cb will tear down the stream
- */
- if (s->eof)
- relay_error(r);
- return;
- }
- if (!s->eof && ustream_pending_data(us, true)) {
- ustream_set_read_blocked(s, true);
- return;
- }
- buf = ustream_get_read_buf(s, &len);
- if (!buf || !len)
- return;
- if (!r->skip_data)
- uh_chunk_write(cl, buf, len);
- ustream_consume(s, len);
- }
- static void relay_close_if_done(struct uloop_timeout *timeout)
- {
- struct relay *r = container_of(timeout, struct relay, timeout);
- struct ustream *s = &r->sfd.stream;
- while (ustream_poll(&r->sfd.stream));
- if (!(r->process_done || s->eof) || (ustream_pending_data(s, false) && !r->header_cb))
- return;
- uh_relay_close(r, r->ret);
- }
- static void relay_state_cb(struct ustream *s)
- {
- struct relay *r = container_of(s, struct relay, sfd.stream);
- if (r->process_done)
- uloop_timeout_set(&r->timeout, 1);
- }
- static void relay_proc_cb(struct uloop_process *proc, int ret)
- {
- struct relay *r = container_of(proc, struct relay, proc);
- r->process_done = true;
- r->ret = ret;
- uloop_timeout_set(&r->timeout, 1);
- }
- void uh_relay_kill(struct client *cl, struct relay *r)
- {
- struct ustream *us = &r->sfd.stream;
- kill(r->proc.pid, SIGKILL);
- us->eof = true;
- ustream_state_change(us);
- }
- void uh_relay_open(struct client *cl, struct relay *r, int fd, int pid)
- {
- struct ustream *us = &r->sfd.stream;
- r->cl = cl;
- us->notify_read = relay_read_cb;
- us->notify_state = relay_state_cb;
- us->string_data = true;
- ustream_fd_init(&r->sfd, fd);
- r->proc.pid = pid;
- r->proc.cb = relay_proc_cb;
- uloop_process_add(&r->proc);
- r->timeout.cb = relay_close_if_done;
- }
|