1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#define FOR_wget
22#include "toys.h"
23
24GLOBALS(
25 char *filename;
26)
27
28
29static unsigned get_hn(const char *url, char *hostname) {
30 unsigned i;
31
32 for (i = 0; url[i] != '\0' && url[i] != ':' && url[i] != '/'; i++) {
33 if(i >= 1024) error_exit("too long hostname in URL");
34 hostname[i] = url[i];
35 }
36 hostname[i] = '\0';
37
38 return i;
39}
40
41
42static unsigned get_port(const char *url, char *port, unsigned url_i) {
43 unsigned i;
44
45 for (i = 0; url[i] != '\0' && url[i] != '/'; i++, url_i++) {
46 if('0' <= url[i] && url[i] <= '9') port[i] = url[i];
47 else error_exit("wrong decimal port number");
48 }
49 if(i <= 6) port[i] = '\0';
50 else error_exit("too long port number");
51
52 return url_i;
53}
54
55
56static void get_info(const char *url, char* hostname, char *port, char *path) {
57 unsigned i = 7, len;
58 char ftp = !strncmp(url, "ftp://", 6);
59
60 if (ftp) i--;
61 else if (strncmp(url, "http://", i)) error_exit("only FTP/HTTP support");
62 len = get_hn(url+i, hostname);
63 i += len;
64
65
66 if (url[i] == ':') {
67 i++;
68 i = get_port(url+i, port, i);
69 } else strcpy(port, "80");
70
71
72 if (url[i] == '\0') strcpy(path, "/");
73 else if (url[i] == '/') {
74 if (strlen(url+i) < 1024) strcpy(path, url+i);
75 else error_exit("too long path in URL");
76 } else error_exit("wrong URL");
77
78 if (ftp) xexec((char *[]){"ftpget", hostname, TT.filename, path, 0});
79}
80
81
82static int conn_svr(const char *hostname, const char *port) {
83 struct addrinfo hints, *result, *rp;
84 int sock;
85
86 memset(&hints, 0, sizeof(struct addrinfo));
87 hints.ai_family = AF_UNSPEC;
88 hints.ai_socktype = SOCK_STREAM;
89 hints.ai_flags = 0;
90 hints.ai_protocol = 0;
91
92 if ((errno = getaddrinfo(hostname, port, &hints, &result)))
93 error_exit("getaddrinfo: %s", gai_strerror(errno));
94
95
96 for (rp = result; rp; rp = rp->ai_next) {
97 if ((sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol))
98 == -1) {
99 perror_msg("socket error");
100 continue;
101 }
102 if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
103 break;
104 else perror_msg("connect error");
105 close(sock);
106 }
107 freeaddrinfo(result);
108 if(!rp) error_exit("can't connect");
109
110 return sock;
111}
112
113
114static void mk_fld(char *name, char *value) {
115 strcat(toybuf, name);
116 strcat(toybuf, ": ");
117 strcat(toybuf, value);
118 strcat(toybuf, "\r\n");
119}
120
121
122static char *get_body(ssize_t len, ssize_t *body_len) {
123 int i;
124
125 for (i = 0; i < len-4; i++)
126 if (!strncmp(toybuf+i, "\r\n\r\n", 4)) break;
127
128 *body_len = len - i - 4;
129 return toybuf+i+4;
130}
131
132void wget_main(void)
133{
134 int sock;
135 FILE *fp;
136 ssize_t len, body_len;
137 char *body, *result, *rc, *r_str;
138 char ua[18] = "toybox wget", ver[6], hostname[1024], port[6], path[1024];
139
140
141 if (!(toys.optflags & FLAG_O)) help_exit("no filename");
142 if (fopen(TT.filename, "r")) error_exit("'%s' already exists", TT.filename);
143
144 if(!toys.optargs[0]) help_exit("no URL");
145 get_info(toys.optargs[0], hostname, port, path);
146
147 sock = conn_svr(hostname, port);
148
149
150 sprintf(toybuf, "GET %s HTTP/1.1\r\n", path);
151 mk_fld("Host", hostname);
152#ifdef TOYBOX_VERSION
153 strcat(ua, "/"), strncpy(ver, TOYBOX_VERSION, 5), strcat(ua, ver);
154#endif
155 mk_fld("User-Agent", ua);
156 mk_fld("Connection", "close");
157 strcat(toybuf, "\r\n");
158
159
160 len = strlen(toybuf);
161 if (write(sock, toybuf, len) != len) perror_exit("write error");
162
163
164 if ((len = read(sock, toybuf, 4096)) == -1) perror_exit("read error");
165 if (!strstr(toybuf, "\r\n\r\n")) error_exit("too long HTTP response");
166 body = get_body(len, &body_len);
167 result = strtok(toybuf, "\r");
168 strtok(result, " ");
169 rc = strtok(NULL, " ");
170 r_str = strtok(NULL, " ");
171
172
173
174 if (strcmp(rc, "200")) error_exit("res: %s(%s)", rc, r_str);
175
176 if (!(fp = fopen(TT.filename, "w"))) perror_exit("fopen error");
177 if (fwrite(body, 1, body_len, fp) != body_len)
178 error_exit("fwrite error");
179 while ((len = read(sock, toybuf, 4096)) > 0)
180 if (fwrite(toybuf, 1, len, fp) != len)
181 error_exit("fwrite error");
182 if (fclose(fp) == EOF) perror_exit("fclose error");
183}
184