OLD | NEW |
---|---|
1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. Use of this | 1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. Use of this |
2 // source code is governed by a BSD-style license that can be found in the | 2 // source code is governed by a BSD-style license that can be found in the |
3 // LICENSE file. | 3 // LICENSE file. |
4 | 4 |
5 #include "net/ftp/ftp_network_transaction.h" | 5 #include "net/ftp/ftp_network_transaction.h" |
6 | 6 |
7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
8 #include "base/string_util.h" | 8 #include "base/string_util.h" |
9 #include "net/base/connection_type_histograms.h" | 9 #include "net/base/connection_type_histograms.h" |
10 #include "net/base/load_log.h" | 10 #include "net/base/load_log.h" |
(...skipping 18 matching lines...) Expand all Loading... | |
29 FtpNetworkSession* session, | 29 FtpNetworkSession* session, |
30 ClientSocketFactory* socket_factory) | 30 ClientSocketFactory* socket_factory) |
31 : command_sent_(COMMAND_NONE), | 31 : command_sent_(COMMAND_NONE), |
32 ALLOW_THIS_IN_INITIALIZER_LIST( | 32 ALLOW_THIS_IN_INITIALIZER_LIST( |
33 io_callback_(this, &FtpNetworkTransaction::OnIOComplete)), | 33 io_callback_(this, &FtpNetworkTransaction::OnIOComplete)), |
34 user_callback_(NULL), | 34 user_callback_(NULL), |
35 session_(session), | 35 session_(session), |
36 request_(NULL), | 36 request_(NULL), |
37 resolver_(session->host_resolver()), | 37 resolver_(session->host_resolver()), |
38 read_ctrl_buf_(new IOBuffer(kCtrlBufLen)), | 38 read_ctrl_buf_(new IOBuffer(kCtrlBufLen)), |
39 ctrl_response_buffer_(new FtpCtrlResponseBuffer()), | |
39 read_data_buf_len_(0), | 40 read_data_buf_len_(0), |
40 file_data_len_(0), | 41 file_data_len_(0), |
41 write_command_buf_written_(0), | 42 write_command_buf_written_(0), |
42 last_error_(OK), | 43 last_error_(OK), |
43 is_anonymous_(false), | |
44 retr_failed_(false), | 44 retr_failed_(false), |
45 data_connection_port_(0), | 45 data_connection_port_(0), |
46 socket_factory_(socket_factory), | 46 socket_factory_(socket_factory), |
47 next_state_(STATE_NONE) { | 47 next_state_(STATE_NONE) { |
48 } | 48 } |
49 | 49 |
50 FtpNetworkTransaction::~FtpNetworkTransaction() { | 50 FtpNetworkTransaction::~FtpNetworkTransaction() { |
51 } | 51 } |
52 | 52 |
53 int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info, | 53 int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info, |
54 CompletionCallback* callback, | 54 CompletionCallback* callback, |
55 LoadLog* load_log) { | 55 LoadLog* load_log) { |
56 load_log_ = load_log; | 56 load_log_ = load_log; |
57 request_ = request_info; | 57 request_ = request_info; |
58 | 58 |
59 if (request_->url.has_username()) { | |
60 username_ = UTF8ToWide(request_->url.username()); | |
wtc
2009/08/25 20:52:50
Please ask Darin and Brett whether the embedded us
eroman
2009/09/01 07:12:37
They definitely do need to be unescaped.
See Http
| |
61 if (request_->url.has_password()) | |
eroman
2009/09/01 07:12:37
Don't actually need the guard, will just be empty
| |
62 password_ = UTF8ToWide(request_->url.password()); | |
63 else | |
wtc
2009/08/25 20:52:50
Do we need the "else" here? password_ is initiali
| |
64 password_ = L""; | |
65 } else { | |
66 username_ = L"anonymous"; | |
67 password_ = L"chrome@example.com"; | |
68 } | |
69 | |
59 next_state_ = STATE_CTRL_INIT; | 70 next_state_ = STATE_CTRL_INIT; |
60 int rv = DoLoop(OK); | 71 int rv = DoLoop(OK); |
61 if (rv == ERR_IO_PENDING) | 72 if (rv == ERR_IO_PENDING) |
62 user_callback_ = callback; | 73 user_callback_ = callback; |
63 return rv; | 74 return rv; |
64 } | 75 } |
65 | 76 |
66 int FtpNetworkTransaction::Stop(int error) { | 77 int FtpNetworkTransaction::Stop(int error) { |
67 if (command_sent_ == COMMAND_QUIT) | 78 if (command_sent_ == COMMAND_QUIT) |
68 return error; | 79 return error; |
69 | 80 |
70 next_state_ = STATE_CTRL_WRITE_QUIT; | 81 next_state_ = STATE_CTRL_WRITE_QUIT; |
71 last_error_ = error; | 82 last_error_ = error; |
72 return OK; | 83 return OK; |
73 } | 84 } |
74 | 85 |
75 int FtpNetworkTransaction::RestartWithAuth(const std::wstring& username, | 86 int FtpNetworkTransaction::RestartWithAuth(const std::wstring& username, |
76 const std::wstring& password, | 87 const std::wstring& password, |
77 CompletionCallback* callback) { | 88 CompletionCallback* callback) { |
78 return ERR_FAILED; | 89 ResetStateForRestart(); |
90 | |
91 username_ = username; | |
92 password_ = password; | |
93 | |
94 next_state_ = STATE_CTRL_INIT; | |
95 int rv = DoLoop(OK); | |
96 if (rv == ERR_IO_PENDING) | |
97 user_callback_ = callback; | |
98 return rv; | |
79 } | 99 } |
80 | 100 |
81 int FtpNetworkTransaction::RestartIgnoringLastError( | 101 int FtpNetworkTransaction::RestartIgnoringLastError( |
82 CompletionCallback* callback) { | 102 CompletionCallback* callback) { |
83 return ERR_FAILED; | 103 return ERR_FAILED; |
84 } | 104 } |
85 | 105 |
86 int FtpNetworkTransaction::Read(IOBuffer* buf, | 106 int FtpNetworkTransaction::Read(IOBuffer* buf, |
87 int buf_len, | 107 int buf_len, |
88 CompletionCallback* callback) { | 108 CompletionCallback* callback) { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
127 uint64 FtpNetworkTransaction::GetUploadProgress() const { | 147 uint64 FtpNetworkTransaction::GetUploadProgress() const { |
128 return 0; | 148 return 0; |
129 } | 149 } |
130 | 150 |
131 // Used to prepare and send FTP command. | 151 // Used to prepare and send FTP command. |
132 int FtpNetworkTransaction::SendFtpCommand(const std::string& command, | 152 int FtpNetworkTransaction::SendFtpCommand(const std::string& command, |
133 Command cmd) { | 153 Command cmd) { |
134 // If we send a new command when we still have unprocessed responses | 154 // If we send a new command when we still have unprocessed responses |
135 // for previous commands, the response receiving code will have no way to know | 155 // for previous commands, the response receiving code will have no way to know |
136 // which responses are for which command. | 156 // which responses are for which command. |
137 DCHECK(!ctrl_response_buffer_.ResponseAvailable()); | 157 DCHECK(!ctrl_response_buffer_->ResponseAvailable()); |
138 | 158 |
139 DCHECK(!write_command_buf_); | 159 DCHECK(!write_command_buf_); |
140 DCHECK(!write_buf_); | 160 DCHECK(!write_buf_); |
141 DLOG(INFO) << " >> " << command; | 161 DLOG(INFO) << " >> " << command; |
142 | 162 |
143 command_sent_ = cmd; | 163 command_sent_ = cmd; |
144 | 164 |
145 write_command_buf_ = new IOBufferWithSize(command.length() + 2); | 165 write_command_buf_ = new IOBufferWithSize(command.length() + 2); |
146 write_buf_ = new ReusedIOBuffer(write_command_buf_, | 166 write_buf_ = new ReusedIOBuffer(write_command_buf_, |
147 write_command_buf_->size()); | 167 write_command_buf_->size()); |
(...skipping 21 matching lines...) Expand all Loading... | |
169 | 189 |
170 if (response_code >= 500 && response_code <= 599) | 190 if (response_code >= 500 && response_code <= 599) |
171 return ERROR_CLASS_PERMANENT_ERROR; | 191 return ERROR_CLASS_PERMANENT_ERROR; |
172 | 192 |
173 // We should not be called on invalid error codes. | 193 // We should not be called on invalid error codes. |
174 NOTREACHED(); | 194 NOTREACHED(); |
175 return ERROR_CLASS_PERMANENT_ERROR; | 195 return ERROR_CLASS_PERMANENT_ERROR; |
176 } | 196 } |
177 | 197 |
178 int FtpNetworkTransaction::ProcessCtrlResponse() { | 198 int FtpNetworkTransaction::ProcessCtrlResponse() { |
179 FtpCtrlResponse response = ctrl_response_buffer_.PopResponse(); | 199 FtpCtrlResponse response = ctrl_response_buffer_->PopResponse(); |
180 | 200 |
181 int rv = OK; | 201 int rv = OK; |
182 switch (command_sent_) { | 202 switch (command_sent_) { |
183 case COMMAND_NONE: | 203 case COMMAND_NONE: |
184 // TODO(phajdan.jr): Check for errors in the welcome message. | 204 // TODO(phajdan.jr): Check for errors in the welcome message. |
185 next_state_ = STATE_CTRL_WRITE_USER; | 205 next_state_ = STATE_CTRL_WRITE_USER; |
186 break; | 206 break; |
187 case COMMAND_USER: | 207 case COMMAND_USER: |
188 rv = ProcessResponseUSER(response); | 208 rv = ProcessResponseUSER(response); |
189 break; | 209 break; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
223 case COMMAND_QUIT: | 243 case COMMAND_QUIT: |
224 rv = ProcessResponseQUIT(response); | 244 rv = ProcessResponseQUIT(response); |
225 break; | 245 break; |
226 default: | 246 default: |
227 LOG(DFATAL) << "Unexpected value of command_sent_: " << command_sent_; | 247 LOG(DFATAL) << "Unexpected value of command_sent_: " << command_sent_; |
228 return ERR_UNEXPECTED; | 248 return ERR_UNEXPECTED; |
229 } | 249 } |
230 | 250 |
231 // We may get multiple responses for some commands, | 251 // We may get multiple responses for some commands, |
232 // see http://crbug.com/18036. | 252 // see http://crbug.com/18036. |
233 while (ctrl_response_buffer_.ResponseAvailable() && rv == OK) { | 253 while (ctrl_response_buffer_->ResponseAvailable() && rv == OK) { |
234 response = ctrl_response_buffer_.PopResponse(); | 254 response = ctrl_response_buffer_->PopResponse(); |
235 | 255 |
236 switch (command_sent_) { | 256 switch (command_sent_) { |
237 case COMMAND_RETR: | 257 case COMMAND_RETR: |
238 rv = ProcessResponseRETR(response); | 258 rv = ProcessResponseRETR(response); |
239 break; | 259 break; |
240 default: | 260 default: |
241 // Multiple responses for other commands are invalid. | 261 // Multiple responses for other commands are invalid. |
242 return Stop(ERR_INVALID_RESPONSE); | 262 return Stop(ERR_INVALID_RESPONSE); |
243 } | 263 } |
244 } | 264 } |
245 | 265 |
246 return rv; | 266 return rv; |
247 } | 267 } |
248 | 268 |
269 void FtpNetworkTransaction::ResetStateForRestart() { | |
270 command_sent_ = COMMAND_NONE; | |
271 user_callback_ = NULL; | |
272 response_ = FtpResponseInfo(); | |
273 read_ctrl_buf_ = new IOBuffer(kCtrlBufLen); | |
274 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer()); | |
275 read_data_buf_ = NULL; | |
276 read_data_buf_len_ = 0; | |
277 file_data_len_ = 0; | |
278 write_command_buf_written_ = 0; | |
279 last_error_ = OK; | |
280 retr_failed_ = false; | |
281 data_connection_port_ = 0; | |
282 ctrl_socket_.reset(); | |
283 data_socket_.reset(); | |
284 next_state_ = STATE_NONE; | |
285 } | |
286 | |
249 void FtpNetworkTransaction::DoCallback(int rv) { | 287 void FtpNetworkTransaction::DoCallback(int rv) { |
250 DCHECK(rv != ERR_IO_PENDING); | 288 DCHECK(rv != ERR_IO_PENDING); |
251 DCHECK(user_callback_); | 289 DCHECK(user_callback_); |
252 | 290 |
253 // Since Run may result in Read being called, clear callback_ up front. | 291 // Since Run may result in Read being called, clear callback_ up front. |
254 CompletionCallback* c = user_callback_; | 292 CompletionCallback* c = user_callback_; |
255 user_callback_ = NULL; | 293 user_callback_ = NULL; |
256 c->Run(rv); | 294 c->Run(rv); |
257 } | 295 } |
258 | 296 |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
436 return ctrl_socket_->Read( | 474 return ctrl_socket_->Read( |
437 read_ctrl_buf_, | 475 read_ctrl_buf_, |
438 kCtrlBufLen, | 476 kCtrlBufLen, |
439 &io_callback_); | 477 &io_callback_); |
440 } | 478 } |
441 | 479 |
442 int FtpNetworkTransaction::DoCtrlReadComplete(int result) { | 480 int FtpNetworkTransaction::DoCtrlReadComplete(int result) { |
443 if (result < 0) | 481 if (result < 0) |
444 return Stop(result); | 482 return Stop(result); |
445 | 483 |
446 ctrl_response_buffer_.ConsumeData(read_ctrl_buf_->data(), result); | 484 ctrl_response_buffer_->ConsumeData(read_ctrl_buf_->data(), result); |
447 | 485 |
448 if (!ctrl_response_buffer_.ResponseAvailable()) { | 486 if (!ctrl_response_buffer_->ResponseAvailable()) { |
449 // Read more data from the control socket. | 487 // Read more data from the control socket. |
450 next_state_ = STATE_CTRL_READ; | 488 next_state_ = STATE_CTRL_READ; |
451 return OK; | 489 return OK; |
452 } | 490 } |
453 | 491 |
454 return ProcessCtrlResponse(); | 492 return ProcessCtrlResponse(); |
455 } | 493 } |
456 | 494 |
457 int FtpNetworkTransaction::DoCtrlWrite() { | 495 int FtpNetworkTransaction::DoCtrlWrite() { |
458 next_state_ = STATE_CTRL_WRITE_COMPLETE; | 496 next_state_ = STATE_CTRL_WRITE_COMPLETE; |
(...skipping 20 matching lines...) Expand all Loading... | |
479 } else { | 517 } else { |
480 next_state_ = STATE_CTRL_WRITE; | 518 next_state_ = STATE_CTRL_WRITE; |
481 } | 519 } |
482 return OK; | 520 return OK; |
483 } | 521 } |
484 | 522 |
485 // FTP Commands and responses | 523 // FTP Commands and responses |
486 | 524 |
487 // USER Command. | 525 // USER Command. |
488 int FtpNetworkTransaction::DoCtrlWriteUSER() { | 526 int FtpNetworkTransaction::DoCtrlWriteUSER() { |
489 std::string command = "USER"; | 527 std::string command = "USER " + WideToUTF8(username_); |
wtc
2009/08/25 20:52:50
Can you add a comment to the header to explain why
| |
490 if (request_->url.has_username()) { | |
491 command.append(" "); | |
492 command.append(request_->url.username()); | |
493 } else { | |
494 is_anonymous_ = true; | |
495 command.append(" anonymous"); | |
496 } | |
497 next_state_ = STATE_CTRL_READ; | 528 next_state_ = STATE_CTRL_READ; |
498 return SendFtpCommand(command, COMMAND_USER); | 529 return SendFtpCommand(command, COMMAND_USER); |
499 } | 530 } |
500 | 531 |
501 int FtpNetworkTransaction::ProcessResponseUSER( | 532 int FtpNetworkTransaction::ProcessResponseUSER( |
502 const FtpCtrlResponse& response) { | 533 const FtpCtrlResponse& response) { |
503 switch (GetErrorClass(response.status_code)) { | 534 switch (GetErrorClass(response.status_code)) { |
504 case ERROR_CLASS_OK: | 535 case ERROR_CLASS_OK: |
505 next_state_ = STATE_CTRL_WRITE_SYST; | 536 next_state_ = STATE_CTRL_WRITE_SYST; |
506 break; | 537 break; |
507 case ERROR_CLASS_INFO_NEEDED: | 538 case ERROR_CLASS_INFO_NEEDED: |
508 next_state_ = STATE_CTRL_WRITE_PASS; | 539 next_state_ = STATE_CTRL_WRITE_PASS; |
509 break; | 540 break; |
510 case ERROR_CLASS_TRANSIENT_ERROR: | 541 case ERROR_CLASS_TRANSIENT_ERROR: |
511 if (response.status_code == 421) | 542 if (response.status_code == 421) |
512 return Stop(ERR_FAILED); | 543 return Stop(ERR_FAILED); |
513 break; | 544 break; |
514 case ERROR_CLASS_PERMANENT_ERROR: | 545 case ERROR_CLASS_PERMANENT_ERROR: |
515 return Stop(ERR_FAILED); | 546 return Stop(ERR_FAILED); |
516 default: | 547 default: |
517 NOTREACHED(); | 548 NOTREACHED(); |
518 return Stop(ERR_UNEXPECTED); | 549 return Stop(ERR_UNEXPECTED); |
519 } | 550 } |
520 return OK; | 551 return OK; |
521 } | 552 } |
522 | 553 |
523 // PASS command. | 554 // PASS command. |
524 int FtpNetworkTransaction::DoCtrlWritePASS() { | 555 int FtpNetworkTransaction::DoCtrlWritePASS() { |
525 std::string command = "PASS"; | 556 std::string command = "PASS " + WideToUTF8(password_); |
eroman
2009/09/01 07:12:37
PLEASE READ: This looks dangerous!
|username_| an
| |
526 if (request_->url.has_password()) { | |
527 command.append(" "); | |
528 command.append(request_->url.password()); | |
529 } else { | |
530 command.append(" "); | |
531 command.append("chrome@example.com"); | |
532 } | |
533 next_state_ = STATE_CTRL_READ; | 557 next_state_ = STATE_CTRL_READ; |
534 return SendFtpCommand(command, COMMAND_PASS); | 558 return SendFtpCommand(command, COMMAND_PASS); |
535 } | 559 } |
536 | 560 |
537 int FtpNetworkTransaction::ProcessResponsePASS( | 561 int FtpNetworkTransaction::ProcessResponsePASS( |
538 const FtpCtrlResponse& response) { | 562 const FtpCtrlResponse& response) { |
539 switch (GetErrorClass(response.status_code)) { | 563 switch (GetErrorClass(response.status_code)) { |
540 case ERROR_CLASS_OK: | 564 case ERROR_CLASS_OK: |
541 next_state_ = STATE_CTRL_WRITE_SYST; | 565 next_state_ = STATE_CTRL_WRITE_SYST; |
542 break; | 566 break; |
543 case ERROR_CLASS_INFO_NEEDED: | 567 case ERROR_CLASS_INFO_NEEDED: |
544 next_state_ = STATE_CTRL_WRITE_ACCT; | 568 next_state_ = STATE_CTRL_WRITE_ACCT; |
545 break; | 569 break; |
546 case ERROR_CLASS_TRANSIENT_ERROR: | 570 case ERROR_CLASS_TRANSIENT_ERROR: |
547 if (response.status_code == 421) { | 571 if (response.status_code == 421) { |
548 // TODO(ibrar): Retry here. | 572 // TODO(ibrar): Retry here. |
549 } | 573 } |
550 return Stop(ERR_FAILED); | 574 return Stop(ERR_FAILED); |
551 case ERROR_CLASS_PERMANENT_ERROR: | 575 case ERROR_CLASS_PERMANENT_ERROR: |
552 if (response.status_code == 503) { | 576 if (response.status_code == 503) { |
553 next_state_ = STATE_CTRL_WRITE_USER; | 577 next_state_ = STATE_CTRL_WRITE_USER; |
554 } else { | 578 } else { |
555 // TODO(ibrar): Retry here. | 579 response_.auth_needed = true; |
eroman
2009/09/01 07:12:37
Hm, I dont know about this... will have to look mo
| |
556 return Stop(ERR_FAILED); | 580 return Stop(ERR_FAILED); |
557 } | 581 } |
558 break; | 582 break; |
559 default: | 583 default: |
560 NOTREACHED(); | 584 NOTREACHED(); |
561 return Stop(ERR_UNEXPECTED); | 585 return Stop(ERR_UNEXPECTED); |
562 } | 586 } |
563 return OK; | 587 return OK; |
564 } | 588 } |
565 | 589 |
(...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
974 read_data_buf_->data()[0] = 0; | 998 read_data_buf_->data()[0] = 0; |
975 return data_socket_->Read(read_data_buf_, read_data_buf_len_, | 999 return data_socket_->Read(read_data_buf_, read_data_buf_len_, |
976 &io_callback_); | 1000 &io_callback_); |
977 } | 1001 } |
978 | 1002 |
979 int FtpNetworkTransaction::DoDataReadComplete(int result) { | 1003 int FtpNetworkTransaction::DoDataReadComplete(int result) { |
980 return result; | 1004 return result; |
981 } | 1005 } |
982 | 1006 |
983 } // namespace net | 1007 } // namespace net |
OLD | NEW |