source: trunk/third-party/shttpd/io_emb.c @ 6644

Last change on this file since 6644 was 6644, checked in by charles, 13 years ago

upgrade to shttpd 1.42

File size: 6.7 KB
Line 
1/*
2 * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
3 * All rights reserved
4 *
5 * "THE BEER-WARE LICENSE" (Revision 42):
6 * Sergey Lyubka wrote this file.  As long as you retain this notice you
7 * can do whatever you want with this stuff. If we meet some day, and you think
8 * this stuff is worth it, you can buy me a beer in return.
9 */
10
11#include "defs.h"
12
13const char *
14shttpd_version(void)
15{
16        return (VERSION);
17}
18
19static void
20call_user(struct conn *c, struct shttpd_arg *arg, shttpd_callback_t func)
21{
22        arg->priv               = c;
23        arg->state              = c->loc.chan.emb.state;
24        arg->out.buf            = io_space(&c->loc.io);
25        arg->out.len            = io_space_len(&c->loc.io);
26        arg->out.num_bytes      = 0;
27        arg->in.buf             = io_data(&c->rem.io);;
28        arg->in.len             = io_data_len(&c->rem.io);
29        arg->in.num_bytes       = 0;
30
31        if (io_data_len(&c->rem.io) >= c->rem.io.size)
32                arg->flags |= SHTTPD_POST_BUFFER_FULL;
33
34        if (c->rem.content_len > 0 && c->rem.io.total < c->rem.content_len)
35                arg->flags |= SHTTPD_MORE_POST_DATA;
36
37        func(arg);
38
39        io_inc_head(&c->loc.io, arg->out.num_bytes);
40        io_inc_tail(&c->rem.io, arg->in.num_bytes);
41        c->loc.chan.emb.state = arg->state;             /* Save state */
42
43        /*
44         * If callback finished output, that means it did all cleanup.
45         * If the connection is terminated unexpectedly, we canna call
46         * the callback via the stream close() method from disconnect.
47         * However, if cleanup is already done, we set close() method to
48         * NULL, to prevent the call from disconnect().
49         */
50
51        if (arg->flags & SHTTPD_END_OF_OUTPUT)
52                c->loc.flags &= ~FLAG_DONT_CLOSE;
53        else
54                c->loc.flags |= FLAG_DONT_CLOSE;
55
56        if (arg->flags & SHTTPD_SUSPEND)
57                c->loc.flags |= FLAG_SUSPEND;
58}
59
60static int
61do_embedded(struct stream *stream, void *buf, size_t len)
62{
63        struct shttpd_arg       arg;
64        buf = NULL; len = 0;            /* Squash warnings */
65
66        arg.user_data   = stream->conn->loc.chan.emb.data;
67        arg.flags       = 0;
68
69        call_user(stream->conn, &arg, (shttpd_callback_t)
70                        stream->conn->loc.chan.emb.func.v_func);
71
72        return (0);
73}
74
75static void
76close_embedded(struct stream *stream)
77{
78        struct shttpd_arg       arg;
79        struct conn             *c = stream->conn;
80
81        arg.flags       = SHTTPD_CONNECTION_ERROR;
82        arg.user_data   = c->loc.chan.emb.data;
83
84        /*
85         * Do not call the user function if SHTTPD_END_OF_OUTPUT was set,
86         * i.e. the callback already terminated correctly
87         */
88        if (stream->flags & FLAG_DONT_CLOSE)
89                call_user(stream->conn, &arg, (shttpd_callback_t)
90                    c->loc.chan.emb.func.v_func);
91}
92
93size_t
94shttpd_printf(struct shttpd_arg *arg, const char *fmt, ...)
95{
96        char            *buf = arg->out.buf + arg->out.num_bytes;
97        int             buflen = arg->out.len - arg->out.num_bytes, len = 0;
98        va_list         ap;
99
100        if (buflen > 0) {
101                va_start(ap, fmt);
102                len = vsnprintf(buf, buflen, fmt, ap);
103                va_end(ap);
104
105                if (len < 0 || len > buflen)
106                        len = buflen;
107                arg->out.num_bytes += len;
108        }
109
110        return (len);
111}
112
113const char *
114shttpd_get_header(struct shttpd_arg *arg, const char *header_name)
115{
116        struct conn     *c = arg->priv;
117        char            *p, *s, *e;
118        size_t          len;
119
120        p = c->headers;
121        e = c->request + c->rem.headers_len;
122        len = strlen(header_name);
123
124        while (p < e) {
125                if ((s = strchr(p, '\n')) != NULL)
126                        s[s[-1] == '\r' ? -1 : 0] = '\0';
127                if (_shttpd_strncasecmp(header_name, p, len) == 0)
128                        return (p + len + 2);
129
130                p += strlen(p) + 1;
131        }
132
133        return (NULL);
134}
135
136const char *
137shttpd_get_env(struct shttpd_arg *arg, const char *env_name)
138{
139        struct conn     *c = arg->priv;
140        struct vec      *vec;
141
142        if (strcmp(env_name, "REQUEST_METHOD") == 0) {
143                return (_shttpd_known_http_methods[c->method].ptr);
144        } else if (strcmp(env_name, "REQUEST_URI") == 0) {
145                return (c->uri);
146        } else if (strcmp(env_name, "QUERY_STRING") == 0) {
147                return (c->query);
148        } else if (strcmp(env_name, "REMOTE_USER") == 0) {
149                vec = &c->ch.user.v_vec;
150                if (vec->len > 0) {
151                        ((char *) vec->ptr)[vec->len] = '\0';
152                        return (vec->ptr);
153                }
154        } else if (strcmp(env_name, "REMOTE_ADDR") == 0) {
155                return (inet_ntoa(c->sa.u.sin.sin_addr));/* FIXME NOT MT safe */
156        }
157
158        return (NULL);
159}
160
161void
162shttpd_get_http_version(struct shttpd_arg *arg,
163                unsigned long *major, unsigned long *minor)
164{
165        struct conn *c = arg->priv;
166       
167        *major = c->major_version;
168        *minor = c->minor_version;
169}
170
171void
172shttpd_register_uri(struct shttpd_ctx *ctx,
173                const char *uri, shttpd_callback_t callback, void *data)
174{
175        struct registered_uri   *e;
176
177        if ((e = malloc(sizeof(*e))) != NULL) {
178                e->uri                  = _shttpd_strdup(uri);
179                e->callback.v_func      = (void (*)(void)) callback;
180                e->callback_data        = data;
181                LL_TAIL(&ctx->registered_uris, &e->link);
182        }
183}
184
185int
186shttpd_get_var(const char *var, const char *buf, int buf_len,
187                char *value, int value_len)
188{
189        const char      *p, *e, *s;
190        size_t          var_len;
191
192        var_len = strlen(var);
193        e = buf + buf_len;              /* End of QUERY_STRING buffer   */
194
195        /* buf is "var1=val1&var2=val2...". Find variable first */
196        for (p = buf; p + var_len < e; p++)
197                if ((p == buf || p[-1] == '&') &&
198                    p[var_len] == '=' &&
199                    !_shttpd_strncasecmp(var, p, var_len)) {
200
201                        /* Point 'p' to var value, 's' to the end of value */
202                        p += var_len + 1;       
203                        if ((s = memchr(p, '&', e - p)) == NULL)
204                                s = e;
205
206                        /* URL-decode value. Return result length */
207                        return (_shttpd_url_decode(p, s - p, value, value_len));
208                }
209
210        return (-1);
211}
212
213static int
214match_regexp(const char *regexp, const char *text)
215{
216        if (*regexp == '\0')
217                return (*text == '\0');
218
219        if (*regexp == '*')
220                do {
221                        if (match_regexp(regexp + 1, text))
222                                return (1);
223                } while (*text++ != '\0');
224
225        if (*text != '\0' && *regexp == *text)
226                return (match_regexp(regexp + 1, text + 1));
227
228        return (0);
229}
230
231struct registered_uri *
232_shttpd_is_registered_uri(struct shttpd_ctx *ctx, const char *uri)
233{
234        struct llhead           *lp;
235        struct registered_uri   *reg_uri;
236
237        LL_FOREACH(&ctx->registered_uris, lp) {
238                reg_uri = LL_ENTRY(lp, struct registered_uri, link);
239                if (match_regexp(reg_uri->uri, uri))
240                        return (reg_uri);
241        }
242
243        return (NULL);
244}
245
246void
247_shttpd_setup_embedded_stream(struct conn *c, union variant func, void *data)
248{
249        c->loc.chan.emb.state = NULL;
250        c->loc.chan.emb.func = func;
251        c->loc.chan.emb.data = data;
252        c->loc.io_class = &_shttpd_io_embedded;
253        c->loc.flags |= FLAG_R | FLAG_W |FLAG_ALWAYS_READY;
254}
255
256void
257shttpd_handle_error(struct shttpd_ctx *ctx, int code,
258                shttpd_callback_t func, void *data)
259{
260        struct error_handler    *e;
261
262        if ((e = malloc(sizeof(*e))) != NULL) {
263                e->code = code;
264                e->callback.v_func = (void (*)(void)) func;
265                e->callback_data = data;
266                LL_TAIL(&ctx->error_handlers, &e->link);
267        }
268}
269
270void
271shttpd_wakeup(const void *priv)
272{
273        const struct conn       *conn = priv;
274        char                    buf[sizeof(int) + sizeof(void *)];
275        int                     cmd = CTL_WAKEUP;
276
277#if 0
278        conn->flags &= ~SHTTPD_SUSPEND;
279#endif
280        (void) memcpy(buf, &cmd, sizeof(cmd));
281        (void) memcpy(buf + sizeof(cmd), conn, sizeof(conn));
282
283        (void) send(conn->worker->ctl[1], buf, sizeof(buf), 0);
284}
285
286const struct io_class   _shttpd_io_embedded =  {
287        "embedded",
288        do_embedded,
289        (int (*)(struct stream *, const void *, size_t)) do_embedded,
290        close_embedded
291};
Note: See TracBrowser for help on using the repository browser.