1 /* 2 * uhttpd - Tiny single-threaded httpd 3 * 4 * Copyright (C) 2010-2013 Jo-Philipp Wich <xm@subsignal.org> 5 * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org> 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <signal.h> 21 #include "uhttpd.h" 22 23 void uh_relay_free(struct relay *r) 24 { 25 if (!r->cl) 26 return; 27 28 if (r->proc.pending) 29 kill(r->proc.pid, SIGKILL); 30 31 uloop_timeout_cancel(&r->timeout); 32 uloop_process_delete(&r->proc); 33 ustream_free(&r->sfd.stream); 34 close(r->sfd.fd.fd); 35 36 r->cl = NULL; 37 } 38 39 void uh_relay_close(struct relay *r, int ret) 40 { 41 struct ustream *us = &r->sfd.stream; 42 43 if (!us->notify_read) 44 return; 45 46 us->notify_read = NULL; 47 us->notify_write = NULL; 48 us->notify_state = NULL; 49 50 if (r->close) 51 r->close(r, ret); 52 } 53 54 static void relay_error(struct relay *r) 55 { 56 struct ustream *s = &r->sfd.stream; 57 int len; 58 59 r->error = true; 60 s->eof = true; 61 ustream_get_read_buf(s, &len); 62 if (len) 63 ustream_consume(s, len); 64 ustream_state_change(s); 65 } 66 67 static void relay_process_headers(struct relay *r) 68 { 69 struct ustream *s = &r->sfd.stream; 70 char *buf, *newline; 71 int len; 72 73 if (!r->header_cb) 74 return; 75 76 while (r->header_cb) { 77 int line_len; 78 char *val; 79 80 buf = ustream_get_read_buf(s, &len); 81 if (!buf || !len) 82 break; 83 84 newline = strchr(buf, '\n'); 85 if (!newline) 86 break; 87 88 line_len = newline + 1 - buf; 89 if (newline > buf && newline[-1] == '\r') 90 newline--; 91 92 *newline = 0; 93 if (newline == buf) { 94 r->header_cb = NULL; 95 if (r->header_end) 96 r->header_end(r); 97 ustream_consume(s, line_len); 98 break; 99 } 100 101 val = uh_split_header(buf); 102 if (!val) { 103 relay_error(r); 104 return; 105 } 106 107 r->header_cb(r, buf, val); 108 ustream_consume(s, line_len); 109 } 110 } 111 112 static void relay_read_cb(struct ustream *s, int bytes) 113 { 114 struct relay *r = container_of(s, struct relay, sfd.stream); 115 struct client *cl = r->cl; 116 struct ustream *us = cl->us; 117 char *buf; 118 int len; 119 120 if (r->process_done) 121 uloop_timeout_set(&r->timeout, 1); 122 123 if (!r->error) 124 relay_process_headers(r); 125 126 if (r->header_cb) { 127 /* 128 * if eof, ensure that remaining data is discarded, so the 129 * state change cb will tear down the stream 130 */ 131 if (s->eof) 132 relay_error(r); 133 return; 134 } 135 136 if (!s->eof && ustream_pending_data(us, true)) { 137 ustream_set_read_blocked(s, true); 138 return; 139 } 140 141 buf = ustream_get_read_buf(s, &len); 142 if (!buf || !len) 143 return; 144 145 if (!r->skip_data) 146 uh_chunk_write(cl, buf, len); 147 148 ustream_consume(s, len); 149 } 150 151 static void relay_close_if_done(struct uloop_timeout *timeout) 152 { 153 struct relay *r = container_of(timeout, struct relay, timeout); 154 struct ustream *s = &r->sfd.stream; 155 156 while (ustream_poll(&r->sfd.stream)); 157 158 if (!(r->process_done || s->eof) || (ustream_pending_data(s, false) && !r->header_cb)) 159 return; 160 161 uh_relay_close(r, r->ret); 162 } 163 164 static void relay_state_cb(struct ustream *s) 165 { 166 struct relay *r = container_of(s, struct relay, sfd.stream); 167 168 if (r->process_done) 169 uloop_timeout_set(&r->timeout, 1); 170 } 171 172 static void relay_proc_cb(struct uloop_process *proc, int ret) 173 { 174 struct relay *r = container_of(proc, struct relay, proc); 175 176 r->process_done = true; 177 r->ret = ret; 178 uloop_timeout_set(&r->timeout, 1); 179 } 180 181 void uh_relay_kill(struct client *cl, struct relay *r) 182 { 183 struct ustream *us = &r->sfd.stream; 184 185 kill(r->proc.pid, SIGKILL); 186 us->eof = true; 187 ustream_state_change(us); 188 } 189 190 void uh_relay_open(struct client *cl, struct relay *r, int fd, int pid) 191 { 192 struct ustream *us = &r->sfd.stream; 193 194 r->cl = cl; 195 us->notify_read = relay_read_cb; 196 us->notify_state = relay_state_cb; 197 us->string_data = true; 198 ustream_fd_init(&r->sfd, fd); 199 200 r->proc.pid = pid; 201 r->proc.cb = relay_proc_cb; 202 uloop_process_add(&r->proc); 203 204 r->timeout.cb = relay_close_if_done; 205 } 206
This page was automatically generated by LXR 0.3.1. • OpenWrt