Initial import from FreeBSD RELENG_4:
[games.git] / release / sysinstall / http.c
1 /*
2  * Copyright (c) 1999
3  *      Philipp Mergenthaler <philipp.mergenthaler@stud.uni-karlsruhe.de>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD: src/release/sysinstall/http.c,v 1.2.2.5 2002/06/24 03:46:55 matusita Exp $
28  */
29
30 #include "sysinstall.h"
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <sys/param.h>
35 #include <netdb.h>
36
37 extern const char *ftp_dirs[]; /* defined in ftp.c */
38
39 Boolean
40 checkAccess(Boolean proxyCheckOnly)
41 {
42 /* 
43  * Some proxies fetch files with certain extensions in "ascii mode" instead
44  * of "binary mode" for FTP. The FTP server then translates all LF to CRLF.
45  *
46  * You can force Squid to use binary mode by appending ";type=i" to the URL,
47  * which is what I do here. For other proxies, the LF->CRLF substitution
48  * is reverted in distExtract().
49  */
50
51     int rv, s, af;
52     bool el, found=FALSE;                   /* end of header line */
53     char *cp, buf[PATH_MAX], req[BUFSIZ];
54     struct addrinfo hints, *res, *res0;
55
56     af = variable_cmp(VAR_IPV6_ENABLE, "YES") ? AF_INET : AF_UNSPEC;
57     memset(&hints, 0, sizeof(hints));
58     hints.ai_family = af;
59     hints.ai_socktype = SOCK_STREAM;
60     hints.ai_protocol = 0;
61     if ((rv = getaddrinfo(variable_get(VAR_HTTP_HOST),
62                           variable_get(VAR_HTTP_PORT), &hints, &res0)) != 0) {
63         msgConfirm("%s", gai_strerror(rv));
64         variable_unset(VAR_HTTP_HOST);
65         return FALSE;
66     }
67     s = -1;
68     for (res = res0; res; res = res->ai_next) {
69         if ((s = socket(res->ai_family, res->ai_socktype,
70                         res->ai_protocol)) < 0)
71             continue;
72         if (connect(s, res->ai_addr, res->ai_addrlen) >= 0)
73             break;
74         close(s);
75         s = -1;
76     }
77     freeaddrinfo(res0);
78     if (s == -1) {
79         msgConfirm("Couldn't connect to proxy %s:%s",
80                     variable_get(VAR_HTTP_HOST),variable_get(VAR_HTTP_PORT));
81         variable_unset(VAR_HTTP_HOST);
82         return FALSE;
83     }
84     if (proxyCheckOnly) {
85        close(s);
86        return TRUE;
87     }
88
89     msgNotify("Checking access to\n %s", variable_get(VAR_HTTP_PATH));
90     sprintf(req,"GET %s/ HTTP/1.0\r\n\r\n", variable_get(VAR_HTTP_PATH));
91     write(s,req,strlen(req));
92 /*
93  *  scan the headers of the response
94  *  this is extremely quick'n dirty
95  *
96  */
97     bzero(buf, PATH_MAX);
98     cp=buf;
99     el=FALSE;
100     rv=read(s,cp,1);
101     variable_set2(VAR_HTTP_FTP_MODE,"",0);
102     while (rv>0) {
103         if ((*cp == '\012') && el) { 
104             /* reached end of a header line */
105             if (!strncmp(buf,"HTTP",4)) {
106                 if (strtol((char *)(buf+9),0,0) == 200) {
107                     found = TRUE;
108                 }
109             }
110
111             if (!strncmp(buf,"Server: ",8)) {
112                 if (!strncmp(buf,"Server: Squid",13)) {
113                     variable_set2(VAR_HTTP_FTP_MODE,";type=i",0);
114                 } else {
115                     variable_set2(VAR_HTTP_FTP_MODE,"",0);
116                 }
117             }
118             /* ignore other headers */
119             /* check for "\015\012" at beginning of line, i.e. end of headers */
120             if ((cp-buf) == 1)
121                 break;
122             cp=buf;
123             rv=read(s,cp,1);
124         } else {
125             el=FALSE;
126             if (*cp == '\015')
127                 el=TRUE;
128             cp++;
129             rv=read(s,cp,1);
130         }
131     }
132     close(s);
133     return found;
134
135
136 Boolean
137 mediaInitHTTP(Device *dev)
138 {
139     bool found=FALSE;               /* end of header line */
140     char *rel, req[BUFSIZ];
141     int fdir;
142
143     /* 
144      * First verify the proxy access
145      */
146     checkAccess(TRUE);
147     while (variable_get(VAR_HTTP_HOST) == NULL) {
148         if (DITEM_STATUS(mediaSetHTTP(NULL)) == DITEM_FAILURE)
149             return FALSE;
150         checkAccess(TRUE);
151     }
152 again:
153     /* If the release is specified as "__RELEASE" or "any", then just
154      * assume that the path the user gave is ok.
155      */
156     rel = variable_get(VAR_RELNAME);
157     /*
158     msgConfirm("rel: -%s-", rel);
159     */
160
161     if (strcmp(rel, "__RELEASE") && strcmp(rel, "any"))  {
162         for (fdir = 0; ftp_dirs[fdir]; fdir++) {
163             sprintf(req, "%s/%s/%s", variable_get(VAR_FTP_PATH),
164                 ftp_dirs[fdir], rel);
165             variable_set2(VAR_HTTP_PATH, req, 0);
166             if (checkAccess(FALSE)) {
167                 found = TRUE;
168                 break;
169             }
170         }
171     } else {
172         variable_set2(VAR_HTTP_PATH, variable_get(VAR_FTP_PATH), 0);
173         found = checkAccess(FALSE);
174     }
175     if (!found) {
176         msgConfirm("No such directory: %s\n"
177                    "please check the URL and try again.", variable_get(VAR_HTTP_PATH));
178         variable_unset(VAR_HTTP_PATH);
179         dialog_clear_norefresh();
180         clear();
181         if (DITEM_STATUS(mediaSetHTTP(NULL)) != DITEM_FAILURE) goto again;
182     }
183     return found;
184 }
185
186 FILE *
187 mediaGetHTTP(Device *dev, char *file, Boolean probe)
188 {
189     FILE *fp;
190     int rv, s, af;
191     bool el;                    /* end of header line */
192     char *cp, buf[PATH_MAX], req[BUFSIZ];
193     struct addrinfo hints, *res, *res0;
194
195     af = variable_cmp(VAR_IPV6_ENABLE, "YES") ? AF_INET : AF_UNSPEC;
196     memset(&hints, 0, sizeof(hints));
197     hints.ai_family = af;
198     hints.ai_socktype = SOCK_STREAM;
199     hints.ai_protocol = 0;
200     if ((rv = getaddrinfo(variable_get(VAR_HTTP_HOST),
201                           variable_get(VAR_HTTP_PORT), &hints, &res0)) != 0) {
202         msgConfirm("%s", gai_strerror(rv));
203         return NULL;
204     }
205     s = -1;
206     for (res = res0; res; res = res->ai_next) {
207         if ((s = socket(res->ai_family, res->ai_socktype,
208                         res->ai_protocol)) < 0)
209             continue;
210         if (connect(s, res->ai_addr, res->ai_addrlen) >= 0)
211             break;
212         close(s);
213         s = -1;
214     }
215     freeaddrinfo(res0);
216     if (s == -1) {
217         msgConfirm("Couldn't connect to proxy %s:%s",
218                     variable_get(VAR_HTTP_HOST),variable_get(VAR_HTTP_PORT));
219         return NULL;
220     }
221                                                    
222     sprintf(req,"GET %s/%s%s HTTP/1.0\r\n\r\n",
223             variable_get(VAR_HTTP_PATH), file, variable_get(VAR_HTTP_FTP_MODE));
224
225     if (isDebug()) {
226         msgDebug("sending http request: %s",req);
227     }
228     write(s,req,strlen(req));
229
230 /*
231  *  scan the headers of the response
232  *  this is extremely quick'n dirty
233  *
234  */
235     cp=buf;
236     el=FALSE;
237     rv=read(s,cp,1);
238     while (rv>0) {
239         if ((*cp == '\012') && el) {
240             /* reached end of a header line */
241             if (!strncmp(buf,"HTTP",4)) {
242                 rv=strtol((char *)(buf+9),0,0);
243                 *(cp-1)='\0';           /* chop the CRLF off */
244                 if (probe && (rv != 200)) {
245                     return NULL;
246                 } else if (rv >= 500) {
247                     msgConfirm("Server error %s when sending %s, you could try an other server",buf, req);
248                     return NULL;
249                 } else if (rv == 404) {
250                     msgConfirm("%s was not found, maybe directory or release-version are wrong?",req);
251                     return NULL;
252                 } else if (rv >= 400) {
253                     msgConfirm("Client error %s, you could try an other server",buf);
254                     return NULL;
255                 } else if (rv >= 300) {
256                     msgConfirm("Error %s,",buf);
257                     return NULL;
258                 } else if (rv != 200) {
259                     msgConfirm("Error %s when sending %s, you could try an other server",buf, req);
260                     return NULL;
261                 }
262             }
263             /* ignore other headers */
264             /* check for "\015\012" at beginning of line, i.e. end of headers */
265             if ((cp-buf) == 1) 
266                 break;
267             cp=buf;
268             rv=read(s,cp,1);
269         } else {
270             el=FALSE;
271             if (*cp == '\015')
272                 el=TRUE;
273             cp++;
274             rv=read(s,cp,1);
275         }
276     }
277     fp=fdopen(s,"r");
278     return fp;
279 }