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