ftp_network_transaction.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "net/ftp/ftp_network_transaction.h" 6 7#include "base/bind.h" 8#include "base/bind_helpers.h" 9#include "base/compiler_specific.h" 10#include "base/metrics/histogram.h" 11#include "base/string_number_conversions.h" 12#include "base/string_util.h" 13#include "base/strings/string_split.h" 14#include "base/utf_string_conversions.h" 15#include "base/values.h" 16#include "net/base/address_list.h" 17#include "net/base/connection_type_histograms.h" 18#include "net/base/escape.h" 19#include "net/base/net_errors.h" 20#include "net/base/net_log.h" 21#include "net/base/net_util.h" 22#include "net/ftp/ftp_network_session.h" 23#include "net/ftp/ftp_request_info.h" 24#include "net/ftp/ftp_util.h" 25#include "net/socket/client_socket_factory.h" 26#include "net/socket/stream_socket.h" 27 28const char kCRLF[] = "\r\n"; 29 30const int kCtrlBufLen = 1024; 31 32namespace { 33 34// Returns true if |input| can be safely used as a part of FTP command. 35bool IsValidFTPCommandString(const std::string& input) { 36 // RFC 959 only allows ASCII strings, but at least Firefox can send non-ASCII 37 // characters in the command if the request path contains them. To be 38 // compatible, we do the same and allow non-ASCII characters in a command. 39 40 // Protect agains newline injection attack. 41 if (input.find_first_of("\r\n") != std::string::npos) 42 return false; 43 44 return true; 45} 46 47enum ErrorClass { 48 // The requested action was initiated. The client should expect another 49 // reply before issuing the next command. 50 ERROR_CLASS_INITIATED, 51 52 // The requested action has been successfully completed. 53 ERROR_CLASS_OK, 54 55 // The command has been accepted, but to complete the operation, more 56 // information must be sent by the client. 57 ERROR_CLASS_INFO_NEEDED, 58 59 // The command was not accepted and the requested action did not take place. 60 // This condition is temporary, and the client is encouraged to restart the 61 // command sequence. 62 ERROR_CLASS_TRANSIENT_ERROR, 63 64 // The command was not accepted and the requested action did not take place. 65 // This condition is rather permanent, and the client is discouraged from 66 // repeating the exact request. 67 ERROR_CLASS_PERMANENT_ERROR, 68}; 69 70// Returns the error class for given response code. Caller should ensure 71// that |response_code| is in range 100-599. 72ErrorClass GetErrorClass(int response_code) { 73 if (response_code >= 100 && response_code <= 199) 74 return ERROR_CLASS_INITIATED; 75 76 if (response_code >= 200 && response_code <= 299) 77 return ERROR_CLASS_OK; 78 79 if (response_code >= 300 && response_code <= 399) 80 return ERROR_CLASS_INFO_NEEDED; 81 82 if (response_code >= 400 && response_code <= 499) 83 return ERROR_CLASS_TRANSIENT_ERROR; 84 85 if (response_code >= 500 && response_code <= 599) 86 return ERROR_CLASS_PERMANENT_ERROR; 87 88 // We should not be called on invalid error codes. 89 NOTREACHED() << response_code; 90 return ERROR_CLASS_PERMANENT_ERROR; 91} 92 93// Returns network error code for received FTP |response_code|. 94int GetNetErrorCodeForFtpResponseCode(int response_code) { 95 switch (response_code) { 96 case 421: 97 return net::ERR_FTP_SERVICE_UNAVAILABLE; 98 case 426: 99 return net::ERR_FTP_TRANSFER_ABORTED; 100 case 450: 101 return net::ERR_FTP_FILE_BUSY; 102 case 500: 103 case 501: 104 return net::ERR_FTP_SYNTAX_ERROR; 105 case 502: 106 case 504: 107 return net::ERR_FTP_COMMAND_NOT_SUPPORTED; 108 case 503: 109 return net::ERR_FTP_BAD_COMMAND_SEQUENCE; 110 default: 111 return net::ERR_FTP_FAILED; 112 } 113} 114 115// From RFC 2428 Section 3: 116// The text returned in response to the EPSV command MUST be: 117// <some text> (<d><d><d><tcp-port><d>) 118// <d> is a delimiter character, ideally to be | 119bool ExtractPortFromEPSVResponse(const net::FtpCtrlResponse& response, 120 int* port) { 121 if (response.lines.size() != 1) 122 return false; 123 const char* ptr = response.lines[0].c_str(); 124 while (*ptr && *ptr != '(') 125 ++ptr; 126 if (!*ptr) 127 return false; 128 char sep = *(++ptr); 129 if (!sep || isdigit(sep) || *(++ptr) != sep || *(++ptr) != sep) 130 return false; 131 if (!isdigit(*(++ptr))) 132 return false; 133 *port = *ptr - '0'; 134 while (isdigit(*(++ptr))) { 135 *port *= 10; 136 *port += *ptr - '0'; 137 } 138 if (*ptr != sep) 139 return false; 140 141 return true; 142} 143 144// There are two way we can receive IP address and port. 145// (127,0,0,1,23,21) IP address and port encapsulated in (). 146// 127,0,0,1,23,21 IP address and port without (). 147// 148// See RFC 959, Section 4.1.2 149bool ExtractPortFromPASVResponse(const net::FtpCtrlResponse& response, 150 int* port) { 151 if (response.lines.size() != 1) 152 return false; 153 154 std::string line(response.lines[0]); 155 if (!IsStringASCII(line)) 156 return false; 157 if (line.length() < 2) 158 return false; 159 160 size_t paren_pos = line.find('('); 161 if (paren_pos == std::string::npos) { 162 // Find the first comma and use it to locate the beginning 163 // of the response data. 164 size_t comma_pos = line.find(','); 165 if (comma_pos == std::string::npos) 166 return false; 167 168 size_t space_pos = line.rfind(' ', comma_pos); 169 if (space_pos != std::string::npos) 170 line = line.substr(space_pos + 1); 171 } else { 172 // Remove the parentheses and use the text inside them. 173 size_t closing_paren_pos = line.rfind(')'); 174 if (closing_paren_pos == std::string::npos) 175 return false; 176 if (closing_paren_pos <= paren_pos) 177 return false; 178 179 line = line.substr(paren_pos + 1, closing_paren_pos - paren_pos - 1); 180 } 181 182 // Split the line into comma-separated pieces and extract 183 // the last two. 184 std::vector<std::string> pieces; 185 base::SplitString(line, ',', &pieces); 186 if (pieces.size() != 6) 187 return false; 188 189 // Ignore the IP address supplied in the response. We are always going 190 // to connect back to the same server to prevent FTP PASV port scanning. 191 int p0, p1; 192 if (!base::StringToInt(pieces[4], &p0)) 193 return false; 194 if (!base::StringToInt(pieces[5], &p1)) 195 return false; 196 *port = (p0 << 8) + p1; 197 198 return true; 199} 200 201} // namespace 202 203namespace net { 204 205FtpNetworkTransaction::FtpNetworkTransaction( 206 FtpNetworkSession* session, 207 ClientSocketFactory* socket_factory) 208 : command_sent_(COMMAND_NONE), 209 io_callback_(base::Bind(&FtpNetworkTransaction::OnIOComplete, 210 base::Unretained(this))), 211 session_(session), 212 request_(NULL), 213 resolver_(session->host_resolver()), 214 read_ctrl_buf_(new IOBuffer(kCtrlBufLen)), 215 ctrl_response_buffer_(NULL), 216 read_data_buf_len_(0), 217 last_error_(OK), 218 system_type_(SYSTEM_TYPE_UNKNOWN), 219 // Use image (binary) transfer by default. It should always work, 220 // whereas the ascii transfer may damage binary data. 221 data_type_(DATA_TYPE_IMAGE), 222 resource_type_(RESOURCE_TYPE_UNKNOWN), 223 use_epsv_(true), 224 data_connection_port_(0), 225 socket_factory_(socket_factory), 226 next_state_(STATE_NONE), 227 state_after_data_connect_complete_(STATE_CTRL_WRITE_SIZE) { 228} 229 230FtpNetworkTransaction::~FtpNetworkTransaction() { 231} 232 233int FtpNetworkTransaction::Stop(int error) { 234 if (command_sent_ == COMMAND_QUIT) 235 return error; 236 237 next_state_ = STATE_CTRL_WRITE_QUIT; 238 last_error_ = error; 239 return OK; 240} 241 242int FtpNetworkTransaction::RestartIgnoringLastError( 243 const CompletionCallback& callback) { 244 return ERR_NOT_IMPLEMENTED; 245} 246 247int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info, 248 const CompletionCallback& callback, 249 const BoundNetLog& net_log) { 250 net_log_ = net_log; 251 request_ = request_info; 252 253 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_)); 254 255 if (request_->url.has_username()) { 256 base::string16 username; 257 base::string16 password; 258 GetIdentityFromURL(request_->url, &username, &password); 259 credentials_.Set(username, password); 260 } else { 261 credentials_.Set(ASCIIToUTF16("anonymous"), 262 ASCIIToUTF16("chrome@example.com")); 263 } 264 265 DetectTypecode(); 266 267 next_state_ = STATE_CTRL_RESOLVE_HOST; 268 int rv = DoLoop(OK); 269 if (rv == ERR_IO_PENDING) 270 user_callback_ = callback; 271 return rv; 272} 273 274int FtpNetworkTransaction::RestartWithAuth(const AuthCredentials& credentials, 275 const CompletionCallback& callback) { 276 ResetStateForRestart(); 277 278 credentials_ = credentials; 279 280 next_state_ = STATE_CTRL_RESOLVE_HOST; 281 int rv = DoLoop(OK); 282 if (rv == ERR_IO_PENDING) 283 user_callback_ = callback; 284 return rv; 285} 286 287int FtpNetworkTransaction::Read(IOBuffer* buf, 288 int buf_len, 289 const CompletionCallback& callback) { 290 DCHECK(buf); 291 DCHECK_GT(buf_len, 0); 292 293 read_data_buf_ = buf; 294 read_data_buf_len_ = buf_len; 295 296 next_state_ = STATE_DATA_READ; 297 int rv = DoLoop(OK); 298 if (rv == ERR_IO_PENDING) 299 user_callback_ = callback; 300 return rv; 301} 302 303const FtpResponseInfo* FtpNetworkTransaction::GetResponseInfo() const { 304 return &response_; 305} 306 307LoadState FtpNetworkTransaction::GetLoadState() const { 308 if (next_state_ == STATE_CTRL_RESOLVE_HOST_COMPLETE) 309 return LOAD_STATE_RESOLVING_HOST; 310 311 if (next_state_ == STATE_CTRL_CONNECT_COMPLETE || 312 next_state_ == STATE_DATA_CONNECT_COMPLETE) 313 return LOAD_STATE_CONNECTING; 314 315 if (next_state_ == STATE_DATA_READ_COMPLETE) 316 return LOAD_STATE_READING_RESPONSE; 317 318 if (command_sent_ == COMMAND_RETR && read_data_buf_.get()) 319 return LOAD_STATE_READING_RESPONSE; 320 321 if (command_sent_ == COMMAND_QUIT) 322 return LOAD_STATE_IDLE; 323 324 if (command_sent_ != COMMAND_NONE) 325 return LOAD_STATE_SENDING_REQUEST; 326 327 return LOAD_STATE_IDLE; 328} 329 330uint64 FtpNetworkTransaction::GetUploadProgress() const { 331 return 0; 332} 333 334void FtpNetworkTransaction::ResetStateForRestart() { 335 command_sent_ = COMMAND_NONE; 336 user_callback_.Reset(); 337 response_ = FtpResponseInfo(); 338 read_ctrl_buf_ = new IOBuffer(kCtrlBufLen); 339 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_)); 340 read_data_buf_ = NULL; 341 read_data_buf_len_ = 0; 342 if (write_buf_) 343 write_buf_->SetOffset(0); 344 last_error_ = OK; 345 data_connection_port_ = 0; 346 ctrl_socket_.reset(); 347 data_socket_.reset(); 348 next_state_ = STATE_NONE; 349 state_after_data_connect_complete_ = STATE_CTRL_WRITE_SIZE; 350} 351 352void FtpNetworkTransaction::ResetDataConnectionAfterError(State next_state) { 353 // The server _might_ have reset the data connection 354 // (see RFC 959 3.2. ESTABLISHING DATA CONNECTIONS: 355 // "The server MUST close the data connection under the following 356 // conditions: 357 // ... 358 // 5. An irrecoverable error condition occurs.") 359 // 360 // It is ambiguous what an irrecoverable error condition is, 361 // so we take no chances. 362 state_after_data_connect_complete_ = next_state; 363 next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; 364} 365 366void FtpNetworkTransaction::DoCallback(int rv) { 367 DCHECK(rv != ERR_IO_PENDING); 368 DCHECK(!user_callback_.is_null()); 369 370 // Since Run may result in Read being called, clear callback_ up front. 371 CompletionCallback c = user_callback_; 372 user_callback_.Reset(); 373 c.Run(rv); 374} 375 376void FtpNetworkTransaction::OnIOComplete(int result) { 377 int rv = DoLoop(result); 378 if (rv != ERR_IO_PENDING) 379 DoCallback(rv); 380} 381 382int FtpNetworkTransaction::ProcessCtrlResponse() { 383 FtpCtrlResponse response = ctrl_response_buffer_->PopResponse(); 384 385 int rv = OK; 386 switch (command_sent_) { 387 case COMMAND_NONE: 388 // TODO(phajdan.jr): Check for errors in the welcome message. 389 next_state_ = STATE_CTRL_WRITE_USER; 390 break; 391 case COMMAND_USER: 392 rv = ProcessResponseUSER(response); 393 break; 394 case COMMAND_PASS: 395 rv = ProcessResponsePASS(response); 396 break; 397 case COMMAND_SYST: 398 rv = ProcessResponseSYST(response); 399 break; 400 case COMMAND_PWD: 401 rv = ProcessResponsePWD(response); 402 break; 403 case COMMAND_TYPE: 404 rv = ProcessResponseTYPE(response); 405 break; 406 case COMMAND_EPSV: 407 rv = ProcessResponseEPSV(response); 408 break; 409 case COMMAND_PASV: 410 rv = ProcessResponsePASV(response); 411 break; 412 case COMMAND_SIZE: 413 rv = ProcessResponseSIZE(response); 414 break; 415 case COMMAND_RETR: 416 rv = ProcessResponseRETR(response); 417 break; 418 case COMMAND_CWD: 419 rv = ProcessResponseCWD(response); 420 break; 421 case COMMAND_LIST: 422 rv = ProcessResponseLIST(response); 423 break; 424 case COMMAND_QUIT: 425 rv = ProcessResponseQUIT(response); 426 break; 427 default: 428 LOG(DFATAL) << "Unexpected value of command_sent_: " << command_sent_; 429 return ERR_UNEXPECTED; 430 } 431 432 // We may get multiple responses for some commands, 433 // see http://crbug.com/18036. 434 while (ctrl_response_buffer_->ResponseAvailable() && rv == OK) { 435 response = ctrl_response_buffer_->PopResponse(); 436 437 switch (command_sent_) { 438 case COMMAND_RETR: 439 rv = ProcessResponseRETR(response); 440 break; 441 case COMMAND_LIST: 442 rv = ProcessResponseLIST(response); 443 break; 444 default: 445 // Multiple responses for other commands are invalid. 446 return Stop(ERR_INVALID_RESPONSE); 447 } 448 } 449 450 return rv; 451} 452 453// Used to prepare and send FTP command. 454int FtpNetworkTransaction::SendFtpCommand(const std::string& command, 455 const std::string& command_for_log, 456 Command cmd) { 457 // If we send a new command when we still have unprocessed responses 458 // for previous commands, the response receiving code will have no way to know 459 // which responses are for which command. 460 DCHECK(!ctrl_response_buffer_->ResponseAvailable()); 461 462 DCHECK(!write_command_buf_); 463 DCHECK(!write_buf_); 464 465 if (!IsValidFTPCommandString(command)) { 466 // Callers should validate the command themselves and return a more specific 467 // error code. 468 NOTREACHED(); 469 return Stop(ERR_UNEXPECTED); 470 } 471 472 command_sent_ = cmd; 473 474 write_command_buf_ = new IOBufferWithSize(command.length() + 2); 475 write_buf_ = new DrainableIOBuffer(write_command_buf_, 476 write_command_buf_->size()); 477 memcpy(write_command_buf_->data(), command.data(), command.length()); 478 memcpy(write_command_buf_->data() + command.length(), kCRLF, 2); 479 480 net_log_.AddEvent(NetLog::TYPE_FTP_COMMAND_SENT, 481 NetLog::StringCallback("command", &command_for_log)); 482 483 next_state_ = STATE_CTRL_WRITE; 484 return OK; 485} 486 487std::string FtpNetworkTransaction::GetRequestPathForFtpCommand( 488 bool is_directory) const { 489 std::string path(current_remote_directory_); 490 if (request_->url.has_path()) { 491 std::string gurl_path(request_->url.path()); 492 493 // Get rid of the typecode, see RFC 1738 section 3.2.2. FTP url-path. 494 std::string::size_type pos = gurl_path.rfind(';'); 495 if (pos != std::string::npos) 496 gurl_path.resize(pos); 497 498 path.append(gurl_path); 499 } 500 // Make sure that if the path is expected to be a file, it won't end 501 // with a trailing slash. 502 if (!is_directory && path.length() > 1 && path[path.length() - 1] == '/') 503 path.erase(path.length() - 1); 504 UnescapeRule::Type unescape_rules = UnescapeRule::SPACES | 505 UnescapeRule::URL_SPECIAL_CHARS; 506 // This may unescape to non-ASCII characters, but we allow that. See the 507 // comment for IsValidFTPCommandString. 508 path = net::UnescapeURLComponent(path, unescape_rules); 509 510 if (system_type_ == SYSTEM_TYPE_VMS) { 511 if (is_directory) 512 path = FtpUtil::UnixDirectoryPathToVMS(path); 513 else 514 path = FtpUtil::UnixFilePathToVMS(path); 515 } 516 517 DCHECK(IsValidFTPCommandString(path)); 518 return path; 519} 520 521void FtpNetworkTransaction::DetectTypecode() { 522 if (!request_->url.has_path()) 523 return; 524 std::string gurl_path(request_->url.path()); 525 526 // Extract the typecode, see RFC 1738 section 3.2.2. FTP url-path. 527 std::string::size_type pos = gurl_path.rfind(';'); 528 if (pos == std::string::npos) 529 return; 530 std::string typecode_string(gurl_path.substr(pos)); 531 if (typecode_string == ";type=a") { 532 data_type_ = DATA_TYPE_ASCII; 533 resource_type_ = RESOURCE_TYPE_FILE; 534 } else if (typecode_string == ";type=i") { 535 data_type_ = DATA_TYPE_IMAGE; 536 resource_type_ = RESOURCE_TYPE_FILE; 537 } else if (typecode_string == ";type=d") { 538 resource_type_ = RESOURCE_TYPE_DIRECTORY; 539 } 540} 541 542int FtpNetworkTransaction::DoLoop(int result) { 543 DCHECK(next_state_ != STATE_NONE); 544 545 int rv = result; 546 do { 547 State state = next_state_; 548 next_state_ = STATE_NONE; 549 switch (state) { 550 case STATE_CTRL_RESOLVE_HOST: 551 DCHECK(rv == OK); 552 rv = DoCtrlResolveHost(); 553 break; 554 case STATE_CTRL_RESOLVE_HOST_COMPLETE: 555 rv = DoCtrlResolveHostComplete(rv); 556 break; 557 case STATE_CTRL_CONNECT: 558 DCHECK(rv == OK); 559 rv = DoCtrlConnect(); 560 break; 561 case STATE_CTRL_CONNECT_COMPLETE: 562 rv = DoCtrlConnectComplete(rv); 563 break; 564 case STATE_CTRL_READ: 565 DCHECK(rv == OK); 566 rv = DoCtrlRead(); 567 break; 568 case STATE_CTRL_READ_COMPLETE: 569 rv = DoCtrlReadComplete(rv); 570 break; 571 case STATE_CTRL_WRITE: 572 DCHECK(rv == OK); 573 rv = DoCtrlWrite(); 574 break; 575 case STATE_CTRL_WRITE_COMPLETE: 576 rv = DoCtrlWriteComplete(rv); 577 break; 578 case STATE_CTRL_WRITE_USER: 579 DCHECK(rv == OK); 580 rv = DoCtrlWriteUSER(); 581 break; 582 case STATE_CTRL_WRITE_PASS: 583 DCHECK(rv == OK); 584 rv = DoCtrlWritePASS(); 585 break; 586 case STATE_CTRL_WRITE_SYST: 587 DCHECK(rv == OK); 588 rv = DoCtrlWriteSYST(); 589 break; 590 case STATE_CTRL_WRITE_PWD: 591 DCHECK(rv == OK); 592 rv = DoCtrlWritePWD(); 593 break; 594 case STATE_CTRL_WRITE_TYPE: 595 DCHECK(rv == OK); 596 rv = DoCtrlWriteTYPE(); 597 break; 598 case STATE_CTRL_WRITE_EPSV: 599 DCHECK(rv == OK); 600 rv = DoCtrlWriteEPSV(); 601 break; 602 case STATE_CTRL_WRITE_PASV: 603 DCHECK(rv == OK); 604 rv = DoCtrlWritePASV(); 605 break; 606 case STATE_CTRL_WRITE_RETR: 607 DCHECK(rv == OK); 608 rv = DoCtrlWriteRETR(); 609 break; 610 case STATE_CTRL_WRITE_SIZE: 611 DCHECK(rv == OK); 612 rv = DoCtrlWriteSIZE(); 613 break; 614 case STATE_CTRL_WRITE_CWD: 615 DCHECK(rv == OK); 616 rv = DoCtrlWriteCWD(); 617 break; 618 case STATE_CTRL_WRITE_LIST: 619 DCHECK(rv == OK); 620 rv = DoCtrlWriteLIST(); 621 break; 622 case STATE_CTRL_WRITE_QUIT: 623 DCHECK(rv == OK); 624 rv = DoCtrlWriteQUIT(); 625 break; 626 case STATE_DATA_CONNECT: 627 DCHECK(rv == OK); 628 rv = DoDataConnect(); 629 break; 630 case STATE_DATA_CONNECT_COMPLETE: 631 rv = DoDataConnectComplete(rv); 632 break; 633 case STATE_DATA_READ: 634 DCHECK(rv == OK); 635 rv = DoDataRead(); 636 break; 637 case STATE_DATA_READ_COMPLETE: 638 rv = DoDataReadComplete(rv); 639 break; 640 default: 641 NOTREACHED() << "bad state"; 642 rv = ERR_UNEXPECTED; 643 break; 644 } 645 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); 646 return rv; 647} 648 649int FtpNetworkTransaction::DoCtrlResolveHost() { 650 next_state_ = STATE_CTRL_RESOLVE_HOST_COMPLETE; 651 652 HostResolver::RequestInfo info(HostPortPair::FromURL(request_->url)); 653 // No known referrer. 654 return resolver_.Resolve( 655 info, &addresses_, 656 base::Bind(&FtpNetworkTransaction::OnIOComplete, base::Unretained(this)), 657 net_log_); 658} 659 660int FtpNetworkTransaction::DoCtrlResolveHostComplete(int result) { 661 if (result == OK) 662 next_state_ = STATE_CTRL_CONNECT; 663 return result; 664} 665 666int FtpNetworkTransaction::DoCtrlConnect() { 667 next_state_ = STATE_CTRL_CONNECT_COMPLETE; 668 ctrl_socket_.reset(socket_factory_->CreateTransportClientSocket( 669 addresses_, net_log_.net_log(), net_log_.source())); 670 net_log_.AddEvent( 671 NetLog::TYPE_FTP_CONTROL_CONNECTION, 672 ctrl_socket_->NetLog().source().ToEventParametersCallback()); 673 return ctrl_socket_->Connect(io_callback_); 674} 675 676int FtpNetworkTransaction::DoCtrlConnectComplete(int result) { 677 if (result == OK) { 678 // Put the peer's IP address and port into the response. 679 IPEndPoint ip_endpoint; 680 result = ctrl_socket_->GetPeerAddress(&ip_endpoint); 681 if (result == OK) { 682 response_.socket_address = HostPortPair::FromIPEndPoint(ip_endpoint); 683 next_state_ = STATE_CTRL_READ; 684 685 if (ip_endpoint.GetFamily() == ADDRESS_FAMILY_IPV4) { 686 // Do not use EPSV for IPv4 connections. Some servers become confused 687 // and we time out while waiting to connect. PASV is perfectly fine for 688 // IPv4. Note that this blacklists IPv4 not to use EPSV instead of 689 // whitelisting IPv6 to use it, to make the code more future-proof: 690 // all future protocols should just use EPSV. 691 use_epsv_ = false; 692 } 693 } 694 } 695 return result; 696} 697 698int FtpNetworkTransaction::DoCtrlRead() { 699 next_state_ = STATE_CTRL_READ_COMPLETE; 700 return ctrl_socket_->Read(read_ctrl_buf_, kCtrlBufLen, io_callback_); 701} 702 703int FtpNetworkTransaction::DoCtrlReadComplete(int result) { 704 if (result == 0) { 705 // Some servers (for example Pure-FTPd) apparently close the control 706 // connection when anonymous login is not permitted. For more details 707 // see http://crbug.com/25023. 708 if (command_sent_ == COMMAND_USER && 709 credentials_.username() == ASCIIToUTF16("anonymous")) { 710 response_.needs_auth = true; 711 } 712 return Stop(ERR_EMPTY_RESPONSE); 713 } 714 if (result < 0) 715 return Stop(result); 716 717 ctrl_response_buffer_->ConsumeData(read_ctrl_buf_->data(), result); 718 719 if (!ctrl_response_buffer_->ResponseAvailable()) { 720 // Read more data from the control socket. 721 next_state_ = STATE_CTRL_READ; 722 return OK; 723 } 724 725 return ProcessCtrlResponse(); 726} 727 728int FtpNetworkTransaction::DoCtrlWrite() { 729 next_state_ = STATE_CTRL_WRITE_COMPLETE; 730 731 return ctrl_socket_->Write(write_buf_, 732 write_buf_->BytesRemaining(), 733 io_callback_); 734} 735 736int FtpNetworkTransaction::DoCtrlWriteComplete(int result) { 737 if (result < 0) 738 return result; 739 740 write_buf_->DidConsume(result); 741 if (write_buf_->BytesRemaining() == 0) { 742 // Clear the write buffer. 743 write_buf_ = NULL; 744 write_command_buf_ = NULL; 745 746 next_state_ = STATE_CTRL_READ; 747 } else { 748 next_state_ = STATE_CTRL_WRITE; 749 } 750 return OK; 751} 752 753// FTP Commands and responses 754 755// USER Command. 756int FtpNetworkTransaction::DoCtrlWriteUSER() { 757 std::string command = "USER " + UTF16ToUTF8(credentials_.username()); 758 759 if (!IsValidFTPCommandString(command)) 760 return Stop(ERR_MALFORMED_IDENTITY); 761 762 next_state_ = STATE_CTRL_READ; 763 return SendFtpCommand(command, "USER ***", COMMAND_USER); 764} 765 766int FtpNetworkTransaction::ProcessResponseUSER( 767 const FtpCtrlResponse& response) { 768 switch (GetErrorClass(response.status_code)) { 769 case ERROR_CLASS_OK: 770 next_state_ = STATE_CTRL_WRITE_SYST; 771 break; 772 case ERROR_CLASS_INFO_NEEDED: 773 next_state_ = STATE_CTRL_WRITE_PASS; 774 break; 775 case ERROR_CLASS_TRANSIENT_ERROR: 776 case ERROR_CLASS_PERMANENT_ERROR: 777 response_.needs_auth = true; 778 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 779 default: 780 NOTREACHED(); 781 return Stop(ERR_UNEXPECTED); 782 } 783 return OK; 784} 785 786// PASS command. 787int FtpNetworkTransaction::DoCtrlWritePASS() { 788 std::string command = "PASS " + UTF16ToUTF8(credentials_.password()); 789 790 if (!IsValidFTPCommandString(command)) 791 return Stop(ERR_MALFORMED_IDENTITY); 792 793 next_state_ = STATE_CTRL_READ; 794 return SendFtpCommand(command, "PASS ***", COMMAND_PASS); 795} 796 797int FtpNetworkTransaction::ProcessResponsePASS( 798 const FtpCtrlResponse& response) { 799 switch (GetErrorClass(response.status_code)) { 800 case ERROR_CLASS_OK: 801 next_state_ = STATE_CTRL_WRITE_SYST; 802 break; 803 case ERROR_CLASS_INFO_NEEDED: 804 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 805 case ERROR_CLASS_TRANSIENT_ERROR: 806 case ERROR_CLASS_PERMANENT_ERROR: 807 response_.needs_auth = true; 808 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 809 default: 810 NOTREACHED(); 811 return Stop(ERR_UNEXPECTED); 812 } 813 return OK; 814} 815 816// SYST command. 817int FtpNetworkTransaction::DoCtrlWriteSYST() { 818 std::string command = "SYST"; 819 next_state_ = STATE_CTRL_READ; 820 return SendFtpCommand(command, command, COMMAND_SYST); 821} 822 823int FtpNetworkTransaction::ProcessResponseSYST( 824 const FtpCtrlResponse& response) { 825 switch (GetErrorClass(response.status_code)) { 826 case ERROR_CLASS_INITIATED: 827 return Stop(ERR_INVALID_RESPONSE); 828 case ERROR_CLASS_OK: { 829 // All important info should be on the first line. 830 std::string line = response.lines[0]; 831 // The response should be ASCII, which allows us to do case-insensitive 832 // comparisons easily. If it is not ASCII, we leave the system type 833 // as unknown. 834 if (IsStringASCII(line)) { 835 line = StringToLowerASCII(line); 836 837 // Remove all whitespace, to correctly handle cases like fancy "V M S" 838 // response instead of "VMS". 839 RemoveChars(line, kWhitespaceASCII, &line); 840 841 // The "magic" strings we test for below have been gathered by an 842 // empirical study. VMS needs to come first because some VMS systems 843 // also respond with "UNIX emulation", which is not perfect. It is much 844 // more reliable to talk to these servers in their native language. 845 if (line.find("vms") != std::string::npos) { 846 system_type_ = SYSTEM_TYPE_VMS; 847 } else if (line.find("l8") != std::string::npos || 848 line.find("unix") != std::string::npos || 849 line.find("bsd") != std::string::npos) { 850 system_type_ = SYSTEM_TYPE_UNIX; 851 } else if (line.find("win32") != std::string::npos || 852 line.find("windows") != std::string::npos) { 853 system_type_ = SYSTEM_TYPE_WINDOWS; 854 } else if (line.find("os/2") != std::string::npos) { 855 system_type_ = SYSTEM_TYPE_OS2; 856 } 857 } 858 next_state_ = STATE_CTRL_WRITE_PWD; 859 break; 860 } 861 case ERROR_CLASS_INFO_NEEDED: 862 return Stop(ERR_INVALID_RESPONSE); 863 case ERROR_CLASS_TRANSIENT_ERROR: 864 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 865 case ERROR_CLASS_PERMANENT_ERROR: 866 // Server does not recognize the SYST command so proceed. 867 next_state_ = STATE_CTRL_WRITE_PWD; 868 break; 869 default: 870 NOTREACHED(); 871 return Stop(ERR_UNEXPECTED); 872 } 873 return OK; 874} 875 876// PWD command. 877int FtpNetworkTransaction::DoCtrlWritePWD() { 878 std::string command = "PWD"; 879 next_state_ = STATE_CTRL_READ; 880 return SendFtpCommand(command, command, COMMAND_PWD); 881} 882 883int FtpNetworkTransaction::ProcessResponsePWD(const FtpCtrlResponse& response) { 884 switch (GetErrorClass(response.status_code)) { 885 case ERROR_CLASS_INITIATED: 886 return Stop(ERR_INVALID_RESPONSE); 887 case ERROR_CLASS_OK: { 888 // The info we look for should be on the first line. 889 std::string line = response.lines[0]; 890 if (line.empty()) 891 return Stop(ERR_INVALID_RESPONSE); 892 std::string::size_type quote_pos = line.find('"'); 893 if (quote_pos != std::string::npos) { 894 line = line.substr(quote_pos + 1); 895 quote_pos = line.find('"'); 896 if (quote_pos == std::string::npos) 897 return Stop(ERR_INVALID_RESPONSE); 898 line = line.substr(0, quote_pos); 899 } 900 if (system_type_ == SYSTEM_TYPE_VMS) 901 line = FtpUtil::VMSPathToUnix(line); 902 if (line.length() && line[line.length() - 1] == '/') 903 line.erase(line.length() - 1); 904 current_remote_directory_ = line; 905 next_state_ = STATE_CTRL_WRITE_TYPE; 906 break; 907 } 908 case ERROR_CLASS_INFO_NEEDED: 909 return Stop(ERR_INVALID_RESPONSE); 910 case ERROR_CLASS_TRANSIENT_ERROR: 911 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 912 case ERROR_CLASS_PERMANENT_ERROR: 913 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 914 default: 915 NOTREACHED(); 916 return Stop(ERR_UNEXPECTED); 917 } 918 return OK; 919} 920 921// TYPE command. 922int FtpNetworkTransaction::DoCtrlWriteTYPE() { 923 std::string command = "TYPE "; 924 if (data_type_ == DATA_TYPE_ASCII) { 925 command += "A"; 926 } else if (data_type_ == DATA_TYPE_IMAGE) { 927 command += "I"; 928 } else { 929 NOTREACHED(); 930 return Stop(ERR_UNEXPECTED); 931 } 932 next_state_ = STATE_CTRL_READ; 933 return SendFtpCommand(command, command, COMMAND_TYPE); 934} 935 936int FtpNetworkTransaction::ProcessResponseTYPE( 937 const FtpCtrlResponse& response) { 938 switch (GetErrorClass(response.status_code)) { 939 case ERROR_CLASS_INITIATED: 940 return Stop(ERR_INVALID_RESPONSE); 941 case ERROR_CLASS_OK: 942 next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; 943 break; 944 case ERROR_CLASS_INFO_NEEDED: 945 return Stop(ERR_INVALID_RESPONSE); 946 case ERROR_CLASS_TRANSIENT_ERROR: 947 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 948 case ERROR_CLASS_PERMANENT_ERROR: 949 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 950 default: 951 NOTREACHED(); 952 return Stop(ERR_UNEXPECTED); 953 } 954 return OK; 955} 956 957// EPSV command 958int FtpNetworkTransaction::DoCtrlWriteEPSV() { 959 const std::string command = "EPSV"; 960 next_state_ = STATE_CTRL_READ; 961 return SendFtpCommand(command, command, COMMAND_EPSV); 962} 963 964int FtpNetworkTransaction::ProcessResponseEPSV( 965 const FtpCtrlResponse& response) { 966 switch (GetErrorClass(response.status_code)) { 967 case ERROR_CLASS_INITIATED: 968 return Stop(ERR_INVALID_RESPONSE); 969 case ERROR_CLASS_OK: 970 if (!ExtractPortFromEPSVResponse( response, &data_connection_port_)) 971 return Stop(ERR_INVALID_RESPONSE); 972 if (data_connection_port_ < 1024 || 973 !IsPortAllowedByFtp(data_connection_port_)) 974 return Stop(ERR_UNSAFE_PORT); 975 next_state_ = STATE_DATA_CONNECT; 976 break; 977 case ERROR_CLASS_INFO_NEEDED: 978 return Stop(ERR_INVALID_RESPONSE); 979 case ERROR_CLASS_TRANSIENT_ERROR: 980 case ERROR_CLASS_PERMANENT_ERROR: 981 use_epsv_ = false; 982 next_state_ = STATE_CTRL_WRITE_PASV; 983 return OK; 984 default: 985 NOTREACHED(); 986 return Stop(ERR_UNEXPECTED); 987 } 988 return OK; 989} 990 991// PASV command 992int FtpNetworkTransaction::DoCtrlWritePASV() { 993 std::string command = "PASV"; 994 next_state_ = STATE_CTRL_READ; 995 return SendFtpCommand(command, command, COMMAND_PASV); 996} 997 998int FtpNetworkTransaction::ProcessResponsePASV( 999 const FtpCtrlResponse& response) { 1000 switch (GetErrorClass(response.status_code)) { 1001 case ERROR_CLASS_INITIATED: 1002 return Stop(ERR_INVALID_RESPONSE); 1003 case ERROR_CLASS_OK: 1004 if (!ExtractPortFromPASVResponse(response, &data_connection_port_)) 1005 return Stop(ERR_INVALID_RESPONSE); 1006 if (data_connection_port_ < 1024 || 1007 !IsPortAllowedByFtp(data_connection_port_)) 1008 return Stop(ERR_UNSAFE_PORT); 1009 next_state_ = STATE_DATA_CONNECT; 1010 break; 1011 case ERROR_CLASS_INFO_NEEDED: 1012 return Stop(ERR_INVALID_RESPONSE); 1013 case ERROR_CLASS_TRANSIENT_ERROR: 1014 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1015 case ERROR_CLASS_PERMANENT_ERROR: 1016 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1017 default: 1018 NOTREACHED(); 1019 return Stop(ERR_UNEXPECTED); 1020 } 1021 return OK; 1022} 1023 1024// RETR command 1025int FtpNetworkTransaction::DoCtrlWriteRETR() { 1026 std::string command = "RETR " + GetRequestPathForFtpCommand(false); 1027 next_state_ = STATE_CTRL_READ; 1028 return SendFtpCommand(command, command, COMMAND_RETR); 1029} 1030 1031int FtpNetworkTransaction::ProcessResponseRETR( 1032 const FtpCtrlResponse& response) { 1033 switch (GetErrorClass(response.status_code)) { 1034 case ERROR_CLASS_INITIATED: 1035 // We want the client to start reading the response at this point. 1036 // It got here either through Start or RestartWithAuth. We want that 1037 // method to complete. Not setting next state here will make DoLoop exit 1038 // and in turn make Start/RestartWithAuth complete. 1039 resource_type_ = RESOURCE_TYPE_FILE; 1040 break; 1041 case ERROR_CLASS_OK: 1042 resource_type_ = RESOURCE_TYPE_FILE; 1043 next_state_ = STATE_CTRL_WRITE_QUIT; 1044 break; 1045 case ERROR_CLASS_INFO_NEEDED: 1046 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1047 case ERROR_CLASS_TRANSIENT_ERROR: 1048 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1049 case ERROR_CLASS_PERMANENT_ERROR: 1050 // Code 550 means "Failed to open file". Other codes are unrelated, 1051 // like "Not logged in" etc. 1052 if (response.status_code != 550 || resource_type_ == RESOURCE_TYPE_FILE) 1053 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1054 1055 // It's possible that RETR failed because the path is a directory. 1056 resource_type_ = RESOURCE_TYPE_DIRECTORY; 1057 1058 // We're going to try CWD next, but first send a PASV one more time, 1059 // because some FTP servers, including FileZilla, require that. 1060 // See http://crbug.com/25316. 1061 next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; 1062 break; 1063 default: 1064 NOTREACHED(); 1065 return Stop(ERR_UNEXPECTED); 1066 } 1067 1068 // We should be sure about our resource type now. Otherwise we risk 1069 // an infinite loop (RETR can later send CWD, and CWD can later send RETR). 1070 DCHECK_NE(RESOURCE_TYPE_UNKNOWN, resource_type_); 1071 1072 return OK; 1073} 1074 1075// SIZE command 1076int FtpNetworkTransaction::DoCtrlWriteSIZE() { 1077 std::string command = "SIZE " + GetRequestPathForFtpCommand(false); 1078 next_state_ = STATE_CTRL_READ; 1079 return SendFtpCommand(command, command, COMMAND_SIZE); 1080} 1081 1082int FtpNetworkTransaction::ProcessResponseSIZE( 1083 const FtpCtrlResponse& response) { 1084 State state_after_size; 1085 if (resource_type_ == RESOURCE_TYPE_FILE) 1086 state_after_size = STATE_CTRL_WRITE_RETR; 1087 else 1088 state_after_size = STATE_CTRL_WRITE_CWD; 1089 1090 switch (GetErrorClass(response.status_code)) { 1091 case ERROR_CLASS_INITIATED: 1092 next_state_ = state_after_size; 1093 break; 1094 case ERROR_CLASS_OK: 1095 if (response.lines.size() != 1) 1096 return Stop(ERR_INVALID_RESPONSE); 1097 int64 size; 1098 if (!base::StringToInt64(response.lines[0], &size)) 1099 return Stop(ERR_INVALID_RESPONSE); 1100 if (size < 0) 1101 return Stop(ERR_INVALID_RESPONSE); 1102 1103 // A successful response to SIZE does not mean the resource is a file. 1104 // Some FTP servers (for example, the qnx one) send a SIZE even for 1105 // directories. 1106 response_.expected_content_size = size; 1107 1108 next_state_ = state_after_size; 1109 break; 1110 case ERROR_CLASS_INFO_NEEDED: 1111 next_state_ = state_after_size; 1112 break; 1113 case ERROR_CLASS_TRANSIENT_ERROR: 1114 ResetDataConnectionAfterError(state_after_size); 1115 break; 1116 case ERROR_CLASS_PERMANENT_ERROR: 1117 // It's possible that SIZE failed because the path is a directory. 1118 if (resource_type_ == RESOURCE_TYPE_UNKNOWN && 1119 response.status_code != 550) { 1120 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1121 } 1122 1123 ResetDataConnectionAfterError(state_after_size); 1124 break; 1125 default: 1126 NOTREACHED(); 1127 return Stop(ERR_UNEXPECTED); 1128 } 1129 1130 return OK; 1131} 1132 1133// CWD command 1134int FtpNetworkTransaction::DoCtrlWriteCWD() { 1135 std::string command = "CWD " + GetRequestPathForFtpCommand(true); 1136 next_state_ = STATE_CTRL_READ; 1137 return SendFtpCommand(command, command, COMMAND_CWD); 1138} 1139 1140int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { 1141 // We should never issue CWD if we know the target resource is a file. 1142 DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_); 1143 1144 switch (GetErrorClass(response.status_code)) { 1145 case ERROR_CLASS_INITIATED: 1146 return Stop(ERR_INVALID_RESPONSE); 1147 case ERROR_CLASS_OK: 1148 next_state_ = STATE_CTRL_WRITE_LIST; 1149 break; 1150 case ERROR_CLASS_INFO_NEEDED: 1151 return Stop(ERR_INVALID_RESPONSE); 1152 case ERROR_CLASS_TRANSIENT_ERROR: 1153 // Some FTP servers send response 451 (not a valid CWD response according 1154 // to RFC 959) instead of 550. 1155 if (response.status_code == 451) 1156 return ProcessResponseCWDNotADirectory(); 1157 1158 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1159 case ERROR_CLASS_PERMANENT_ERROR: 1160 if (response.status_code == 550) 1161 return ProcessResponseCWDNotADirectory(); 1162 1163 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1164 default: 1165 NOTREACHED(); 1166 return Stop(ERR_UNEXPECTED); 1167 } 1168 1169 return OK; 1170} 1171 1172int FtpNetworkTransaction::ProcessResponseCWDNotADirectory() { 1173 if (resource_type_ == RESOURCE_TYPE_DIRECTORY) { 1174 // We're assuming that the resource is a directory, but the server 1175 // says it's not true. The most probable interpretation is that it 1176 // doesn't exist (with FTP we can't be sure). 1177 return Stop(ERR_FILE_NOT_FOUND); 1178 } 1179 1180 // We are here because SIZE failed and we are not sure what the resource 1181 // type is. It could still be file, and SIZE could fail because of 1182 // an access error (http://crbug.com/56734). Try RETR just to be sure. 1183 resource_type_ = RESOURCE_TYPE_FILE; 1184 1185 ResetDataConnectionAfterError(STATE_CTRL_WRITE_RETR); 1186 return OK; 1187} 1188 1189// LIST command 1190int FtpNetworkTransaction::DoCtrlWriteLIST() { 1191 // Use the -l option for mod_ftp configured in LISTIsNLST mode: the option 1192 // forces LIST output instead of NLST (which would be ambiguous for us 1193 // to parse). 1194 std::string command("LIST -l"); 1195 if (system_type_ == SYSTEM_TYPE_VMS) 1196 command = "LIST *.*;0"; 1197 1198 next_state_ = STATE_CTRL_READ; 1199 return SendFtpCommand(command, command, COMMAND_LIST); 1200} 1201 1202int FtpNetworkTransaction::ProcessResponseLIST( 1203 const FtpCtrlResponse& response) { 1204 switch (GetErrorClass(response.status_code)) { 1205 case ERROR_CLASS_INITIATED: 1206 // We want the client to start reading the response at this point. 1207 // It got here either through Start or RestartWithAuth. We want that 1208 // method to complete. Not setting next state here will make DoLoop exit 1209 // and in turn make Start/RestartWithAuth complete. 1210 response_.is_directory_listing = true; 1211 break; 1212 case ERROR_CLASS_OK: 1213 response_.is_directory_listing = true; 1214 next_state_ = STATE_CTRL_WRITE_QUIT; 1215 break; 1216 case ERROR_CLASS_INFO_NEEDED: 1217 return Stop(ERR_INVALID_RESPONSE); 1218 case ERROR_CLASS_TRANSIENT_ERROR: 1219 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1220 case ERROR_CLASS_PERMANENT_ERROR: 1221 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1222 default: 1223 NOTREACHED(); 1224 return Stop(ERR_UNEXPECTED); 1225 } 1226 return OK; 1227} 1228 1229// QUIT command 1230int FtpNetworkTransaction::DoCtrlWriteQUIT() { 1231 std::string command = "QUIT"; 1232 next_state_ = STATE_CTRL_READ; 1233 return SendFtpCommand(command, command, COMMAND_QUIT); 1234} 1235 1236int FtpNetworkTransaction::ProcessResponseQUIT( 1237 const FtpCtrlResponse& response) { 1238 ctrl_socket_->Disconnect(); 1239 return last_error_; 1240} 1241 1242// Data Connection 1243 1244int FtpNetworkTransaction::DoDataConnect() { 1245 next_state_ = STATE_DATA_CONNECT_COMPLETE; 1246 IPEndPoint ip_endpoint; 1247 AddressList data_address; 1248 // Connect to the same host as the control socket to prevent PASV port 1249 // scanning attacks. 1250 int rv = ctrl_socket_->GetPeerAddress(&ip_endpoint); 1251 if (rv != OK) 1252 return Stop(rv); 1253 data_address = AddressList::CreateFromIPAddress( 1254 ip_endpoint.address(), data_connection_port_); 1255 data_socket_.reset(socket_factory_->CreateTransportClientSocket( 1256 data_address, net_log_.net_log(), net_log_.source())); 1257 net_log_.AddEvent( 1258 NetLog::TYPE_FTP_DATA_CONNECTION, 1259 data_socket_->NetLog().source().ToEventParametersCallback()); 1260 return data_socket_->Connect(io_callback_); 1261} 1262 1263int FtpNetworkTransaction::DoDataConnectComplete(int result) { 1264 if (result != OK && use_epsv_) { 1265 // It's possible we hit a broken server, sadly. They can break in different 1266 // ways. Some time out, some reset a connection. Fall back to PASV. 1267 // TODO(phajdan.jr): remember it for future transactions with this server. 1268 // TODO(phajdan.jr): write a test for this code path. 1269 use_epsv_ = false; 1270 next_state_ = STATE_CTRL_WRITE_PASV; 1271 return OK; 1272 } 1273 1274 // Only record the connection error after we've applied all our fallbacks. 1275 // We want to capture the final error, one we're not going to recover from. 1276 RecordDataConnectionError(result); 1277 1278 if (result != OK) 1279 return Stop(result); 1280 1281 next_state_ = state_after_data_connect_complete_; 1282 return OK; 1283} 1284 1285int FtpNetworkTransaction::DoDataRead() { 1286 DCHECK(read_data_buf_); 1287 DCHECK_GT(read_data_buf_len_, 0); 1288 1289 if (data_socket_ == NULL || !data_socket_->IsConnected()) { 1290 // If we don't destroy the data socket completely, some servers will wait 1291 // for us (http://crbug.com/21127). The half-closed TCP connection needs 1292 // to be closed on our side too. 1293 data_socket_.reset(); 1294 1295 if (ctrl_socket_->IsConnected()) { 1296 // Wait for the server's response, we should get it before sending QUIT. 1297 next_state_ = STATE_CTRL_READ; 1298 return OK; 1299 } 1300 1301 // We are no longer connected to the server, so just finish the transaction. 1302 return Stop(OK); 1303 } 1304 1305 next_state_ = STATE_DATA_READ_COMPLETE; 1306 read_data_buf_->data()[0] = 0; 1307 return data_socket_->Read(read_data_buf_, read_data_buf_len_, io_callback_); 1308} 1309 1310int FtpNetworkTransaction::DoDataReadComplete(int result) { 1311 return result; 1312} 1313 1314// We're using a histogram as a group of counters, with one bucket for each 1315// enumeration value. We're only interested in the values of the counters. 1316// Ignore the shape, average, and standard deviation of the histograms because 1317// they are meaningless. 1318// 1319// We use two histograms. In the first histogram we tally whether the user has 1320// seen an error of that type during the session. In the second histogram we 1321// tally the total number of times the users sees each errer. 1322void FtpNetworkTransaction::RecordDataConnectionError(int result) { 1323 // Gather data for http://crbug.com/3073. See how many users have trouble 1324 // establishing FTP data connection in passive FTP mode. 1325 enum { 1326 // Data connection successful. 1327 NET_ERROR_OK = 0, 1328 1329 // Local firewall blocked the connection. 1330 NET_ERROR_ACCESS_DENIED = 1, 1331 1332 // Connection timed out. 1333 NET_ERROR_TIMED_OUT = 2, 1334 1335 // Connection has been estabilished, but then got broken (either reset 1336 // or aborted). 1337 NET_ERROR_CONNECTION_BROKEN = 3, 1338 1339 // Connection has been refused. 1340 NET_ERROR_CONNECTION_REFUSED = 4, 1341 1342 // No connection to the internet. 1343 NET_ERROR_INTERNET_DISCONNECTED = 5, 1344 1345 // Could not reach the destination address. 1346 NET_ERROR_ADDRESS_UNREACHABLE = 6, 1347 1348 // A programming error in our network stack. 1349 NET_ERROR_UNEXPECTED = 7, 1350 1351 // Other kind of error. 1352 NET_ERROR_OTHER = 20, 1353 1354 NUM_OF_NET_ERROR_TYPES 1355 } type; 1356 switch (result) { 1357 case OK: 1358 type = NET_ERROR_OK; 1359 break; 1360 case ERR_ACCESS_DENIED: 1361 case ERR_NETWORK_ACCESS_DENIED: 1362 type = NET_ERROR_ACCESS_DENIED; 1363 break; 1364 case ERR_TIMED_OUT: 1365 type = NET_ERROR_TIMED_OUT; 1366 break; 1367 case ERR_CONNECTION_ABORTED: 1368 case ERR_CONNECTION_RESET: 1369 case ERR_CONNECTION_CLOSED: 1370 type = NET_ERROR_CONNECTION_BROKEN; 1371 break; 1372 case ERR_CONNECTION_FAILED: 1373 case ERR_CONNECTION_REFUSED: 1374 type = NET_ERROR_CONNECTION_REFUSED; 1375 break; 1376 case ERR_INTERNET_DISCONNECTED: 1377 type = NET_ERROR_INTERNET_DISCONNECTED; 1378 break; 1379 case ERR_ADDRESS_INVALID: 1380 case ERR_ADDRESS_UNREACHABLE: 1381 type = NET_ERROR_ADDRESS_UNREACHABLE; 1382 break; 1383 case ERR_UNEXPECTED: 1384 type = NET_ERROR_UNEXPECTED; 1385 break; 1386 default: 1387 type = NET_ERROR_OTHER; 1388 break; 1389 }; 1390 static bool had_error_type[NUM_OF_NET_ERROR_TYPES]; 1391 1392 DCHECK(type >= 0 && type < NUM_OF_NET_ERROR_TYPES); 1393 if (!had_error_type[type]) { 1394 had_error_type[type] = true; 1395 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", 1396 type, NUM_OF_NET_ERROR_TYPES); 1397 } 1398 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", 1399 type, NUM_OF_NET_ERROR_TYPES); 1400} 1401 1402} // namespace net 1403