11 # define alloca __builtin_alloca
15 # define alloca _alloca
33 #include "wvhttppool.h"
34 #include "wvbufstream.h"
36 #include "wvsslstream.h"
43 cont(wv::bind(&
WvFtpStream::real_execute, this, _1))
48 last_request_time = time(0);
53 void WvFtpStream::doneurl()
55 log(
"Done URL: %s\n", curl->url);
61 last_request_time = time(0);
66 if (urls.isempty() && waiting_urls.isempty())
71 void WvFtpStream::request_next()
75 if (request_count >= max_requests || waiting_urls.isempty())
84 waiting_urls.unlink_first();
87 log(
"Request #%s: %s\n", request_count, url->url);
88 urls.append(url,
false,
"request_url");
103 if (!curl && !urls.isempty())
105 if (!curl && !waiting_urls.isempty())
106 curl = waiting_urls.first();
108 log(
"URL '%s' is FAILED\n", curl->url);
118 char *WvFtpStream::get_important_line()
127 while (line[3] ==
'-');
128 log(WvLog::Debug5,
">> %s\n", line);
142 if (curl && curl->putstream)
159 if (curl && curl->putstream && curl->putstream->
post_select(si))
168 void *WvFtpStream::real_execute(
void*)
175 log(WvLog::Debug4,
"urls count: %s\n", urls.count());
184 line = get_important_line();
191 if (strncmp(line,
"220", 3))
193 log(
"Server rejected connection: %s\n", line);
194 seterr(
"server rejected connection");
197 print(
"USER %s\r\n", !target.username ?
WvString(
"anonymous") :
199 line = get_important_line();
203 if (!strncmp(line,
"230", 3))
205 log(WvLog::Info,
"Server doesn't need password.\n");
208 else if (!strncmp(line,
"33", 2))
210 print(
"PASS %s\r\n", !password ? DEFAULT_ANON_PW : password);
212 line = get_important_line();
218 log(WvLog::Info,
"Authenticated.\n");
223 log(
"Strange response to PASS command: %s\n", line);
224 seterr(
"strange response to PASS command");
230 log(
"Strange response to USER command: %s\n", line);
231 seterr(
"strange response to USER command");
236 log(WvLog::Debug5,
"<< TYPE I\n");
237 line = get_important_line();
241 if (strncmp(line,
"200", 3))
243 log(
"Strange response to TYPE I command: %s\n", line);
244 seterr(
"strange response to TYPE I command");
249 if (!curl && !urls.isempty())
253 print(
"CWD %s\r\n", curl->url.getfile());
254 line = get_important_line();
258 if (!strncmp(line,
"250", 3))
260 log(WvLog::Debug5,
"This is a directory.\n");
265 line = get_important_line();
268 WvIPPortAddr *dataip = parse_pasv_response(line.edit());
273 log(WvLog::Debug4,
"Data port is %s.\n", *dataip);
278 log(
"Can't open data connection.\n");
279 seterr(
"can't open data connection");
285 if (!curl->putstream)
287 print(
"LIST %s\r\n", curl->url.getfile());
290 WvString url_no_pw(
"ftp://%s%s%s%s", curl->url.getuser(),
291 !!curl->url.getuser() ?
"@" :
"",
293 curl->url.getfile());
294 curl->outstream->print(
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML "
296 "<html>\n<head>\n<title>%s</title>\n"
297 "<meta http-equiv=\"Content-Type\" "
298 "content=\"text/html; "
299 "charset=ISO-8859-1\">\n"
300 "<base href=\"%s\"/>\n</head>\n"
301 "<style type=\"text/css\">\n"
302 "img { border: 0; padding: 0 2px; vertical-align: "
304 "td { font-family: monospace; padding: 2px 3px; "
305 "text-align: right; vertical-align: bottom; }\n"
306 "td:first-child { text-align: left; padding: "
307 "2px 10px 2px 3px; }\n"
308 "table { border: 0; }\n"
309 "a.symlink { font-style: italic; }\n"
311 "<h1>Index of %s</h1>\n"
312 "<hr/><table>\n", url_no_pw, curl->url, url_no_pw
318 log(
"Target is a directory.\n");
319 seterr(
"target is a directory");
324 else if (!curl->putstream)
325 print(
"RETR %s\r\n", curl->url.getfile());
328 if (curl->create_dirs)
330 print(
"CWD %s\r\n", getdirname(curl->url.getfile()));
331 line = get_important_line();
334 if (strncmp(line,
"250", 3))
336 log(
"Path doesn't exist; creating directories...\n");
340 dirs.
split(getdirname(curl->url.getfile()),
"/");
341 WvStringList::Iter i(dirs);
342 for (i.rewind(); i.next(); )
344 current_dir.append(
WvString(
"/%s", i()));
345 print(
"MKD %s\r\n", current_dir);
346 line = get_important_line();
352 print(
"STOR %s\r\n", curl->url.getfile());
355 log(WvLog::Debug5,
"Waiting for response to %s\n", curl->putstream ?
"STOR" :
356 curl->is_dir ?
"LIST" :
"RETR");
357 line = get_important_line();
361 else if (strncmp(line,
"150", 3))
363 log(
"Strange response to %s command: %s\n",
364 curl->putstream ?
"STOR" :
"RETR", line);
366 curl->putstream ?
"STOR" :
"RETR"));
377 if (line && curl->outstream)
379 WvString output_line(parse_for_links(line.edit()));
381 curl->outstream->
write(output_line);
383 curl->outstream->
write(
"Unknown format of LIST "
395 int len = curl->putstream->
read(buf,
sizeof(buf));
396 log(WvLog::Debug5,
"Read %s bytes.\n%s\n", len,
hexdump_buffer(buf, len));
400 int wrote = data->
write(buf, len);
401 log(WvLog::Debug5,
"Wrote %s bytes\n", wrote);
405 curl->putstream->
close();
411 int len = data->
read(buf,
sizeof(buf));
412 log(WvLog::Debug5,
"Read %s bytes from remote.\n", len);
414 if (len && curl->outstream)
416 int wrote = curl->outstream->
write(buf, len);
417 log(WvLog::Debug5,
"Wrote %s bytes to local.\n", wrote);
423 if (!data->
isok() || (curl->putstream && !curl->putstream->
isok()))
425 log(
"OK, we should have finished writing!\n");
426 if (curl->putstream && data->
isok())
428 line = get_important_line();
435 if (strncmp(line,
"226", 3))
436 log(
"Unexpected message: %s\n", line);
441 curl->outstream->
write(
"</table><hr/></body>\n"
444 log(WvLog::Debug5,
"Waiting for response to CWD /\n");
445 line = get_important_line();
449 if (strncmp(line,
"250", 3))
450 log(
"Strange resonse to \"CWD /\": %s\n", line);
457 log(
"Why are we here??\n");
471 WvString WvFtpStream::parse_for_links(
char *line)
476 if (curl->is_dir && curl->outstream)
479 int res =
ftpparse(&fp, line, strlen(line));
482 char *linkname = (
char *)alloca(fp.namelen+1);
484 for (i = 0; i < fp.namelen; i++)
486 if (fp.name[i] >= 32)
487 linkname[i] = fp.name[i];
496 if (linkurl.cstr()[linkurl.len()-1] !=
'/')
498 linkurl.append(linkname);
500 curl->outstream->links.append(link,
true);
502 output_line.append(
"<tr>\n");
504 output_line.append(
WvString(
" <td>%s%s</td>\n", linkname,
505 fp.flagtrycwd ?
"/" :
""));
510 output_line.append(
" <td>? bytes</td>\n");
512 output_line.append(
WvString(
" <td>%s bytes</td>\n",
514 if (fp.mtimetype > 0)
515 output_line.append(
WvString(
" <td>%s</td>\n", (fp.mtime)));
517 output_line.append(
" <td>?</td>\n");
520 output_line.append(
" <td></td>\n");
522 output_line.append(
"</tr>\n");
529 WvIPPortAddr *WvFtpStream::parse_pasv_response(
char *line)
531 if (strncmp(line,
"227 ", 4))
533 log(
"Strange response to PASV command: %s\n", line);
534 seterr(
"strange response to PASV command");
541 if (*p ==
'\0' || *p ==
'\r' || *p ==
'\n')
543 log(
"Couldn't parse PASV response: %s\n", line);
544 seterr(
"couldn't parse response to PASV command");
551 for (
int i = 0; i < 4; i++)
556 log(
"Couldn't parse PASV IP: %s\n", line);
557 seterr(
"couldn't parse PASV IP");
566 pasvport = atoi(p)*256;
570 log(
"Couldn't parse PASV IP port: %s\n", line);
571 seterr(
"couldn't parse PASV IP port");
574 pasvport += atoi(++p);