]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - usr.sbin/sysinstall/http.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / usr.sbin / 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$
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 connectCheckOnly, Boolean isProxy)
41 {
42     int rv, s, af;
43     bool el, found=FALSE;                   /* end of header line */
44     char *cp, buf[PATH_MAX], req[BUFSIZ];
45     struct addrinfo hints, *res, *res0;
46
47     af = variable_cmp(VAR_IPV6_ENABLE, "YES") ? AF_INET : AF_UNSPEC;
48     memset(&hints, 0, sizeof(hints));
49     hints.ai_family = af;
50     hints.ai_socktype = SOCK_STREAM;
51     hints.ai_protocol = 0;
52     if ((rv = getaddrinfo(variable_get(VAR_HTTP_HOST),
53                           variable_get(VAR_HTTP_PORT), &hints, &res0)) != 0) {
54         msgConfirm("%s", gai_strerror(rv));
55         variable_unset(VAR_HTTP_HOST);
56         return FALSE;
57     }
58     s = -1;
59     for (res = res0; res; res = res->ai_next) {
60         if ((s = socket(res->ai_family, res->ai_socktype,
61                         res->ai_protocol)) < 0)
62             continue;
63         if (connect(s, res->ai_addr, res->ai_addrlen) >= 0)
64             break;
65         close(s);
66         s = -1;
67     }
68     freeaddrinfo(res0);
69     if (s == -1) {
70         if (isProxy) {
71                 msgConfirm("Couldn't connect to proxy %s:%s",
72                             variable_get(VAR_HTTP_HOST),variable_get(VAR_HTTP_PORT));
73         } else {
74                 msgConfirm("Couldn't connect to server http://%s:%s/",
75                             variable_get(VAR_HTTP_HOST),variable_get(VAR_HTTP_PORT));
76         }
77         variable_unset(VAR_HTTP_HOST);
78         return FALSE;
79     }
80     if (connectCheckOnly) {
81        close(s);
82        return TRUE;
83     }
84
85     msgNotify("Checking access to\n %s", variable_get(VAR_HTTP_PATH));
86     if (isProxy)
87         sprintf(req,"GET %s/ HTTP/1.0\r\n\r\n", variable_get(VAR_HTTP_PATH));
88     else
89         sprintf(req,"GET /%s/ HTTP/1.0\r\n\r\n", variable_get(VAR_HTTP_PATH));
90     write(s,req,strlen(req));
91 /*
92  *  scan the headers of the response
93  *  this is extremely quick'n dirty
94  *
95  */
96     bzero(buf, PATH_MAX);
97     cp=buf;
98     el=FALSE;
99     rv=read(s,cp,1);
100     variable_set2(VAR_HTTP_FTP_MODE,"",0);
101     while (rv>0) {
102         if ((*cp == '\012') && el) { 
103             /* reached end of a header line */
104             if (!strncmp(buf,"HTTP",4)) {
105                 if (strtol((char *)(buf+9),0,0) == 200) {
106                     found = TRUE;
107                 }
108             }
109
110             /* 
111              * Some proxies fetch files with certain extensions in "ascii mode"
112              * instead of "binary mode" for FTP. The FTP server then translates
113              * all LF to CRLF.
114              *
115              * You can force Squid to use binary mode by appending ";type=i" to
116              * the URL, which is what I do here. For other proxies, the
117              * LF->CRLF substitution is reverted in distExtract().
118              */
119             if (isProxy && !strncmp(buf,"Server: ",8)) {
120                 if (!strncmp(buf,"Server: Squid",13)) {
121                     variable_set2(VAR_HTTP_FTP_MODE,";type=i",0);
122                 } else {
123                     variable_set2(VAR_HTTP_FTP_MODE,"",0);
124                 }
125             }
126             /* ignore other headers */
127             /* check for "\015\012" at beginning of line, i.e. end of headers */
128             if ((cp-buf) == 1)
129                 break;
130             cp=buf;
131             rv=read(s,cp,1);
132         } else {
133             el=FALSE;
134             if (*cp == '\015')
135                 el=TRUE;
136             cp++;
137             rv=read(s,cp,1);
138         }
139     }
140     close(s);
141     return found;
142
143
144 Boolean
145 mediaInitHTTP(Device *dev)
146 {
147     bool found=FALSE;               /* end of header line */
148     char *rel, req[BUFSIZ];
149     int fdir;
150
151     /* 
152      * First verify the proxy access
153      */
154     checkAccess(TRUE, TRUE);
155     while (variable_get(VAR_HTTP_HOST) == NULL) {
156         if (DITEM_STATUS(mediaSetHTTP(NULL)) == DITEM_FAILURE)
157             return FALSE;
158         checkAccess(TRUE, TRUE);
159     }
160 again:
161     /* If the release is specified as "__RELEASE" or "any", then just
162      * assume that the path the user gave is ok.
163      */
164     rel = variable_get(VAR_RELNAME);
165     /*
166     msgConfirm("rel: -%s-", rel);
167     */
168
169     if (strcmp(rel, "__RELEASE") && strcmp(rel, "any"))  {
170         for (fdir = 0; ftp_dirs[fdir]; fdir++) {
171             sprintf(req, "%s/%s/%s", variable_get(VAR_FTP_PATH),
172                 ftp_dirs[fdir], rel);
173             variable_set2(VAR_HTTP_PATH, req, 0);
174             if (checkAccess(FALSE, TRUE)) {
175                 found = TRUE;
176                 break;
177             }
178         }
179     } else {
180         variable_set2(VAR_HTTP_PATH, variable_get(VAR_FTP_PATH), 0);
181         found = checkAccess(FALSE, TRUE);
182     }
183     if (!found) {
184         msgConfirm("No such directory: %s\n"
185                    "please check the URL and try again.", variable_get(VAR_HTTP_PATH));
186         variable_unset(VAR_HTTP_PATH);
187         dialog_clear_norefresh();
188         clear();
189         if (DITEM_STATUS(mediaSetHTTP(NULL)) != DITEM_FAILURE) goto again;
190     }
191     return found;
192 }
193
194 FILE *
195 mediaGetHTTP(Device *dev, char *file, Boolean probe)
196 {
197     FILE *fp;
198     int rv, s, af;
199     bool el;                    /* end of header line */
200     char *cp, buf[PATH_MAX], req[BUFSIZ];
201     struct addrinfo hints, *res, *res0;
202
203     af = variable_cmp(VAR_IPV6_ENABLE, "YES") ? AF_INET : AF_UNSPEC;
204     memset(&hints, 0, sizeof(hints));
205     hints.ai_family = af;
206     hints.ai_socktype = SOCK_STREAM;
207     hints.ai_protocol = 0;
208     if ((rv = getaddrinfo(variable_get(VAR_HTTP_HOST),
209                           variable_get(VAR_HTTP_PORT), &hints, &res0)) != 0) {
210         msgConfirm("%s", gai_strerror(rv));
211         return NULL;
212     }
213     s = -1;
214     for (res = res0; res; res = res->ai_next) {
215         if ((s = socket(res->ai_family, res->ai_socktype,
216                         res->ai_protocol)) < 0)
217             continue;
218         if (connect(s, res->ai_addr, res->ai_addrlen) >= 0)
219             break;
220         close(s);
221         s = -1;
222     }
223     freeaddrinfo(res0);
224     if (s == -1) {
225         msgConfirm("Couldn't connect to proxy %s:%s",
226                     variable_get(VAR_HTTP_HOST),variable_get(VAR_HTTP_PORT));
227         return NULL;
228     }
229                                                    
230     sprintf(req,"GET %s/%s%s HTTP/1.0\r\n\r\n",
231             variable_get(VAR_HTTP_PATH), file, variable_get(VAR_HTTP_FTP_MODE));
232
233     if (isDebug()) {
234         msgDebug("sending http request: %s\n",req);
235     }
236     write(s,req,strlen(req));
237
238 /*
239  *  scan the headers of the response
240  *  this is extremely quick'n dirty
241  *
242  */
243     cp=buf;
244     el=FALSE;
245     rv=read(s,cp,1);
246     while (rv>0) {
247         if ((*cp == '\012') && el) {
248             /* reached end of a header line */
249             if (!strncmp(buf,"HTTP",4)) {
250                 rv=strtol((char *)(buf+9),0,0);
251                 *(cp-1)='\0';           /* chop the CRLF off */
252                 if (probe && (rv != 200)) {
253                     return NULL;
254                 } else if (rv >= 500) {
255                     msgConfirm("Server error %s when sending %s, you could try an other server",buf, req);
256                     return NULL;
257                 } else if (rv == 404) {
258                     msgConfirm("%s was not found, maybe directory or release-version are wrong?",req);
259                     return NULL;
260                 } else if (rv >= 400) {
261                     msgConfirm("Client error %s, you could try an other server",buf);
262                     return NULL;
263                 } else if (rv >= 300) {
264                     msgConfirm("Error %s",buf);
265                     return NULL;
266                 } else if (rv != 200) {
267                     msgConfirm("Error %s when sending %s, you could try an other server",buf, req);
268                     return NULL;
269                 }
270             }
271             /* ignore other headers */
272             /* check for "\015\012" at beginning of line, i.e. end of headers */
273             if ((cp-buf) == 1) 
274                 break;
275             cp=buf;
276             rv=read(s,cp,1);
277         } else {
278             el=FALSE;
279             if (*cp == '\015')
280                 el=TRUE;
281             cp++;
282             rv=read(s,cp,1);
283         }
284     }
285     fp=fdopen(s,"r");
286     return fp;
287 }