/[soft]/drakx/trunk/mdk-stage1/url.c
ViewVC logotype

Contents of /drakx/trunk/mdk-stage1/url.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2834 - (show annotations) (download) (as text)
Fri Jan 27 07:14:12 2012 UTC (9 months, 2 weeks ago) by tv
File MIME type: text/x-c
File size: 12365 byte(s)
kill dead emails
1 /*
2 * Guillaume Cottenceau (gc)
3 *
4 * Copyright 2000 Mandriva
5 *
6 * This software may be freely redistributed under the terms of the GNU
7 * public license.
8 *
9 * You should have received a copy of the GNU General Public License
10 * along with this program; if not, write to the Free Software
11 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
12 *
13 */
14
15 /*
16 * Portions from Erik Troan <ewt@redhat.com> and Matt Wilson <msw@redhat.com>
17 *
18 * Copyright 1999 Red Hat, Inc.
19 *
20 */
21
22 #include <alloca.h>
23 #include <sys/socket.h>
24 #include <sys/types.h>
25 #include <netinet/in_systm.h>
26
27 #include <ctype.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <netdb.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <strings.h>
36 #include <sys/socket.h>
37 #include <sys/time.h>
38 #include <sys/types.h>
39 #include <unistd.h>
40 #include <sys/poll.h>
41
42 #include <netinet/in.h>
43 #include <netinet/ip.h>
44 #include <arpa/inet.h>
45
46 #include "dns.h"
47 #include "log.h"
48 #include "tools.h"
49 #include "utils.h"
50
51 #include "url.h"
52
53
54 #define TIMEOUT_SECS 60
55 #define BUFFER_SIZE 4096
56 #define HTTP_MAX_RECURSION 5
57
58
59 static int ftp_check_response(int sock, char ** str)
60 {
61 static char buf[BUFFER_SIZE + 1];
62 int bufLength = 0;
63 struct pollfd polls;
64 char * chptr, * start;
65 int bytesRead, rc = 0;
66 int doesContinue = 1;
67 char errorCode[4];
68
69 errorCode[0] = '\0';
70
71 do {
72 polls.fd = sock;
73 polls.events = POLLIN;
74 if (poll(&polls, 1, TIMEOUT_SECS*1000) != 1)
75 return FTPERR_BAD_SERVER_RESPONSE;
76
77 bytesRead = read(sock, buf + bufLength, sizeof(buf) - bufLength - 1);
78
79 bufLength += bytesRead;
80
81 buf[bufLength] = '\0';
82
83 /* divide the response into lines, checking each one to see if
84 we are finished or need to continue */
85
86 start = chptr = buf;
87
88 do {
89 while (*chptr != '\n' && *chptr) chptr++;
90
91 if (*chptr == '\n') {
92 *chptr = '\0';
93 if (*(chptr - 1) == '\r') *(chptr - 1) = '\0';
94 if (str) *str = start;
95
96 if (errorCode[0]) {
97 if (!strncmp(start, errorCode, 3) && start[3] == ' ')
98 doesContinue = 0;
99 } else {
100 strncpy(errorCode, start, 3);
101 errorCode[3] = '\0';
102 if (start[3] != '-') {
103 doesContinue = 0;
104 }
105 }
106
107 start = chptr + 1;
108 chptr++;
109 } else {
110 chptr++;
111 }
112 } while (*chptr);
113
114 if (doesContinue && chptr > start) {
115 memcpy(buf, start, chptr - start - 1);
116 bufLength = chptr - start - 1;
117 } else {
118 bufLength = 0;
119 }
120 } while (doesContinue);
121
122 if (*errorCode == '4' || *errorCode == '5') {
123 if (!strncmp(errorCode, "550", 3)) {
124 return FTPERR_FILE_NOT_FOUND;
125 }
126
127 return FTPERR_BAD_SERVER_RESPONSE;
128 }
129
130 if (rc) return rc;
131
132 return 0;
133 }
134
135 static int ftp_command(int sock, char * command, char * param)
136 {
137 char buf[500];
138 int rc;
139
140 snprintf(buf, sizeof(buf), "%s%s%s\r\n", command, param ? " " : "", param ? param : "");
141
142 if (write(sock, buf, strlen(buf)) != (ssize_t)strlen(buf)) {
143 return FTPERR_SERVER_IO_ERROR;
144 }
145
146 if ((rc = ftp_check_response(sock, NULL)))
147 return rc;
148
149 return 0;
150 }
151
152 static int get_host_address(char * host, struct in_addr * address)
153 {
154 if (isdigit(host[0])) {
155 if (!inet_aton(host, address)) {
156 return FTPERR_BAD_HOST_ADDR;
157 }
158 } else {
159 if (mygethostbyname(host, address))
160 return FTPERR_BAD_HOSTNAME;
161 }
162
163 return 0;
164 }
165
166 int ftp_open_connection(char * host, char * name, char * password, char * proxy)
167 {
168 int sock;
169 struct in_addr serverAddress;
170 struct sockaddr_in destPort;
171 int rc;
172 int port = 21;
173
174 if (!strcmp(name, "")) {
175 name = "anonymous";
176 password = "-drakx@";
177 }
178
179 if (strcmp(proxy, "")) {
180 name = asprintf_("%s@%s", name, host);
181 host = proxy;
182 }
183
184 if ((rc = get_host_address(host, &serverAddress))) return rc;
185
186 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
187 if (sock < 0) {
188 return FTPERR_FAILED_CONNECT;
189 }
190
191 destPort.sin_family = AF_INET;
192 destPort.sin_port = htons(port);
193 destPort.sin_addr = serverAddress;
194
195 if (connect(sock, (struct sockaddr *) &destPort, sizeof(destPort))) {
196 close(sock);
197 return FTPERR_FAILED_CONNECT;
198 }
199
200 /* ftpCheckResponse() assumes the socket is nonblocking */
201 if (fcntl(sock, F_SETFL, O_NONBLOCK)) {
202 close(sock);
203 return FTPERR_FAILED_CONNECT;
204 }
205
206 if ((rc = ftp_check_response(sock, NULL))) {
207 return rc;
208 }
209
210 if ((rc = ftp_command(sock, "USER", name))) {
211 close(sock);
212 return rc;
213 }
214
215 if ((rc = ftp_command(sock, "PASS", password))) {
216 close(sock);
217 return rc;
218 }
219
220 if ((rc = ftp_command(sock, "TYPE", "I"))) {
221 close(sock);
222 return rc;
223 }
224
225 return sock;
226 }
227
228
229 int ftp_data_command(int sock, char * command, char * param)
230 {
231 int dataSocket;
232 struct sockaddr_in dataAddress;
233 int i, j;
234 char * passReply;
235 char * chptr;
236 char retrCommand[500];
237 int rc;
238
239 if (write(sock, "PASV\r\n", 6) != 6) {
240 return FTPERR_SERVER_IO_ERROR;
241 }
242 if ((rc = ftp_check_response(sock, &passReply)))
243 return FTPERR_PASSIVE_ERROR;
244
245 chptr = passReply;
246 while (*chptr && *chptr != '(') chptr++;
247 if (*chptr != '(') return FTPERR_PASSIVE_ERROR;
248 chptr++;
249 passReply = chptr;
250 while (*chptr && *chptr != ')') chptr++;
251 if (*chptr != ')') return FTPERR_PASSIVE_ERROR;
252 *chptr-- = '\0';
253
254 while (*chptr && *chptr != ',') chptr--;
255 if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
256 chptr--;
257 while (*chptr && *chptr != ',') chptr--;
258 if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
259 *chptr++ = '\0';
260
261 /* now passReply points to the IP portion, and chptr points to the
262 port number portion */
263
264 dataAddress.sin_family = AF_INET;
265 if (sscanf(chptr, "%d,%d", &i, &j) != 2) {
266 return FTPERR_PASSIVE_ERROR;
267 }
268 dataAddress.sin_port = htons((i << 8) + j);
269
270 chptr = passReply;
271 while (*chptr++) {
272 if (*chptr == ',') *chptr = '.';
273 }
274
275 if (!inet_aton(passReply, &dataAddress.sin_addr))
276 return FTPERR_PASSIVE_ERROR;
277
278 dataSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
279 if (dataSocket < 0) {
280 return FTPERR_FAILED_CONNECT;
281 }
282
283 if (!param)
284 sprintf(retrCommand, "%s\r\n", command);
285 else
286 sprintf(retrCommand, "%s %s\r\n", command, param);
287
288 i = strlen(retrCommand);
289
290 if (write(sock, retrCommand, i) != i) {
291 return FTPERR_SERVER_IO_ERROR;
292 }
293
294 if (connect(dataSocket, (struct sockaddr *) &dataAddress,
295 sizeof(dataAddress))) {
296 close(dataSocket);
297 return FTPERR_FAILED_DATA_CONNECT;
298 }
299
300 if ((rc = ftp_check_response(sock, NULL))) {
301 close(dataSocket);
302 return rc;
303 }
304
305 return dataSocket;
306 }
307
308
309 int ftp_get_filesize(int sock, char * remotename)
310 {
311 int size = 0;
312 char buf[2000];
313 char file[500];
314 char * ptr;
315 int fd, rc, tot;
316 int i;
317
318 strcpy(buf, remotename);
319 ptr = strrchr(buf, '/');
320 if (!*ptr)
321 return -1;
322 *ptr = '\0';
323
324 strcpy(file, ptr+1);
325
326 if ((rc = ftp_command(sock, "CWD", buf))) {
327 return -1;
328 }
329
330 fd = ftp_data_command(sock, "LIST", file);
331 if (fd <= 0) {
332 close(sock);
333 return -1;
334 }
335
336 ptr = buf;
337 while ((tot = read(fd, ptr, sizeof(buf) - (ptr - buf) - 1)) != 0)
338 ptr += tot;
339 *ptr = '\0';
340 close(fd);
341
342 if (!(ptr = strstr(buf, file))) {
343 log_message("FTP/get_filesize: Bad mood, directory does not contain searched file (%s)", file);
344 if (ftp_end_data_command(sock))
345 close(sock);
346 return -1;
347 }
348
349 for (i=0; i<4; i++) {
350 while (*ptr && *ptr != ' ')
351 ptr--;
352 while (*ptr && *ptr == ' ')
353 ptr--;
354 }
355 while (*ptr && *ptr != ' ')
356 ptr--;
357
358 if (ptr)
359 size = charstar_to_int(ptr+1);
360 else
361 size = 0;
362
363 if (ftp_end_data_command(sock)) {
364 close(sock);
365 return -1;
366 }
367
368 return size;
369 }
370
371
372 int ftp_start_download(int sock, char * remotename, int * size)
373 {
374 if ((*size = ftp_get_filesize(sock, remotename)) == -1) {
375 log_message("FTP: could not get filesize (trying to continue)");
376 *size = 0;
377 }
378 return ftp_data_command(sock, "RETR", remotename);
379 }
380
381
382 int ftp_end_data_command(int sock)
383 {
384 if (ftp_check_response(sock, NULL))
385 return FTPERR_BAD_SERVER_RESPONSE;
386
387 return 0;
388 }
389
390
391 char *str_ftp_error(int error)
392 {
393 return error == FTPERR_PASSIVE_ERROR ? "error with passive connection" :
394 error == FTPERR_FAILED_CONNECT ? "couldn't connect to server" :
395 error == FTPERR_FILE_NOT_FOUND ? "file not found" :
396 error == FTPERR_BAD_SERVER_RESPONSE ? "bad server response (server too busy?)" :
397 NULL;
398 }
399
400
401 static int _http_download_file(char * hostname, char * remotename, int * size, char * proxyprotocol, char * proxyname, char * proxyport, int recursion)
402 {
403 char * buf;
404 char headers[4096];
405 char * nextChar = headers;
406 int statusCode;
407 struct in_addr serverAddress;
408 struct pollfd polls;
409 int sock;
410 int rc;
411 struct sockaddr_in destPort;
412 const char * header_content_length = "Content-Length: ";
413 const char * header_location = "Location: http://";
414 char * http_server_name;
415 int http_server_port;
416
417 if (proxyprotocol) {
418 http_server_name = proxyname;
419 http_server_port = atoi(proxyport);
420 } else {
421 http_server_name = hostname;
422 http_server_port = 80;
423 }
424
425 log_message("HTTP: connecting to server %s:%i (%s)",
426 http_server_name, http_server_port,
427 proxyprotocol ? "proxy" : "no proxy");
428
429 if ((rc = get_host_address(http_server_name, &serverAddress))) return rc;
430
431 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
432 if (sock < 0) {
433 return FTPERR_FAILED_CONNECT;
434 }
435
436 destPort.sin_family = AF_INET;
437 destPort.sin_port = htons(http_server_port);
438 destPort.sin_addr = serverAddress;
439
440 if (connect(sock, (struct sockaddr *) &destPort, sizeof(destPort))) {
441 close(sock);
442 return FTPERR_FAILED_CONNECT;
443 }
444
445 buf = proxyprotocol ? asprintf_("GET %s://%s%s HTTP/1.0\r\nHost: %s\r\n\r\n", proxyprotocol, hostname, remotename, hostname)
446 : asprintf_("GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", remotename, hostname);
447
448 write(sock, buf, strlen(buf));
449
450 /* This is fun; read the response a character at a time until we:
451
452 1) Get our first \r\n; which lets us check the return code
453 2) Get a \r\n\r\n, which means we're done */
454
455 *nextChar = '\0';
456 statusCode = 0;
457 while (!strstr(headers, "\r\n\r\n")) {
458 polls.fd = sock;
459 polls.events = POLLIN;
460 rc = poll(&polls, 1, TIMEOUT_SECS*1000);
461
462 if (rc == 0) {
463 close(sock);
464 return FTPERR_SERVER_TIMEOUT;
465 } else if (rc < 0) {
466 close(sock);
467 return FTPERR_SERVER_IO_ERROR;
468 }
469
470 if (read(sock, nextChar, 1) != 1) {
471 close(sock);
472 return FTPERR_SERVER_IO_ERROR;
473 }
474
475 nextChar++;
476 *nextChar = '\0';
477
478 if (nextChar - headers == sizeof(headers)) {
479 close(sock);
480 return FTPERR_SERVER_IO_ERROR;
481 }
482
483 if (!statusCode && strstr(headers, "\r\n")) {
484 char * start, * end;
485
486 start = headers;
487 while (!isspace(*start) && *start) start++;
488 if (!*start) {
489 close(sock);
490 return FTPERR_SERVER_IO_ERROR;
491 }
492 start++;
493
494 end = start;
495 while (!isspace(*end) && *end) end++;
496 if (!*end) {
497 close(sock);
498 return FTPERR_SERVER_IO_ERROR;
499 }
500
501 *end = '\0';
502 log_message("HTTP: server response '%s'", start);
503 if (streq(start, "404")) {
504 close(sock);
505 return FTPERR_FILE_NOT_FOUND;
506 } else if (streq(start, "302")) {
507 log_message("HTTP: found, but document has moved");
508 statusCode = 302;
509 } else if (streq(start, "200")) {
510 statusCode = 200;
511 } else {
512 close(sock);
513 return FTPERR_BAD_SERVER_RESPONSE;
514 }
515
516 *end = ' ';
517 }
518 }
519
520 if (statusCode == 302) {
521 if (recursion >= HTTP_MAX_RECURSION) {
522 log_message("HTTP: too many levels of recursion, aborting");
523 close(sock);
524 return FTPERR_UNKNOWN;
525 }
526 if ((buf = strstr(headers, header_location))) {
527 char * found_host;
528 char *found_file;
529 found_host = buf + strlen(header_location);
530 if ((found_file = index(found_host, '/'))) {
531 if ((buf = index(found_file, '\r'))) {
532 buf[0] = '\0';
533 remotename = strdup(found_file);
534 found_file[0] = '\0';
535 hostname = strdup(found_host);
536 log_message("HTTP: redirected to new host \"%s\" and file \"%s\"", hostname, remotename);
537 }
538 }
539
540 }
541 /*
542 * don't fail if new URL can't be parsed,
543 * asking the same URL may work if the DNS server are doing round-robin
544 */
545 return _http_download_file(hostname, remotename, size, proxyprotocol, proxyname, proxyport, recursion + 1);
546 }
547
548 if ((buf = strstr(headers, header_content_length)))
549 *size = charstar_to_int(buf + strlen(header_content_length));
550 else
551 *size = 0;
552
553 return sock;
554 }
555
556
557 int http_download_file(char * hostname, char * remotename, int * size, char * proxyprotocol, char * proxyname, char * proxyport)
558 {
559 return _http_download_file(hostname, remotename, size, proxyprotocol, proxyname, proxyport, 0);
560 }

Properties

Name Value
svn:eol-style native

  ViewVC Help
Powered by ViewVC 1.1.15