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