source: rtems/cpukit/shttpd/io_emb.c @ 039267fc

4.104.115
Last change on this file since 039267fc was 484cd8d, checked in by Ralf Corsepius <ralf.corsepius@…>, on 06/11/07 at 13:24:29

Import from shttpd-1.37.

  • Property mode set to 100644
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
13#if defined(EMBEDDED)
14const char *
15shttpd_version(void)
16{
17        return (VERSION);
18}
19
20static void
21call_user(struct conn *c, struct shttpd_arg *arg, shttpd_callback_t func)
22{
23        arg->priv               = c;
24        arg->state              = c->loc.chan.emb.state;
25        arg->out.buf            = io_space(&c->loc.io);
26        arg->out.len            = io_space_len(&c->loc.io);
27        arg->out.num_bytes      = 0;
28        arg->in.buf             = io_data(&c->rem.io);;
29        arg->in.len             = io_data_len(&c->rem.io);
30        arg->in.num_bytes       = 0;
31
32        func(arg);
33
34        io_inc_head(&c->loc.io, arg->out.num_bytes);
35        io_inc_tail(&c->rem.io, arg->in.num_bytes);
36        c->loc.chan.emb.state = arg->state;             /* Save state */
37
38        /*
39         * If callback finished output, that means it did all cleanup.
40         * If the connection is terminated unexpectedly, we canna call
41         * the callback via the stream close() method from disconnect.
42         * However, if cleanup is already done, we set close() method to
43         * NULL, to prevent the call from disconnect().
44         */
45
46        if (arg->flags & SHTTPD_END_OF_OUTPUT)
47                c->loc.flags &= ~FLAG_DONT_CLOSE;
48        else
49                c->loc.flags |= FLAG_DONT_CLOSE;
50}
51
52static int
53do_embedded(struct stream *stream, void *buf, size_t len)
54{
55        struct shttpd_arg       arg;
56        buf = NULL; len = 0;            /* Squash warnings */
57
58        arg.user_data   = stream->conn->loc.chan.emb.data;
59        arg.flags       = 0;
60
61        call_user(stream->conn, &arg, (shttpd_callback_t)
62                        stream->conn->loc.chan.emb.func.v_func);
63
64        return (0);
65}
66
67static void
68close_embedded(struct stream *stream)
69{
70        struct shttpd_arg       arg;
71        struct conn             *c = stream->conn;
72
73        arg.flags       = SHTTPD_CONNECTION_ERROR;
74        arg.user_data   = c->loc.chan.emb.data;
75
76        /*
77         * Do not call the user function if SHTTPD_END_OF_OUTPUT was set,
78         * i.e. the callback already terminated correctly
79         */
80        if (stream->flags & FLAG_DONT_CLOSE)
81                call_user(stream->conn, &arg, (shttpd_callback_t)
82                    c->loc.chan.emb.func.v_func);
83}
84
85size_t
86shttpd_printf(struct shttpd_arg *arg, const char *fmt, ...)
87{
88        struct conn     *c = arg->priv;
89        struct io       *io = &c->loc.io;
90        char            *buf = io_space(io) + arg->out.num_bytes;
91        int             buflen, len = 0;
92        va_list         ap;
93
94        assert(buf <= io->buf + io->size);
95
96        if ((buflen = (io->buf + io->size) - buf) > 0) {
97                va_start(ap, fmt);
98                len = vsnprintf(buf, buflen, fmt, ap);
99                va_end(ap);
100
101                if (len < 0 || len > buflen)
102                        len = buflen;
103                arg->out.num_bytes += len;
104        }
105
106        return (len);
107}
108
109const char *
110shttpd_get_header(struct shttpd_arg *arg, const char *header_name)
111{
112        struct conn     *c = arg->priv;
113        char            *p, *s, *e;
114        size_t          len;
115
116        p = c->headers;
117        e = c->request + c->rem.headers_len;
118        len = strlen(header_name);
119
120        while (p < e) {
121                if ((s = strchr(p, '\n')) != NULL)
122                        s[s[-1] == '\r' ? -1 : 0] = '\0';
123                if (my_strncasecmp(header_name, p, len) == 0)
124                        return (p + len + 2);
125
126                p += strlen(p) + 1;
127        }
128
129        return (NULL);
130}
131
132const char *
133shttpd_get_env(struct shttpd_arg *arg, const char *env_name)
134{
135        struct conn     *c = arg->priv;
136        struct vec      *vec;
137
138        if (strcmp(env_name, "REQUEST_METHOD") == 0) {
139                return (known_http_methods[c->method].ptr);
140        } else if (strcmp(env_name, "REQUEST_URI") == 0) {
141                return (c->uri);
142        } else if (strcmp(env_name, "QUERY_STRING") == 0) {
143                return (c->query);
144        } else if (strcmp(env_name, "REMOTE_USER") == 0) {
145                vec = &c->ch.user.v_vec;
146                if (vec->len > 0) {
147                        ((char *) vec->ptr)[vec->len] = '\0';
148                        return (vec->ptr);
149                }
150        } else if (strcmp(env_name, "REMOTE_ADDR") == 0) {
151                return (inet_ntoa(c->sa.u.sin.sin_addr));/* FIXME NOT MT safe */
152        }
153
154        return (NULL);
155}
156
157void
158shttpd_get_http_version(struct shttpd_arg *arg, unsigned long *major, unsigned long *minor)
159{
160        struct conn *c = arg->priv;
161       
162        *major = c->major_version;
163        *minor = c->minor_version;
164}
165
166void
167shttpd_register_uri(struct shttpd_ctx *ctx,
168                const char *uri, shttpd_callback_t callback, void *data)
169{
170        struct registered_uri   *e;
171
172        if ((e = malloc(sizeof(*e))) != NULL) {
173                e->uri                  = my_strdup(uri);
174                e->callback.v_func      = (void (*)(void)) callback;
175                e->callback_data        = data;
176                LL_TAIL(&ctx->registered_uris, &e->link);
177        }
178}
179
180#if 0
181struct shttpd_ctx *
182shttpd_init2(const char *config_file, char *names[], char *values[], size_t n)
183{
184        size_t i;
185
186        for (i = 0; i < n; i++)
187                set_option(names[i], values[i]);
188
189        return (init_ctx(config_file, 0, NULL));
190}
191#endif
192
193void
194shttpd_protect_uri(struct shttpd_ctx *ctx, const char *uri, const char *file)
195{
196        struct uri_auth *auth;
197
198        if ((auth = malloc(sizeof(*auth))) != NULL) {
199                auth->uri       = my_strdup(uri);
200                auth->file_name = my_strdup(file);
201                auth->uri_len   = strlen(uri);
202                LL_ADD(&ctx->uri_auths, &auth->link);
203        }
204}
205
206int
207shttpd_get_var(const char *var, const char *buf, int buf_len,
208                char *value, int value_len)
209{
210        const char      *p, *e, *s;
211        size_t          var_len;
212
213        var_len = strlen(var);
214        e = buf + buf_len - var_len;
215
216        /* buf is "var1=val1&var2=val2...". Find variable first */
217        for (p = buf; p < e; p++)
218                if (!my_strncasecmp(var, p, var_len) && p[var_len] == '=') {
219
220                        /* Found. Shift to variable value */
221                        e = buf + buf_len;
222                        p += var_len + 1;
223
224                        /* Find where the value ends */
225                        if ((s = memchr(p, '&', e - p)) == NULL)
226                                s = e;
227
228                        /* Copy value into the buffer, decoding it */
229                        decode_url_encoded_string(p, s - p, value, value_len);
230
231                        return (1);
232                }
233
234        return (0);
235}
236
237static int
238match_regexp(const char *regexp, const char *text)
239{
240        if (*regexp == '\0')
241                return (*text == '\0');
242
243        if (*regexp == '*')
244                do {
245                        if (match_regexp(regexp + 1, text))
246                                return (1);
247                } while (*text++ != '\0');
248
249        if (*text != '\0' && *regexp == *text)
250                return (match_regexp(regexp + 1, text + 1));
251
252        return (0);
253}
254
255struct registered_uri *
256is_registered_uri(struct shttpd_ctx *ctx, const char *uri)
257{
258        struct llhead           *lp;
259        struct registered_uri   *reg_uri;
260
261        LL_FOREACH(&ctx->registered_uris, lp) {
262                reg_uri = LL_ENTRY(lp, struct registered_uri, link);
263                if (match_regexp(reg_uri->uri, uri))
264                        return (reg_uri);
265        }
266
267        return (NULL);
268}
269
270void
271setup_embedded_stream(struct conn *c, union variant func, void *data)
272{
273        c->loc.chan.emb.state = NULL;
274        c->loc.chan.emb.func = func;
275        c->loc.chan.emb.data = data;
276        c->loc.io_class = &io_embedded;
277        c->loc.flags |= FLAG_R | FLAG_W |FLAG_ALWAYS_READY;
278}
279
280void
281shttpd_handle_error(struct shttpd_ctx *ctx, int code,
282                shttpd_callback_t func, void *data)
283{
284        struct error_handler    *e;
285
286        if ((e = malloc(sizeof(*e))) != NULL) {
287                e->code = code;
288                e->callback.v_func = (void (*)(void)) func;
289                e->callback_data = data;
290                LL_TAIL(&ctx->error_handlers, &e->link);
291        }
292}
293
294const struct io_class   io_embedded =  {
295        "embedded",
296        do_embedded,
297        (int (*)(struct stream *, const void *, size_t)) do_embedded,
298        close_embedded
299};
300
301#endif /* EMBEDDED */
Note: See TracBrowser for help on using the repository browser.