/[hydra]/hydra/src/cgi_header.c
ViewVC logotype

Annotation of /hydra/src/cgi_header.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.7 - (hide annotations)
Sat Jul 24 23:39:48 2004 UTC (19 years, 8 months ago) by nmav
Branch: MAIN
CVS Tags: hydra_0_1_6_without_hic, hydra_0_1_7, hydra_0_1_6, hydra_0_1_8, HEAD
Changes since 1.6: +2 -3 lines
File MIME type: text/plain
*** empty log message ***

1 nmav 1.1 /*
2 nmav 1.2 * Hydra, an http server
3 nmav 1.1 * cgi_header.c - cgi header parsing and control
4     * Copyright (C) 1997-99 Jon Nelson <jnelson@boa.org>
5     *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 1, or (at your option)
9     * any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19     *
20     */
21    
22     #include "boa.h"
23    
24     /* process_cgi_header
25    
26     * returns 0 -=> error or HEAD, close down.
27     * returns 1 -=> done processing
28     * leaves req->cgi_status as WRITE
29     */
30    
31     /*
32     The server MUST also resolve any conflicts between header fields returned by
33     the script and header fields that it would otherwise send itself.
34    
35     ...
36    
37     At least one CGI-Field MUST be supplied, but no CGI field name may be used
38     more than once in a response. If a body is supplied, then a
39     "Content-type" header field MUST be supplied by the script,
40     otherwise the script MUST send a "Location" or "Status" header
41     field. If a Location CGI-Field is returned, then the script
42     MUST NOT supply any HTTP-Fields.
43     */
44    
45     /* TODO:
46     We still need to cycle through the data before the end of the headers,
47     line-by-line, and check for any problems with the CGI
48     outputting overriding http responses, etc...
49     */
50     int process_cgi_header(request * req)
51     {
52     char *buf;
53     char *c;
54    
55     if (req->cgi_status != CGI_DONE)
56     req->cgi_status = CGI_BUFFER;
57    
58     buf = req->header_line;
59    
60     c = strstr(buf, "\n\r\n");
61     if (c == NULL) {
62     c = strstr(buf, "\n\n");
63     if (c == NULL) {
64     log_error_time();
65     fputs("cgi_header: unable to find LFLF\n", stderr);
66     #ifdef FASCIST_LOGGING
67     log_error_time();
68     fprintf(stderr, "\"%s\"\n", buf);
69     #endif
70     send_r_bad_gateway(req);
71     return 0;
72     }
73     }
74 nmav 1.5 if (req->http_version == HTTP_0_9) {
75 nmav 1.1 if (*(c + 1) == '\r')
76     req->header_line = c + 2;
77     else
78     req->header_line = c + 1;
79     return 1;
80     }
81 nmav 1.4 if (!strncasecmp(buf, "Location: ", 10)) { /* got a location header */
82 nmav 1.1 #ifdef FASCIST_LOGGING
83    
84     log_error_time();
85     fprintf(stderr, "%s:%d - found Location header \"%s\"\n",
86     __FILE__, __LINE__, buf + 10);
87     #endif
88    
89    
90     if (buf[10] == '/') { /* virtual path */
91     log_error_time();
92     fprintf(stderr,
93     "server does not support internal redirection: " \
94     "\"%s\"\n", buf + 10);
95     send_r_bad_request(req);
96    
97     /*
98     * We (I, Jon) have declined to support absolute-path parsing
99     * because I see it as a major security hole.
100     * Location: /etc/passwd or Location: /etc/shadow is not funny.
101     *
102     * Also, the below code is borked.
103     * request_uri could contain /cgi-bin/bob/extra_path
104     */
105    
106     /*
107     strcpy(req->request_uri, buf + 10);
108     return internal_redirect(req);
109     */
110     } else { /* URL */
111     char *c2;
112     c2 = strchr(buf + 10, '\n');
113     /* c2 cannot ever equal NULL here because we already have found one */
114    
115     --c2;
116     while (*c2 == '\r')
117     --c2;
118     ++c2;
119     /* c2 now points to a '\r' or the '\n' */
120     *c2++ = '\0'; /* end header */
121    
122     /* first next header, or is at req->header_end */
123     while ((*c2 == '\n' || *c2 == '\r') && c2 < req->header_end)
124     ++c2;
125     if (c2 == req->header_end)
126     send_r_moved_temp(req, buf + 10, "");
127     else
128     send_r_moved_temp(req, buf + 10, c2);
129     }
130     req->status = DONE;
131     return 1;
132 nmav 1.4 } else { /* not location */
133 nmav 1.1 char *dest;
134     int howmuch;
135 nmav 1.4
136     if (!strncasecmp(buf, "Status: ", 8)) {
137 nmav 1.7 char str_status[4];
138 nmav 1.4 char desc[32];
139     int len;
140     char *p = buf+8;
141    
142     len = 0;
143 nmav 1.7 while(*p != '\r' && *p != ' ' && *p != 0) { len++; p++; }
144 nmav 1.4
145 nmav 1.6 if (len > sizeof(str_status)-1) { /* status code too long! */
146 nmav 1.4 req->buffer_start = req->buffer_end = 0;
147 nmav 1.6 log_error_time();
148     fprintf(stderr, "status code (%d bytes) is too long\n", len);
149 nmav 1.4 send_r_error(req);
150     return 0;
151     }
152     memcpy( str_status, buf+8, 3);
153     str_status[3] = 0;
154    
155     len = 0;
156     if (*p == ' ') p++;
157     while( (*p != '\r') && *p != 0) { len++; p++; }
158    
159     if (len > sizeof(desc)-1) { /* description long! */
160     req->buffer_start = req->buffer_end = 0;
161 nmav 1.6 log_error_time();
162     fprintf(stderr, "description (%d bytes) is too long\n", len);
163 nmav 1.4 send_r_error(req);
164     return 0;
165     }
166    
167     memcpy( desc, p-len, len);
168     desc[len] = 0;
169    
170     send_r_request_cgi_status(req, str_status, desc); /* does not terminate */
171    
172     if (*p=='\r' && *(p+1)=='\n')
173     p+=2; /* skip \r\n and move to the next line */
174    
175     req->header_line = p;
176     } else {
177     send_r_request_cgi_status(req, "200", "OK"); /* does not terminate */
178     }
179    
180 nmav 1.1 /* got to do special things because
181     a) we have a single buffer divided into 2 pieces
182     b) we need to merge those pieces
183     Easiest way is to memmove the cgi data backward until
184     it touches the buffered data, then reset the cgi data pointers
185     */
186     dest = req->buffer + req->buffer_end;
187     if (req->method == M_HEAD) {
188     if (*(c + 1) == '\r')
189     req->header_end = c + 2;
190     else
191     req->header_end = c + 1;
192     req->cgi_status = CGI_DONE;
193     }
194     howmuch = req->header_end - req->header_line;
195    
196     if (dest + howmuch > req->buffer + BUFFER_SIZE) {
197     /* big problem */
198     log_error_time();
199     fprintf(stderr, "Too much data to move! Aborting! %s %d\n",
200     __FILE__, __LINE__);
201     /* reset buffer pointers because we already called
202     send_r_request_ok... */
203     req->buffer_start = req->buffer_end = 0;
204     send_r_error(req);
205     return 0;
206     }
207     memmove(dest, req->header_line, howmuch);
208     req->buffer_end += howmuch;
209     req->header_line = req->buffer + req->buffer_end;
210     req->header_end = req->header_line;
211     req_flush(req);
212 nmav 1.4
213 nmav 1.1 if (req->method == M_HEAD)
214     return 0;
215     }
216     return 1;
217     }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26