Blame


1 56a48c69 2005-03-18 devnull #include <u.h>
2 56a48c69 2005-03-18 devnull #include <libc.h>
3 56a48c69 2005-03-18 devnull #include <ctype.h>
4 56a48c69 2005-03-18 devnull #include <bio.h>
5 56a48c69 2005-03-18 devnull #include <ip.h>
6 56a48c69 2005-03-18 devnull #include <libsec.h>
7 56a48c69 2005-03-18 devnull #include <auth.h>
8 56a48c69 2005-03-18 devnull #include <thread.h>
9 56a48c69 2005-03-18 devnull
10 56a48c69 2005-03-18 devnull typedef struct URL URL;
11 56a48c69 2005-03-18 devnull struct URL
12 56a48c69 2005-03-18 devnull {
13 56a48c69 2005-03-18 devnull int method;
14 56a48c69 2005-03-18 devnull char *host;
15 56a48c69 2005-03-18 devnull char *port;
16 56a48c69 2005-03-18 devnull char *page;
17 56a48c69 2005-03-18 devnull char *etag;
18 56a48c69 2005-03-18 devnull char *redirect;
19 56a48c69 2005-03-18 devnull char *postbody;
20 56a48c69 2005-03-18 devnull char *cred;
21 56a48c69 2005-03-18 devnull long mtime;
22 56a48c69 2005-03-18 devnull };
23 56a48c69 2005-03-18 devnull
24 56a48c69 2005-03-18 devnull typedef struct Range Range;
25 56a48c69 2005-03-18 devnull struct Range
26 56a48c69 2005-03-18 devnull {
27 56a48c69 2005-03-18 devnull long start; /* only 2 gig supported, tdb */
28 56a48c69 2005-03-18 devnull long end;
29 56a48c69 2005-03-18 devnull };
30 56a48c69 2005-03-18 devnull
31 56a48c69 2005-03-18 devnull typedef struct Out Out;
32 56a48c69 2005-03-18 devnull struct Out
33 56a48c69 2005-03-18 devnull {
34 56a48c69 2005-03-18 devnull int fd;
35 56a48c69 2005-03-18 devnull int offset; /* notional current offset in output */
36 56a48c69 2005-03-18 devnull int written; /* number of bytes successfully transferred to output */
37 56a48c69 2005-03-18 devnull DigestState *curr; /* digest state up to offset (if known) */
38 56a48c69 2005-03-18 devnull DigestState *hiwat; /* digest state of all bytes written */
39 56a48c69 2005-03-18 devnull };
40 56a48c69 2005-03-18 devnull
41 56a48c69 2005-03-18 devnull enum
42 56a48c69 2005-03-18 devnull {
43 56a48c69 2005-03-18 devnull Http,
44 56a48c69 2005-03-18 devnull Https,
45 56a48c69 2005-03-18 devnull Ftp,
46 56a48c69 2005-03-18 devnull Other
47 56a48c69 2005-03-18 devnull };
48 56a48c69 2005-03-18 devnull
49 56a48c69 2005-03-18 devnull enum
50 56a48c69 2005-03-18 devnull {
51 56a48c69 2005-03-18 devnull Eof = 0,
52 56a48c69 2005-03-18 devnull Error = -1,
53 56a48c69 2005-03-18 devnull Server = -2,
54 cbeb0b26 2006-04-01 devnull Changed = -3
55 56a48c69 2005-03-18 devnull };
56 56a48c69 2005-03-18 devnull
57 56a48c69 2005-03-18 devnull int debug;
58 56a48c69 2005-03-18 devnull char *ofile;
59 56a48c69 2005-03-18 devnull
60 56a48c69 2005-03-18 devnull
61 56a48c69 2005-03-18 devnull int doftp(URL*, URL*, Range*, Out*, long);
62 56a48c69 2005-03-18 devnull int dohttp(URL*, URL*, Range*, Out*, long);
63 56a48c69 2005-03-18 devnull int crackurl(URL*, char*);
64 56a48c69 2005-03-18 devnull Range* crackrange(char*);
65 56a48c69 2005-03-18 devnull int getheader(int, char*, int);
66 56a48c69 2005-03-18 devnull int httpheaders(int, int, URL*, Range*);
67 56a48c69 2005-03-18 devnull int httprcode(int);
68 56a48c69 2005-03-18 devnull int cistrncmp(char*, char*, int);
69 56a48c69 2005-03-18 devnull int cistrcmp(char*, char*);
70 56a48c69 2005-03-18 devnull void initibuf(void);
71 56a48c69 2005-03-18 devnull int readline(int, char*, int);
72 56a48c69 2005-03-18 devnull int readibuf(int, char*, int);
73 56a48c69 2005-03-18 devnull int dfprint(int, char*, ...);
74 56a48c69 2005-03-18 devnull void unreadline(char*);
75 56a48c69 2005-03-18 devnull int output(Out*, char*, int);
76 56a48c69 2005-03-18 devnull void setoffset(Out*, int);
77 56a48c69 2005-03-18 devnull
78 56a48c69 2005-03-18 devnull int verbose;
79 56a48c69 2005-03-18 devnull char *net;
80 56a48c69 2005-03-18 devnull char tcpdir[NETPATHLEN];
81 56a48c69 2005-03-18 devnull int headerprint;
82 56a48c69 2005-03-18 devnull
83 56a48c69 2005-03-18 devnull struct {
84 56a48c69 2005-03-18 devnull char *name;
85 56a48c69 2005-03-18 devnull int (*f)(URL*, URL*, Range*, Out*, long);
86 56a48c69 2005-03-18 devnull } method[] = {
87 d82651b8 2005-07-13 devnull { "http", dohttp },
88 d82651b8 2005-07-13 devnull { "https", dohttp },
89 d82651b8 2005-07-13 devnull { "ftp", doftp },
90 d82651b8 2005-07-13 devnull { "_______", nil },
91 56a48c69 2005-03-18 devnull };
92 56a48c69 2005-03-18 devnull
93 56a48c69 2005-03-18 devnull void
94 56a48c69 2005-03-18 devnull usage(void)
95 56a48c69 2005-03-18 devnull {
96 56a48c69 2005-03-18 devnull fprint(2, "usage: %s [-hv] [-o outfile] [-p body] [-x netmtpt] url\n", argv0);
97 56a48c69 2005-03-18 devnull threadexitsall("usage");
98 56a48c69 2005-03-18 devnull }
99 56a48c69 2005-03-18 devnull
100 56a48c69 2005-03-18 devnull void
101 56a48c69 2005-03-18 devnull threadmain(int argc, char **argv)
102 56a48c69 2005-03-18 devnull {
103 56a48c69 2005-03-18 devnull URL u;
104 56a48c69 2005-03-18 devnull Range r;
105 56a48c69 2005-03-18 devnull int errs, n;
106 56a48c69 2005-03-18 devnull ulong mtime;
107 56a48c69 2005-03-18 devnull Dir *d;
108 56a48c69 2005-03-18 devnull char postbody[4096], *p, *e, *t, *hpx;
109 cbeb0b26 2006-04-01 devnull URL px; /* Proxy */
110 56a48c69 2005-03-18 devnull Out out;
111 56a48c69 2005-03-18 devnull
112 56a48c69 2005-03-18 devnull ofile = nil;
113 56a48c69 2005-03-18 devnull p = postbody;
114 56a48c69 2005-03-18 devnull e = p + sizeof(postbody);
115 56a48c69 2005-03-18 devnull r.start = 0;
116 56a48c69 2005-03-18 devnull r.end = -1;
117 56a48c69 2005-03-18 devnull mtime = 0;
118 56a48c69 2005-03-18 devnull memset(&u, 0, sizeof(u));
119 56a48c69 2005-03-18 devnull memset(&px, 0, sizeof(px));
120 56a48c69 2005-03-18 devnull hpx = getenv("httpproxy");
121 56a48c69 2005-03-18 devnull
122 56a48c69 2005-03-18 devnull ARGBEGIN {
123 56a48c69 2005-03-18 devnull case 'o':
124 56a48c69 2005-03-18 devnull ofile = ARGF();
125 56a48c69 2005-03-18 devnull break;
126 56a48c69 2005-03-18 devnull case 'd':
127 56a48c69 2005-03-18 devnull debug = 1;
128 56a48c69 2005-03-18 devnull break;
129 56a48c69 2005-03-18 devnull case 'h':
130 56a48c69 2005-03-18 devnull headerprint = 1;
131 56a48c69 2005-03-18 devnull break;
132 56a48c69 2005-03-18 devnull case 'v':
133 56a48c69 2005-03-18 devnull verbose = 1;
134 56a48c69 2005-03-18 devnull break;
135 56a48c69 2005-03-18 devnull case 'x':
136 56a48c69 2005-03-18 devnull net = ARGF();
137 56a48c69 2005-03-18 devnull if(net == nil)
138 56a48c69 2005-03-18 devnull usage();
139 56a48c69 2005-03-18 devnull break;
140 56a48c69 2005-03-18 devnull case 'p':
141 56a48c69 2005-03-18 devnull t = ARGF();
142 56a48c69 2005-03-18 devnull if(t == nil)
143 56a48c69 2005-03-18 devnull usage();
144 56a48c69 2005-03-18 devnull if(p != postbody)
145 56a48c69 2005-03-18 devnull p = seprint(p, e, "&%s", t);
146 56a48c69 2005-03-18 devnull else
147 56a48c69 2005-03-18 devnull p = seprint(p, e, "%s", t);
148 56a48c69 2005-03-18 devnull u.postbody = postbody;
149 fa325e9b 2020-01-10 cross
150 56a48c69 2005-03-18 devnull break;
151 56a48c69 2005-03-18 devnull default:
152 56a48c69 2005-03-18 devnull usage();
153 56a48c69 2005-03-18 devnull } ARGEND;
154 56a48c69 2005-03-18 devnull
155 56a48c69 2005-03-18 devnull if(net != nil){
156 56a48c69 2005-03-18 devnull if(strlen(net) > sizeof(tcpdir)-5)
157 56a48c69 2005-03-18 devnull sysfatal("network mount point too long");
158 56a48c69 2005-03-18 devnull snprint(tcpdir, sizeof(tcpdir), "%s/tcp", net);
159 56a48c69 2005-03-18 devnull } else
160 56a48c69 2005-03-18 devnull snprint(tcpdir, sizeof(tcpdir), "tcp");
161 56a48c69 2005-03-18 devnull
162 56a48c69 2005-03-18 devnull if(argc != 1)
163 56a48c69 2005-03-18 devnull usage();
164 56a48c69 2005-03-18 devnull
165 fa325e9b 2020-01-10 cross
166 56a48c69 2005-03-18 devnull out.fd = 1;
167 56a48c69 2005-03-18 devnull out.written = 0;
168 56a48c69 2005-03-18 devnull out.offset = 0;
169 56a48c69 2005-03-18 devnull out.curr = nil;
170 56a48c69 2005-03-18 devnull out.hiwat = nil;
171 56a48c69 2005-03-18 devnull if(ofile != nil){
172 56a48c69 2005-03-18 devnull d = dirstat(ofile);
173 56a48c69 2005-03-18 devnull if(d == nil){
174 56a48c69 2005-03-18 devnull out.fd = create(ofile, OWRITE, 0664);
175 56a48c69 2005-03-18 devnull if(out.fd < 0)
176 56a48c69 2005-03-18 devnull sysfatal("creating %s: %r", ofile);
177 56a48c69 2005-03-18 devnull } else {
178 56a48c69 2005-03-18 devnull out.fd = open(ofile, OWRITE);
179 56a48c69 2005-03-18 devnull if(out.fd < 0)
180 56a48c69 2005-03-18 devnull sysfatal("can't open %s: %r", ofile);
181 56a48c69 2005-03-18 devnull r.start = d->length;
182 56a48c69 2005-03-18 devnull mtime = d->mtime;
183 56a48c69 2005-03-18 devnull free(d);
184 56a48c69 2005-03-18 devnull }
185 56a48c69 2005-03-18 devnull }
186 56a48c69 2005-03-18 devnull
187 56a48c69 2005-03-18 devnull errs = 0;
188 56a48c69 2005-03-18 devnull
189 56a48c69 2005-03-18 devnull if(crackurl(&u, argv[0]) < 0)
190 56a48c69 2005-03-18 devnull sysfatal("%r");
191 56a48c69 2005-03-18 devnull if(hpx && crackurl(&px, hpx) < 0)
192 56a48c69 2005-03-18 devnull sysfatal("%r");
193 56a48c69 2005-03-18 devnull
194 56a48c69 2005-03-18 devnull for(;;){
195 56a48c69 2005-03-18 devnull setoffset(&out, 0);
196 56a48c69 2005-03-18 devnull /* transfer data */
197 56a48c69 2005-03-18 devnull werrstr("");
198 56a48c69 2005-03-18 devnull n = (*method[u.method].f)(&u, &px, &r, &out, mtime);
199 56a48c69 2005-03-18 devnull
200 56a48c69 2005-03-18 devnull switch(n){
201 56a48c69 2005-03-18 devnull case Eof:
202 56a48c69 2005-03-18 devnull threadexitsall(0);
203 56a48c69 2005-03-18 devnull break;
204 56a48c69 2005-03-18 devnull case Error:
205 56a48c69 2005-03-18 devnull if(errs++ < 10)
206 56a48c69 2005-03-18 devnull continue;
207 56a48c69 2005-03-18 devnull sysfatal("too many errors with no progress %r");
208 56a48c69 2005-03-18 devnull break;
209 56a48c69 2005-03-18 devnull case Server:
210 56a48c69 2005-03-18 devnull sysfatal("server returned: %r");
211 56a48c69 2005-03-18 devnull break;
212 56a48c69 2005-03-18 devnull }
213 56a48c69 2005-03-18 devnull
214 56a48c69 2005-03-18 devnull /* forward progress */
215 56a48c69 2005-03-18 devnull errs = 0;
216 56a48c69 2005-03-18 devnull r.start += n;
217 56a48c69 2005-03-18 devnull if(r.start >= r.end)
218 56a48c69 2005-03-18 devnull break;
219 56a48c69 2005-03-18 devnull }
220 56a48c69 2005-03-18 devnull
221 56a48c69 2005-03-18 devnull threadexitsall(0);
222 56a48c69 2005-03-18 devnull }
223 56a48c69 2005-03-18 devnull
224 56a48c69 2005-03-18 devnull int
225 56a48c69 2005-03-18 devnull crackurl(URL *u, char *s)
226 56a48c69 2005-03-18 devnull {
227 56a48c69 2005-03-18 devnull char *p;
228 56a48c69 2005-03-18 devnull int i;
229 56a48c69 2005-03-18 devnull
230 56a48c69 2005-03-18 devnull if(u->host != nil){
231 56a48c69 2005-03-18 devnull free(u->host);
232 56a48c69 2005-03-18 devnull u->host = nil;
233 56a48c69 2005-03-18 devnull }
234 56a48c69 2005-03-18 devnull if(u->page != nil){
235 56a48c69 2005-03-18 devnull free(u->page);
236 56a48c69 2005-03-18 devnull u->page = nil;
237 56a48c69 2005-03-18 devnull }
238 56a48c69 2005-03-18 devnull
239 56a48c69 2005-03-18 devnull /* get type */
240 56a48c69 2005-03-18 devnull u->method = Other;
241 56a48c69 2005-03-18 devnull for(p = s; *p; p++){
242 56a48c69 2005-03-18 devnull if(*p == '/'){
243 56a48c69 2005-03-18 devnull u->method = Http;
244 56a48c69 2005-03-18 devnull p = s;
245 56a48c69 2005-03-18 devnull break;
246 56a48c69 2005-03-18 devnull }
247 56a48c69 2005-03-18 devnull if(*p == ':' && *(p+1)=='/' && *(p+2)=='/'){
248 56a48c69 2005-03-18 devnull *p = 0;
249 56a48c69 2005-03-18 devnull p += 3;
250 56a48c69 2005-03-18 devnull for(i = 0; i < nelem(method); i++){
251 56a48c69 2005-03-18 devnull if(cistrcmp(s, method[i].name) == 0){
252 56a48c69 2005-03-18 devnull u->method = i;
253 56a48c69 2005-03-18 devnull break;
254 56a48c69 2005-03-18 devnull }
255 56a48c69 2005-03-18 devnull }
256 56a48c69 2005-03-18 devnull break;
257 56a48c69 2005-03-18 devnull }
258 56a48c69 2005-03-18 devnull }
259 56a48c69 2005-03-18 devnull
260 56a48c69 2005-03-18 devnull if(u->method == Other){
261 56a48c69 2005-03-18 devnull werrstr("unsupported URL type %s", s);
262 56a48c69 2005-03-18 devnull return -1;
263 56a48c69 2005-03-18 devnull }
264 56a48c69 2005-03-18 devnull
265 56a48c69 2005-03-18 devnull /* get system */
266 56a48c69 2005-03-18 devnull s = p;
267 56a48c69 2005-03-18 devnull p = strchr(s, '/');
268 56a48c69 2005-03-18 devnull if(p == nil){
269 56a48c69 2005-03-18 devnull u->host = strdup(s);
270 56a48c69 2005-03-18 devnull u->page = strdup("/");
271 56a48c69 2005-03-18 devnull } else {
272 56a48c69 2005-03-18 devnull u->page = strdup(p);
273 56a48c69 2005-03-18 devnull *p = 0;
274 56a48c69 2005-03-18 devnull u->host = strdup(s);
275 56a48c69 2005-03-18 devnull *p = '/';
276 56a48c69 2005-03-18 devnull }
277 56a48c69 2005-03-18 devnull
278 56a48c69 2005-03-18 devnull if(p = strchr(u->host, ':')) {
279 56a48c69 2005-03-18 devnull *p++ = 0;
280 56a48c69 2005-03-18 devnull u->port = p;
281 fa325e9b 2020-01-10 cross } else
282 56a48c69 2005-03-18 devnull u->port = method[u->method].name;
283 56a48c69 2005-03-18 devnull
284 56a48c69 2005-03-18 devnull if(*(u->host) == 0){
285 56a48c69 2005-03-18 devnull werrstr("bad url, null host");
286 56a48c69 2005-03-18 devnull return -1;
287 56a48c69 2005-03-18 devnull }
288 56a48c69 2005-03-18 devnull
289 56a48c69 2005-03-18 devnull return 0;
290 56a48c69 2005-03-18 devnull }
291 56a48c69 2005-03-18 devnull
292 56a48c69 2005-03-18 devnull char *day[] = {
293 56a48c69 2005-03-18 devnull "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
294 56a48c69 2005-03-18 devnull };
295 56a48c69 2005-03-18 devnull
296 56a48c69 2005-03-18 devnull char *month[] = {
297 56a48c69 2005-03-18 devnull "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
298 56a48c69 2005-03-18 devnull };
299 56a48c69 2005-03-18 devnull
300 56a48c69 2005-03-18 devnull struct
301 56a48c69 2005-03-18 devnull {
302 56a48c69 2005-03-18 devnull int fd;
303 56a48c69 2005-03-18 devnull long mtime;
304 56a48c69 2005-03-18 devnull } note;
305 56a48c69 2005-03-18 devnull
306 56a48c69 2005-03-18 devnull void
307 56a48c69 2005-03-18 devnull catch(void *v, char *s)
308 56a48c69 2005-03-18 devnull {
309 56a48c69 2005-03-18 devnull Dir d;
310 56a48c69 2005-03-18 devnull
311 56a48c69 2005-03-18 devnull USED(v);
312 56a48c69 2005-03-18 devnull USED(s);
313 56a48c69 2005-03-18 devnull
314 56a48c69 2005-03-18 devnull nulldir(&d);
315 56a48c69 2005-03-18 devnull d.mtime = note.mtime;
316 56a48c69 2005-03-18 devnull if(dirfwstat(note.fd, &d) < 0)
317 56a48c69 2005-03-18 devnull sysfatal("catch: can't dirfwstat: %r");
318 56a48c69 2005-03-18 devnull noted(NDFLT);
319 56a48c69 2005-03-18 devnull }
320 56a48c69 2005-03-18 devnull
321 56a48c69 2005-03-18 devnull int
322 56a48c69 2005-03-18 devnull dohttp(URL *u, URL *px, Range *r, Out *out, long mtime)
323 56a48c69 2005-03-18 devnull {
324 56a48c69 2005-03-18 devnull int fd, cfd;
325 56a48c69 2005-03-18 devnull int redirect, auth, loop;
326 56a48c69 2005-03-18 devnull int n, rv, code;
327 56a48c69 2005-03-18 devnull long tot, vtime;
328 56a48c69 2005-03-18 devnull Tm *tm;
329 56a48c69 2005-03-18 devnull char buf[1024];
330 56a48c69 2005-03-18 devnull char err[ERRMAX];
331 56a48c69 2005-03-18 devnull
332 56a48c69 2005-03-18 devnull
333 56a48c69 2005-03-18 devnull /* always move back to a previous 512 byte bound because some
334 56a48c69 2005-03-18 devnull * servers can't seem to deal with requests that start at the
335 56a48c69 2005-03-18 devnull * end of the file
336 56a48c69 2005-03-18 devnull */
337 56a48c69 2005-03-18 devnull if(r->start)
338 56a48c69 2005-03-18 devnull r->start = ((r->start-1)/512)*512;
339 56a48c69 2005-03-18 devnull
340 56a48c69 2005-03-18 devnull /* loop for redirects, requires reading both response code and headers */
341 56a48c69 2005-03-18 devnull fd = -1;
342 56a48c69 2005-03-18 devnull for(loop = 0; loop < 32; loop++){
343 56a48c69 2005-03-18 devnull if(px->host == nil){
344 56a48c69 2005-03-18 devnull fd = dial(netmkaddr(u->host, tcpdir, u->port), 0, 0, 0);
345 56a48c69 2005-03-18 devnull } else {
346 56a48c69 2005-03-18 devnull fd = dial(netmkaddr(px->host, tcpdir, px->port), 0, 0, 0);
347 56a48c69 2005-03-18 devnull }
348 56a48c69 2005-03-18 devnull if(fd < 0)
349 56a48c69 2005-03-18 devnull return Error;
350 56a48c69 2005-03-18 devnull
351 56a48c69 2005-03-18 devnull if(u->method == Https){
352 56a48c69 2005-03-18 devnull int tfd;
353 56a48c69 2005-03-18 devnull TLSconn conn;
354 56a48c69 2005-03-18 devnull
355 56a48c69 2005-03-18 devnull memset(&conn, 0, sizeof conn);
356 56a48c69 2005-03-18 devnull tfd = tlsClient(fd, &conn);
357 56a48c69 2005-03-18 devnull if(tfd < 0){
358 56a48c69 2005-03-18 devnull fprint(2, "tlsClient: %r\n");
359 56a48c69 2005-03-18 devnull close(fd);
360 56a48c69 2005-03-18 devnull return Error;
361 56a48c69 2005-03-18 devnull }
362 56a48c69 2005-03-18 devnull /* BUG: check cert here? */
363 56a48c69 2005-03-18 devnull if(conn.cert)
364 56a48c69 2005-03-18 devnull free(conn.cert);
365 56a48c69 2005-03-18 devnull close(fd);
366 56a48c69 2005-03-18 devnull fd = tfd;
367 56a48c69 2005-03-18 devnull }
368 56a48c69 2005-03-18 devnull
369 56a48c69 2005-03-18 devnull /* write request, use range if not start of file */
370 56a48c69 2005-03-18 devnull if(u->postbody == nil){
371 56a48c69 2005-03-18 devnull if(px->host == nil){
372 56a48c69 2005-03-18 devnull dfprint(fd, "GET %s HTTP/1.0\r\n"
373 56a48c69 2005-03-18 devnull "Host: %s\r\n"
374 56a48c69 2005-03-18 devnull "User-agent: Plan9/hget\r\n"
375 56a48c69 2005-03-18 devnull "Cache-Control: no-cache\r\n"
376 56a48c69 2005-03-18 devnull "Pragma: no-cache\r\n",
377 56a48c69 2005-03-18 devnull u->page, u->host);
378 56a48c69 2005-03-18 devnull } else {
379 56a48c69 2005-03-18 devnull dfprint(fd, "GET http://%s%s HTTP/1.0\r\n"
380 56a48c69 2005-03-18 devnull "Host: %s\r\n"
381 56a48c69 2005-03-18 devnull "User-agent: Plan9/hget\r\n"
382 56a48c69 2005-03-18 devnull "Cache-Control: no-cache\r\n"
383 56a48c69 2005-03-18 devnull "Pragma: no-cache\r\n",
384 56a48c69 2005-03-18 devnull u->host, u->page, u->host);
385 56a48c69 2005-03-18 devnull }
386 56a48c69 2005-03-18 devnull if(u->cred)
387 56a48c69 2005-03-18 devnull dfprint(fd, "Authorization: Basic %s\r\n",
388 56a48c69 2005-03-18 devnull u->cred);
389 56a48c69 2005-03-18 devnull } else {
390 598020ec 2010-06-28 rsc if(px->host == nil){
391 598020ec 2010-06-28 rsc dfprint(fd, "POST %s HTTP/1.0\r\n"
392 598020ec 2010-06-28 rsc "Host: %s\r\n"
393 598020ec 2010-06-28 rsc "Content-type: application/x-www-form-urlencoded\r\n"
394 598020ec 2010-06-28 rsc "Content-length: %d\r\n"
395 598020ec 2010-06-28 rsc "User-agent: Plan9/hget\r\n"
396 598020ec 2010-06-28 rsc "\r\n",
397 598020ec 2010-06-28 rsc u->page, u->host, strlen(u->postbody));
398 598020ec 2010-06-28 rsc } else {
399 598020ec 2010-06-28 rsc dfprint(fd, "POST http://%s%s HTTP/1.0\r\n"
400 598020ec 2010-06-28 rsc "Host: %s\r\n"
401 598020ec 2010-06-28 rsc "Content-type: application/x-www-form-urlencoded\r\n"
402 598020ec 2010-06-28 rsc "Content-length: %d\r\n"
403 598020ec 2010-06-28 rsc "User-agent: Plan9/hget\r\n"
404 598020ec 2010-06-28 rsc "\r\n",
405 598020ec 2010-06-28 rsc u->host, u->page, u->host, strlen(u->postbody));
406 598020ec 2010-06-28 rsc }
407 56a48c69 2005-03-18 devnull dfprint(fd, "%s", u->postbody);
408 56a48c69 2005-03-18 devnull }
409 56a48c69 2005-03-18 devnull if(r->start != 0){
410 56a48c69 2005-03-18 devnull dfprint(fd, "Range: bytes=%d-\n", r->start);
411 56a48c69 2005-03-18 devnull if(u->etag != nil){
412 56a48c69 2005-03-18 devnull dfprint(fd, "If-range: %s\n", u->etag);
413 56a48c69 2005-03-18 devnull } else {
414 56a48c69 2005-03-18 devnull tm = gmtime(mtime);
415 56a48c69 2005-03-18 devnull dfprint(fd, "If-range: %s, %d %s %d %2d:%2.2d:%2.2d GMT\n",
416 56a48c69 2005-03-18 devnull day[tm->wday], tm->mday, month[tm->mon],
417 56a48c69 2005-03-18 devnull tm->year+1900, tm->hour, tm->min, tm->sec);
418 56a48c69 2005-03-18 devnull }
419 56a48c69 2005-03-18 devnull }
420 56a48c69 2005-03-18 devnull if((cfd = open("/mnt/webcookies/http", ORDWR)) >= 0){
421 56a48c69 2005-03-18 devnull if(fprint(cfd, "http://%s%s", u->host, u->page) > 0){
422 56a48c69 2005-03-18 devnull while((n = read(cfd, buf, sizeof buf)) > 0){
423 56a48c69 2005-03-18 devnull if(debug)
424 56a48c69 2005-03-18 devnull write(2, buf, n);
425 56a48c69 2005-03-18 devnull write(fd, buf, n);
426 56a48c69 2005-03-18 devnull }
427 56a48c69 2005-03-18 devnull }else{
428 56a48c69 2005-03-18 devnull close(cfd);
429 56a48c69 2005-03-18 devnull cfd = -1;
430 56a48c69 2005-03-18 devnull }
431 56a48c69 2005-03-18 devnull }
432 fa325e9b 2020-01-10 cross
433 56a48c69 2005-03-18 devnull dfprint(fd, "\r\n", u->host);
434 56a48c69 2005-03-18 devnull
435 56a48c69 2005-03-18 devnull auth = 0;
436 56a48c69 2005-03-18 devnull redirect = 0;
437 56a48c69 2005-03-18 devnull initibuf();
438 56a48c69 2005-03-18 devnull code = httprcode(fd);
439 56a48c69 2005-03-18 devnull switch(code){
440 56a48c69 2005-03-18 devnull case Error: /* connection timed out */
441 56a48c69 2005-03-18 devnull case Eof:
442 56a48c69 2005-03-18 devnull close(fd);
443 56a48c69 2005-03-18 devnull close(cfd);
444 56a48c69 2005-03-18 devnull return code;
445 56a48c69 2005-03-18 devnull
446 56a48c69 2005-03-18 devnull case 200: /* OK */
447 56a48c69 2005-03-18 devnull case 201: /* Created */
448 56a48c69 2005-03-18 devnull case 202: /* Accepted */
449 56a48c69 2005-03-18 devnull if(ofile == nil && r->start != 0)
450 56a48c69 2005-03-18 devnull sysfatal("page changed underfoot");
451 56a48c69 2005-03-18 devnull break;
452 56a48c69 2005-03-18 devnull
453 56a48c69 2005-03-18 devnull case 204: /* No Content */
454 56a48c69 2005-03-18 devnull sysfatal("No Content");
455 56a48c69 2005-03-18 devnull
456 56a48c69 2005-03-18 devnull case 206: /* Partial Content */
457 56a48c69 2005-03-18 devnull setoffset(out, r->start);
458 56a48c69 2005-03-18 devnull break;
459 56a48c69 2005-03-18 devnull
460 56a48c69 2005-03-18 devnull case 301: /* Moved Permanently */
461 56a48c69 2005-03-18 devnull case 302: /* Moved Temporarily */
462 56a48c69 2005-03-18 devnull redirect = 1;
463 56a48c69 2005-03-18 devnull u->postbody = nil;
464 56a48c69 2005-03-18 devnull break;
465 56a48c69 2005-03-18 devnull
466 56a48c69 2005-03-18 devnull case 304: /* Not Modified */
467 56a48c69 2005-03-18 devnull break;
468 56a48c69 2005-03-18 devnull
469 56a48c69 2005-03-18 devnull case 400: /* Bad Request */
470 56a48c69 2005-03-18 devnull sysfatal("Bad Request");
471 56a48c69 2005-03-18 devnull
472 56a48c69 2005-03-18 devnull case 401: /* Unauthorized */
473 56a48c69 2005-03-18 devnull if (auth)
474 56a48c69 2005-03-18 devnull sysfatal("Authentication failed");
475 56a48c69 2005-03-18 devnull auth = 1;
476 56a48c69 2005-03-18 devnull break;
477 56a48c69 2005-03-18 devnull
478 56a48c69 2005-03-18 devnull case 402: /* ??? */
479 56a48c69 2005-03-18 devnull sysfatal("Unauthorized");
480 56a48c69 2005-03-18 devnull
481 56a48c69 2005-03-18 devnull case 403: /* Forbidden */
482 56a48c69 2005-03-18 devnull sysfatal("Forbidden by server");
483 56a48c69 2005-03-18 devnull
484 56a48c69 2005-03-18 devnull case 404: /* Not Found */
485 56a48c69 2005-03-18 devnull sysfatal("Not found on server");
486 56a48c69 2005-03-18 devnull
487 56a48c69 2005-03-18 devnull case 407: /* Proxy Authentication */
488 56a48c69 2005-03-18 devnull sysfatal("Proxy authentication required");
489 56a48c69 2005-03-18 devnull
490 56a48c69 2005-03-18 devnull case 500: /* Internal server error */
491 56a48c69 2005-03-18 devnull sysfatal("Server choked");
492 56a48c69 2005-03-18 devnull
493 56a48c69 2005-03-18 devnull case 501: /* Not implemented */
494 56a48c69 2005-03-18 devnull sysfatal("Server can't do it!");
495 56a48c69 2005-03-18 devnull
496 56a48c69 2005-03-18 devnull case 502: /* Bad gateway */
497 56a48c69 2005-03-18 devnull sysfatal("Bad gateway");
498 56a48c69 2005-03-18 devnull
499 56a48c69 2005-03-18 devnull case 503: /* Service unavailable */
500 56a48c69 2005-03-18 devnull sysfatal("Service unavailable");
501 fa325e9b 2020-01-10 cross
502 56a48c69 2005-03-18 devnull default:
503 56a48c69 2005-03-18 devnull sysfatal("Unknown response code %d", code);
504 56a48c69 2005-03-18 devnull }
505 56a48c69 2005-03-18 devnull
506 56a48c69 2005-03-18 devnull if(u->redirect != nil){
507 56a48c69 2005-03-18 devnull free(u->redirect);
508 56a48c69 2005-03-18 devnull u->redirect = nil;
509 56a48c69 2005-03-18 devnull }
510 56a48c69 2005-03-18 devnull
511 56a48c69 2005-03-18 devnull rv = httpheaders(fd, cfd, u, r);
512 56a48c69 2005-03-18 devnull close(cfd);
513 56a48c69 2005-03-18 devnull if(rv != 0){
514 56a48c69 2005-03-18 devnull close(fd);
515 56a48c69 2005-03-18 devnull return rv;
516 56a48c69 2005-03-18 devnull }
517 56a48c69 2005-03-18 devnull
518 56a48c69 2005-03-18 devnull if(!redirect && !auth)
519 56a48c69 2005-03-18 devnull break;
520 56a48c69 2005-03-18 devnull
521 56a48c69 2005-03-18 devnull if (redirect){
522 56a48c69 2005-03-18 devnull if(u->redirect == nil)
523 56a48c69 2005-03-18 devnull sysfatal("redirect: no URL");
524 56a48c69 2005-03-18 devnull if(crackurl(u, u->redirect) < 0)
525 56a48c69 2005-03-18 devnull sysfatal("redirect: %r");
526 56a48c69 2005-03-18 devnull }
527 56a48c69 2005-03-18 devnull }
528 56a48c69 2005-03-18 devnull
529 56a48c69 2005-03-18 devnull /* transfer whatever you get */
530 56a48c69 2005-03-18 devnull if(ofile != nil && u->mtime != 0){
531 56a48c69 2005-03-18 devnull note.fd = out->fd;
532 56a48c69 2005-03-18 devnull note.mtime = u->mtime;
533 56a48c69 2005-03-18 devnull notify(catch);
534 56a48c69 2005-03-18 devnull }
535 56a48c69 2005-03-18 devnull
536 56a48c69 2005-03-18 devnull tot = 0;
537 56a48c69 2005-03-18 devnull vtime = 0;
538 56a48c69 2005-03-18 devnull for(;;){
539 56a48c69 2005-03-18 devnull n = readibuf(fd, buf, sizeof(buf));
540 56a48c69 2005-03-18 devnull if(n <= 0)
541 56a48c69 2005-03-18 devnull break;
542 56a48c69 2005-03-18 devnull if(output(out, buf, n) != n)
543 56a48c69 2005-03-18 devnull break;
544 56a48c69 2005-03-18 devnull tot += n;
545 1866bcc9 2006-10-12 devnull if(verbose && (vtime != time(0) || r->start == r->end)) {
546 56a48c69 2005-03-18 devnull vtime = time(0);
547 56a48c69 2005-03-18 devnull fprint(2, "%ld %ld\n", r->start+tot, r->end);
548 56a48c69 2005-03-18 devnull }
549 56a48c69 2005-03-18 devnull }
550 56a48c69 2005-03-18 devnull notify(nil);
551 56a48c69 2005-03-18 devnull close(fd);
552 56a48c69 2005-03-18 devnull
553 56a48c69 2005-03-18 devnull if(ofile != nil && u->mtime != 0){
554 56a48c69 2005-03-18 devnull Dir d;
555 56a48c69 2005-03-18 devnull
556 56a48c69 2005-03-18 devnull rerrstr(err, sizeof err);
557 56a48c69 2005-03-18 devnull nulldir(&d);
558 56a48c69 2005-03-18 devnull d.mtime = u->mtime;
559 56a48c69 2005-03-18 devnull if(dirfwstat(out->fd, &d) < 0)
560 56a48c69 2005-03-18 devnull fprint(2, "couldn't set mtime: %r\n");
561 56a48c69 2005-03-18 devnull errstr(err, sizeof err);
562 56a48c69 2005-03-18 devnull }
563 56a48c69 2005-03-18 devnull
564 56a48c69 2005-03-18 devnull return tot;
565 56a48c69 2005-03-18 devnull }
566 56a48c69 2005-03-18 devnull
567 56a48c69 2005-03-18 devnull /* get the http response code */
568 56a48c69 2005-03-18 devnull int
569 56a48c69 2005-03-18 devnull httprcode(int fd)
570 56a48c69 2005-03-18 devnull {
571 56a48c69 2005-03-18 devnull int n;
572 56a48c69 2005-03-18 devnull char *p;
573 56a48c69 2005-03-18 devnull char buf[256];
574 56a48c69 2005-03-18 devnull
575 56a48c69 2005-03-18 devnull n = readline(fd, buf, sizeof(buf)-1);
576 56a48c69 2005-03-18 devnull if(n <= 0)
577 56a48c69 2005-03-18 devnull return n;
578 56a48c69 2005-03-18 devnull if(debug)
579 56a48c69 2005-03-18 devnull fprint(2, "%d <- %s\n", fd, buf);
580 56a48c69 2005-03-18 devnull p = strchr(buf, ' ');
581 56a48c69 2005-03-18 devnull if(strncmp(buf, "HTTP/", 5) != 0 || p == nil){
582 56a48c69 2005-03-18 devnull werrstr("bad response from server");
583 56a48c69 2005-03-18 devnull return -1;
584 56a48c69 2005-03-18 devnull }
585 56a48c69 2005-03-18 devnull buf[n] = 0;
586 56a48c69 2005-03-18 devnull return atoi(p+1);
587 56a48c69 2005-03-18 devnull }
588 56a48c69 2005-03-18 devnull
589 56a48c69 2005-03-18 devnull /* read in and crack the http headers, update u and r */
590 56a48c69 2005-03-18 devnull void hhetag(char*, URL*, Range*);
591 56a48c69 2005-03-18 devnull void hhmtime(char*, URL*, Range*);
592 56a48c69 2005-03-18 devnull void hhclen(char*, URL*, Range*);
593 56a48c69 2005-03-18 devnull void hhcrange(char*, URL*, Range*);
594 56a48c69 2005-03-18 devnull void hhuri(char*, URL*, Range*);
595 56a48c69 2005-03-18 devnull void hhlocation(char*, URL*, Range*);
596 56a48c69 2005-03-18 devnull void hhauth(char*, URL*, Range*);
597 56a48c69 2005-03-18 devnull
598 56a48c69 2005-03-18 devnull struct {
599 56a48c69 2005-03-18 devnull char *name;
600 56a48c69 2005-03-18 devnull void (*f)(char*, URL*, Range*);
601 56a48c69 2005-03-18 devnull } headers[] = {
602 56a48c69 2005-03-18 devnull { "etag:", hhetag },
603 56a48c69 2005-03-18 devnull { "last-modified:", hhmtime },
604 56a48c69 2005-03-18 devnull { "content-length:", hhclen },
605 56a48c69 2005-03-18 devnull { "content-range:", hhcrange },
606 56a48c69 2005-03-18 devnull { "uri:", hhuri },
607 56a48c69 2005-03-18 devnull { "location:", hhlocation },
608 56a48c69 2005-03-18 devnull { "WWW-Authenticate:", hhauth },
609 56a48c69 2005-03-18 devnull };
610 56a48c69 2005-03-18 devnull int
611 56a48c69 2005-03-18 devnull httpheaders(int fd, int cfd, URL *u, Range *r)
612 56a48c69 2005-03-18 devnull {
613 56a48c69 2005-03-18 devnull char buf[2048];
614 56a48c69 2005-03-18 devnull char *p;
615 56a48c69 2005-03-18 devnull int i, n;
616 56a48c69 2005-03-18 devnull
617 56a48c69 2005-03-18 devnull for(;;){
618 56a48c69 2005-03-18 devnull n = getheader(fd, buf, sizeof(buf));
619 56a48c69 2005-03-18 devnull if(n <= 0)
620 56a48c69 2005-03-18 devnull break;
621 56a48c69 2005-03-18 devnull if(cfd >= 0)
622 56a48c69 2005-03-18 devnull fprint(cfd, "%s\n", buf);
623 56a48c69 2005-03-18 devnull for(i = 0; i < nelem(headers); i++){
624 56a48c69 2005-03-18 devnull n = strlen(headers[i].name);
625 56a48c69 2005-03-18 devnull if(cistrncmp(buf, headers[i].name, n) == 0){
626 56a48c69 2005-03-18 devnull /* skip field name and leading white */
627 56a48c69 2005-03-18 devnull p = buf + n;
628 56a48c69 2005-03-18 devnull while(*p == ' ' || *p == '\t')
629 56a48c69 2005-03-18 devnull p++;
630 56a48c69 2005-03-18 devnull
631 56a48c69 2005-03-18 devnull (*headers[i].f)(p, u, r);
632 56a48c69 2005-03-18 devnull break;
633 56a48c69 2005-03-18 devnull }
634 56a48c69 2005-03-18 devnull }
635 56a48c69 2005-03-18 devnull }
636 56a48c69 2005-03-18 devnull return n;
637 56a48c69 2005-03-18 devnull }
638 56a48c69 2005-03-18 devnull
639 56a48c69 2005-03-18 devnull /*
640 56a48c69 2005-03-18 devnull * read a single mime header, collect continuations.
641 56a48c69 2005-03-18 devnull *
642 56a48c69 2005-03-18 devnull * this routine assumes that there is a blank line twixt
643 56a48c69 2005-03-18 devnull * the header and the message body, otherwise bytes will
644 56a48c69 2005-03-18 devnull * be lost.
645 56a48c69 2005-03-18 devnull */
646 56a48c69 2005-03-18 devnull int
647 56a48c69 2005-03-18 devnull getheader(int fd, char *buf, int n)
648 56a48c69 2005-03-18 devnull {
649 56a48c69 2005-03-18 devnull char *p, *e;
650 56a48c69 2005-03-18 devnull int i;
651 56a48c69 2005-03-18 devnull
652 56a48c69 2005-03-18 devnull n--;
653 56a48c69 2005-03-18 devnull p = buf;
654 56a48c69 2005-03-18 devnull for(e = p + n; ; p += i){
655 56a48c69 2005-03-18 devnull i = readline(fd, p, e-p);
656 56a48c69 2005-03-18 devnull if(i < 0)
657 56a48c69 2005-03-18 devnull return i;
658 56a48c69 2005-03-18 devnull
659 56a48c69 2005-03-18 devnull if(p == buf){
660 56a48c69 2005-03-18 devnull /* first line */
661 56a48c69 2005-03-18 devnull if(strchr(buf, ':') == nil)
662 56a48c69 2005-03-18 devnull break; /* end of headers */
663 56a48c69 2005-03-18 devnull } else {
664 56a48c69 2005-03-18 devnull /* continuation line */
665 56a48c69 2005-03-18 devnull if(*p != ' ' && *p != '\t'){
666 56a48c69 2005-03-18 devnull unreadline(p);
667 56a48c69 2005-03-18 devnull *p = 0;
668 56a48c69 2005-03-18 devnull break; /* end of this header */
669 56a48c69 2005-03-18 devnull }
670 56a48c69 2005-03-18 devnull }
671 56a48c69 2005-03-18 devnull }
672 56a48c69 2005-03-18 devnull if(headerprint)
673 56a48c69 2005-03-18 devnull print("%s\n", buf);
674 56a48c69 2005-03-18 devnull
675 56a48c69 2005-03-18 devnull if(debug)
676 56a48c69 2005-03-18 devnull fprint(2, "%d <- %s\n", fd, buf);
677 56a48c69 2005-03-18 devnull return p-buf;
678 56a48c69 2005-03-18 devnull }
679 56a48c69 2005-03-18 devnull
680 56a48c69 2005-03-18 devnull void
681 56a48c69 2005-03-18 devnull hhetag(char *p, URL *u, Range *r)
682 56a48c69 2005-03-18 devnull {
683 56a48c69 2005-03-18 devnull USED(r);
684 fa325e9b 2020-01-10 cross
685 56a48c69 2005-03-18 devnull if(u->etag != nil){
686 56a48c69 2005-03-18 devnull if(strcmp(u->etag, p) != 0)
687 56a48c69 2005-03-18 devnull sysfatal("file changed underfoot");
688 56a48c69 2005-03-18 devnull } else
689 56a48c69 2005-03-18 devnull u->etag = strdup(p);
690 56a48c69 2005-03-18 devnull }
691 56a48c69 2005-03-18 devnull
692 56a48c69 2005-03-18 devnull char* monthchars = "janfebmaraprmayjunjulaugsepoctnovdec";
693 56a48c69 2005-03-18 devnull
694 56a48c69 2005-03-18 devnull void
695 56a48c69 2005-03-18 devnull hhmtime(char *p, URL *u, Range *r)
696 56a48c69 2005-03-18 devnull {
697 56a48c69 2005-03-18 devnull char *month, *day, *yr, *hms;
698 56a48c69 2005-03-18 devnull char *fields[6];
699 56a48c69 2005-03-18 devnull Tm tm, now;
700 56a48c69 2005-03-18 devnull int i;
701 56a48c69 2005-03-18 devnull
702 56a48c69 2005-03-18 devnull USED(r);
703 fa325e9b 2020-01-10 cross
704 56a48c69 2005-03-18 devnull i = getfields(p, fields, 6, 1, " \t");
705 56a48c69 2005-03-18 devnull if(i < 5)
706 56a48c69 2005-03-18 devnull return;
707 56a48c69 2005-03-18 devnull
708 56a48c69 2005-03-18 devnull day = fields[1];
709 56a48c69 2005-03-18 devnull month = fields[2];
710 56a48c69 2005-03-18 devnull yr = fields[3];
711 56a48c69 2005-03-18 devnull hms = fields[4];
712 56a48c69 2005-03-18 devnull
713 56a48c69 2005-03-18 devnull /* default time */
714 56a48c69 2005-03-18 devnull now = *gmtime(time(0));
715 56a48c69 2005-03-18 devnull tm = now;
716 56a48c69 2005-03-18 devnull tm.yday = 0;
717 56a48c69 2005-03-18 devnull
718 56a48c69 2005-03-18 devnull /* convert ascii month to a number twixt 1 and 12 */
719 56a48c69 2005-03-18 devnull if(*month >= '0' && *month <= '9'){
720 56a48c69 2005-03-18 devnull tm.mon = atoi(month) - 1;
721 56a48c69 2005-03-18 devnull if(tm.mon < 0 || tm.mon > 11)
722 56a48c69 2005-03-18 devnull tm.mon = 5;
723 56a48c69 2005-03-18 devnull } else {
724 56a48c69 2005-03-18 devnull for(p = month; *p; p++)
725 1c171e3a 2005-07-19 devnull *p = tolower((uchar)*p);
726 56a48c69 2005-03-18 devnull for(i = 0; i < 12; i++)
727 56a48c69 2005-03-18 devnull if(strncmp(&monthchars[i*3], month, 3) == 0){
728 56a48c69 2005-03-18 devnull tm.mon = i;
729 56a48c69 2005-03-18 devnull break;
730 56a48c69 2005-03-18 devnull }
731 56a48c69 2005-03-18 devnull }
732 56a48c69 2005-03-18 devnull
733 56a48c69 2005-03-18 devnull tm.mday = atoi(day);
734 56a48c69 2005-03-18 devnull
735 56a48c69 2005-03-18 devnull if(hms) {
736 56a48c69 2005-03-18 devnull tm.hour = strtoul(hms, &p, 10);
737 56a48c69 2005-03-18 devnull if(*p == ':') {
738 56a48c69 2005-03-18 devnull p++;
739 56a48c69 2005-03-18 devnull tm.min = strtoul(p, &p, 10);
740 56a48c69 2005-03-18 devnull if(*p == ':') {
741 56a48c69 2005-03-18 devnull p++;
742 56a48c69 2005-03-18 devnull tm.sec = strtoul(p, &p, 10);
743 56a48c69 2005-03-18 devnull }
744 56a48c69 2005-03-18 devnull }
745 1c171e3a 2005-07-19 devnull if(tolower((uchar)*p) == 'p')
746 56a48c69 2005-03-18 devnull tm.hour += 12;
747 56a48c69 2005-03-18 devnull }
748 56a48c69 2005-03-18 devnull
749 56a48c69 2005-03-18 devnull if(yr) {
750 56a48c69 2005-03-18 devnull tm.year = atoi(yr);
751 56a48c69 2005-03-18 devnull if(tm.year >= 1900)
752 56a48c69 2005-03-18 devnull tm.year -= 1900;
753 56a48c69 2005-03-18 devnull } else {
754 56a48c69 2005-03-18 devnull if(tm.mon > now.mon || (tm.mon == now.mon && tm.mday > now.mday+1))
755 56a48c69 2005-03-18 devnull tm.year--;
756 56a48c69 2005-03-18 devnull }
757 56a48c69 2005-03-18 devnull
758 56a48c69 2005-03-18 devnull strcpy(tm.zone, "GMT");
759 56a48c69 2005-03-18 devnull /* convert to epoch seconds */
760 56a48c69 2005-03-18 devnull u->mtime = tm2sec(&tm);
761 56a48c69 2005-03-18 devnull }
762 56a48c69 2005-03-18 devnull
763 56a48c69 2005-03-18 devnull void
764 56a48c69 2005-03-18 devnull hhclen(char *p, URL *u, Range *r)
765 56a48c69 2005-03-18 devnull {
766 56a48c69 2005-03-18 devnull USED(u);
767 fa325e9b 2020-01-10 cross
768 56a48c69 2005-03-18 devnull r->end = atoi(p);
769 56a48c69 2005-03-18 devnull }
770 56a48c69 2005-03-18 devnull
771 56a48c69 2005-03-18 devnull void
772 56a48c69 2005-03-18 devnull hhcrange(char *p, URL *u, Range *r)
773 56a48c69 2005-03-18 devnull {
774 56a48c69 2005-03-18 devnull char *x;
775 56a48c69 2005-03-18 devnull vlong l;
776 56a48c69 2005-03-18 devnull
777 56a48c69 2005-03-18 devnull USED(u);
778 56a48c69 2005-03-18 devnull l = 0;
779 56a48c69 2005-03-18 devnull x = strchr(p, '/');
780 56a48c69 2005-03-18 devnull if(x)
781 56a48c69 2005-03-18 devnull l = atoll(x+1);
782 56a48c69 2005-03-18 devnull if(l == 0)
783 56a48c69 2005-03-18 devnull x = strchr(p, '-');
784 56a48c69 2005-03-18 devnull if(x)
785 56a48c69 2005-03-18 devnull l = atoll(x+1);
786 56a48c69 2005-03-18 devnull if(l)
787 56a48c69 2005-03-18 devnull r->end = l;
788 56a48c69 2005-03-18 devnull }
789 56a48c69 2005-03-18 devnull
790 56a48c69 2005-03-18 devnull void
791 56a48c69 2005-03-18 devnull hhuri(char *p, URL *u, Range *r)
792 56a48c69 2005-03-18 devnull {
793 56a48c69 2005-03-18 devnull USED(r);
794 fa325e9b 2020-01-10 cross
795 56a48c69 2005-03-18 devnull if(*p != '<')
796 56a48c69 2005-03-18 devnull return;
797 56a48c69 2005-03-18 devnull u->redirect = strdup(p+1);
798 56a48c69 2005-03-18 devnull p = strchr(u->redirect, '>');
799 56a48c69 2005-03-18 devnull if(p != nil)
800 56a48c69 2005-03-18 devnull *p = 0;
801 56a48c69 2005-03-18 devnull }
802 56a48c69 2005-03-18 devnull
803 56a48c69 2005-03-18 devnull void
804 56a48c69 2005-03-18 devnull hhlocation(char *p, URL *u, Range *r)
805 56a48c69 2005-03-18 devnull {
806 56a48c69 2005-03-18 devnull USED(r);
807 fa325e9b 2020-01-10 cross
808 56a48c69 2005-03-18 devnull u->redirect = strdup(p);
809 56a48c69 2005-03-18 devnull }
810 56a48c69 2005-03-18 devnull
811 56a48c69 2005-03-18 devnull void
812 56a48c69 2005-03-18 devnull hhauth(char *p, URL *u, Range *r)
813 56a48c69 2005-03-18 devnull {
814 56a48c69 2005-03-18 devnull char *f[4];
815 56a48c69 2005-03-18 devnull UserPasswd *up;
816 56a48c69 2005-03-18 devnull char *s, cred[64];
817 fa325e9b 2020-01-10 cross
818 56a48c69 2005-03-18 devnull USED(r);
819 56a48c69 2005-03-18 devnull
820 56a48c69 2005-03-18 devnull if (cistrncmp(p, "basic ", 6) != 0)
821 56a48c69 2005-03-18 devnull sysfatal("only Basic authentication supported");
822 56a48c69 2005-03-18 devnull
823 56a48c69 2005-03-18 devnull if (gettokens(p, f, nelem(f), "\"") < 2)
824 56a48c69 2005-03-18 devnull sysfatal("garbled auth data");
825 56a48c69 2005-03-18 devnull
826 56a48c69 2005-03-18 devnull if ((up = auth_getuserpasswd(auth_getkey, "proto=pass service=http dom=%q relm=%q",
827 56a48c69 2005-03-18 devnull u->host, f[1])) == nil)
828 56a48c69 2005-03-18 devnull sysfatal("cannot authenticate");
829 56a48c69 2005-03-18 devnull
830 56a48c69 2005-03-18 devnull s = smprint("%s:%s", up->user, up->passwd);
831 56a48c69 2005-03-18 devnull if(enc64(cred, sizeof(cred), (uchar *)s, strlen(s)) == -1)
832 56a48c69 2005-03-18 devnull sysfatal("enc64");
833 56a48c69 2005-03-18 devnull free(s);
834 56a48c69 2005-03-18 devnull
835 56a48c69 2005-03-18 devnull assert(u->cred = strdup(cred));
836 56a48c69 2005-03-18 devnull }
837 56a48c69 2005-03-18 devnull
838 56a48c69 2005-03-18 devnull enum
839 56a48c69 2005-03-18 devnull {
840 56a48c69 2005-03-18 devnull /* ftp return codes */
841 56a48c69 2005-03-18 devnull Extra= 1,
842 56a48c69 2005-03-18 devnull Success= 2,
843 56a48c69 2005-03-18 devnull Incomplete= 3,
844 56a48c69 2005-03-18 devnull TempFail= 4,
845 56a48c69 2005-03-18 devnull PermFail= 5,
846 56a48c69 2005-03-18 devnull
847 56a48c69 2005-03-18 devnull Nnetdir= 64, /* max length of network directory paths */
848 cbeb0b26 2006-04-01 devnull Ndialstr= 64 /* max length of dial strings */
849 56a48c69 2005-03-18 devnull };
850 56a48c69 2005-03-18 devnull
851 56a48c69 2005-03-18 devnull int ftpcmd(int, char*, ...);
852 56a48c69 2005-03-18 devnull int ftprcode(int, char*, int);
853 56a48c69 2005-03-18 devnull int hello(int);
854 56a48c69 2005-03-18 devnull int logon(int);
855 56a48c69 2005-03-18 devnull int xfertype(int, char*);
856 56a48c69 2005-03-18 devnull int passive(int, URL*);
857 56a48c69 2005-03-18 devnull int active(int, URL*);
858 56a48c69 2005-03-18 devnull int ftpxfer(int, Out*, Range*);
859 56a48c69 2005-03-18 devnull int terminateftp(int, int);
860 56a48c69 2005-03-18 devnull int getaddrport(char*, uchar*, uchar*);
861 56a48c69 2005-03-18 devnull int ftprestart(int, Out*, URL*, Range*, long);
862 56a48c69 2005-03-18 devnull
863 56a48c69 2005-03-18 devnull int
864 56a48c69 2005-03-18 devnull doftp(URL *u, URL *px, Range *r, Out *out, long mtime)
865 56a48c69 2005-03-18 devnull {
866 56a48c69 2005-03-18 devnull int pid, ctl, data, rv;
867 56a48c69 2005-03-18 devnull Waitmsg *w;
868 56a48c69 2005-03-18 devnull char msg[64];
869 56a48c69 2005-03-18 devnull
870 56a48c69 2005-03-18 devnull /* untested, proxy dosn't work with ftp (I think) */
871 56a48c69 2005-03-18 devnull if(px->host == nil){
872 54eacd0b 2005-12-30 devnull ctl = dial(netmkaddr(u->host, tcpdir, u->port), 0, 0, 0);
873 56a48c69 2005-03-18 devnull } else {
874 54eacd0b 2005-12-30 devnull ctl = dial(netmkaddr(px->host, tcpdir, px->port), 0, 0, 0);
875 56a48c69 2005-03-18 devnull }
876 56a48c69 2005-03-18 devnull
877 56a48c69 2005-03-18 devnull if(ctl < 0)
878 56a48c69 2005-03-18 devnull return Error;
879 54eacd0b 2005-12-30 devnull if(net == nil)
880 54eacd0b 2005-12-30 devnull strcpy(tcpdir, "tcp");
881 56a48c69 2005-03-18 devnull
882 56a48c69 2005-03-18 devnull initibuf();
883 56a48c69 2005-03-18 devnull
884 56a48c69 2005-03-18 devnull rv = hello(ctl);
885 56a48c69 2005-03-18 devnull if(rv < 0)
886 56a48c69 2005-03-18 devnull return terminateftp(ctl, rv);
887 56a48c69 2005-03-18 devnull
888 56a48c69 2005-03-18 devnull rv = logon(ctl);
889 56a48c69 2005-03-18 devnull if(rv < 0)
890 56a48c69 2005-03-18 devnull return terminateftp(ctl, rv);
891 56a48c69 2005-03-18 devnull
892 56a48c69 2005-03-18 devnull rv = xfertype(ctl, "I");
893 56a48c69 2005-03-18 devnull if(rv < 0)
894 56a48c69 2005-03-18 devnull return terminateftp(ctl, rv);
895 56a48c69 2005-03-18 devnull
896 56a48c69 2005-03-18 devnull /* if file is up to date and the right size, stop */
897 56a48c69 2005-03-18 devnull if(ftprestart(ctl, out, u, r, mtime) > 0){
898 56a48c69 2005-03-18 devnull close(ctl);
899 56a48c69 2005-03-18 devnull return Eof;
900 56a48c69 2005-03-18 devnull }
901 fa325e9b 2020-01-10 cross
902 56a48c69 2005-03-18 devnull /* first try passive mode, then active */
903 56a48c69 2005-03-18 devnull data = passive(ctl, u);
904 56a48c69 2005-03-18 devnull if(data < 0){
905 56a48c69 2005-03-18 devnull data = active(ctl, u);
906 56a48c69 2005-03-18 devnull if(data < 0)
907 56a48c69 2005-03-18 devnull return Error;
908 56a48c69 2005-03-18 devnull }
909 56a48c69 2005-03-18 devnull
910 56a48c69 2005-03-18 devnull /* fork */
911 56a48c69 2005-03-18 devnull switch(pid = fork()){
912 56a48c69 2005-03-18 devnull case -1:
913 56a48c69 2005-03-18 devnull close(data);
914 56a48c69 2005-03-18 devnull return terminateftp(ctl, Error);
915 56a48c69 2005-03-18 devnull case 0:
916 56a48c69 2005-03-18 devnull ftpxfer(data, out, r);
917 56a48c69 2005-03-18 devnull close(data);
918 56a48c69 2005-03-18 devnull #undef _exits
919 56a48c69 2005-03-18 devnull _exits(0);
920 56a48c69 2005-03-18 devnull default:
921 56a48c69 2005-03-18 devnull close(data);
922 56a48c69 2005-03-18 devnull break;
923 56a48c69 2005-03-18 devnull }
924 56a48c69 2005-03-18 devnull
925 56a48c69 2005-03-18 devnull /* wait for reply message */
926 56a48c69 2005-03-18 devnull rv = ftprcode(ctl, msg, sizeof(msg));
927 56a48c69 2005-03-18 devnull close(ctl);
928 56a48c69 2005-03-18 devnull
929 56a48c69 2005-03-18 devnull /* wait for process to terminate */
930 56a48c69 2005-03-18 devnull w = nil;
931 56a48c69 2005-03-18 devnull for(;;){
932 56a48c69 2005-03-18 devnull free(w);
933 56a48c69 2005-03-18 devnull w = wait();
934 56a48c69 2005-03-18 devnull if(w == nil)
935 56a48c69 2005-03-18 devnull return Error;
936 56a48c69 2005-03-18 devnull if(w->pid == pid){
937 56a48c69 2005-03-18 devnull if(w->msg[0] == 0){
938 56a48c69 2005-03-18 devnull free(w);
939 56a48c69 2005-03-18 devnull break;
940 56a48c69 2005-03-18 devnull }
941 56a48c69 2005-03-18 devnull werrstr("xfer: %s", w->msg);
942 56a48c69 2005-03-18 devnull free(w);
943 56a48c69 2005-03-18 devnull return Error;
944 56a48c69 2005-03-18 devnull }
945 56a48c69 2005-03-18 devnull }
946 56a48c69 2005-03-18 devnull
947 56a48c69 2005-03-18 devnull switch(rv){
948 56a48c69 2005-03-18 devnull case Success:
949 56a48c69 2005-03-18 devnull return Eof;
950 56a48c69 2005-03-18 devnull case TempFail:
951 56a48c69 2005-03-18 devnull return Server;
952 56a48c69 2005-03-18 devnull default:
953 56a48c69 2005-03-18 devnull return Error;
954 56a48c69 2005-03-18 devnull }
955 56a48c69 2005-03-18 devnull }
956 56a48c69 2005-03-18 devnull
957 56a48c69 2005-03-18 devnull int
958 56a48c69 2005-03-18 devnull ftpcmd(int ctl, char *fmt, ...)
959 56a48c69 2005-03-18 devnull {
960 56a48c69 2005-03-18 devnull va_list arg;
961 56a48c69 2005-03-18 devnull char buf[2*1024], *s;
962 56a48c69 2005-03-18 devnull
963 56a48c69 2005-03-18 devnull va_start(arg, fmt);
964 56a48c69 2005-03-18 devnull s = vseprint(buf, buf + (sizeof(buf)-4) / sizeof(*buf), fmt, arg);
965 56a48c69 2005-03-18 devnull va_end(arg);
966 56a48c69 2005-03-18 devnull if(debug)
967 56a48c69 2005-03-18 devnull fprint(2, "%d -> %s\n", ctl, buf);
968 56a48c69 2005-03-18 devnull *s++ = '\r';
969 56a48c69 2005-03-18 devnull *s++ = '\n';
970 56a48c69 2005-03-18 devnull if(write(ctl, buf, s - buf) != s - buf)
971 56a48c69 2005-03-18 devnull return -1;
972 56a48c69 2005-03-18 devnull return 0;
973 56a48c69 2005-03-18 devnull }
974 56a48c69 2005-03-18 devnull
975 56a48c69 2005-03-18 devnull int
976 56a48c69 2005-03-18 devnull ftprcode(int ctl, char *msg, int len)
977 56a48c69 2005-03-18 devnull {
978 56a48c69 2005-03-18 devnull int rv;
979 56a48c69 2005-03-18 devnull int i;
980 56a48c69 2005-03-18 devnull char *p;
981 56a48c69 2005-03-18 devnull
982 56a48c69 2005-03-18 devnull len--; /* room for terminating null */
983 56a48c69 2005-03-18 devnull for(;;){
984 56a48c69 2005-03-18 devnull *msg = 0;
985 56a48c69 2005-03-18 devnull i = readline(ctl, msg, len);
986 56a48c69 2005-03-18 devnull if(i < 0)
987 56a48c69 2005-03-18 devnull break;
988 56a48c69 2005-03-18 devnull if(debug)
989 56a48c69 2005-03-18 devnull fprint(2, "%d <- %s\n", ctl, msg);
990 56a48c69 2005-03-18 devnull
991 56a48c69 2005-03-18 devnull /* stop if not a continuation */
992 56a48c69 2005-03-18 devnull rv = strtol(msg, &p, 10);
993 56a48c69 2005-03-18 devnull if(rv >= 100 && rv < 600 && p==msg+3 && *p == ' ')
994 56a48c69 2005-03-18 devnull return rv/100;
995 56a48c69 2005-03-18 devnull }
996 56a48c69 2005-03-18 devnull *msg = 0;
997 56a48c69 2005-03-18 devnull
998 56a48c69 2005-03-18 devnull return -1;
999 56a48c69 2005-03-18 devnull }
1000 56a48c69 2005-03-18 devnull
1001 56a48c69 2005-03-18 devnull int
1002 56a48c69 2005-03-18 devnull hello(int ctl)
1003 56a48c69 2005-03-18 devnull {
1004 56a48c69 2005-03-18 devnull char msg[1024];
1005 56a48c69 2005-03-18 devnull
1006 56a48c69 2005-03-18 devnull /* wait for hello from other side */
1007 56a48c69 2005-03-18 devnull if(ftprcode(ctl, msg, sizeof(msg)) != Success){
1008 56a48c69 2005-03-18 devnull werrstr("HELLO: %s", msg);
1009 56a48c69 2005-03-18 devnull return Server;
1010 56a48c69 2005-03-18 devnull }
1011 56a48c69 2005-03-18 devnull return 0;
1012 56a48c69 2005-03-18 devnull }
1013 56a48c69 2005-03-18 devnull
1014 56a48c69 2005-03-18 devnull int
1015 56a48c69 2005-03-18 devnull getdec(char *p, int n)
1016 56a48c69 2005-03-18 devnull {
1017 56a48c69 2005-03-18 devnull int x = 0;
1018 56a48c69 2005-03-18 devnull int i;
1019 56a48c69 2005-03-18 devnull
1020 56a48c69 2005-03-18 devnull for(i = 0; i < n; i++)
1021 56a48c69 2005-03-18 devnull x = x*10 + (*p++ - '0');
1022 56a48c69 2005-03-18 devnull return x;
1023 56a48c69 2005-03-18 devnull }
1024 56a48c69 2005-03-18 devnull
1025 56a48c69 2005-03-18 devnull int
1026 56a48c69 2005-03-18 devnull ftprestart(int ctl, Out *out, URL *u, Range *r, long mtime)
1027 56a48c69 2005-03-18 devnull {
1028 56a48c69 2005-03-18 devnull Tm tm;
1029 56a48c69 2005-03-18 devnull char msg[1024];
1030 56a48c69 2005-03-18 devnull long x, rmtime;
1031 56a48c69 2005-03-18 devnull
1032 56a48c69 2005-03-18 devnull ftpcmd(ctl, "MDTM %s", u->page);
1033 56a48c69 2005-03-18 devnull if(ftprcode(ctl, msg, sizeof(msg)) != Success){
1034 56a48c69 2005-03-18 devnull r->start = 0;
1035 56a48c69 2005-03-18 devnull return 0; /* need to do something */
1036 56a48c69 2005-03-18 devnull }
1037 56a48c69 2005-03-18 devnull
1038 56a48c69 2005-03-18 devnull /* decode modification time */
1039 56a48c69 2005-03-18 devnull if(strlen(msg) < 4 + 4 + 2 + 2 + 2 + 2 + 2){
1040 56a48c69 2005-03-18 devnull r->start = 0;
1041 56a48c69 2005-03-18 devnull return 0; /* need to do something */
1042 56a48c69 2005-03-18 devnull }
1043 56a48c69 2005-03-18 devnull memset(&tm, 0, sizeof(tm));
1044 56a48c69 2005-03-18 devnull tm.year = getdec(msg+4, 4) - 1900;
1045 56a48c69 2005-03-18 devnull tm.mon = getdec(msg+4+4, 2) - 1;
1046 56a48c69 2005-03-18 devnull tm.mday = getdec(msg+4+4+2, 2);
1047 56a48c69 2005-03-18 devnull tm.hour = getdec(msg+4+4+2+2, 2);
1048 56a48c69 2005-03-18 devnull tm.min = getdec(msg+4+4+2+2+2, 2);
1049 56a48c69 2005-03-18 devnull tm.sec = getdec(msg+4+4+2+2+2+2, 2);
1050 56a48c69 2005-03-18 devnull strcpy(tm.zone, "GMT");
1051 56a48c69 2005-03-18 devnull rmtime = tm2sec(&tm);
1052 56a48c69 2005-03-18 devnull if(rmtime > mtime)
1053 56a48c69 2005-03-18 devnull r->start = 0;
1054 56a48c69 2005-03-18 devnull
1055 56a48c69 2005-03-18 devnull /* get size */
1056 56a48c69 2005-03-18 devnull ftpcmd(ctl, "SIZE %s", u->page);
1057 56a48c69 2005-03-18 devnull if(ftprcode(ctl, msg, sizeof(msg)) == Success){
1058 56a48c69 2005-03-18 devnull x = atol(msg+4);
1059 56a48c69 2005-03-18 devnull if(r->start == x)
1060 56a48c69 2005-03-18 devnull return 1; /* we're up to date */
1061 56a48c69 2005-03-18 devnull r->end = x;
1062 56a48c69 2005-03-18 devnull }
1063 56a48c69 2005-03-18 devnull
1064 56a48c69 2005-03-18 devnull /* seek to restart point */
1065 56a48c69 2005-03-18 devnull if(r->start > 0){
1066 56a48c69 2005-03-18 devnull ftpcmd(ctl, "REST %lud", r->start);
1067 56a48c69 2005-03-18 devnull if(ftprcode(ctl, msg, sizeof(msg)) == Incomplete){
1068 56a48c69 2005-03-18 devnull setoffset(out, r->start);
1069 56a48c69 2005-03-18 devnull }else
1070 56a48c69 2005-03-18 devnull r->start = 0;
1071 56a48c69 2005-03-18 devnull }
1072 56a48c69 2005-03-18 devnull
1073 56a48c69 2005-03-18 devnull return 0; /* need to do something */
1074 56a48c69 2005-03-18 devnull }
1075 56a48c69 2005-03-18 devnull
1076 56a48c69 2005-03-18 devnull int
1077 56a48c69 2005-03-18 devnull logon(int ctl)
1078 56a48c69 2005-03-18 devnull {
1079 56a48c69 2005-03-18 devnull char msg[1024];
1080 56a48c69 2005-03-18 devnull
1081 56a48c69 2005-03-18 devnull /* login anonymous */
1082 56a48c69 2005-03-18 devnull ftpcmd(ctl, "USER anonymous");
1083 56a48c69 2005-03-18 devnull switch(ftprcode(ctl, msg, sizeof(msg))){
1084 56a48c69 2005-03-18 devnull case Success:
1085 56a48c69 2005-03-18 devnull return 0;
1086 56a48c69 2005-03-18 devnull case Incomplete:
1087 56a48c69 2005-03-18 devnull break; /* need password */
1088 56a48c69 2005-03-18 devnull default:
1089 56a48c69 2005-03-18 devnull werrstr("USER: %s", msg);
1090 56a48c69 2005-03-18 devnull return Server;
1091 56a48c69 2005-03-18 devnull }
1092 56a48c69 2005-03-18 devnull
1093 56a48c69 2005-03-18 devnull /* send user id as password */
1094 56a48c69 2005-03-18 devnull sprint(msg, "%s@closedmind.org", getuser());
1095 56a48c69 2005-03-18 devnull ftpcmd(ctl, "PASS %s", msg);
1096 56a48c69 2005-03-18 devnull if(ftprcode(ctl, msg, sizeof(msg)) != Success){
1097 56a48c69 2005-03-18 devnull werrstr("PASS: %s", msg);
1098 56a48c69 2005-03-18 devnull return Server;
1099 56a48c69 2005-03-18 devnull }
1100 56a48c69 2005-03-18 devnull
1101 56a48c69 2005-03-18 devnull return 0;
1102 56a48c69 2005-03-18 devnull }
1103 56a48c69 2005-03-18 devnull
1104 56a48c69 2005-03-18 devnull int
1105 56a48c69 2005-03-18 devnull xfertype(int ctl, char *t)
1106 56a48c69 2005-03-18 devnull {
1107 56a48c69 2005-03-18 devnull char msg[1024];
1108 56a48c69 2005-03-18 devnull
1109 56a48c69 2005-03-18 devnull ftpcmd(ctl, "TYPE %s", t);
1110 56a48c69 2005-03-18 devnull if(ftprcode(ctl, msg, sizeof(msg)) != Success){
1111 56a48c69 2005-03-18 devnull werrstr("TYPE %s: %s", t, msg);
1112 56a48c69 2005-03-18 devnull return Server;
1113 56a48c69 2005-03-18 devnull }
1114 56a48c69 2005-03-18 devnull
1115 56a48c69 2005-03-18 devnull return 0;
1116 56a48c69 2005-03-18 devnull }
1117 56a48c69 2005-03-18 devnull
1118 56a48c69 2005-03-18 devnull int
1119 56a48c69 2005-03-18 devnull passive(int ctl, URL *u)
1120 56a48c69 2005-03-18 devnull {
1121 56a48c69 2005-03-18 devnull char msg[1024];
1122 56a48c69 2005-03-18 devnull char ipaddr[32];
1123 56a48c69 2005-03-18 devnull char *f[6];
1124 56a48c69 2005-03-18 devnull char *p;
1125 56a48c69 2005-03-18 devnull int fd;
1126 56a48c69 2005-03-18 devnull int port;
1127 56a48c69 2005-03-18 devnull char aport[12];
1128 56a48c69 2005-03-18 devnull
1129 56a48c69 2005-03-18 devnull ftpcmd(ctl, "PASV");
1130 56a48c69 2005-03-18 devnull if(ftprcode(ctl, msg, sizeof(msg)) != Success)
1131 56a48c69 2005-03-18 devnull return Error;
1132 56a48c69 2005-03-18 devnull
1133 56a48c69 2005-03-18 devnull /* get address and port number from reply, this is AI */
1134 56a48c69 2005-03-18 devnull p = strchr(msg, '(');
1135 56a48c69 2005-03-18 devnull if(p == nil){
1136 56a48c69 2005-03-18 devnull for(p = msg+3; *p; p++)
1137 1c171e3a 2005-07-19 devnull if(isdigit((uchar)*p))
1138 56a48c69 2005-03-18 devnull break;
1139 56a48c69 2005-03-18 devnull } else
1140 56a48c69 2005-03-18 devnull p++;
1141 56a48c69 2005-03-18 devnull if(getfields(p, f, 6, 0, ",)") < 6){
1142 56a48c69 2005-03-18 devnull werrstr("ftp protocol botch");
1143 56a48c69 2005-03-18 devnull return Server;
1144 56a48c69 2005-03-18 devnull }
1145 56a48c69 2005-03-18 devnull snprint(ipaddr, sizeof(ipaddr), "%s.%s.%s.%s",
1146 56a48c69 2005-03-18 devnull f[0], f[1], f[2], f[3]);
1147 56a48c69 2005-03-18 devnull port = ((atoi(f[4])&0xff)<<8) + (atoi(f[5])&0xff);
1148 56a48c69 2005-03-18 devnull sprint(aport, "%d", port);
1149 56a48c69 2005-03-18 devnull
1150 56a48c69 2005-03-18 devnull /* open data connection */
1151 56a48c69 2005-03-18 devnull fd = dial(netmkaddr(ipaddr, tcpdir, aport), 0, 0, 0);
1152 56a48c69 2005-03-18 devnull if(fd < 0){
1153 56a48c69 2005-03-18 devnull werrstr("passive mode failed: %r");
1154 56a48c69 2005-03-18 devnull return Error;
1155 56a48c69 2005-03-18 devnull }
1156 56a48c69 2005-03-18 devnull
1157 56a48c69 2005-03-18 devnull /* tell remote to send a file */
1158 56a48c69 2005-03-18 devnull ftpcmd(ctl, "RETR %s", u->page);
1159 56a48c69 2005-03-18 devnull if(ftprcode(ctl, msg, sizeof(msg)) != Extra){
1160 56a48c69 2005-03-18 devnull werrstr("RETR %s: %s", u->page, msg);
1161 56a48c69 2005-03-18 devnull return Error;
1162 56a48c69 2005-03-18 devnull }
1163 56a48c69 2005-03-18 devnull return fd;
1164 56a48c69 2005-03-18 devnull }
1165 56a48c69 2005-03-18 devnull
1166 56a48c69 2005-03-18 devnull int
1167 56a48c69 2005-03-18 devnull active(int ctl, URL *u)
1168 56a48c69 2005-03-18 devnull {
1169 56a48c69 2005-03-18 devnull char msg[1024];
1170 56a48c69 2005-03-18 devnull char dir[40], ldir[40];
1171 56a48c69 2005-03-18 devnull uchar ipaddr[4];
1172 56a48c69 2005-03-18 devnull uchar port[2];
1173 56a48c69 2005-03-18 devnull int lcfd, dfd, afd;
1174 56a48c69 2005-03-18 devnull
1175 56a48c69 2005-03-18 devnull /* announce a port for the call back */
1176 56a48c69 2005-03-18 devnull snprint(msg, sizeof(msg), "%s!*!0", tcpdir);
1177 56a48c69 2005-03-18 devnull afd = announce(msg, dir);
1178 56a48c69 2005-03-18 devnull if(afd < 0)
1179 56a48c69 2005-03-18 devnull return Error;
1180 56a48c69 2005-03-18 devnull
1181 56a48c69 2005-03-18 devnull /* get a local address/port of the annoucement */
1182 56a48c69 2005-03-18 devnull if(getaddrport(dir, ipaddr, port) < 0){
1183 56a48c69 2005-03-18 devnull close(afd);
1184 56a48c69 2005-03-18 devnull return Error;
1185 56a48c69 2005-03-18 devnull }
1186 56a48c69 2005-03-18 devnull
1187 56a48c69 2005-03-18 devnull /* tell remote side address and port*/
1188 56a48c69 2005-03-18 devnull ftpcmd(ctl, "PORT %d,%d,%d,%d,%d,%d", ipaddr[0], ipaddr[1], ipaddr[2],
1189 56a48c69 2005-03-18 devnull ipaddr[3], port[0], port[1]);
1190 56a48c69 2005-03-18 devnull if(ftprcode(ctl, msg, sizeof(msg)) != Success){
1191 56a48c69 2005-03-18 devnull close(afd);
1192 56a48c69 2005-03-18 devnull werrstr("active: %s", msg);
1193 56a48c69 2005-03-18 devnull return Error;
1194 56a48c69 2005-03-18 devnull }
1195 56a48c69 2005-03-18 devnull
1196 56a48c69 2005-03-18 devnull /* tell remote to send a file */
1197 56a48c69 2005-03-18 devnull ftpcmd(ctl, "RETR %s", u->page);
1198 56a48c69 2005-03-18 devnull if(ftprcode(ctl, msg, sizeof(msg)) != Extra){
1199 56a48c69 2005-03-18 devnull close(afd);
1200 56a48c69 2005-03-18 devnull werrstr("RETR: %s", msg);
1201 56a48c69 2005-03-18 devnull return Server;
1202 56a48c69 2005-03-18 devnull }
1203 56a48c69 2005-03-18 devnull
1204 56a48c69 2005-03-18 devnull /* wait for a connection */
1205 56a48c69 2005-03-18 devnull lcfd = listen(dir, ldir);
1206 56a48c69 2005-03-18 devnull if(lcfd < 0){
1207 56a48c69 2005-03-18 devnull close(afd);
1208 56a48c69 2005-03-18 devnull return Error;
1209 56a48c69 2005-03-18 devnull }
1210 56a48c69 2005-03-18 devnull dfd = accept(lcfd, ldir);
1211 56a48c69 2005-03-18 devnull if(dfd < 0){
1212 56a48c69 2005-03-18 devnull close(afd);
1213 56a48c69 2005-03-18 devnull close(lcfd);
1214 56a48c69 2005-03-18 devnull return Error;
1215 56a48c69 2005-03-18 devnull }
1216 56a48c69 2005-03-18 devnull close(afd);
1217 56a48c69 2005-03-18 devnull close(lcfd);
1218 fa325e9b 2020-01-10 cross
1219 56a48c69 2005-03-18 devnull return dfd;
1220 56a48c69 2005-03-18 devnull }
1221 56a48c69 2005-03-18 devnull
1222 56a48c69 2005-03-18 devnull int
1223 56a48c69 2005-03-18 devnull ftpxfer(int in, Out *out, Range *r)
1224 56a48c69 2005-03-18 devnull {
1225 56a48c69 2005-03-18 devnull char buf[1024];
1226 56a48c69 2005-03-18 devnull long vtime;
1227 56a48c69 2005-03-18 devnull int i, n;
1228 56a48c69 2005-03-18 devnull
1229 56a48c69 2005-03-18 devnull vtime = 0;
1230 56a48c69 2005-03-18 devnull for(n = 0;;n += i){
1231 56a48c69 2005-03-18 devnull i = read(in, buf, sizeof(buf));
1232 56a48c69 2005-03-18 devnull if(i == 0)
1233 56a48c69 2005-03-18 devnull break;
1234 56a48c69 2005-03-18 devnull if(i < 0)
1235 56a48c69 2005-03-18 devnull return Error;
1236 56a48c69 2005-03-18 devnull if(output(out, buf, i) != i)
1237 56a48c69 2005-03-18 devnull return Error;
1238 56a48c69 2005-03-18 devnull r->start += i;
1239 1866bcc9 2006-10-12 devnull if(verbose && (vtime != time(0) || r->start == r->end)) {
1240 56a48c69 2005-03-18 devnull vtime = time(0);
1241 56a48c69 2005-03-18 devnull fprint(2, "%ld %ld\n", r->start, r->end);
1242 56a48c69 2005-03-18 devnull }
1243 56a48c69 2005-03-18 devnull }
1244 56a48c69 2005-03-18 devnull return n;
1245 56a48c69 2005-03-18 devnull }
1246 56a48c69 2005-03-18 devnull
1247 56a48c69 2005-03-18 devnull int
1248 56a48c69 2005-03-18 devnull terminateftp(int ctl, int rv)
1249 56a48c69 2005-03-18 devnull {
1250 56a48c69 2005-03-18 devnull close(ctl);
1251 56a48c69 2005-03-18 devnull return rv;
1252 56a48c69 2005-03-18 devnull }
1253 56a48c69 2005-03-18 devnull
1254 56a48c69 2005-03-18 devnull /*
1255 56a48c69 2005-03-18 devnull * case insensitive strcmp (why aren't these in libc?)
1256 56a48c69 2005-03-18 devnull */
1257 56a48c69 2005-03-18 devnull int
1258 56a48c69 2005-03-18 devnull cistrncmp(char *a, char *b, int n)
1259 56a48c69 2005-03-18 devnull {
1260 56a48c69 2005-03-18 devnull while(n-- > 0){
1261 1c171e3a 2005-07-19 devnull if(tolower((uchar)*a++) != tolower((uchar)*b++))
1262 56a48c69 2005-03-18 devnull return -1;
1263 56a48c69 2005-03-18 devnull }
1264 56a48c69 2005-03-18 devnull return 0;
1265 56a48c69 2005-03-18 devnull }
1266 56a48c69 2005-03-18 devnull
1267 56a48c69 2005-03-18 devnull int
1268 56a48c69 2005-03-18 devnull cistrcmp(char *a, char *b)
1269 56a48c69 2005-03-18 devnull {
1270 56a48c69 2005-03-18 devnull while(*a || *b)
1271 94d85bc0 2005-09-09 devnull if(tolower((uchar)*a++) != tolower((uchar)*b++))
1272 56a48c69 2005-03-18 devnull return -1;
1273 56a48c69 2005-03-18 devnull
1274 56a48c69 2005-03-18 devnull return 0;
1275 56a48c69 2005-03-18 devnull }
1276 56a48c69 2005-03-18 devnull
1277 56a48c69 2005-03-18 devnull /*
1278 56a48c69 2005-03-18 devnull * buffered io
1279 56a48c69 2005-03-18 devnull */
1280 56a48c69 2005-03-18 devnull struct
1281 56a48c69 2005-03-18 devnull {
1282 56a48c69 2005-03-18 devnull char *rp;
1283 56a48c69 2005-03-18 devnull char *wp;
1284 56a48c69 2005-03-18 devnull char buf[4*1024];
1285 56a48c69 2005-03-18 devnull } b;
1286 56a48c69 2005-03-18 devnull
1287 56a48c69 2005-03-18 devnull void
1288 56a48c69 2005-03-18 devnull initibuf(void)
1289 56a48c69 2005-03-18 devnull {
1290 56a48c69 2005-03-18 devnull b.rp = b.wp = b.buf;
1291 56a48c69 2005-03-18 devnull }
1292 56a48c69 2005-03-18 devnull
1293 56a48c69 2005-03-18 devnull /*
1294 56a48c69 2005-03-18 devnull * read a possibly buffered line, strip off trailing while
1295 56a48c69 2005-03-18 devnull */
1296 56a48c69 2005-03-18 devnull int
1297 56a48c69 2005-03-18 devnull readline(int fd, char *buf, int len)
1298 56a48c69 2005-03-18 devnull {
1299 56a48c69 2005-03-18 devnull int n;
1300 56a48c69 2005-03-18 devnull char *p;
1301 56a48c69 2005-03-18 devnull int eof = 0;
1302 56a48c69 2005-03-18 devnull
1303 56a48c69 2005-03-18 devnull len--;
1304 56a48c69 2005-03-18 devnull
1305 56a48c69 2005-03-18 devnull for(p = buf;;){
1306 56a48c69 2005-03-18 devnull if(b.rp >= b.wp){
1307 56a48c69 2005-03-18 devnull n = read(fd, b.wp, sizeof(b.buf)/2);
1308 56a48c69 2005-03-18 devnull if(n < 0)
1309 56a48c69 2005-03-18 devnull return -1;
1310 56a48c69 2005-03-18 devnull if(n == 0){
1311 56a48c69 2005-03-18 devnull eof = 1;
1312 56a48c69 2005-03-18 devnull break;
1313 56a48c69 2005-03-18 devnull }
1314 56a48c69 2005-03-18 devnull b.wp += n;
1315 56a48c69 2005-03-18 devnull }
1316 56a48c69 2005-03-18 devnull n = *b.rp++;
1317 56a48c69 2005-03-18 devnull if(len > 0){
1318 56a48c69 2005-03-18 devnull *p++ = n;
1319 56a48c69 2005-03-18 devnull len--;
1320 56a48c69 2005-03-18 devnull }
1321 56a48c69 2005-03-18 devnull if(n == '\n')
1322 56a48c69 2005-03-18 devnull break;
1323 56a48c69 2005-03-18 devnull }
1324 56a48c69 2005-03-18 devnull
1325 56a48c69 2005-03-18 devnull /* drop trailing white */
1326 56a48c69 2005-03-18 devnull for(;;){
1327 56a48c69 2005-03-18 devnull if(p <= buf)
1328 56a48c69 2005-03-18 devnull break;
1329 56a48c69 2005-03-18 devnull n = *(p-1);
1330 56a48c69 2005-03-18 devnull if(n != ' ' && n != '\t' && n != '\r' && n != '\n')
1331 56a48c69 2005-03-18 devnull break;
1332 56a48c69 2005-03-18 devnull p--;
1333 56a48c69 2005-03-18 devnull }
1334 56a48c69 2005-03-18 devnull *p = 0;
1335 56a48c69 2005-03-18 devnull
1336 56a48c69 2005-03-18 devnull if(eof && p == buf)
1337 56a48c69 2005-03-18 devnull return -1;
1338 56a48c69 2005-03-18 devnull
1339 56a48c69 2005-03-18 devnull return p-buf;
1340 56a48c69 2005-03-18 devnull }
1341 56a48c69 2005-03-18 devnull
1342 56a48c69 2005-03-18 devnull void
1343 56a48c69 2005-03-18 devnull unreadline(char *line)
1344 56a48c69 2005-03-18 devnull {
1345 56a48c69 2005-03-18 devnull int i, n;
1346 56a48c69 2005-03-18 devnull
1347 56a48c69 2005-03-18 devnull i = strlen(line);
1348 56a48c69 2005-03-18 devnull n = b.wp-b.rp;
1349 56a48c69 2005-03-18 devnull memmove(&b.buf[i+1], b.rp, n);
1350 56a48c69 2005-03-18 devnull memmove(b.buf, line, i);
1351 56a48c69 2005-03-18 devnull b.buf[i] = '\n';
1352 56a48c69 2005-03-18 devnull b.rp = b.buf;
1353 56a48c69 2005-03-18 devnull b.wp = b.rp + i + 1 + n;
1354 56a48c69 2005-03-18 devnull }
1355 56a48c69 2005-03-18 devnull
1356 56a48c69 2005-03-18 devnull int
1357 56a48c69 2005-03-18 devnull readibuf(int fd, char *buf, int len)
1358 56a48c69 2005-03-18 devnull {
1359 56a48c69 2005-03-18 devnull int n;
1360 56a48c69 2005-03-18 devnull
1361 56a48c69 2005-03-18 devnull n = b.wp-b.rp;
1362 56a48c69 2005-03-18 devnull if(n > 0){
1363 56a48c69 2005-03-18 devnull if(n > len)
1364 56a48c69 2005-03-18 devnull n = len;
1365 56a48c69 2005-03-18 devnull memmove(buf, b.rp, n);
1366 56a48c69 2005-03-18 devnull b.rp += n;
1367 56a48c69 2005-03-18 devnull return n;
1368 56a48c69 2005-03-18 devnull }
1369 56a48c69 2005-03-18 devnull return read(fd, buf, len);
1370 56a48c69 2005-03-18 devnull }
1371 56a48c69 2005-03-18 devnull
1372 56a48c69 2005-03-18 devnull int
1373 56a48c69 2005-03-18 devnull dfprint(int fd, char *fmt, ...)
1374 56a48c69 2005-03-18 devnull {
1375 56a48c69 2005-03-18 devnull char buf[4*1024];
1376 56a48c69 2005-03-18 devnull va_list arg;
1377 56a48c69 2005-03-18 devnull
1378 56a48c69 2005-03-18 devnull va_start(arg, fmt);
1379 56a48c69 2005-03-18 devnull vseprint(buf, buf+sizeof(buf), fmt, arg);
1380 56a48c69 2005-03-18 devnull va_end(arg);
1381 56a48c69 2005-03-18 devnull if(debug)
1382 56a48c69 2005-03-18 devnull fprint(2, "%d -> %s", fd, buf);
1383 56a48c69 2005-03-18 devnull return fprint(fd, "%s", buf);
1384 56a48c69 2005-03-18 devnull }
1385 56a48c69 2005-03-18 devnull
1386 56a48c69 2005-03-18 devnull int
1387 56a48c69 2005-03-18 devnull getaddrport(char *dir, uchar *ipaddr, uchar *port)
1388 56a48c69 2005-03-18 devnull {
1389 56a48c69 2005-03-18 devnull char buf[256];
1390 56a48c69 2005-03-18 devnull int fd, i;
1391 56a48c69 2005-03-18 devnull char *p;
1392 56a48c69 2005-03-18 devnull
1393 56a48c69 2005-03-18 devnull snprint(buf, sizeof(buf), "%s/local", dir);
1394 56a48c69 2005-03-18 devnull fd = open(buf, OREAD);
1395 56a48c69 2005-03-18 devnull if(fd < 0)
1396 56a48c69 2005-03-18 devnull return -1;
1397 56a48c69 2005-03-18 devnull i = read(fd, buf, sizeof(buf)-1);
1398 56a48c69 2005-03-18 devnull close(fd);
1399 56a48c69 2005-03-18 devnull if(i <= 0)
1400 56a48c69 2005-03-18 devnull return -1;
1401 56a48c69 2005-03-18 devnull buf[i] = 0;
1402 56a48c69 2005-03-18 devnull p = strchr(buf, '!');
1403 56a48c69 2005-03-18 devnull if(p != nil)
1404 56a48c69 2005-03-18 devnull *p++ = 0;
1405 56a48c69 2005-03-18 devnull v4parseip(ipaddr, buf);
1406 56a48c69 2005-03-18 devnull i = atoi(p);
1407 56a48c69 2005-03-18 devnull port[0] = i>>8;
1408 56a48c69 2005-03-18 devnull port[1] = i;
1409 56a48c69 2005-03-18 devnull return 0;
1410 56a48c69 2005-03-18 devnull }
1411 56a48c69 2005-03-18 devnull
1412 56a48c69 2005-03-18 devnull void
1413 56a48c69 2005-03-18 devnull md5free(DigestState *state)
1414 56a48c69 2005-03-18 devnull {
1415 56a48c69 2005-03-18 devnull uchar x[MD5dlen];
1416 56a48c69 2005-03-18 devnull md5(nil, 0, x, state);
1417 56a48c69 2005-03-18 devnull }
1418 56a48c69 2005-03-18 devnull
1419 56a48c69 2005-03-18 devnull DigestState*
1420 56a48c69 2005-03-18 devnull md5dup(DigestState *state)
1421 56a48c69 2005-03-18 devnull {
1422 56a48c69 2005-03-18 devnull DigestState *s2;
1423 fa325e9b 2020-01-10 cross
1424 56a48c69 2005-03-18 devnull s2 = malloc(sizeof(DigestState));
1425 56a48c69 2005-03-18 devnull if(s2 == nil)
1426 56a48c69 2005-03-18 devnull sysfatal("malloc: %r");
1427 56a48c69 2005-03-18 devnull *s2 = *state;
1428 56a48c69 2005-03-18 devnull s2->malloced = 1;
1429 56a48c69 2005-03-18 devnull return s2;
1430 56a48c69 2005-03-18 devnull }
1431 56a48c69 2005-03-18 devnull
1432 56a48c69 2005-03-18 devnull void
1433 56a48c69 2005-03-18 devnull setoffset(Out *out, int offset)
1434 56a48c69 2005-03-18 devnull {
1435 56a48c69 2005-03-18 devnull md5free(out->curr);
1436 56a48c69 2005-03-18 devnull if(offset == 0)
1437 56a48c69 2005-03-18 devnull out->curr = md5(nil, 0, nil, nil);
1438 56a48c69 2005-03-18 devnull else
1439 56a48c69 2005-03-18 devnull out->curr = nil;
1440 56a48c69 2005-03-18 devnull out->offset = offset;
1441 56a48c69 2005-03-18 devnull }
1442 56a48c69 2005-03-18 devnull
1443 56a48c69 2005-03-18 devnull /*
1444 56a48c69 2005-03-18 devnull * write some output, discarding it (but keeping track)
1445 56a48c69 2005-03-18 devnull * if we've already written it. if we've gone backwards,
1446 56a48c69 2005-03-18 devnull * verify that everything previously written matches
1447 56a48c69 2005-03-18 devnull * that which would have been written from the current
1448 56a48c69 2005-03-18 devnull * output.
1449 56a48c69 2005-03-18 devnull */
1450 56a48c69 2005-03-18 devnull int
1451 56a48c69 2005-03-18 devnull output(Out *out, char *buf, int nb)
1452 56a48c69 2005-03-18 devnull {
1453 56a48c69 2005-03-18 devnull int n, d;
1454 56a48c69 2005-03-18 devnull uchar m0[MD5dlen], m1[MD5dlen];
1455 56a48c69 2005-03-18 devnull
1456 56a48c69 2005-03-18 devnull n = nb;
1457 56a48c69 2005-03-18 devnull d = out->written - out->offset;
1458 56a48c69 2005-03-18 devnull assert(d >= 0);
1459 56a48c69 2005-03-18 devnull if(d > 0){
1460 56a48c69 2005-03-18 devnull if(n < d){
1461 56a48c69 2005-03-18 devnull if(out->curr != nil)
1462 56a48c69 2005-03-18 devnull md5((uchar*)buf, n, nil, out->curr);
1463 56a48c69 2005-03-18 devnull out->offset += n;
1464 56a48c69 2005-03-18 devnull return n;
1465 56a48c69 2005-03-18 devnull }
1466 56a48c69 2005-03-18 devnull if(out->curr != nil){
1467 56a48c69 2005-03-18 devnull md5((uchar*)buf, d, m0, out->curr);
1468 56a48c69 2005-03-18 devnull out->curr = nil;
1469 56a48c69 2005-03-18 devnull md5(nil, 0, m1, md5dup(out->hiwat));
1470 56a48c69 2005-03-18 devnull if(memcmp(m0, m1, MD5dlen) != 0){
1471 56a48c69 2005-03-18 devnull fprint(2, "integrity check failure at offset %d\n", out->written);
1472 56a48c69 2005-03-18 devnull return -1;
1473 56a48c69 2005-03-18 devnull }
1474 56a48c69 2005-03-18 devnull }
1475 56a48c69 2005-03-18 devnull buf += d;
1476 56a48c69 2005-03-18 devnull n -= d;
1477 56a48c69 2005-03-18 devnull out->offset += d;
1478 56a48c69 2005-03-18 devnull }
1479 56a48c69 2005-03-18 devnull if(n > 0){
1480 56a48c69 2005-03-18 devnull out->hiwat = md5((uchar*)buf, n, nil, out->hiwat);
1481 56a48c69 2005-03-18 devnull n = write(out->fd, buf, n);
1482 56a48c69 2005-03-18 devnull if(n > 0){
1483 56a48c69 2005-03-18 devnull out->offset += n;
1484 56a48c69 2005-03-18 devnull out->written += n;
1485 56a48c69 2005-03-18 devnull }
1486 56a48c69 2005-03-18 devnull }
1487 56a48c69 2005-03-18 devnull return n + d;
1488 56a48c69 2005-03-18 devnull }