• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/uhttpd/relay.c

  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))
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