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/strings/string_number_conversions.h" 12 #include "base/strings/string_util.h" 13 #include "base/strings/string_split.h" 14 #include "base/strings/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 28 const char kCRLF[] = "\r\n"; 29 30 const int kCtrlBufLen = 1024; 31 32 namespace { 33 34 // Returns true if |input| can be safely used as a part of FTP command. 35 bool 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 47 enum 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. 72 ErrorClass 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|. 94 int 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 | 119 bool 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 149 bool 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 (!base::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 203 namespace net { 204 205 FtpNetworkTransaction::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 read_data_buf_len_(0), 216 last_error_(OK), 217 system_type_(SYSTEM_TYPE_UNKNOWN), 218 // Use image (binary) transfer by default. It should always work, 219 // whereas the ascii transfer may damage binary data. 220 data_type_(DATA_TYPE_IMAGE), 221 resource_type_(RESOURCE_TYPE_UNKNOWN), 222 use_epsv_(true), 223 data_connection_port_(0), 224 socket_factory_(socket_factory), 225 next_state_(STATE_NONE), 226 state_after_data_connect_complete_(STATE_CTRL_WRITE_SIZE) {} 227 228 FtpNetworkTransaction::~FtpNetworkTransaction() { 229 } 230 231 int FtpNetworkTransaction::Stop(int error) { 232 if (command_sent_ == COMMAND_QUIT) 233 return error; 234 235 next_state_ = STATE_CTRL_WRITE_QUIT; 236 last_error_ = error; 237 return OK; 238 } 239 240 int FtpNetworkTransaction::RestartIgnoringLastError( 241 const CompletionCallback& callback) { 242 return ERR_NOT_IMPLEMENTED; 243 } 244 245 int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info, 246 const CompletionCallback& callback, 247 const BoundNetLog& net_log) { 248 net_log_ = net_log; 249 request_ = request_info; 250 251 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_)); 252 253 if (request_->url.has_username()) { 254 base::string16 username; 255 base::string16 password; 256 GetIdentityFromURL(request_->url, &username, &password); 257 credentials_.Set(username, password); 258 } else { 259 credentials_.Set(base::ASCIIToUTF16("anonymous"), 260 base::ASCIIToUTF16("chrome (at) example.com")); 261 } 262 263 DetectTypecode(); 264 265 next_state_ = STATE_CTRL_RESOLVE_HOST; 266 int rv = DoLoop(OK); 267 if (rv == ERR_IO_PENDING) 268 user_callback_ = callback; 269 return rv; 270 } 271 272 int FtpNetworkTransaction::RestartWithAuth(const AuthCredentials& credentials, 273 const CompletionCallback& callback) { 274 ResetStateForRestart(); 275 276 credentials_ = credentials; 277 278 next_state_ = STATE_CTRL_RESOLVE_HOST; 279 int rv = DoLoop(OK); 280 if (rv == ERR_IO_PENDING) 281 user_callback_ = callback; 282 return rv; 283 } 284 285 int FtpNetworkTransaction::Read(IOBuffer* buf, 286 int buf_len, 287 const CompletionCallback& callback) { 288 DCHECK(buf); 289 DCHECK_GT(buf_len, 0); 290 291 read_data_buf_ = buf; 292 read_data_buf_len_ = buf_len; 293 294 next_state_ = STATE_DATA_READ; 295 int rv = DoLoop(OK); 296 if (rv == ERR_IO_PENDING) 297 user_callback_ = callback; 298 return rv; 299 } 300 301 const FtpResponseInfo* FtpNetworkTransaction::GetResponseInfo() const { 302 return &response_; 303 } 304 305 LoadState FtpNetworkTransaction::GetLoadState() const { 306 if (next_state_ == STATE_CTRL_RESOLVE_HOST_COMPLETE) 307 return LOAD_STATE_RESOLVING_HOST; 308 309 if (next_state_ == STATE_CTRL_CONNECT_COMPLETE || 310 next_state_ == STATE_DATA_CONNECT_COMPLETE) 311 return LOAD_STATE_CONNECTING; 312 313 if (next_state_ == STATE_DATA_READ_COMPLETE) 314 return LOAD_STATE_READING_RESPONSE; 315 316 if (command_sent_ == COMMAND_RETR && read_data_buf_.get()) 317 return LOAD_STATE_READING_RESPONSE; 318 319 if (command_sent_ == COMMAND_QUIT) 320 return LOAD_STATE_IDLE; 321 322 if (command_sent_ != COMMAND_NONE) 323 return LOAD_STATE_SENDING_REQUEST; 324 325 return LOAD_STATE_IDLE; 326 } 327 328 uint64 FtpNetworkTransaction::GetUploadProgress() const { 329 return 0; 330 } 331 332 void FtpNetworkTransaction::ResetStateForRestart() { 333 command_sent_ = COMMAND_NONE; 334 user_callback_.Reset(); 335 response_ = FtpResponseInfo(); 336 read_ctrl_buf_ = new IOBuffer(kCtrlBufLen); 337 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_)); 338 read_data_buf_ = NULL; 339 read_data_buf_len_ = 0; 340 if (write_buf_.get()) 341 write_buf_->SetOffset(0); 342 last_error_ = OK; 343 data_connection_port_ = 0; 344 ctrl_socket_.reset(); 345 data_socket_.reset(); 346 next_state_ = STATE_NONE; 347 state_after_data_connect_complete_ = STATE_CTRL_WRITE_SIZE; 348 } 349 350 void FtpNetworkTransaction::ResetDataConnectionAfterError(State next_state) { 351 // The server _might_ have reset the data connection 352 // (see RFC 959 3.2. ESTABLISHING DATA CONNECTIONS: 353 // "The server MUST close the data connection under the following 354 // conditions: 355 // ... 356 // 5. An irrecoverable error condition occurs.") 357 // 358 // It is ambiguous what an irrecoverable error condition is, 359 // so we take no chances. 360 state_after_data_connect_complete_ = next_state; 361 next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; 362 } 363 364 void FtpNetworkTransaction::DoCallback(int rv) { 365 DCHECK(rv != ERR_IO_PENDING); 366 DCHECK(!user_callback_.is_null()); 367 368 // Since Run may result in Read being called, clear callback_ up front. 369 CompletionCallback c = user_callback_; 370 user_callback_.Reset(); 371 c.Run(rv); 372 } 373 374 void FtpNetworkTransaction::OnIOComplete(int result) { 375 int rv = DoLoop(result); 376 if (rv != ERR_IO_PENDING) 377 DoCallback(rv); 378 } 379 380 int FtpNetworkTransaction::ProcessCtrlResponse() { 381 FtpCtrlResponse response = ctrl_response_buffer_->PopResponse(); 382 383 int rv = OK; 384 switch (command_sent_) { 385 case COMMAND_NONE: 386 // TODO(phajdan.jr): Check for errors in the welcome message. 387 next_state_ = STATE_CTRL_WRITE_USER; 388 break; 389 case COMMAND_USER: 390 rv = ProcessResponseUSER(response); 391 break; 392 case COMMAND_PASS: 393 rv = ProcessResponsePASS(response); 394 break; 395 case COMMAND_SYST: 396 rv = ProcessResponseSYST(response); 397 break; 398 case COMMAND_PWD: 399 rv = ProcessResponsePWD(response); 400 break; 401 case COMMAND_TYPE: 402 rv = ProcessResponseTYPE(response); 403 break; 404 case COMMAND_EPSV: 405 rv = ProcessResponseEPSV(response); 406 break; 407 case COMMAND_PASV: 408 rv = ProcessResponsePASV(response); 409 break; 410 case COMMAND_SIZE: 411 rv = ProcessResponseSIZE(response); 412 break; 413 case COMMAND_RETR: 414 rv = ProcessResponseRETR(response); 415 break; 416 case COMMAND_CWD: 417 rv = ProcessResponseCWD(response); 418 break; 419 case COMMAND_LIST: 420 rv = ProcessResponseLIST(response); 421 break; 422 case COMMAND_QUIT: 423 rv = ProcessResponseQUIT(response); 424 break; 425 default: 426 LOG(DFATAL) << "Unexpected value of command_sent_: " << command_sent_; 427 return ERR_UNEXPECTED; 428 } 429 430 // We may get multiple responses for some commands, 431 // see http://crbug.com/18036. 432 while (ctrl_response_buffer_->ResponseAvailable() && rv == OK) { 433 response = ctrl_response_buffer_->PopResponse(); 434 435 switch (command_sent_) { 436 case COMMAND_RETR: 437 rv = ProcessResponseRETR(response); 438 break; 439 case COMMAND_LIST: 440 rv = ProcessResponseLIST(response); 441 break; 442 default: 443 // Multiple responses for other commands are invalid. 444 return Stop(ERR_INVALID_RESPONSE); 445 } 446 } 447 448 return rv; 449 } 450 451 // Used to prepare and send FTP command. 452 int FtpNetworkTransaction::SendFtpCommand(const std::string& command, 453 const std::string& command_for_log, 454 Command cmd) { 455 // If we send a new command when we still have unprocessed responses 456 // for previous commands, the response receiving code will have no way to know 457 // which responses are for which command. 458 DCHECK(!ctrl_response_buffer_->ResponseAvailable()); 459 460 DCHECK(!write_command_buf_.get()); 461 DCHECK(!write_buf_.get()); 462 463 if (!IsValidFTPCommandString(command)) { 464 // Callers should validate the command themselves and return a more specific 465 // error code. 466 NOTREACHED(); 467 return Stop(ERR_UNEXPECTED); 468 } 469 470 command_sent_ = cmd; 471 472 write_command_buf_ = new IOBufferWithSize(command.length() + 2); 473 write_buf_ = new DrainableIOBuffer(write_command_buf_.get(), 474 write_command_buf_->size()); 475 memcpy(write_command_buf_->data(), command.data(), command.length()); 476 memcpy(write_command_buf_->data() + command.length(), kCRLF, 2); 477 478 net_log_.AddEvent(NetLog::TYPE_FTP_COMMAND_SENT, 479 NetLog::StringCallback("command", &command_for_log)); 480 481 next_state_ = STATE_CTRL_WRITE; 482 return OK; 483 } 484 485 std::string FtpNetworkTransaction::GetRequestPathForFtpCommand( 486 bool is_directory) const { 487 std::string path(current_remote_directory_); 488 if (request_->url.has_path()) { 489 std::string gurl_path(request_->url.path()); 490 491 // Get rid of the typecode, see RFC 1738 section 3.2.2. FTP url-path. 492 std::string::size_type pos = gurl_path.rfind(';'); 493 if (pos != std::string::npos) 494 gurl_path.resize(pos); 495 496 path.append(gurl_path); 497 } 498 // Make sure that if the path is expected to be a file, it won't end 499 // with a trailing slash. 500 if (!is_directory && path.length() > 1 && path[path.length() - 1] == '/') 501 path.erase(path.length() - 1); 502 UnescapeRule::Type unescape_rules = UnescapeRule::SPACES | 503 UnescapeRule::URL_SPECIAL_CHARS; 504 // This may unescape to non-ASCII characters, but we allow that. See the 505 // comment for IsValidFTPCommandString. 506 path = net::UnescapeURLComponent(path, unescape_rules); 507 508 if (system_type_ == SYSTEM_TYPE_VMS) { 509 if (is_directory) 510 path = FtpUtil::UnixDirectoryPathToVMS(path); 511 else 512 path = FtpUtil::UnixFilePathToVMS(path); 513 } 514 515 DCHECK(IsValidFTPCommandString(path)); 516 return path; 517 } 518 519 void FtpNetworkTransaction::DetectTypecode() { 520 if (!request_->url.has_path()) 521 return; 522 std::string gurl_path(request_->url.path()); 523 524 // Extract the typecode, see RFC 1738 section 3.2.2. FTP url-path. 525 std::string::size_type pos = gurl_path.rfind(';'); 526 if (pos == std::string::npos) 527 return; 528 std::string typecode_string(gurl_path.substr(pos)); 529 if (typecode_string == ";type=a") { 530 data_type_ = DATA_TYPE_ASCII; 531 resource_type_ = RESOURCE_TYPE_FILE; 532 } else if (typecode_string == ";type=i") { 533 data_type_ = DATA_TYPE_IMAGE; 534 resource_type_ = RESOURCE_TYPE_FILE; 535 } else if (typecode_string == ";type=d") { 536 resource_type_ = RESOURCE_TYPE_DIRECTORY; 537 } 538 } 539 540 int FtpNetworkTransaction::DoLoop(int result) { 541 DCHECK(next_state_ != STATE_NONE); 542 543 int rv = result; 544 do { 545 State state = next_state_; 546 next_state_ = STATE_NONE; 547 switch (state) { 548 case STATE_CTRL_RESOLVE_HOST: 549 DCHECK(rv == OK); 550 rv = DoCtrlResolveHost(); 551 break; 552 case STATE_CTRL_RESOLVE_HOST_COMPLETE: 553 rv = DoCtrlResolveHostComplete(rv); 554 break; 555 case STATE_CTRL_CONNECT: 556 DCHECK(rv == OK); 557 rv = DoCtrlConnect(); 558 break; 559 case STATE_CTRL_CONNECT_COMPLETE: 560 rv = DoCtrlConnectComplete(rv); 561 break; 562 case STATE_CTRL_READ: 563 DCHECK(rv == OK); 564 rv = DoCtrlRead(); 565 break; 566 case STATE_CTRL_READ_COMPLETE: 567 rv = DoCtrlReadComplete(rv); 568 break; 569 case STATE_CTRL_WRITE: 570 DCHECK(rv == OK); 571 rv = DoCtrlWrite(); 572 break; 573 case STATE_CTRL_WRITE_COMPLETE: 574 rv = DoCtrlWriteComplete(rv); 575 break; 576 case STATE_CTRL_WRITE_USER: 577 DCHECK(rv == OK); 578 rv = DoCtrlWriteUSER(); 579 break; 580 case STATE_CTRL_WRITE_PASS: 581 DCHECK(rv == OK); 582 rv = DoCtrlWritePASS(); 583 break; 584 case STATE_CTRL_WRITE_SYST: 585 DCHECK(rv == OK); 586 rv = DoCtrlWriteSYST(); 587 break; 588 case STATE_CTRL_WRITE_PWD: 589 DCHECK(rv == OK); 590 rv = DoCtrlWritePWD(); 591 break; 592 case STATE_CTRL_WRITE_TYPE: 593 DCHECK(rv == OK); 594 rv = DoCtrlWriteTYPE(); 595 break; 596 case STATE_CTRL_WRITE_EPSV: 597 DCHECK(rv == OK); 598 rv = DoCtrlWriteEPSV(); 599 break; 600 case STATE_CTRL_WRITE_PASV: 601 DCHECK(rv == OK); 602 rv = DoCtrlWritePASV(); 603 break; 604 case STATE_CTRL_WRITE_RETR: 605 DCHECK(rv == OK); 606 rv = DoCtrlWriteRETR(); 607 break; 608 case STATE_CTRL_WRITE_SIZE: 609 DCHECK(rv == OK); 610 rv = DoCtrlWriteSIZE(); 611 break; 612 case STATE_CTRL_WRITE_CWD: 613 DCHECK(rv == OK); 614 rv = DoCtrlWriteCWD(); 615 break; 616 case STATE_CTRL_WRITE_LIST: 617 DCHECK(rv == OK); 618 rv = DoCtrlWriteLIST(); 619 break; 620 case STATE_CTRL_WRITE_QUIT: 621 DCHECK(rv == OK); 622 rv = DoCtrlWriteQUIT(); 623 break; 624 case STATE_DATA_CONNECT: 625 DCHECK(rv == OK); 626 rv = DoDataConnect(); 627 break; 628 case STATE_DATA_CONNECT_COMPLETE: 629 rv = DoDataConnectComplete(rv); 630 break; 631 case STATE_DATA_READ: 632 DCHECK(rv == OK); 633 rv = DoDataRead(); 634 break; 635 case STATE_DATA_READ_COMPLETE: 636 rv = DoDataReadComplete(rv); 637 break; 638 default: 639 NOTREACHED() << "bad state"; 640 rv = ERR_UNEXPECTED; 641 break; 642 } 643 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); 644 return rv; 645 } 646 647 int FtpNetworkTransaction::DoCtrlResolveHost() { 648 next_state_ = STATE_CTRL_RESOLVE_HOST_COMPLETE; 649 650 HostResolver::RequestInfo info(HostPortPair::FromURL(request_->url)); 651 // No known referrer. 652 return resolver_.Resolve( 653 info, 654 DEFAULT_PRIORITY, 655 &addresses_, 656 base::Bind(&FtpNetworkTransaction::OnIOComplete, base::Unretained(this)), 657 net_log_); 658 } 659 660 int FtpNetworkTransaction::DoCtrlResolveHostComplete(int result) { 661 if (result == OK) 662 next_state_ = STATE_CTRL_CONNECT; 663 return result; 664 } 665 666 int FtpNetworkTransaction::DoCtrlConnect() { 667 next_state_ = STATE_CTRL_CONNECT_COMPLETE; 668 ctrl_socket_ = 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 676 int 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 698 int FtpNetworkTransaction::DoCtrlRead() { 699 next_state_ = STATE_CTRL_READ_COMPLETE; 700 return ctrl_socket_->Read(read_ctrl_buf_.get(), kCtrlBufLen, io_callback_); 701 } 702 703 int 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() == base::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 728 int FtpNetworkTransaction::DoCtrlWrite() { 729 next_state_ = STATE_CTRL_WRITE_COMPLETE; 730 731 return ctrl_socket_->Write( 732 write_buf_.get(), write_buf_->BytesRemaining(), io_callback_); 733 } 734 735 int FtpNetworkTransaction::DoCtrlWriteComplete(int result) { 736 if (result < 0) 737 return result; 738 739 write_buf_->DidConsume(result); 740 if (write_buf_->BytesRemaining() == 0) { 741 // Clear the write buffer. 742 write_buf_ = NULL; 743 write_command_buf_ = NULL; 744 745 next_state_ = STATE_CTRL_READ; 746 } else { 747 next_state_ = STATE_CTRL_WRITE; 748 } 749 return OK; 750 } 751 752 // FTP Commands and responses 753 754 // USER Command. 755 int FtpNetworkTransaction::DoCtrlWriteUSER() { 756 std::string command = "USER " + base::UTF16ToUTF8(credentials_.username()); 757 758 if (!IsValidFTPCommandString(command)) 759 return Stop(ERR_MALFORMED_IDENTITY); 760 761 next_state_ = STATE_CTRL_READ; 762 return SendFtpCommand(command, "USER ***", COMMAND_USER); 763 } 764 765 int FtpNetworkTransaction::ProcessResponseUSER( 766 const FtpCtrlResponse& response) { 767 switch (GetErrorClass(response.status_code)) { 768 case ERROR_CLASS_OK: 769 next_state_ = STATE_CTRL_WRITE_SYST; 770 break; 771 case ERROR_CLASS_INFO_NEEDED: 772 next_state_ = STATE_CTRL_WRITE_PASS; 773 break; 774 case ERROR_CLASS_TRANSIENT_ERROR: 775 case ERROR_CLASS_PERMANENT_ERROR: 776 response_.needs_auth = true; 777 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 778 default: 779 NOTREACHED(); 780 return Stop(ERR_UNEXPECTED); 781 } 782 return OK; 783 } 784 785 // PASS command. 786 int FtpNetworkTransaction::DoCtrlWritePASS() { 787 std::string command = "PASS " + base::UTF16ToUTF8(credentials_.password()); 788 789 if (!IsValidFTPCommandString(command)) 790 return Stop(ERR_MALFORMED_IDENTITY); 791 792 next_state_ = STATE_CTRL_READ; 793 return SendFtpCommand(command, "PASS ***", COMMAND_PASS); 794 } 795 796 int FtpNetworkTransaction::ProcessResponsePASS( 797 const FtpCtrlResponse& response) { 798 switch (GetErrorClass(response.status_code)) { 799 case ERROR_CLASS_OK: 800 next_state_ = STATE_CTRL_WRITE_SYST; 801 break; 802 case ERROR_CLASS_INFO_NEEDED: 803 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 804 case ERROR_CLASS_TRANSIENT_ERROR: 805 case ERROR_CLASS_PERMANENT_ERROR: 806 response_.needs_auth = true; 807 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 808 default: 809 NOTREACHED(); 810 return Stop(ERR_UNEXPECTED); 811 } 812 return OK; 813 } 814 815 // SYST command. 816 int FtpNetworkTransaction::DoCtrlWriteSYST() { 817 std::string command = "SYST"; 818 next_state_ = STATE_CTRL_READ; 819 return SendFtpCommand(command, command, COMMAND_SYST); 820 } 821 822 int FtpNetworkTransaction::ProcessResponseSYST( 823 const FtpCtrlResponse& response) { 824 switch (GetErrorClass(response.status_code)) { 825 case ERROR_CLASS_INITIATED: 826 return Stop(ERR_INVALID_RESPONSE); 827 case ERROR_CLASS_OK: { 828 // All important info should be on the first line. 829 std::string line = response.lines[0]; 830 // The response should be ASCII, which allows us to do case-insensitive 831 // comparisons easily. If it is not ASCII, we leave the system type 832 // as unknown. 833 if (base::IsStringASCII(line)) { 834 line = StringToLowerASCII(line); 835 836 // Remove all whitespace, to correctly handle cases like fancy "V M S" 837 // response instead of "VMS". 838 base::RemoveChars(line, base::kWhitespaceASCII, &line); 839 840 // The "magic" strings we test for below have been gathered by an 841 // empirical study. VMS needs to come first because some VMS systems 842 // also respond with "UNIX emulation", which is not perfect. It is much 843 // more reliable to talk to these servers in their native language. 844 if (line.find("vms") != std::string::npos) { 845 system_type_ = SYSTEM_TYPE_VMS; 846 } else if (line.find("l8") != std::string::npos || 847 line.find("unix") != std::string::npos || 848 line.find("bsd") != std::string::npos) { 849 system_type_ = SYSTEM_TYPE_UNIX; 850 } else if (line.find("win32") != std::string::npos || 851 line.find("windows") != std::string::npos) { 852 system_type_ = SYSTEM_TYPE_WINDOWS; 853 } else if (line.find("os/2") != std::string::npos) { 854 system_type_ = SYSTEM_TYPE_OS2; 855 } 856 } 857 next_state_ = STATE_CTRL_WRITE_PWD; 858 break; 859 } 860 case ERROR_CLASS_INFO_NEEDED: 861 return Stop(ERR_INVALID_RESPONSE); 862 case ERROR_CLASS_TRANSIENT_ERROR: 863 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 864 case ERROR_CLASS_PERMANENT_ERROR: 865 // Server does not recognize the SYST command so proceed. 866 next_state_ = STATE_CTRL_WRITE_PWD; 867 break; 868 default: 869 NOTREACHED(); 870 return Stop(ERR_UNEXPECTED); 871 } 872 return OK; 873 } 874 875 // PWD command. 876 int FtpNetworkTransaction::DoCtrlWritePWD() { 877 std::string command = "PWD"; 878 next_state_ = STATE_CTRL_READ; 879 return SendFtpCommand(command, command, COMMAND_PWD); 880 } 881 882 int FtpNetworkTransaction::ProcessResponsePWD(const FtpCtrlResponse& response) { 883 switch (GetErrorClass(response.status_code)) { 884 case ERROR_CLASS_INITIATED: 885 return Stop(ERR_INVALID_RESPONSE); 886 case ERROR_CLASS_OK: { 887 // The info we look for should be on the first line. 888 std::string line = response.lines[0]; 889 if (line.empty()) 890 return Stop(ERR_INVALID_RESPONSE); 891 std::string::size_type quote_pos = line.find('"'); 892 if (quote_pos != std::string::npos) { 893 line = line.substr(quote_pos + 1); 894 quote_pos = line.find('"'); 895 if (quote_pos == std::string::npos) 896 return Stop(ERR_INVALID_RESPONSE); 897 line = line.substr(0, quote_pos); 898 } 899 if (system_type_ == SYSTEM_TYPE_VMS) 900 line = FtpUtil::VMSPathToUnix(line); 901 if (line.length() && line[line.length() - 1] == '/') 902 line.erase(line.length() - 1); 903 current_remote_directory_ = line; 904 next_state_ = STATE_CTRL_WRITE_TYPE; 905 break; 906 } 907 case ERROR_CLASS_INFO_NEEDED: 908 return Stop(ERR_INVALID_RESPONSE); 909 case ERROR_CLASS_TRANSIENT_ERROR: 910 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 911 case ERROR_CLASS_PERMANENT_ERROR: 912 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 913 default: 914 NOTREACHED(); 915 return Stop(ERR_UNEXPECTED); 916 } 917 return OK; 918 } 919 920 // TYPE command. 921 int FtpNetworkTransaction::DoCtrlWriteTYPE() { 922 std::string command = "TYPE "; 923 if (data_type_ == DATA_TYPE_ASCII) { 924 command += "A"; 925 } else if (data_type_ == DATA_TYPE_IMAGE) { 926 command += "I"; 927 } else { 928 NOTREACHED(); 929 return Stop(ERR_UNEXPECTED); 930 } 931 next_state_ = STATE_CTRL_READ; 932 return SendFtpCommand(command, command, COMMAND_TYPE); 933 } 934 935 int FtpNetworkTransaction::ProcessResponseTYPE( 936 const FtpCtrlResponse& response) { 937 switch (GetErrorClass(response.status_code)) { 938 case ERROR_CLASS_INITIATED: 939 return Stop(ERR_INVALID_RESPONSE); 940 case ERROR_CLASS_OK: 941 next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; 942 break; 943 case ERROR_CLASS_INFO_NEEDED: 944 return Stop(ERR_INVALID_RESPONSE); 945 case ERROR_CLASS_TRANSIENT_ERROR: 946 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 947 case ERROR_CLASS_PERMANENT_ERROR: 948 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 949 default: 950 NOTREACHED(); 951 return Stop(ERR_UNEXPECTED); 952 } 953 return OK; 954 } 955 956 // EPSV command 957 int FtpNetworkTransaction::DoCtrlWriteEPSV() { 958 const std::string command = "EPSV"; 959 next_state_ = STATE_CTRL_READ; 960 return SendFtpCommand(command, command, COMMAND_EPSV); 961 } 962 963 int FtpNetworkTransaction::ProcessResponseEPSV( 964 const FtpCtrlResponse& response) { 965 switch (GetErrorClass(response.status_code)) { 966 case ERROR_CLASS_INITIATED: 967 return Stop(ERR_INVALID_RESPONSE); 968 case ERROR_CLASS_OK: 969 if (!ExtractPortFromEPSVResponse( response, &data_connection_port_)) 970 return Stop(ERR_INVALID_RESPONSE); 971 if (data_connection_port_ < 1024 || 972 !IsPortAllowedByFtp(data_connection_port_)) 973 return Stop(ERR_UNSAFE_PORT); 974 next_state_ = STATE_DATA_CONNECT; 975 break; 976 case ERROR_CLASS_INFO_NEEDED: 977 return Stop(ERR_INVALID_RESPONSE); 978 case ERROR_CLASS_TRANSIENT_ERROR: 979 case ERROR_CLASS_PERMANENT_ERROR: 980 use_epsv_ = false; 981 next_state_ = STATE_CTRL_WRITE_PASV; 982 return OK; 983 default: 984 NOTREACHED(); 985 return Stop(ERR_UNEXPECTED); 986 } 987 return OK; 988 } 989 990 // PASV command 991 int FtpNetworkTransaction::DoCtrlWritePASV() { 992 std::string command = "PASV"; 993 next_state_ = STATE_CTRL_READ; 994 return SendFtpCommand(command, command, COMMAND_PASV); 995 } 996 997 int FtpNetworkTransaction::ProcessResponsePASV( 998 const FtpCtrlResponse& response) { 999 switch (GetErrorClass(response.status_code)) { 1000 case ERROR_CLASS_INITIATED: 1001 return Stop(ERR_INVALID_RESPONSE); 1002 case ERROR_CLASS_OK: 1003 if (!ExtractPortFromPASVResponse(response, &data_connection_port_)) 1004 return Stop(ERR_INVALID_RESPONSE); 1005 if (data_connection_port_ < 1024 || 1006 !IsPortAllowedByFtp(data_connection_port_)) 1007 return Stop(ERR_UNSAFE_PORT); 1008 next_state_ = STATE_DATA_CONNECT; 1009 break; 1010 case ERROR_CLASS_INFO_NEEDED: 1011 return Stop(ERR_INVALID_RESPONSE); 1012 case ERROR_CLASS_TRANSIENT_ERROR: 1013 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1014 case ERROR_CLASS_PERMANENT_ERROR: 1015 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1016 default: 1017 NOTREACHED(); 1018 return Stop(ERR_UNEXPECTED); 1019 } 1020 return OK; 1021 } 1022 1023 // RETR command 1024 int FtpNetworkTransaction::DoCtrlWriteRETR() { 1025 std::string command = "RETR " + GetRequestPathForFtpCommand(false); 1026 next_state_ = STATE_CTRL_READ; 1027 return SendFtpCommand(command, command, COMMAND_RETR); 1028 } 1029 1030 int FtpNetworkTransaction::ProcessResponseRETR( 1031 const FtpCtrlResponse& response) { 1032 switch (GetErrorClass(response.status_code)) { 1033 case ERROR_CLASS_INITIATED: 1034 // We want the client to start reading the response at this point. 1035 // It got here either through Start or RestartWithAuth. We want that 1036 // method to complete. Not setting next state here will make DoLoop exit 1037 // and in turn make Start/RestartWithAuth complete. 1038 resource_type_ = RESOURCE_TYPE_FILE; 1039 break; 1040 case ERROR_CLASS_OK: 1041 resource_type_ = RESOURCE_TYPE_FILE; 1042 next_state_ = STATE_CTRL_WRITE_QUIT; 1043 break; 1044 case ERROR_CLASS_INFO_NEEDED: 1045 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1046 case ERROR_CLASS_TRANSIENT_ERROR: 1047 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1048 case ERROR_CLASS_PERMANENT_ERROR: 1049 // Code 550 means "Failed to open file". Other codes are unrelated, 1050 // like "Not logged in" etc. 1051 if (response.status_code != 550 || resource_type_ == RESOURCE_TYPE_FILE) 1052 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1053 1054 // It's possible that RETR failed because the path is a directory. 1055 resource_type_ = RESOURCE_TYPE_DIRECTORY; 1056 1057 // We're going to try CWD next, but first send a PASV one more time, 1058 // because some FTP servers, including FileZilla, require that. 1059 // See http://crbug.com/25316. 1060 next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; 1061 break; 1062 default: 1063 NOTREACHED(); 1064 return Stop(ERR_UNEXPECTED); 1065 } 1066 1067 // We should be sure about our resource type now. Otherwise we risk 1068 // an infinite loop (RETR can later send CWD, and CWD can later send RETR). 1069 DCHECK_NE(RESOURCE_TYPE_UNKNOWN, resource_type_); 1070 1071 return OK; 1072 } 1073 1074 // SIZE command 1075 int FtpNetworkTransaction::DoCtrlWriteSIZE() { 1076 std::string command = "SIZE " + GetRequestPathForFtpCommand(false); 1077 next_state_ = STATE_CTRL_READ; 1078 return SendFtpCommand(command, command, COMMAND_SIZE); 1079 } 1080 1081 int FtpNetworkTransaction::ProcessResponseSIZE( 1082 const FtpCtrlResponse& response) { 1083 State state_after_size; 1084 if (resource_type_ == RESOURCE_TYPE_FILE) 1085 state_after_size = STATE_CTRL_WRITE_RETR; 1086 else 1087 state_after_size = STATE_CTRL_WRITE_CWD; 1088 1089 switch (GetErrorClass(response.status_code)) { 1090 case ERROR_CLASS_INITIATED: 1091 next_state_ = state_after_size; 1092 break; 1093 case ERROR_CLASS_OK: 1094 if (response.lines.size() != 1) 1095 return Stop(ERR_INVALID_RESPONSE); 1096 int64 size; 1097 if (!base::StringToInt64(response.lines[0], &size)) 1098 return Stop(ERR_INVALID_RESPONSE); 1099 if (size < 0) 1100 return Stop(ERR_INVALID_RESPONSE); 1101 1102 // A successful response to SIZE does not mean the resource is a file. 1103 // Some FTP servers (for example, the qnx one) send a SIZE even for 1104 // directories. 1105 response_.expected_content_size = size; 1106 1107 next_state_ = state_after_size; 1108 break; 1109 case ERROR_CLASS_INFO_NEEDED: 1110 next_state_ = state_after_size; 1111 break; 1112 case ERROR_CLASS_TRANSIENT_ERROR: 1113 ResetDataConnectionAfterError(state_after_size); 1114 break; 1115 case ERROR_CLASS_PERMANENT_ERROR: 1116 // It's possible that SIZE failed because the path is a directory. 1117 if (resource_type_ == RESOURCE_TYPE_UNKNOWN && 1118 response.status_code != 550) { 1119 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1120 } 1121 1122 ResetDataConnectionAfterError(state_after_size); 1123 break; 1124 default: 1125 NOTREACHED(); 1126 return Stop(ERR_UNEXPECTED); 1127 } 1128 1129 return OK; 1130 } 1131 1132 // CWD command 1133 int FtpNetworkTransaction::DoCtrlWriteCWD() { 1134 std::string command = "CWD " + GetRequestPathForFtpCommand(true); 1135 next_state_ = STATE_CTRL_READ; 1136 return SendFtpCommand(command, command, COMMAND_CWD); 1137 } 1138 1139 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { 1140 // We should never issue CWD if we know the target resource is a file. 1141 DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_); 1142 1143 switch (GetErrorClass(response.status_code)) { 1144 case ERROR_CLASS_INITIATED: 1145 return Stop(ERR_INVALID_RESPONSE); 1146 case ERROR_CLASS_OK: 1147 next_state_ = STATE_CTRL_WRITE_LIST; 1148 break; 1149 case ERROR_CLASS_INFO_NEEDED: 1150 return Stop(ERR_INVALID_RESPONSE); 1151 case ERROR_CLASS_TRANSIENT_ERROR: 1152 // Some FTP servers send response 451 (not a valid CWD response according 1153 // to RFC 959) instead of 550. 1154 if (response.status_code == 451) 1155 return ProcessResponseCWDNotADirectory(); 1156 1157 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1158 case ERROR_CLASS_PERMANENT_ERROR: 1159 if (response.status_code == 550) 1160 return ProcessResponseCWDNotADirectory(); 1161 1162 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1163 default: 1164 NOTREACHED(); 1165 return Stop(ERR_UNEXPECTED); 1166 } 1167 1168 return OK; 1169 } 1170 1171 int FtpNetworkTransaction::ProcessResponseCWDNotADirectory() { 1172 if (resource_type_ == RESOURCE_TYPE_DIRECTORY) { 1173 // We're assuming that the resource is a directory, but the server 1174 // says it's not true. The most probable interpretation is that it 1175 // doesn't exist (with FTP we can't be sure). 1176 return Stop(ERR_FILE_NOT_FOUND); 1177 } 1178 1179 // We are here because SIZE failed and we are not sure what the resource 1180 // type is. It could still be file, and SIZE could fail because of 1181 // an access error (http://crbug.com/56734). Try RETR just to be sure. 1182 resource_type_ = RESOURCE_TYPE_FILE; 1183 1184 ResetDataConnectionAfterError(STATE_CTRL_WRITE_RETR); 1185 return OK; 1186 } 1187 1188 // LIST command 1189 int FtpNetworkTransaction::DoCtrlWriteLIST() { 1190 // Use the -l option for mod_ftp configured in LISTIsNLST mode: the option 1191 // forces LIST output instead of NLST (which would be ambiguous for us 1192 // to parse). 1193 std::string command("LIST -l"); 1194 if (system_type_ == SYSTEM_TYPE_VMS) 1195 command = "LIST *.*;0"; 1196 1197 next_state_ = STATE_CTRL_READ; 1198 return SendFtpCommand(command, command, COMMAND_LIST); 1199 } 1200 1201 int FtpNetworkTransaction::ProcessResponseLIST( 1202 const FtpCtrlResponse& response) { 1203 switch (GetErrorClass(response.status_code)) { 1204 case ERROR_CLASS_INITIATED: 1205 // We want the client to start reading the response at this point. 1206 // It got here either through Start or RestartWithAuth. We want that 1207 // method to complete. Not setting next state here will make DoLoop exit 1208 // and in turn make Start/RestartWithAuth complete. 1209 response_.is_directory_listing = true; 1210 break; 1211 case ERROR_CLASS_OK: 1212 response_.is_directory_listing = true; 1213 next_state_ = STATE_CTRL_WRITE_QUIT; 1214 break; 1215 case ERROR_CLASS_INFO_NEEDED: 1216 return Stop(ERR_INVALID_RESPONSE); 1217 case ERROR_CLASS_TRANSIENT_ERROR: 1218 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1219 case ERROR_CLASS_PERMANENT_ERROR: 1220 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1221 default: 1222 NOTREACHED(); 1223 return Stop(ERR_UNEXPECTED); 1224 } 1225 return OK; 1226 } 1227 1228 // QUIT command 1229 int FtpNetworkTransaction::DoCtrlWriteQUIT() { 1230 std::string command = "QUIT"; 1231 next_state_ = STATE_CTRL_READ; 1232 return SendFtpCommand(command, command, COMMAND_QUIT); 1233 } 1234 1235 int FtpNetworkTransaction::ProcessResponseQUIT( 1236 const FtpCtrlResponse& response) { 1237 ctrl_socket_->Disconnect(); 1238 return last_error_; 1239 } 1240 1241 // Data Connection 1242 1243 int FtpNetworkTransaction::DoDataConnect() { 1244 next_state_ = STATE_DATA_CONNECT_COMPLETE; 1245 IPEndPoint ip_endpoint; 1246 AddressList data_address; 1247 // Connect to the same host as the control socket to prevent PASV port 1248 // scanning attacks. 1249 int rv = ctrl_socket_->GetPeerAddress(&ip_endpoint); 1250 if (rv != OK) 1251 return Stop(rv); 1252 data_address = AddressList::CreateFromIPAddress( 1253 ip_endpoint.address(), data_connection_port_); 1254 data_socket_ = socket_factory_->CreateTransportClientSocket( 1255 data_address, net_log_.net_log(), net_log_.source()); 1256 net_log_.AddEvent( 1257 NetLog::TYPE_FTP_DATA_CONNECTION, 1258 data_socket_->NetLog().source().ToEventParametersCallback()); 1259 return data_socket_->Connect(io_callback_); 1260 } 1261 1262 int FtpNetworkTransaction::DoDataConnectComplete(int result) { 1263 if (result != OK && use_epsv_) { 1264 // It's possible we hit a broken server, sadly. They can break in different 1265 // ways. Some time out, some reset a connection. Fall back to PASV. 1266 // TODO(phajdan.jr): remember it for future transactions with this server. 1267 // TODO(phajdan.jr): write a test for this code path. 1268 use_epsv_ = false; 1269 next_state_ = STATE_CTRL_WRITE_PASV; 1270 return OK; 1271 } 1272 1273 // Only record the connection error after we've applied all our fallbacks. 1274 // We want to capture the final error, one we're not going to recover from. 1275 RecordDataConnectionError(result); 1276 1277 if (result != OK) 1278 return Stop(result); 1279 1280 next_state_ = state_after_data_connect_complete_; 1281 return OK; 1282 } 1283 1284 int FtpNetworkTransaction::DoDataRead() { 1285 DCHECK(read_data_buf_.get()); 1286 DCHECK_GT(read_data_buf_len_, 0); 1287 1288 if (data_socket_ == NULL || !data_socket_->IsConnected()) { 1289 // If we don't destroy the data socket completely, some servers will wait 1290 // for us (http://crbug.com/21127). The half-closed TCP connection needs 1291 // to be closed on our side too. 1292 data_socket_.reset(); 1293 1294 if (ctrl_socket_->IsConnected()) { 1295 // Wait for the server's response, we should get it before sending QUIT. 1296 next_state_ = STATE_CTRL_READ; 1297 return OK; 1298 } 1299 1300 // We are no longer connected to the server, so just finish the transaction. 1301 return Stop(OK); 1302 } 1303 1304 next_state_ = STATE_DATA_READ_COMPLETE; 1305 read_data_buf_->data()[0] = 0; 1306 return data_socket_->Read( 1307 read_data_buf_.get(), read_data_buf_len_, io_callback_); 1308 } 1309 1310 int 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. 1322 void 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