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 (!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(ASCIIToUTF16("anonymous"), 260 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, &addresses_, 654 base::Bind(&FtpNetworkTransaction::OnIOComplete, base::Unretained(this)), 655 net_log_); 656 } 657 658 int FtpNetworkTransaction::DoCtrlResolveHostComplete(int result) { 659 if (result == OK) 660 next_state_ = STATE_CTRL_CONNECT; 661 return result; 662 } 663 664 int FtpNetworkTransaction::DoCtrlConnect() { 665 next_state_ = STATE_CTRL_CONNECT_COMPLETE; 666 ctrl_socket_.reset(socket_factory_->CreateTransportClientSocket( 667 addresses_, net_log_.net_log(), net_log_.source())); 668 net_log_.AddEvent( 669 NetLog::TYPE_FTP_CONTROL_CONNECTION, 670 ctrl_socket_->NetLog().source().ToEventParametersCallback()); 671 return ctrl_socket_->Connect(io_callback_); 672 } 673 674 int FtpNetworkTransaction::DoCtrlConnectComplete(int result) { 675 if (result == OK) { 676 // Put the peer's IP address and port into the response. 677 IPEndPoint ip_endpoint; 678 result = ctrl_socket_->GetPeerAddress(&ip_endpoint); 679 if (result == OK) { 680 response_.socket_address = HostPortPair::FromIPEndPoint(ip_endpoint); 681 next_state_ = STATE_CTRL_READ; 682 683 if (ip_endpoint.GetFamily() == ADDRESS_FAMILY_IPV4) { 684 // Do not use EPSV for IPv4 connections. Some servers become confused 685 // and we time out while waiting to connect. PASV is perfectly fine for 686 // IPv4. Note that this blacklists IPv4 not to use EPSV instead of 687 // whitelisting IPv6 to use it, to make the code more future-proof: 688 // all future protocols should just use EPSV. 689 use_epsv_ = false; 690 } 691 } 692 } 693 return result; 694 } 695 696 int FtpNetworkTransaction::DoCtrlRead() { 697 next_state_ = STATE_CTRL_READ_COMPLETE; 698 return ctrl_socket_->Read(read_ctrl_buf_.get(), kCtrlBufLen, io_callback_); 699 } 700 701 int FtpNetworkTransaction::DoCtrlReadComplete(int result) { 702 if (result == 0) { 703 // Some servers (for example Pure-FTPd) apparently close the control 704 // connection when anonymous login is not permitted. For more details 705 // see http://crbug.com/25023. 706 if (command_sent_ == COMMAND_USER && 707 credentials_.username() == ASCIIToUTF16("anonymous")) { 708 response_.needs_auth = true; 709 } 710 return Stop(ERR_EMPTY_RESPONSE); 711 } 712 if (result < 0) 713 return Stop(result); 714 715 ctrl_response_buffer_->ConsumeData(read_ctrl_buf_->data(), result); 716 717 if (!ctrl_response_buffer_->ResponseAvailable()) { 718 // Read more data from the control socket. 719 next_state_ = STATE_CTRL_READ; 720 return OK; 721 } 722 723 return ProcessCtrlResponse(); 724 } 725 726 int FtpNetworkTransaction::DoCtrlWrite() { 727 next_state_ = STATE_CTRL_WRITE_COMPLETE; 728 729 return ctrl_socket_->Write( 730 write_buf_.get(), write_buf_->BytesRemaining(), io_callback_); 731 } 732 733 int FtpNetworkTransaction::DoCtrlWriteComplete(int result) { 734 if (result < 0) 735 return result; 736 737 write_buf_->DidConsume(result); 738 if (write_buf_->BytesRemaining() == 0) { 739 // Clear the write buffer. 740 write_buf_ = NULL; 741 write_command_buf_ = NULL; 742 743 next_state_ = STATE_CTRL_READ; 744 } else { 745 next_state_ = STATE_CTRL_WRITE; 746 } 747 return OK; 748 } 749 750 // FTP Commands and responses 751 752 // USER Command. 753 int FtpNetworkTransaction::DoCtrlWriteUSER() { 754 std::string command = "USER " + UTF16ToUTF8(credentials_.username()); 755 756 if (!IsValidFTPCommandString(command)) 757 return Stop(ERR_MALFORMED_IDENTITY); 758 759 next_state_ = STATE_CTRL_READ; 760 return SendFtpCommand(command, "USER ***", COMMAND_USER); 761 } 762 763 int FtpNetworkTransaction::ProcessResponseUSER( 764 const FtpCtrlResponse& response) { 765 switch (GetErrorClass(response.status_code)) { 766 case ERROR_CLASS_OK: 767 next_state_ = STATE_CTRL_WRITE_SYST; 768 break; 769 case ERROR_CLASS_INFO_NEEDED: 770 next_state_ = STATE_CTRL_WRITE_PASS; 771 break; 772 case ERROR_CLASS_TRANSIENT_ERROR: 773 case ERROR_CLASS_PERMANENT_ERROR: 774 response_.needs_auth = true; 775 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 776 default: 777 NOTREACHED(); 778 return Stop(ERR_UNEXPECTED); 779 } 780 return OK; 781 } 782 783 // PASS command. 784 int FtpNetworkTransaction::DoCtrlWritePASS() { 785 std::string command = "PASS " + UTF16ToUTF8(credentials_.password()); 786 787 if (!IsValidFTPCommandString(command)) 788 return Stop(ERR_MALFORMED_IDENTITY); 789 790 next_state_ = STATE_CTRL_READ; 791 return SendFtpCommand(command, "PASS ***", COMMAND_PASS); 792 } 793 794 int FtpNetworkTransaction::ProcessResponsePASS( 795 const FtpCtrlResponse& response) { 796 switch (GetErrorClass(response.status_code)) { 797 case ERROR_CLASS_OK: 798 next_state_ = STATE_CTRL_WRITE_SYST; 799 break; 800 case ERROR_CLASS_INFO_NEEDED: 801 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 802 case ERROR_CLASS_TRANSIENT_ERROR: 803 case ERROR_CLASS_PERMANENT_ERROR: 804 response_.needs_auth = true; 805 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 806 default: 807 NOTREACHED(); 808 return Stop(ERR_UNEXPECTED); 809 } 810 return OK; 811 } 812 813 // SYST command. 814 int FtpNetworkTransaction::DoCtrlWriteSYST() { 815 std::string command = "SYST"; 816 next_state_ = STATE_CTRL_READ; 817 return SendFtpCommand(command, command, COMMAND_SYST); 818 } 819 820 int FtpNetworkTransaction::ProcessResponseSYST( 821 const FtpCtrlResponse& response) { 822 switch (GetErrorClass(response.status_code)) { 823 case ERROR_CLASS_INITIATED: 824 return Stop(ERR_INVALID_RESPONSE); 825 case ERROR_CLASS_OK: { 826 // All important info should be on the first line. 827 std::string line = response.lines[0]; 828 // The response should be ASCII, which allows us to do case-insensitive 829 // comparisons easily. If it is not ASCII, we leave the system type 830 // as unknown. 831 if (IsStringASCII(line)) { 832 line = StringToLowerASCII(line); 833 834 // Remove all whitespace, to correctly handle cases like fancy "V M S" 835 // response instead of "VMS". 836 RemoveChars(line, kWhitespaceASCII, &line); 837 838 // The "magic" strings we test for below have been gathered by an 839 // empirical study. VMS needs to come first because some VMS systems 840 // also respond with "UNIX emulation", which is not perfect. It is much 841 // more reliable to talk to these servers in their native language. 842 if (line.find("vms") != std::string::npos) { 843 system_type_ = SYSTEM_TYPE_VMS; 844 } else if (line.find("l8") != std::string::npos || 845 line.find("unix") != std::string::npos || 846 line.find("bsd") != std::string::npos) { 847 system_type_ = SYSTEM_TYPE_UNIX; 848 } else if (line.find("win32") != std::string::npos || 849 line.find("windows") != std::string::npos) { 850 system_type_ = SYSTEM_TYPE_WINDOWS; 851 } else if (line.find("os/2") != std::string::npos) { 852 system_type_ = SYSTEM_TYPE_OS2; 853 } 854 } 855 next_state_ = STATE_CTRL_WRITE_PWD; 856 break; 857 } 858 case ERROR_CLASS_INFO_NEEDED: 859 return Stop(ERR_INVALID_RESPONSE); 860 case ERROR_CLASS_TRANSIENT_ERROR: 861 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 862 case ERROR_CLASS_PERMANENT_ERROR: 863 // Server does not recognize the SYST command so proceed. 864 next_state_ = STATE_CTRL_WRITE_PWD; 865 break; 866 default: 867 NOTREACHED(); 868 return Stop(ERR_UNEXPECTED); 869 } 870 return OK; 871 } 872 873 // PWD command. 874 int FtpNetworkTransaction::DoCtrlWritePWD() { 875 std::string command = "PWD"; 876 next_state_ = STATE_CTRL_READ; 877 return SendFtpCommand(command, command, COMMAND_PWD); 878 } 879 880 int FtpNetworkTransaction::ProcessResponsePWD(const FtpCtrlResponse& response) { 881 switch (GetErrorClass(response.status_code)) { 882 case ERROR_CLASS_INITIATED: 883 return Stop(ERR_INVALID_RESPONSE); 884 case ERROR_CLASS_OK: { 885 // The info we look for should be on the first line. 886 std::string line = response.lines[0]; 887 if (line.empty()) 888 return Stop(ERR_INVALID_RESPONSE); 889 std::string::size_type quote_pos = line.find('"'); 890 if (quote_pos != std::string::npos) { 891 line = line.substr(quote_pos + 1); 892 quote_pos = line.find('"'); 893 if (quote_pos == std::string::npos) 894 return Stop(ERR_INVALID_RESPONSE); 895 line = line.substr(0, quote_pos); 896 } 897 if (system_type_ == SYSTEM_TYPE_VMS) 898 line = FtpUtil::VMSPathToUnix(line); 899 if (line.length() && line[line.length() - 1] == '/') 900 line.erase(line.length() - 1); 901 current_remote_directory_ = line; 902 next_state_ = STATE_CTRL_WRITE_TYPE; 903 break; 904 } 905 case ERROR_CLASS_INFO_NEEDED: 906 return Stop(ERR_INVALID_RESPONSE); 907 case ERROR_CLASS_TRANSIENT_ERROR: 908 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 909 case ERROR_CLASS_PERMANENT_ERROR: 910 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 911 default: 912 NOTREACHED(); 913 return Stop(ERR_UNEXPECTED); 914 } 915 return OK; 916 } 917 918 // TYPE command. 919 int FtpNetworkTransaction::DoCtrlWriteTYPE() { 920 std::string command = "TYPE "; 921 if (data_type_ == DATA_TYPE_ASCII) { 922 command += "A"; 923 } else if (data_type_ == DATA_TYPE_IMAGE) { 924 command += "I"; 925 } else { 926 NOTREACHED(); 927 return Stop(ERR_UNEXPECTED); 928 } 929 next_state_ = STATE_CTRL_READ; 930 return SendFtpCommand(command, command, COMMAND_TYPE); 931 } 932 933 int FtpNetworkTransaction::ProcessResponseTYPE( 934 const FtpCtrlResponse& response) { 935 switch (GetErrorClass(response.status_code)) { 936 case ERROR_CLASS_INITIATED: 937 return Stop(ERR_INVALID_RESPONSE); 938 case ERROR_CLASS_OK: 939 next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; 940 break; 941 case ERROR_CLASS_INFO_NEEDED: 942 return Stop(ERR_INVALID_RESPONSE); 943 case ERROR_CLASS_TRANSIENT_ERROR: 944 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 945 case ERROR_CLASS_PERMANENT_ERROR: 946 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 947 default: 948 NOTREACHED(); 949 return Stop(ERR_UNEXPECTED); 950 } 951 return OK; 952 } 953 954 // EPSV command 955 int FtpNetworkTransaction::DoCtrlWriteEPSV() { 956 const std::string command = "EPSV"; 957 next_state_ = STATE_CTRL_READ; 958 return SendFtpCommand(command, command, COMMAND_EPSV); 959 } 960 961 int FtpNetworkTransaction::ProcessResponseEPSV( 962 const FtpCtrlResponse& response) { 963 switch (GetErrorClass(response.status_code)) { 964 case ERROR_CLASS_INITIATED: 965 return Stop(ERR_INVALID_RESPONSE); 966 case ERROR_CLASS_OK: 967 if (!ExtractPortFromEPSVResponse( response, &data_connection_port_)) 968 return Stop(ERR_INVALID_RESPONSE); 969 if (data_connection_port_ < 1024 || 970 !IsPortAllowedByFtp(data_connection_port_)) 971 return Stop(ERR_UNSAFE_PORT); 972 next_state_ = STATE_DATA_CONNECT; 973 break; 974 case ERROR_CLASS_INFO_NEEDED: 975 return Stop(ERR_INVALID_RESPONSE); 976 case ERROR_CLASS_TRANSIENT_ERROR: 977 case ERROR_CLASS_PERMANENT_ERROR: 978 use_epsv_ = false; 979 next_state_ = STATE_CTRL_WRITE_PASV; 980 return OK; 981 default: 982 NOTREACHED(); 983 return Stop(ERR_UNEXPECTED); 984 } 985 return OK; 986 } 987 988 // PASV command 989 int FtpNetworkTransaction::DoCtrlWritePASV() { 990 std::string command = "PASV"; 991 next_state_ = STATE_CTRL_READ; 992 return SendFtpCommand(command, command, COMMAND_PASV); 993 } 994 995 int FtpNetworkTransaction::ProcessResponsePASV( 996 const FtpCtrlResponse& response) { 997 switch (GetErrorClass(response.status_code)) { 998 case ERROR_CLASS_INITIATED: 999 return Stop(ERR_INVALID_RESPONSE); 1000 case ERROR_CLASS_OK: 1001 if (!ExtractPortFromPASVResponse(response, &data_connection_port_)) 1002 return Stop(ERR_INVALID_RESPONSE); 1003 if (data_connection_port_ < 1024 || 1004 !IsPortAllowedByFtp(data_connection_port_)) 1005 return Stop(ERR_UNSAFE_PORT); 1006 next_state_ = STATE_DATA_CONNECT; 1007 break; 1008 case ERROR_CLASS_INFO_NEEDED: 1009 return Stop(ERR_INVALID_RESPONSE); 1010 case ERROR_CLASS_TRANSIENT_ERROR: 1011 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1012 case ERROR_CLASS_PERMANENT_ERROR: 1013 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1014 default: 1015 NOTREACHED(); 1016 return Stop(ERR_UNEXPECTED); 1017 } 1018 return OK; 1019 } 1020 1021 // RETR command 1022 int FtpNetworkTransaction::DoCtrlWriteRETR() { 1023 std::string command = "RETR " + GetRequestPathForFtpCommand(false); 1024 next_state_ = STATE_CTRL_READ; 1025 return SendFtpCommand(command, command, COMMAND_RETR); 1026 } 1027 1028 int FtpNetworkTransaction::ProcessResponseRETR( 1029 const FtpCtrlResponse& response) { 1030 switch (GetErrorClass(response.status_code)) { 1031 case ERROR_CLASS_INITIATED: 1032 // We want the client to start reading the response at this point. 1033 // It got here either through Start or RestartWithAuth. We want that 1034 // method to complete. Not setting next state here will make DoLoop exit 1035 // and in turn make Start/RestartWithAuth complete. 1036 resource_type_ = RESOURCE_TYPE_FILE; 1037 break; 1038 case ERROR_CLASS_OK: 1039 resource_type_ = RESOURCE_TYPE_FILE; 1040 next_state_ = STATE_CTRL_WRITE_QUIT; 1041 break; 1042 case ERROR_CLASS_INFO_NEEDED: 1043 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1044 case ERROR_CLASS_TRANSIENT_ERROR: 1045 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1046 case ERROR_CLASS_PERMANENT_ERROR: 1047 // Code 550 means "Failed to open file". Other codes are unrelated, 1048 // like "Not logged in" etc. 1049 if (response.status_code != 550 || resource_type_ == RESOURCE_TYPE_FILE) 1050 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1051 1052 // It's possible that RETR failed because the path is a directory. 1053 resource_type_ = RESOURCE_TYPE_DIRECTORY; 1054 1055 // We're going to try CWD next, but first send a PASV one more time, 1056 // because some FTP servers, including FileZilla, require that. 1057 // See http://crbug.com/25316. 1058 next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; 1059 break; 1060 default: 1061 NOTREACHED(); 1062 return Stop(ERR_UNEXPECTED); 1063 } 1064 1065 // We should be sure about our resource type now. Otherwise we risk 1066 // an infinite loop (RETR can later send CWD, and CWD can later send RETR). 1067 DCHECK_NE(RESOURCE_TYPE_UNKNOWN, resource_type_); 1068 1069 return OK; 1070 } 1071 1072 // SIZE command 1073 int FtpNetworkTransaction::DoCtrlWriteSIZE() { 1074 std::string command = "SIZE " + GetRequestPathForFtpCommand(false); 1075 next_state_ = STATE_CTRL_READ; 1076 return SendFtpCommand(command, command, COMMAND_SIZE); 1077 } 1078 1079 int FtpNetworkTransaction::ProcessResponseSIZE( 1080 const FtpCtrlResponse& response) { 1081 State state_after_size; 1082 if (resource_type_ == RESOURCE_TYPE_FILE) 1083 state_after_size = STATE_CTRL_WRITE_RETR; 1084 else 1085 state_after_size = STATE_CTRL_WRITE_CWD; 1086 1087 switch (GetErrorClass(response.status_code)) { 1088 case ERROR_CLASS_INITIATED: 1089 next_state_ = state_after_size; 1090 break; 1091 case ERROR_CLASS_OK: 1092 if (response.lines.size() != 1) 1093 return Stop(ERR_INVALID_RESPONSE); 1094 int64 size; 1095 if (!base::StringToInt64(response.lines[0], &size)) 1096 return Stop(ERR_INVALID_RESPONSE); 1097 if (size < 0) 1098 return Stop(ERR_INVALID_RESPONSE); 1099 1100 // A successful response to SIZE does not mean the resource is a file. 1101 // Some FTP servers (for example, the qnx one) send a SIZE even for 1102 // directories. 1103 response_.expected_content_size = size; 1104 1105 next_state_ = state_after_size; 1106 break; 1107 case ERROR_CLASS_INFO_NEEDED: 1108 next_state_ = state_after_size; 1109 break; 1110 case ERROR_CLASS_TRANSIENT_ERROR: 1111 ResetDataConnectionAfterError(state_after_size); 1112 break; 1113 case ERROR_CLASS_PERMANENT_ERROR: 1114 // It's possible that SIZE failed because the path is a directory. 1115 if (resource_type_ == RESOURCE_TYPE_UNKNOWN && 1116 response.status_code != 550) { 1117 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1118 } 1119 1120 ResetDataConnectionAfterError(state_after_size); 1121 break; 1122 default: 1123 NOTREACHED(); 1124 return Stop(ERR_UNEXPECTED); 1125 } 1126 1127 return OK; 1128 } 1129 1130 // CWD command 1131 int FtpNetworkTransaction::DoCtrlWriteCWD() { 1132 std::string command = "CWD " + GetRequestPathForFtpCommand(true); 1133 next_state_ = STATE_CTRL_READ; 1134 return SendFtpCommand(command, command, COMMAND_CWD); 1135 } 1136 1137 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { 1138 // We should never issue CWD if we know the target resource is a file. 1139 DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_); 1140 1141 switch (GetErrorClass(response.status_code)) { 1142 case ERROR_CLASS_INITIATED: 1143 return Stop(ERR_INVALID_RESPONSE); 1144 case ERROR_CLASS_OK: 1145 next_state_ = STATE_CTRL_WRITE_LIST; 1146 break; 1147 case ERROR_CLASS_INFO_NEEDED: 1148 return Stop(ERR_INVALID_RESPONSE); 1149 case ERROR_CLASS_TRANSIENT_ERROR: 1150 // Some FTP servers send response 451 (not a valid CWD response according 1151 // to RFC 959) instead of 550. 1152 if (response.status_code == 451) 1153 return ProcessResponseCWDNotADirectory(); 1154 1155 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1156 case ERROR_CLASS_PERMANENT_ERROR: 1157 if (response.status_code == 550) 1158 return ProcessResponseCWDNotADirectory(); 1159 1160 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1161 default: 1162 NOTREACHED(); 1163 return Stop(ERR_UNEXPECTED); 1164 } 1165 1166 return OK; 1167 } 1168 1169 int FtpNetworkTransaction::ProcessResponseCWDNotADirectory() { 1170 if (resource_type_ == RESOURCE_TYPE_DIRECTORY) { 1171 // We're assuming that the resource is a directory, but the server 1172 // says it's not true. The most probable interpretation is that it 1173 // doesn't exist (with FTP we can't be sure). 1174 return Stop(ERR_FILE_NOT_FOUND); 1175 } 1176 1177 // We are here because SIZE failed and we are not sure what the resource 1178 // type is. It could still be file, and SIZE could fail because of 1179 // an access error (http://crbug.com/56734). Try RETR just to be sure. 1180 resource_type_ = RESOURCE_TYPE_FILE; 1181 1182 ResetDataConnectionAfterError(STATE_CTRL_WRITE_RETR); 1183 return OK; 1184 } 1185 1186 // LIST command 1187 int FtpNetworkTransaction::DoCtrlWriteLIST() { 1188 // Use the -l option for mod_ftp configured in LISTIsNLST mode: the option 1189 // forces LIST output instead of NLST (which would be ambiguous for us 1190 // to parse). 1191 std::string command("LIST -l"); 1192 if (system_type_ == SYSTEM_TYPE_VMS) 1193 command = "LIST *.*;0"; 1194 1195 next_state_ = STATE_CTRL_READ; 1196 return SendFtpCommand(command, command, COMMAND_LIST); 1197 } 1198 1199 int FtpNetworkTransaction::ProcessResponseLIST( 1200 const FtpCtrlResponse& response) { 1201 switch (GetErrorClass(response.status_code)) { 1202 case ERROR_CLASS_INITIATED: 1203 // We want the client to start reading the response at this point. 1204 // It got here either through Start or RestartWithAuth. We want that 1205 // method to complete. Not setting next state here will make DoLoop exit 1206 // and in turn make Start/RestartWithAuth complete. 1207 response_.is_directory_listing = true; 1208 break; 1209 case ERROR_CLASS_OK: 1210 response_.is_directory_listing = true; 1211 next_state_ = STATE_CTRL_WRITE_QUIT; 1212 break; 1213 case ERROR_CLASS_INFO_NEEDED: 1214 return Stop(ERR_INVALID_RESPONSE); 1215 case ERROR_CLASS_TRANSIENT_ERROR: 1216 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1217 case ERROR_CLASS_PERMANENT_ERROR: 1218 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1219 default: 1220 NOTREACHED(); 1221 return Stop(ERR_UNEXPECTED); 1222 } 1223 return OK; 1224 } 1225 1226 // QUIT command 1227 int FtpNetworkTransaction::DoCtrlWriteQUIT() { 1228 std::string command = "QUIT"; 1229 next_state_ = STATE_CTRL_READ; 1230 return SendFtpCommand(command, command, COMMAND_QUIT); 1231 } 1232 1233 int FtpNetworkTransaction::ProcessResponseQUIT( 1234 const FtpCtrlResponse& response) { 1235 ctrl_socket_->Disconnect(); 1236 return last_error_; 1237 } 1238 1239 // Data Connection 1240 1241 int FtpNetworkTransaction::DoDataConnect() { 1242 next_state_ = STATE_DATA_CONNECT_COMPLETE; 1243 IPEndPoint ip_endpoint; 1244 AddressList data_address; 1245 // Connect to the same host as the control socket to prevent PASV port 1246 // scanning attacks. 1247 int rv = ctrl_socket_->GetPeerAddress(&ip_endpoint); 1248 if (rv != OK) 1249 return Stop(rv); 1250 data_address = AddressList::CreateFromIPAddress( 1251 ip_endpoint.address(), data_connection_port_); 1252 data_socket_.reset(socket_factory_->CreateTransportClientSocket( 1253 data_address, net_log_.net_log(), net_log_.source())); 1254 net_log_.AddEvent( 1255 NetLog::TYPE_FTP_DATA_CONNECTION, 1256 data_socket_->NetLog().source().ToEventParametersCallback()); 1257 return data_socket_->Connect(io_callback_); 1258 } 1259 1260 int FtpNetworkTransaction::DoDataConnectComplete(int result) { 1261 if (result != OK && use_epsv_) { 1262 // It's possible we hit a broken server, sadly. They can break in different 1263 // ways. Some time out, some reset a connection. Fall back to PASV. 1264 // TODO(phajdan.jr): remember it for future transactions with this server. 1265 // TODO(phajdan.jr): write a test for this code path. 1266 use_epsv_ = false; 1267 next_state_ = STATE_CTRL_WRITE_PASV; 1268 return OK; 1269 } 1270 1271 // Only record the connection error after we've applied all our fallbacks. 1272 // We want to capture the final error, one we're not going to recover from. 1273 RecordDataConnectionError(result); 1274 1275 if (result != OK) 1276 return Stop(result); 1277 1278 next_state_ = state_after_data_connect_complete_; 1279 return OK; 1280 } 1281 1282 int FtpNetworkTransaction::DoDataRead() { 1283 DCHECK(read_data_buf_.get()); 1284 DCHECK_GT(read_data_buf_len_, 0); 1285 1286 if (data_socket_ == NULL || !data_socket_->IsConnected()) { 1287 // If we don't destroy the data socket completely, some servers will wait 1288 // for us (http://crbug.com/21127). The half-closed TCP connection needs 1289 // to be closed on our side too. 1290 data_socket_.reset(); 1291 1292 if (ctrl_socket_->IsConnected()) { 1293 // Wait for the server's response, we should get it before sending QUIT. 1294 next_state_ = STATE_CTRL_READ; 1295 return OK; 1296 } 1297 1298 // We are no longer connected to the server, so just finish the transaction. 1299 return Stop(OK); 1300 } 1301 1302 next_state_ = STATE_DATA_READ_COMPLETE; 1303 read_data_buf_->data()[0] = 0; 1304 return data_socket_->Read( 1305 read_data_buf_.get(), read_data_buf_len_, io_callback_); 1306 } 1307 1308 int FtpNetworkTransaction::DoDataReadComplete(int result) { 1309 return result; 1310 } 1311 1312 // We're using a histogram as a group of counters, with one bucket for each 1313 // enumeration value. We're only interested in the values of the counters. 1314 // Ignore the shape, average, and standard deviation of the histograms because 1315 // they are meaningless. 1316 // 1317 // We use two histograms. In the first histogram we tally whether the user has 1318 // seen an error of that type during the session. In the second histogram we 1319 // tally the total number of times the users sees each errer. 1320 void FtpNetworkTransaction::RecordDataConnectionError(int result) { 1321 // Gather data for http://crbug.com/3073. See how many users have trouble 1322 // establishing FTP data connection in passive FTP mode. 1323 enum { 1324 // Data connection successful. 1325 NET_ERROR_OK = 0, 1326 1327 // Local firewall blocked the connection. 1328 NET_ERROR_ACCESS_DENIED = 1, 1329 1330 // Connection timed out. 1331 NET_ERROR_TIMED_OUT = 2, 1332 1333 // Connection has been estabilished, but then got broken (either reset 1334 // or aborted). 1335 NET_ERROR_CONNECTION_BROKEN = 3, 1336 1337 // Connection has been refused. 1338 NET_ERROR_CONNECTION_REFUSED = 4, 1339 1340 // No connection to the internet. 1341 NET_ERROR_INTERNET_DISCONNECTED = 5, 1342 1343 // Could not reach the destination address. 1344 NET_ERROR_ADDRESS_UNREACHABLE = 6, 1345 1346 // A programming error in our network stack. 1347 NET_ERROR_UNEXPECTED = 7, 1348 1349 // Other kind of error. 1350 NET_ERROR_OTHER = 20, 1351 1352 NUM_OF_NET_ERROR_TYPES 1353 } type; 1354 switch (result) { 1355 case OK: 1356 type = NET_ERROR_OK; 1357 break; 1358 case ERR_ACCESS_DENIED: 1359 case ERR_NETWORK_ACCESS_DENIED: 1360 type = NET_ERROR_ACCESS_DENIED; 1361 break; 1362 case ERR_TIMED_OUT: 1363 type = NET_ERROR_TIMED_OUT; 1364 break; 1365 case ERR_CONNECTION_ABORTED: 1366 case ERR_CONNECTION_RESET: 1367 case ERR_CONNECTION_CLOSED: 1368 type = NET_ERROR_CONNECTION_BROKEN; 1369 break; 1370 case ERR_CONNECTION_FAILED: 1371 case ERR_CONNECTION_REFUSED: 1372 type = NET_ERROR_CONNECTION_REFUSED; 1373 break; 1374 case ERR_INTERNET_DISCONNECTED: 1375 type = NET_ERROR_INTERNET_DISCONNECTED; 1376 break; 1377 case ERR_ADDRESS_INVALID: 1378 case ERR_ADDRESS_UNREACHABLE: 1379 type = NET_ERROR_ADDRESS_UNREACHABLE; 1380 break; 1381 case ERR_UNEXPECTED: 1382 type = NET_ERROR_UNEXPECTED; 1383 break; 1384 default: 1385 type = NET_ERROR_OTHER; 1386 break; 1387 }; 1388 static bool had_error_type[NUM_OF_NET_ERROR_TYPES]; 1389 1390 DCHECK(type >= 0 && type < NUM_OF_NET_ERROR_TYPES); 1391 if (!had_error_type[type]) { 1392 had_error_type[type] = true; 1393 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", 1394 type, NUM_OF_NET_ERROR_TYPES); 1395 } 1396 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", 1397 type, NUM_OF_NET_ERROR_TYPES); 1398 } 1399 1400 } // namespace net 1401