| 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 "webkit/glue/ftp_directory_listing_response_delegate.h" | 5 #include "webkit/glue/ftp_directory_listing_response_delegate.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/i18n/icu_string_conversions.h" | 9 #include "base/i18n/icu_string_conversions.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
| 12 #include "base/sys_string_conversions.h" | 12 #include "base/sys_string_conversions.h" |
| 13 #include "base/time.h" | 13 #include "base/time.h" |
| 14 #include "net/base/escape.h" | 14 #include "net/base/escape.h" |
| 15 #include "net/base/net_errors.h" |
| 15 #include "net/base/net_util.h" | 16 #include "net/base/net_util.h" |
| 17 #include "net/ftp/ftp_directory_listing_parsers.h" |
| 16 #include "net/ftp/ftp_server_type_histograms.h" | 18 #include "net/ftp/ftp_server_type_histograms.h" |
| 17 #include "unicode/ucsdet.h" | 19 #include "unicode/ucsdet.h" |
| 18 #include "webkit/api/public/WebURL.h" | 20 #include "webkit/api/public/WebURL.h" |
| 19 #include "webkit/api/public/WebURLLoaderClient.h" | 21 #include "webkit/api/public/WebURLLoaderClient.h" |
| 20 | 22 |
| 21 using WebKit::WebURLLoader; | 23 using WebKit::WebURLLoader; |
| 22 using WebKit::WebURLLoaderClient; | 24 using WebKit::WebURLLoaderClient; |
| 23 using WebKit::WebURLResponse; | 25 using WebKit::WebURLResponse; |
| 24 | 26 |
| 25 namespace { | 27 namespace { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 } // namespace | 113 } // namespace |
| 112 | 114 |
| 113 namespace webkit_glue { | 115 namespace webkit_glue { |
| 114 | 116 |
| 115 FtpDirectoryListingResponseDelegate::FtpDirectoryListingResponseDelegate( | 117 FtpDirectoryListingResponseDelegate::FtpDirectoryListingResponseDelegate( |
| 116 WebURLLoaderClient* client, | 118 WebURLLoaderClient* client, |
| 117 WebURLLoader* loader, | 119 WebURLLoader* loader, |
| 118 const WebURLResponse& response) | 120 const WebURLResponse& response) |
| 119 : client_(client), | 121 : client_(client), |
| 120 loader_(loader), | 122 loader_(loader), |
| 121 original_response_(response) { | 123 original_response_(response), |
| 124 parser_fallback_(false) { |
| 122 Init(); | 125 Init(); |
| 123 } | 126 } |
| 124 | 127 |
| 125 void FtpDirectoryListingResponseDelegate::OnReceivedData(const char* data, | 128 void FtpDirectoryListingResponseDelegate::OnReceivedData(const char* data, |
| 126 int data_len) { | 129 int data_len) { |
| 130 // Keep the raw data in case we have to use the old parser later. |
| 127 input_buffer_.append(data, data_len); | 131 input_buffer_.append(data, data_len); |
| 128 | 132 |
| 133 if (!parser_fallback_) { |
| 134 if (buffer_.ConsumeData(data, data_len) == net::OK) |
| 135 return; |
| 136 parser_fallback_ = true; |
| 137 } |
| 138 |
| 139 FeedFallbackParser(); |
| 140 SendResponseBufferToClient(); |
| 141 } |
| 142 |
| 143 void FtpDirectoryListingResponseDelegate::OnCompletedRequest() { |
| 144 if (!parser_fallback_) { |
| 145 if (buffer_.ProcessRemainingData() == net::OK) { |
| 146 while (buffer_.EntryAvailable()) |
| 147 AppendEntryToResponseBuffer(buffer_.PopEntry()); |
| 148 SendResponseBufferToClient(); |
| 149 net::UpdateFtpServerTypeHistograms(buffer_.GetServerType()); |
| 150 return; |
| 151 } |
| 152 parser_fallback_ = true; |
| 153 } |
| 154 |
| 155 FeedFallbackParser(); |
| 156 SendResponseBufferToClient(); |
| 157 |
| 158 // Only log the server type if we got enough data to reliably detect it. |
| 159 if (parse_state_.parsed_one) |
| 160 LogFtpServerType(parse_state_.lstyle); |
| 161 } |
| 162 |
| 163 void FtpDirectoryListingResponseDelegate::Init() { |
| 164 memset(&parse_state_, 0, sizeof(parse_state_)); |
| 165 |
| 166 GURL response_url(original_response_.url()); |
| 167 UnescapeRule::Type unescape_rules = UnescapeRule::SPACES | |
| 168 UnescapeRule::URL_SPECIAL_CHARS; |
| 169 std::string unescaped_path = UnescapeURLComponent(response_url.path(), |
| 170 unescape_rules); |
| 171 string16 path_utf16; |
| 172 // Per RFC 2640, FTP servers should use UTF-8 or its proper subset ASCII, |
| 173 // but many old FTP servers use legacy encodings. Try UTF-8 first and |
| 174 // detect the encoding. |
| 175 if (IsStringUTF8(unescaped_path)) { |
| 176 path_utf16 = UTF8ToUTF16(unescaped_path); |
| 177 } else { |
| 178 std::string encoding = DetectEncoding(unescaped_path); |
| 179 // Try the detected encoding. If it fails, resort to the |
| 180 // OS native encoding. |
| 181 if (encoding.empty() || |
| 182 !base::CodepageToUTF16(unescaped_path, encoding.c_str(), |
| 183 base::OnStringConversionError::SUBSTITUTE, |
| 184 &path_utf16)) |
| 185 path_utf16 = WideToUTF16Hack(base::SysNativeMBToWide(unescaped_path)); |
| 186 } |
| 187 |
| 188 response_buffer_ = net::GetDirectoryListingHeader(path_utf16); |
| 189 |
| 190 // If this isn't top level directory (i.e. the path isn't "/",) |
| 191 // add a link to the parent directory. |
| 192 if (response_url.path().length() > 1) { |
| 193 response_buffer_.append( |
| 194 net::GetDirectoryListingEntry(ASCIIToUTF16(".."), |
| 195 std::string(), |
| 196 false, 0, |
| 197 base::Time())); |
| 198 } |
| 199 } |
| 200 |
| 201 void FtpDirectoryListingResponseDelegate::FeedFallbackParser() { |
| 129 // If all we've seen so far is ASCII, encoding_ is empty. Try to detect the | 202 // If all we've seen so far is ASCII, encoding_ is empty. Try to detect the |
| 130 // encoding. We don't do the separate UTF-8 check here because the encoding | 203 // encoding. We don't do the separate UTF-8 check here because the encoding |
| 131 // detection with a longer chunk (as opposed to the relatively short path | 204 // detection with a longer chunk (as opposed to the relatively short path |
| 132 // component of the url) is unlikely to mistake UTF-8 for a legacy encoding. | 205 // component of the url) is unlikely to mistake UTF-8 for a legacy encoding. |
| 133 // If it turns out to be wrong, a separate UTF-8 check has to be added. | 206 // If it turns out to be wrong, a separate UTF-8 check has to be added. |
| 134 // | 207 // |
| 135 // TODO(jungshik): UTF-8 has to be 'enforced' without any heuristics when | 208 // TODO(jungshik): UTF-8 has to be 'enforced' without any heuristics when |
| 136 // we're talking to an FTP server compliant to RFC 2640 (that is, its response | 209 // we're talking to an FTP server compliant to RFC 2640 (that is, its response |
| 137 // to FEAT command includes 'UTF8'). | 210 // to FEAT command includes 'UTF8'). |
| 138 // See http://wiki.filezilla-project.org/Character_Set | 211 // See http://wiki.filezilla-project.org/Character_Set |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 } | 263 } |
| 191 break; | 264 break; |
| 192 case '?': // Junk entry. | 265 case '?': // Junk entry. |
| 193 case '"': // Comment entry. | 266 case '"': // Comment entry. |
| 194 break; | 267 break; |
| 195 default: | 268 default: |
| 196 NOTREACHED(); | 269 NOTREACHED(); |
| 197 break; | 270 break; |
| 198 } | 271 } |
| 199 } | 272 } |
| 200 | |
| 201 SendResponseBufferToClient(); | |
| 202 } | 273 } |
| 203 | 274 |
| 204 void FtpDirectoryListingResponseDelegate::OnCompletedRequest() { | 275 void FtpDirectoryListingResponseDelegate::AppendEntryToResponseBuffer( |
| 205 SendResponseBufferToClient(); | 276 const net::FtpDirectoryListingEntry& entry) { |
| 206 | 277 switch (entry.type) { |
| 207 // Only log the server type if we got enough data to reliably detect it. | 278 case net::FtpDirectoryListingEntry::FILE: |
| 208 if (parse_state_.parsed_one) | 279 response_buffer_.append( |
| 209 LogFtpServerType(parse_state_.lstyle); | 280 net::GetDirectoryListingEntry(entry.name, std::string(), false, |
| 210 } | 281 entry.size, entry.last_modified)); |
| 211 | 282 break; |
| 212 void FtpDirectoryListingResponseDelegate::Init() { | 283 case net::FtpDirectoryListingEntry::DIRECTORY: |
| 213 memset(&parse_state_, 0, sizeof(parse_state_)); | 284 response_buffer_.append( |
| 214 | 285 net::GetDirectoryListingEntry(entry.name, std::string(), true, |
| 215 GURL response_url(original_response_.url()); | 286 0, entry.last_modified)); |
| 216 UnescapeRule::Type unescape_rules = UnescapeRule::SPACES | | 287 break; |
| 217 UnescapeRule::URL_SPECIAL_CHARS; | 288 case net::FtpDirectoryListingEntry::SYMLINK: |
| 218 std::string unescaped_path = UnescapeURLComponent(response_url.path(), | 289 response_buffer_.append( |
| 219 unescape_rules); | 290 net::GetDirectoryListingEntry(entry.name, std::string(), false, |
| 220 string16 path_utf16; | 291 0, entry.last_modified)); |
| 221 // Per RFC 2640, FTP servers should use UTF-8 or its proper subset ASCII, | 292 break; |
| 222 // but many old FTP servers use legacy encodings. Try UTF-8 first and | 293 default: |
| 223 // detect the encoding. | 294 NOTREACHED(); |
| 224 if (IsStringUTF8(unescaped_path)) { | 295 break; |
| 225 path_utf16 = UTF8ToUTF16(unescaped_path); | |
| 226 } else { | |
| 227 std::string encoding = DetectEncoding(unescaped_path); | |
| 228 // Try the detected encoding. If it fails, resort to the | |
| 229 // OS native encoding. | |
| 230 if (encoding.empty() || | |
| 231 !base::CodepageToUTF16(unescaped_path, encoding.c_str(), | |
| 232 base::OnStringConversionError::SUBSTITUTE, | |
| 233 &path_utf16)) | |
| 234 path_utf16 = WideToUTF16Hack(base::SysNativeMBToWide(unescaped_path)); | |
| 235 } | |
| 236 | |
| 237 response_buffer_ = net::GetDirectoryListingHeader(path_utf16); | |
| 238 | |
| 239 // If this isn't top level directory (i.e. the path isn't "/",) | |
| 240 // add a link to the parent directory. | |
| 241 if (response_url.path().length() > 1) { | |
| 242 response_buffer_.append( | |
| 243 net::GetDirectoryListingEntry(ASCIIToUTF16(".."), | |
| 244 std::string(), | |
| 245 false, 0, | |
| 246 base::Time())); | |
| 247 } | 296 } |
| 248 } | 297 } |
| 249 | 298 |
| 250 void FtpDirectoryListingResponseDelegate::SendResponseBufferToClient() { | 299 void FtpDirectoryListingResponseDelegate::SendResponseBufferToClient() { |
| 251 if (!response_buffer_.empty()) { | 300 if (!response_buffer_.empty()) { |
| 252 client_->didReceiveData(loader_, response_buffer_.data(), | 301 client_->didReceiveData(loader_, response_buffer_.data(), |
| 253 response_buffer_.length()); | 302 response_buffer_.length()); |
| 254 response_buffer_.clear(); | 303 response_buffer_.clear(); |
| 255 } | 304 } |
| 256 } | 305 } |
| 257 | 306 |
| 258 } // namespace webkit_glue | 307 } // namespace webkit_glue |
| OLD | NEW |