30be3ec1c495b246033b9d5363a77dab1b43482f
[project/uhttpd.git] / relay.c
1 /*
2  * uhttpd - Tiny single-threaded httpd
3  *
4  *   Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
5  *   Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
6  *
7  *  Licensed under the Apache License, Version 2.0 (the "License");
8  *  you may not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS,
15  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
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_process_delete(&r->proc);
32         ustream_free(&r->sfd.stream);
33         close(r->sfd.fd.fd);
34
35         r->cl = NULL;
36 }
37
38 void uh_relay_close(struct relay *r, int ret)
39 {
40         struct ustream *us = &r->sfd.stream;
41
42         if (!us->notify_read)
43                 return;
44
45         us->notify_read = NULL;
46         us->notify_write = NULL;
47         us->notify_state = NULL;
48
49         if (r->close)
50                 r->close(r, ret);
51 }
52
53 static void relay_error(struct relay *r)
54 {
55         struct ustream *s = &r->sfd.stream;
56         int len;
57
58         s->eof = true;
59         ustream_get_read_buf(s, &len);
60         if (len)
61                 ustream_consume(s, len);
62         ustream_state_change(s);
63 }
64
65 static void relay_process_headers(struct relay *r)
66 {
67         struct ustream *s = &r->sfd.stream;
68         char *buf, *newline;
69         int len;
70
71         if (!r->header_cb)
72                 return;
73
74         while (r->header_cb) {
75                 int line_len;
76                 char *val;
77
78                 buf = ustream_get_read_buf(s, &len);
79                 newline = strchr(buf, '\n');
80                 if (!newline)
81                         break;
82
83                 line_len = newline + 1 - buf;
84                 if (newline > buf && newline[-1] == '\r') {
85                         newline--;
86                         line_len++;
87                 }
88
89                 *newline = 0;
90                 if (newline == buf) {
91                         r->header_cb = NULL;
92                         if (r->header_end)
93                                 r->header_end(r);
94                         break;
95                 }
96
97                 val = uh_split_header(buf);
98                 if (!val) {
99                         relay_error(r);
100                         return;
101                 }
102
103                 r->header_cb(r, buf, val);
104                 ustream_consume(s, line_len);
105         }
106 }
107
108 static void relay_read_cb(struct ustream *s, int bytes)
109 {
110         struct relay *r = container_of(s, struct relay, sfd.stream);
111         struct client *cl = r->cl;
112         struct ustream *us = cl->us;
113         char *buf;
114         int len;
115
116         relay_process_headers(r);
117
118         if (r->header_cb) {
119                 /*
120                  * if eof, ensure that remaining data is discarded, so the
121                  * state change cb will tear down the stream
122                  */
123                 if (s->eof)
124                         relay_error(r);
125                 return;
126         }
127
128         if (!s->eof && ustream_pending_data(us, true)) {
129                 ustream_set_read_blocked(s, true);
130                 return;
131         }
132
133         buf = ustream_get_read_buf(s, &len);
134         uh_chunk_write(cl, buf, len);
135         ustream_consume(s, len);
136 }
137
138 static void relay_close_if_done(struct relay *r)
139 {
140         struct ustream *s = &r->sfd.stream;
141
142         if (!s->eof || ustream_pending_data(s, false))
143                 return;
144
145         uh_relay_close(r, r->ret);
146 }
147
148 static void relay_state_cb(struct ustream *s)
149 {
150         struct relay *r = container_of(s, struct relay, sfd.stream);
151
152         if (r->process_done)
153                 relay_close_if_done(r);
154 }
155
156 static void relay_proc_cb(struct uloop_process *proc, int ret)
157 {
158         struct relay *r = container_of(proc, struct relay, proc);
159
160         r->process_done = true;
161         r->ret = ret;
162         relay_close_if_done(r);
163 }
164
165 void uh_relay_open(struct client *cl, struct relay *r, int fd, int pid)
166 {
167         struct ustream *us = &r->sfd.stream;
168
169         r->cl = cl;
170         ustream_fd_init(&r->sfd, fd);
171         us->notify_read = relay_read_cb;
172         us->notify_state = relay_state_cb;
173         us->string_data = true;
174
175         r->proc.pid = pid;
176         r->proc.cb = relay_proc_cb;
177         uloop_process_add(&r->proc);
178 }