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

Contents of /hydra/src/cgi_header.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.6 - (show annotations)
Sat Jul 24 17:35:38 2004 UTC (19 years, 9 months ago) by nmav
Branch: MAIN
Changes since 1.5: +7 -2 lines
File MIME type: text/plain
* Some changes to support the new PHP REQUEST_STATUS environment
  variable.
* Some fixes for gnutls.

1 /*
2 * Hydra, an http server
3 * 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 if (req->http_version == HTTP_0_9) {
75 if (*(c + 1) == '\r')
76 req->header_line = c + 2;
77 else
78 req->header_line = c + 1;
79 return 1;
80 }
81 if (!strncasecmp(buf, "Location: ", 10)) { /* got a location header */
82 #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 } else { /* not location */
133 char *dest;
134 int howmuch;
135
136 if (!strncasecmp(buf, "Status: ", 8)) {
137 char str_status[24];
138 char desc[32];
139 int len;
140 char *p = buf+8;
141
142 len = 0;
143 while( *p != ' ' && *p != 0) { len++; p++; }
144
145 if (len > sizeof(str_status)-1) { /* status code too long! */
146 req->buffer_start = req->buffer_end = 0;
147 log_error_time();
148 fprintf(stderr, "status code (%d bytes) is too long\n", len);
149 fprintf(stderr, "status code: '%s'\n", buf+8);
150 send_r_error(req);
151 return 0;
152 }
153 memcpy( str_status, buf+8, 3);
154 str_status[3] = 0;
155
156 len = 0;
157 if (*p == ' ') p++;
158 while( (*p != '\r') && *p != 0) { len++; p++; }
159
160 if (len > sizeof(desc)-1) { /* description long! */
161 req->buffer_start = req->buffer_end = 0;
162 log_error_time();
163 fprintf(stderr, "description (%d bytes) is too long\n", len);
164 send_r_error(req);
165 return 0;
166 }
167
168 memcpy( desc, p-len, len);
169 desc[len] = 0;
170
171 send_r_request_cgi_status(req, str_status, desc); /* does not terminate */
172
173 if (*p=='\r' && *(p+1)=='\n')
174 p+=2; /* skip \r\n and move to the next line */
175
176 req->header_line = p;
177 } else {
178 send_r_request_cgi_status(req, "200", "OK"); /* does not terminate */
179 }
180
181 /* got to do special things because
182 a) we have a single buffer divided into 2 pieces
183 b) we need to merge those pieces
184 Easiest way is to memmove the cgi data backward until
185 it touches the buffered data, then reset the cgi data pointers
186 */
187 dest = req->buffer + req->buffer_end;
188 if (req->method == M_HEAD) {
189 if (*(c + 1) == '\r')
190 req->header_end = c + 2;
191 else
192 req->header_end = c + 1;
193 req->cgi_status = CGI_DONE;
194 }
195 howmuch = req->header_end - req->header_line;
196
197 if (dest + howmuch > req->buffer + BUFFER_SIZE) {
198 /* big problem */
199 log_error_time();
200 fprintf(stderr, "Too much data to move! Aborting! %s %d\n",
201 __FILE__, __LINE__);
202 /* reset buffer pointers because we already called
203 send_r_request_ok... */
204 req->buffer_start = req->buffer_end = 0;
205 send_r_error(req);
206 return 0;
207 }
208 memmove(dest, req->header_line, howmuch);
209 req->buffer_end += howmuch;
210 req->header_line = req->buffer + req->buffer_end;
211 req->header_end = req->header_line;
212 req_flush(req);
213
214 if (req->method == M_HEAD)
215 return 0;
216 }
217 return 1;
218 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26