source: rtems/cpukit/shttpd/io_cgi.c @ 394ac3c

4.104.115
Last change on this file since 394ac3c was 394ac3c, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/03/10 at 05:52:56

#include <unistd.h>.

  • Property mode set to 100644
File size: 3.4 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#include <unistd.h>
14
15static int
16write_cgi(struct stream *stream, const void *buf, size_t len)
17{
18        assert(stream->chan.sock != -1);
19        assert(stream->flags & FLAG_W);
20
21        return (send(stream->chan.sock, buf, len, 0));
22}
23
24static int
25read_cgi(struct stream *stream, void *buf, size_t len)
26{
27        struct headers  parsed;
28        char            status[4];
29        int             n;
30
31        assert(stream->chan.sock != -1);
32        assert(stream->flags & FLAG_R);
33
34        stream->flags &= ~FLAG_DONT_CLOSE;
35
36        n = recv(stream->chan.sock, buf, len, 0);
37
38        if (stream->flags & FLAG_HEADERS_PARSED)
39                return (n);
40
41        if (n <= 0 && ERRNO != EWOULDBLOCK) {
42                send_server_error(stream->conn, 500, "Error running CGI");
43                return (n);
44        }
45
46        /*
47         * CGI script may output Status: and Location: headers, which
48         * may alter the status code. Buffer in headers, parse
49         * them, send correct status code and then forward all data
50         * from CGI script back to the remote end.
51         * Reply line was alredy appended to the IO buffer in
52         * decide_what_to_do(), with blank status code.
53         */
54
55        stream->flags |= FLAG_DONT_CLOSE;
56        io_inc_head(&stream->io, n);
57
58        stream->headers_len = get_headers_len(stream->io.buf, stream->io.head);
59        if (stream->headers_len < 0) {
60                stream->flags &= ~FLAG_DONT_CLOSE;
61                send_server_error(stream->conn, 500, "Bad headers sent");
62                elog(E_LOG, stream->conn, "CGI script sent invalid headers: "
63                    "[%.*s]", stream->io.head - CGI_REPLY_LEN,
64                    stream->io.buf + CGI_REPLY_LEN);
65                return (0);
66        }
67
68        /*
69         * If we did not received full headers yet, we must not send any
70         * data read from the CGI back to the client. Suspend sending by
71         * setting tail = head, which tells that there is no data in IO buffer
72         */
73
74        if (stream->headers_len == 0) {
75                stream->io.tail = stream->io.head;
76                return (0);
77        }
78
79        /* Received all headers. Set status code for the connection. */
80        (void) memset(&parsed, 0, sizeof(parsed));
81        parse_headers(stream->io.buf, stream->headers_len, &parsed);
82        stream->content_len = parsed.cl.v_big_int;
83        stream->conn->status = (int) parsed.status.v_big_int;
84
85        /* If script outputs 'Location:' header, set status code to 302 */
86        if (parsed.location.v_vec.len > 0)
87                stream->conn->status = 302;
88
89        /*
90         * If script did not output neither 'Location:' nor 'Status' headers,
91         * set the default status code 200, which means 'success'.
92         */
93        if (stream->conn->status == 0)
94                stream->conn->status = 200;
95
96        /* Append the status line to the beginning of the output */
97        (void) my_snprintf(status, sizeof(status), "%3d", stream->conn->status);
98        (void) memcpy(stream->io.buf + 9, status, 3);
99        DBG(("read_cgi: content len %lu status %s",
100            stream->content_len, status));
101
102        /* Next time, pass output directly back to the client */
103        assert((big_int_t) stream->headers_len <= stream->io.total);
104        stream->io.total -= stream->headers_len;
105        stream->io.tail = 0;
106        stream->flags |= FLAG_HEADERS_PARSED;
107
108        /* Return 0 because we've already shifted the head */
109        return (0);
110}
111
112static void
113close_cgi(struct stream *stream)
114{
115        assert(stream->chan.sock != -1);
116        (void) closesocket(stream->chan.sock);
117}
118
119const struct io_class   io_cgi =  {
120        "cgi",
121        read_cgi,
122        write_cgi,
123        close_cgi
124};
Note: See TracBrowser for help on using the repository browser.