| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/url_request/url_request_new_ftp_job.h" | 5 #include "net/url_request/url_request_new_ftp_job.h" |
| 6 | 6 |
| 7 #include "base/file_version_info.h" | 7 #include "base/file_version_info.h" |
| 8 #include "base/message_loop.h" |
| 9 #include "net/base/escape.h" |
| 8 #include "net/base/net_util.h" | 10 #include "net/base/net_util.h" |
| 11 #include "net/ftp/ftp_directory_parser.h" |
| 12 #include "net/ftp/ftp_response_info.h" |
| 13 #include "net/ftp/ftp_transaction_factory.h" |
| 9 #include "net/url_request/url_request.h" | 14 #include "net/url_request/url_request.h" |
| 10 #include "net/url_request/url_request_context.h" | 15 #include "net/url_request/url_request_context.h" |
| 11 #include "net/url_request/url_request_error_job.h" | 16 #include "net/url_request/url_request_error_job.h" |
| 12 | 17 |
| 13 | |
| 14 URLRequestNewFtpJob::URLRequestNewFtpJob(URLRequest* request) | 18 URLRequestNewFtpJob::URLRequestNewFtpJob(URLRequest* request) |
| 15 : URLRequestJob(request), | 19 : URLRequestJob(request), |
| 16 server_auth_state_(net::AUTH_STATE_DONT_NEED_AUTH), | 20 server_auth_state_(net::AUTH_STATE_DONT_NEED_AUTH), |
| 17 ALLOW_THIS_IN_INITIALIZER_LIST( | 21 ALLOW_THIS_IN_INITIALIZER_LIST( |
| 18 start_callback_(this, &URLRequestNewFtpJob::OnStartCompleted)), | 22 start_callback_(this, &URLRequestNewFtpJob::OnStartCompleted)), |
| 19 ALLOW_THIS_IN_INITIALIZER_LIST( | 23 ALLOW_THIS_IN_INITIALIZER_LIST( |
| 20 read_callback_(this, &URLRequestNewFtpJob::OnReadCompleted)), | 24 read_callback_(this, &URLRequestNewFtpJob::OnReadCompleted)), |
| 21 read_in_progress_(false), | 25 read_in_progress_(false), |
| 22 context_(request->context()) { | 26 context_(request->context()) { |
| 23 } | 27 } |
| 24 | 28 |
| 25 URLRequestNewFtpJob::~URLRequestNewFtpJob() { | 29 URLRequestNewFtpJob::~URLRequestNewFtpJob() { |
| 26 } | 30 } |
| 27 | 31 |
| 28 // static | 32 // static |
| 29 URLRequestJob* URLRequestNewFtpJob::Factory(URLRequest* request, | 33 URLRequestJob* URLRequestNewFtpJob::Factory(URLRequest* request, |
| 30 const std::string& scheme) { | 34 const std::string& scheme) { |
| 31 DCHECK(scheme == "ftp"); | 35 DCHECK(scheme == "ftp"); |
| 32 | 36 |
| 33 if (request->url().has_port() && | 37 if (request->url().has_port() && |
| 34 !net::IsPortAllowedByFtp(request->url().IntPort())) | 38 !net::IsPortAllowedByFtp(request->url().IntPort())) |
| 35 return new URLRequestErrorJob(request, net::ERR_UNSAFE_PORT); | 39 return new URLRequestErrorJob(request, net::ERR_UNSAFE_PORT); |
| 36 | 40 |
| 37 DCHECK(request->context()); | 41 DCHECK(request->context()); |
| 38 DCHECK(request->context()->ftp_transaction_factory()); | 42 DCHECK(request->context()->ftp_transaction_factory()); |
| 39 return new URLRequestNewFtpJob(request); | 43 return new URLRequestNewFtpJob(request); |
| 40 } | 44 } |
| 41 | 45 |
| 42 void URLRequestNewFtpJob::Start() { | 46 void URLRequestNewFtpJob::Start() { |
| 43 NOTIMPLEMENTED(); | 47 DCHECK(!transaction_.get()); |
| 48 request_info_.url = request_->url(); |
| 49 StartTransaction(); |
| 44 } | 50 } |
| 45 | 51 |
| 46 void URLRequestNewFtpJob::Kill() { | 52 void URLRequestNewFtpJob::Kill() { |
| 47 NOTIMPLEMENTED(); | 53 if (!transaction_.get()) |
| 48 } | 54 return; |
| 49 | 55 DestroyTransaction(); |
| 50 uint64 URLRequestNewFtpJob::GetUploadProgress() const { | 56 URLRequestJob::Kill(); |
| 51 NOTIMPLEMENTED(); | |
| 52 return 0; | |
| 53 } | |
| 54 | |
| 55 void URLRequestNewFtpJob::GetResponseInfo() { | |
| 56 NOTIMPLEMENTED(); | |
| 57 } | |
| 58 | |
| 59 int URLRequestNewFtpJob::GetResponseCode() const { | |
| 60 NOTIMPLEMENTED(); | |
| 61 return -1; | |
| 62 } | |
| 63 | |
| 64 bool URLRequestNewFtpJob::GetMoreData() { | |
| 65 NOTIMPLEMENTED(); | |
| 66 return false; | |
| 67 } | 57 } |
| 68 | 58 |
| 69 bool URLRequestNewFtpJob::ReadRawData(net::IOBuffer* buf, | 59 bool URLRequestNewFtpJob::ReadRawData(net::IOBuffer* buf, |
| 70 int buf_size, | 60 int buf_size, |
| 71 int *bytes_read) { | 61 int *bytes_read) { |
| 72 NOTIMPLEMENTED(); | 62 DCHECK_NE(buf_size, 0); |
| 63 DCHECK(bytes_read); |
| 64 DCHECK(!read_in_progress_); |
| 65 if (response_info_ == NULL) { |
| 66 response_info_ = transaction_->GetResponseInfo(); |
| 67 if (response_info_->is_directory_listing) { |
| 68 // Unescape the URL path and pass the raw 8bit directly to the browser. |
| 69 directory_html_ = net::GetDirectoryListingHeader( |
| 70 UnescapeURLComponent(request_->url().path(), |
| 71 UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS)); |
| 72 // If this isn't top level directory (i.e. the path isn't "/",) |
| 73 // add a link to the parent directory. |
| 74 if (request_->url().path().length() > 1) |
| 75 directory_html_.append(net::GetDirectoryListingEntry("..", |
| 76 false, |
| 77 0, |
| 78 base::Time())); |
| 79 } |
| 80 } |
| 81 if (!directory_html_.empty()) { |
| 82 size_t bytes_to_copy = std::min(static_cast<size_t>(buf_size), |
| 83 directory_html_.size()); |
| 84 memcpy(buf->data(), directory_html_.c_str(), bytes_to_copy); |
| 85 *bytes_read = bytes_to_copy; |
| 86 directory_html_.erase(0, bytes_to_copy); |
| 87 return true; |
| 88 } |
| 89 int rv = transaction_->Read(buf, buf_size, &read_callback_); |
| 90 if (response_info_->is_directory_listing) { |
| 91 std::string file_entry; |
| 92 if (rv > 0) { |
| 93 std::string line; |
| 94 buf->data()[rv] = 0; |
| 95 std::istringstream iss(buf->data()); |
| 96 while (getline(iss, line)) { |
| 97 struct net::ListState state; |
| 98 struct net::ListResult result; |
| 99 // TODO(ibrar): Use a more descriptive variable name than 'lt', which |
| 100 // looks like 'it'. |
| 101 net::LineType lt = ParseFTPLine(line.c_str(), &state, &result); |
| 102 switch (lt) { |
| 103 case net::FTP_TYPE_DIRECTORY: |
| 104 file_entry.append(net::GetDirectoryListingEntry(result.fe_fname, |
| 105 true, |
| 106 rv, |
| 107 base::Time())); |
| 108 break; |
| 109 case net::FTP_TYPE_FILE: |
| 110 file_entry.append(net::GetDirectoryListingEntry(result.fe_fname, |
| 111 false, |
| 112 rv, |
| 113 base::Time())); |
| 114 break; |
| 115 case net::FTP_TYPE_SYMLINK: |
| 116 case net::FTP_TYPE_JUNK: |
| 117 case net::FTP_TYPE_COMMENT: |
| 118 break; |
| 119 default: |
| 120 break; |
| 121 } |
| 122 } |
| 123 memcpy(buf->data(), file_entry.c_str(), file_entry.length()); |
| 124 *bytes_read = file_entry.length(); |
| 125 return true; |
| 126 } |
| 127 } else { |
| 128 rv = transaction_->Read(buf, buf_size, &read_callback_); |
| 129 } |
| 130 if (rv >= 0) { |
| 131 *bytes_read = rv; |
| 132 return true; |
| 133 } |
| 134 if (rv == net::ERR_IO_PENDING) { |
| 135 read_in_progress_ = true; |
| 136 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); |
| 137 } else { |
| 138 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv)); |
| 139 } |
| 73 return false; | 140 return false; |
| 74 } | 141 } |
| 75 | 142 |
| 76 void URLRequestNewFtpJob::OnStartCompleted(int result) { | 143 void URLRequestNewFtpJob::OnStartCompleted(int result) { |
| 77 NOTIMPLEMENTED(); | 144 // If the request was destroyed, then there is no more work to do. |
| 145 if (!request_ || !request_->delegate()) |
| 146 return; |
| 147 // If the transaction was destroyed, then the job was cancelled, and |
| 148 // we can just ignore this notification. |
| 149 if (!transaction_.get()) |
| 150 return; |
| 151 // Clear the IO_PENDING status |
| 152 SetStatus(URLRequestStatus()); |
| 153 if (result == net::OK) { |
| 154 URLRequestJob::NotifyHeadersComplete(); |
| 155 } else { |
| 156 NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result)); |
| 157 } |
| 78 } | 158 } |
| 79 | 159 |
| 80 void URLRequestNewFtpJob::OnReadCompleted(int result) { | 160 void URLRequestNewFtpJob::OnReadCompleted(int result) { |
| 81 NOTIMPLEMENTED(); | 161 read_in_progress_ = false; |
| 162 if (result == 0) { |
| 163 NotifyDone(URLRequestStatus()); |
| 164 } else if (result < 0) { |
| 165 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result)); |
| 166 } else { |
| 167 // Clear the IO_PENDING status |
| 168 SetStatus(URLRequestStatus()); |
| 169 } |
| 170 NotifyReadComplete(result); |
| 171 } |
| 172 |
| 173 void URLRequestNewFtpJob::StartTransaction() { |
| 174 // Create a transaction. |
| 175 DCHECK(!transaction_.get()); |
| 176 DCHECK(request_->context()); |
| 177 DCHECK(request_->context()->ftp_transaction_factory()); |
| 178 |
| 179 transaction_.reset( |
| 180 request_->context()->ftp_transaction_factory()->CreateTransaction()); |
| 181 |
| 182 // No matter what, we want to report our status as IO pending since we will |
| 183 // be notifying our consumer asynchronously via OnStartCompleted. |
| 184 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); |
| 185 int rv; |
| 186 if (transaction_.get()) { |
| 187 rv = transaction_->Start(&request_info_, &start_callback_); |
| 188 if (rv == net::ERR_IO_PENDING) |
| 189 return; |
| 190 } else { |
| 191 rv = net::ERR_FAILED; |
| 192 } |
| 193 // The transaction started synchronously, but we need to notify the |
| 194 // URLRequest delegate via the message loop. |
| 195 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( |
| 196 this, &URLRequestNewFtpJob::OnStartCompleted, rv)); |
| 82 } | 197 } |
| 83 | 198 |
| 84 void URLRequestNewFtpJob::DestroyTransaction() { | 199 void URLRequestNewFtpJob::DestroyTransaction() { |
| 85 NOTIMPLEMENTED(); | 200 DCHECK(transaction_.get()); |
| 201 |
| 202 transaction_.reset(); |
| 203 response_info_ = NULL; |
| 86 } | 204 } |
| 87 | |
| 88 void URLRequestNewFtpJob::StartTransaction() { | |
| 89 NOTIMPLEMENTED(); | |
| 90 } | |
| OLD | NEW |