1 /*
2 ** ____ _
3 ** ___| _ \ ___ _ __| |
4 ** / _ \ |_) / _ \ '__| |
5 ** | __/ __/ __/ | | |
6 ** \___|_| \___|_| |_|
7 **
8 ** ePerl -- Embedded Perl 5 Language
9 **
10 ** ePerl interprets an ASCII file bristled with Perl 5 program statements
11 ** by evaluating the Perl 5 code while passing through the plain ASCII
12 ** data. It can operate both as a standard Unix filter for general file
13 ** generation tasks and as a powerful Webserver scripting language for
14 ** dynamic HTML page programming.
15 **
16 ** ======================================================================
17 **
18 ** Copyright (c) 1996,1997,1998 Ralf S. Engelschall <rse@engelschall.com>
19 **
20 ** This program is free software; it may be redistributed and/or modified
21 ** only under the terms of either the Artistic License or the GNU General
22 ** Public License, which may be found in the ePerl source distribution.
23 ** Look at the files ARTISTIC and COPYING or run ``eperl -l'' to receive
24 ** a built-in copy of both license files.
25 **
26 ** This program is distributed in the hope that it will be useful, but
27 ** WITHOUT ANY WARRANTY; without even the implied warranty of
28 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the
29 ** Artistic License or the GNU General Public License for more details.
30 **
31 ** ======================================================================
32 **
33 ** eperl_http.c -- ePerl HTTP stuff
34 */
35
36 #include "eperl_config.h"
37 #include "eperl_global.h"
38 #include "eperl_proto.h"
39
40
41 /*
42 **
43 ** print a standard HTTP reponse of header lines
44 **
45 */
HTTP_PrintResponseHeaders(char * cpBuf)46 void HTTP_PrintResponseHeaders(char *cpBuf)
47 {
48 char *cp;
49
50 if ((cp = getenv("SERVER_PROTOCOL")) == NULL)
51 cp = "HTTP/1.0";
52 printf("%s 200 OK\n", cp);
53
54 if (!HTTP_HeaderLineExists(cpBuf, "Server")) {
55 if ((cp = getenv("SERVER_SOFTWARE")) == NULL)
56 cp = "unknown-server/0.0";
57 printf("Server: %s %s Perl/%s\n", cp, ePerl_WebID, AC_perl_vers);
58 }
59
60 if (!HTTP_HeaderLineExists(cpBuf, "Date"))
61 printf("Date: %s\n", WebTime());
62
63 if (!HTTP_HeaderLineExists(cpBuf, "Connection"))
64 printf("Connection: close\n");
65
66 return;
67 }
68
69 /*
70 **
71 ** strip standard HTTP reponse header lines
72 **
73 */
HTTP_StripResponseHeaders(char ** cpBuf,int * nBuf)74 void HTTP_StripResponseHeaders(char **cpBuf, int *nBuf)
75 {
76 return;
77 }
78
79 /*
80 **
81 ** check if the line is a valid HTTP header line
82 **
83 */
HTTP_IsHeaderLine(char * cp1,char * cp2)84 int HTTP_IsHeaderLine(char *cp1, char *cp2)
85 {
86 char *cp3;
87 char *cp4;
88 char ca[1024];
89
90 while (cp1 < cp2 && (*cp1 == '\n' || *cp1 == '\r'))
91 cp1++;
92 while (cp2 > cp1 && (*(cp2-1) == '\n' || *(cp2-1) == '\r'))
93 cp2--;
94 strncpy(ca, cp1, cp2-cp1);
95 ca[cp2-cp1] = NUL;
96 if ((cp3 = strchr(ca, ':')) == NULL)
97 return 0;
98 for (cp4 = ca; cp4 < cp3; cp4++) {
99 if (! ((*cp4 >= 'A' && *cp4 <= 'Z') ||
100 (*cp4 >= 'a' && *cp4 <= 'z') ||
101 (*cp4 >= '0' && *cp4 <= '9') ||
102 (*cp4 == '-' || *cp4 == '_') ))
103 return 0;
104 }
105 return 1;
106 }
107
108 /*
109 **
110 ** check if there is a valid HTTP header
111 **
112 */
HTTP_HeadersExists(char * cpBuf)113 int HTTP_HeadersExists(char *cpBuf)
114 {
115 char *cp1;
116 char *cp2;
117 char *cp2a;
118 char *cp3;
119
120 cp2 = NULL;
121 if ((cp2a = strstr(cpBuf, "\n\n")) != NULL)
122 cp2 = cp2a;
123 if ((cp2a = strstr(cpBuf, "\r\n\r\n")) != NULL && (cp2 == NULL || cp2a < cp2))
124 cp2 = cp2a;
125 if (cp2 != NULL) {
126 for (cp1 = cpBuf; cp1 < cp2-1; ) {
127 cp3 = strchr(cp1, '\n');
128 if (!HTTP_IsHeaderLine(cp1, cp3))
129 return 0;
130 cp1 = cp3+1;
131 }
132 return 1;
133 }
134 return 0;
135 }
136
137 /*
138 **
139 ** check if there a particular HTTP headerline exists
140 **
141 */
HTTP_HeaderLineExists(char * cpBuf,char * name)142 int HTTP_HeaderLineExists(char *cpBuf, char *name)
143 {
144 char *cp1;
145 char *cp2;
146 char *cp2a;
147 char *cp3;
148 int n;
149
150 n = strlen(name);
151 cp2 = NULL;
152 if ((cp2a = strstr(cpBuf, "\n\n")) != NULL)
153 cp2 = cp2a;
154 if ((cp2a = strstr(cpBuf, "\r\n\r\n")) != NULL && (cp2 == NULL || cp2a < cp2))
155 cp2 = cp2a;
156 if (cp2 != NULL) {
157 for (cp1 = cpBuf; cp1 < cp2-1; ) {
158 cp3 = strchr(cp1, '\n');
159 if (HTTP_IsHeaderLine(cp1, cp3) && cp3-cp1 > n+1)
160 if (strncasecmp(cp1, name, n) == 0)
161 return 1;
162 cp1 = cp3+1;
163 }
164 return 0;
165 }
166 return 0;
167 }
168
169 /*
170 **
171 ** Give back acceptable HTTP time format string
172 **
173 */
WebTime(void)174 char *WebTime(void)
175 {
176 time_t t;
177 struct tm *tm;
178 char *cp;
179
180 t = time(&t);
181 tm = localtime(&t);
182 cp = ctime(&t);
183 cp[strlen(cp)-1] = NUL;
184 return cp;
185 }
186
187
188 /*
189 ** extracts the host name from an url
190 */
HTTP_HostOfURL(char * url)191 static char *HTTP_HostOfURL(char *url)
192 {
193 static char host[1024];
194 char *cps;
195 char *cpe;
196
197 cps = strstr(url, "//");
198 cps += 2;
199 for (cpe = cps; *cpe != '/' && *cpe != ':' && *cpe != NUL; cpe++)
200 ;
201 strncpy(host, cps, cpe-cps);
202 host[cpe-cps] = NUL;
203 return host;
204 }
205
206 /*
207 ** extracts the port from an url
208 */
HTTP_PortOfURL(char * url)209 static char *HTTP_PortOfURL(char *url)
210 {
211 static char port[128];
212 char *cps;
213 char *cpe;
214
215 cps = strstr(url, "//");
216 cps += 2;
217 for ( ; *cps != '/' && *cps != ':' && *cps != NUL; cps++)
218 ;
219 if (*cps == ':') {
220 cps++;
221 for (cpe = cps; *cpe != '/' && *cpe != NUL; cpe++)
222 ;
223 strncpy(port, cps, cpe-cps);
224 port[cpe-cps] = NUL;
225 }
226 else
227 strcpy(port, "80");
228 return port;
229 }
230
231
232 /*
233 ** extracts a file name from a url
234 */
HTTP_FileOfURL(char * url)235 static char *HTTP_FileOfURL(char *url)
236 {
237 static char file[2048];
238 char *cps;
239
240 cps = strstr(url, "//");
241 cps = strstr(cps+2, "/");
242 if (cps == NUL)
243 strcpy(file, "/");
244 else
245 strcpy(file, cps);
246 return file;
247 }
248
249 /*
250 ** open an URL as a file descriptor
251 */
HTTP_openURLasFP(char * url)252 FILE *HTTP_openURLasFP(char *url)
253 {
254 struct hostent *he;
255 struct sockaddr_in sar;
256 struct protoent *pe;
257 char cmd[1024];
258 char buf[1024];
259 char newurl[8192];
260 char *host;
261 char *port;
262 char *file;
263 FILE *fp;
264 char *cp;
265 char *cp2;
266 int s;
267
268 /* parse URL */
269 host = HTTP_HostOfURL(url);
270 port = HTTP_PortOfURL(url);
271 file = HTTP_FileOfURL(url);
272
273 /* get the host name */
274 if ((he = gethostbyname(host)) == NULL)
275 return NULL;
276
277 /* get TCP protocol information */
278 if ((pe = getprotobyname("tcp")) == NULL)
279 return NULL;
280
281 /* open the socket */
282 if ((s = socket(AF_INET, SOCK_STREAM, pe->p_proto)) == -1)
283 return NULL;
284
285 /* fill in the socket information */
286 sar.sin_family = AF_INET;
287 sar.sin_addr.s_addr = *((u_long *)(he->h_addr_list[0]));
288 sar.sin_port = htons(atoi(port));
289
290 /* actually connect */
291 if (connect(s, (struct sockaddr *)&sar, sizeof(sar)) == -1)
292 return NULL;
293
294 /* form the HTTP/1.0 request */
295 sprintf(cmd, "GET %s HTTP/1.0\n", file);
296 sprintf(cmd+strlen(cmd), "Host: %s:%s\n", host, port);
297 sprintf(cmd+strlen(cmd), "User-Agent: %s\n", ePerl_WebID);
298 sprintf(cmd+strlen(cmd), "\n");
299
300 /* send the request */
301 write(s, cmd, strlen(cmd));
302
303 /* convert the file descriptor to a FILE pointer */
304 fp = fdopen(s, "r");
305
306 /* read the HTTP response line and check for 200 OK response */
307 if (fgets(buf, sizeof(buf), fp) == NULL)
308 return NULL;
309 if (strncmp(buf, "HTTP/1.", 7) != 0)
310 return NULL;
311 if (buf[7] != '0' && buf[7] != '1')
312 return NULL;
313 for (cp = buf+8; *cp == ' ' || *cp == '\t'; cp++)
314 ;
315 if (strncmp(cp, "200", 3 /* OK */) != 0) {
316 if (strncmp(cp, "301", 3 /* MOVED PERMANENTLY */) != 0 ||
317 strncmp(cp, "302", 3 /* MOVED TEMPORARILY */) != 0 ) {
318 /* we try to determine the new URL from
319 the HTTP header 'Location' and restart from
320 the beginning if an URL is found */
321 newurl[0] = NUL;
322 while (fgets(buf, sizeof(buf), fp) != NULL) {
323 if ((*buf == '\n' && *(buf+1) == NUL) ||
324 (*buf == '\n' && *(buf+1) == '\r' && *(buf+2) == NUL) ||
325 (*buf == '\r' && *(buf+1) == '\n' && *(buf+2) == NUL))
326 break;
327 if (strncasecmp(buf, "Location:", 9) == 0) {
328 for (cp = buf+9; *cp == ' ' || *cp == '\t'; cp++)
329 ;
330 for (cp2 = cp; *cp2 != ' ' && *cp2 != '\t' && *cp2 != '\n' && *cp2 != NUL; cp2++)
331 ;
332 *cp2 = NUL;
333 strcpy(newurl, cp);
334 break;
335 }
336 }
337 if (newurl[0] != NUL)
338 return HTTP_openURLasFP(newurl);
339 else
340 return NULL;
341 }
342 return NULL;
343 }
344
345 /* now read until a blank line, i.e. skip HTTP headers */
346 while (fgets(buf, sizeof(buf), fp) != NULL) {
347 if ((*buf == '\n' && *(buf+1) == NUL) ||
348 (*buf == '\n' && *(buf+1) == '\r' && *(buf+2) == NUL) ||
349 (*buf == '\r' && *(buf+1) == '\n' && *(buf+2) == NUL))
350 break;
351 }
352
353 /* return the (still open) FILE pointer */
354 return fp;
355 }
356
357
358 /*EOF*/
359