source: rtems/cpukit/shttpd/io_emb.c @ 9fcba88

4.104.115
Last change on this file since 9fcba88 was c648ca5, checked in by Ralf Corsepius <ralf.corsepius@…>, on 03/26/10 at 17:42:24

Add HAVE_STRINGS_H for better POSIX compliance.

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